// L============================================================================= // L This software is distributed under the MIT license. // L Copyright 2021 Péter Kardos // L============================================================================= #pragma once // Specialization for floats. #include "../IoStream.hpp" #include "../Matrix.hpp" #include "../Vector.hpp" #include namespace mathter { template bool AlmostEqual(T d1, T d2, std::true_type) { if (std::abs(d1) < 1e-38 && std::abs(d2) < 1e-38) { return true; } if ((d1 == 0 && d2 < 1e-4) || (d2 == 0 && d1 < 1e-4)) { return true; } T scaler = pow(T(10), floor(std::log10(std::abs(d1)))); d1 /= scaler; d2 /= scaler; d1 *= T(1000.0); d2 *= T(1000.0); return round(d1) == round(d2); } // Specialization for int, complex and custom types: simple equality. template bool AlmostEqual(T d1, T d2, std::false_type) { return d1 == d2; } // Check equivalence with tolerance. template ::value && traits::NotMatrix::value && traits::NotQuaternion::value>> bool AlmostEqual(T d1, U d2) { using P = traits::MatMulElemT; return AlmostEqual(P(d1), P(d2), std::integral_constant::value>()); } template bool AlmostEqual(const Vector& lhs, const Vector& rhs) { bool eq = true; for (auto i : impl::Range(Dim)) { eq = eq && AlmostEqual(lhs[i], rhs[i]); } return eq; } template bool AlmostEqual(const Quaternion& lhs, const Quaternion& rhs) { bool eq = true; for (auto i : impl::Range(4)) { eq = eq && AlmostEqual(lhs.vec[i], rhs.vec[i]); } return eq; } template bool AlmostEqual(const Matrix& lhs, const Matrix& rhs) { bool eq = true; for (auto i : impl::Range(Rows)) { for (auto j : impl::Range(Columns)) { eq = eq && AlmostEqual(lhs(i, j), rhs(i, j)); } } return eq; } // Floating point comparison helper class, works like Catch2 units testing framework's float Approx. template struct ApproxHelper { ApproxHelper() {} explicit ApproxHelper(LinalgClass object) { this->object = object; } LinalgClass object; }; template bool operator==(const ApproxHelper& lhs, const LinalgClass2& rhs) { return AlmostEqual(lhs.object, rhs); } template bool operator==(const LinalgClass1& lhs, const ApproxHelper& rhs) { return AlmostEqual(rhs.object, lhs); } template bool operator==(const ApproxHelper& lhs, const ApproxHelper& rhs) { return AlmostEqual(lhs.object, rhs.object); } template std::ostream& operator<<(std::ostream& os, const ApproxHelper& arg) { os << arg.object; return os; } template ApproxHelper ApproxVec(const LinalgClass& arg) { return ApproxHelper{ arg }; } } // namespace mathter