| // SPDX-FileCopyrightText: The Eigen Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #include "packetmath_test_shared.h" | |
| #include <Eigen/Geometry> | |
| #include <Eigen/SparseCore> | |
| template <typename Real> | |
| void comparison_helpers() { | |
| const Real inf = NumTraits<Real>::infinity(); | |
| const Real nan = NumTraits<Real>::quiet_NaN(); | |
| VERIFY(test_isCwiseApprox(inf, inf, true)); | |
| VERIFY(!test_isCwiseApprox(inf, -inf, false)); | |
| VERIFY(!test_isApprox(inf, -inf)); | |
| VERIFY(test_isApprox(inf, inf)); | |
| VERIFY(test_isApprox(nan, nan)); | |
| VERIFY(!test_isMuchSmallerThan(inf, inf)); | |
| VERIFY(!test_isMuchSmallerThan(nan, nan)); | |
| VERIFY(!test_isApproxOrLessThan(inf, -inf)); | |
| VERIFY(!test_isApproxOrLessThan(nan, nan)); | |
| VERIFY(test_isApproxOrLessThan(inf, inf)); | |
| VERIFY(test_isCwiseApprox(nan, nan, true)); | |
| VERIFY(!test_isCwiseApprox(nan, Real(0), false)); | |
| VERIFY(!test_isCwiseApprox(inf, NumTraits<Real>::highest(), false)); | |
| VERIFY(test_isCwiseApprox(Real(0), Real(-0.0), true)); | |
| VERIFY(!test_isCwiseApprox(Real(1), Real(2), false)); | |
| const Real eps = NumTraits<Real>::epsilon(); | |
| const Real near = Real(1) + Real(8) * eps; | |
| VERIFY(test_isCwiseApprox(Real(1), near, false, Real(8) * eps)); | |
| VERIFY(!test_isCwiseApprox(Real(1), near, false, Real(7) * eps)); | |
| VERIFY(test_isCwiseApprox(Real(1), Real(1) + test_precision<Real>() / Real(2), false)); | |
| using Complex = std::complex<Real>; | |
| VERIFY(test_isApprox(Complex(1), Real(1))); | |
| VERIFY(test_isApprox(Real(1), Complex(1))); | |
| VERIFY(test_isMuchSmallerThan(Complex(0), Real(1))); | |
| VERIFY(test_isMuchSmallerThan(Real(0), Complex(1))); | |
| using ArrayType = Array<Complex, 2, 2>; | |
| ArrayType x, y; | |
| x << Complex(inf), Complex(nan), Complex(1), Complex(0); | |
| y = x; | |
| VERIFY(test_isCwiseApprox(x, y, true)); | |
| VERIFY(test_isCwiseApprox(x, y, false)); | |
| y(1, 0) = Complex(1, test_precision<Real>() / Real(2)); | |
| VERIFY(test_isCwiseApprox(x, y, false)); | |
| VERIFY(!test_isCwiseApprox(x, y, true)); | |
| y(0, 0) = Complex(-inf); | |
| VERIFY(!test_isCwiseApprox(x, y, false)); | |
| VERIFY(!test_isCwiseApprox(x, y.row(0), false)); | |
| VERIFY(!test_isApprox(Complex(inf), Complex(inf))); | |
| VERIFY(!test_isApprox(Complex(nan), Complex(nan))); | |
| for (Real scale : | |
| {Real(1), NumTraits<Real>::highest() / Real(32), (numext::numeric_limits<Real>::min)() * Real(32)}) { | |
| x.setConstant(Complex(scale)); | |
| y = Real(2) * x; | |
| VERIFY(!test_isCwiseApprox(x, y, false)); | |
| VERIFY(!test_isApprox(Complex(scale), Complex(Real(2) * scale))); | |
| VERIFY(!test_isMuchSmallerThan(Complex(scale), Complex(Real(2) * scale))); | |
| VERIFY(test_isMuchSmallerThan(x * Real(0), y)); | |
| VERIFY(test_isMuchSmallerThan(x * Real(0), scale)); | |
| VERIFY_IS_EQUAL(test_relative_error(x, y), Real(1)); | |
| VERIFY_IS_EQUAL(test_relative_error(x.real(), y), Real(1)); | |
| VERIFY_IS_EQUAL(test_relative_error(scale, Real(2) * scale), Real(1)); | |
| } | |
| x.setZero(); | |
| y.setZero(); | |
| VERIFY_IS_EQUAL(test_relative_error(x, y), Real(0)); | |
| VERIFY_IS_EQUAL(test_relative_error(Real(0), Real(0)), Real(0)); | |
| y.setOnes(); | |
| VERIFY((numext::isinf)(test_relative_error(x, y))); | |
| const SparseMatrix<Complex> sx = x.matrix().sparseView(); | |
| const SparseMatrix<Complex> sy = y.matrix().sparseView(); | |
| VERIFY(test_isCwiseApprox(sx, sx, true)); | |
| VERIFY(!test_isCwiseApprox(sx, sy, false)); | |
| using Vector = Matrix<Real, 2, 1>; | |
| ParametrizedLine<Real, 2> a(Vector::Ones(), Vector::UnitX()); | |
| ParametrizedLine<Real, 2> b(Vector::Ones(), -Vector::UnitX()); | |
| VERIFY_IS_EQUAL(test_relative_error(a, b), Real(2)); | |
| } | |
| void integer_diagnostics() { | |
| const int low = NumTraits<int>::lowest(); | |
| const int high = NumTraits<int>::highest(); | |
| VERIFY(test_relative_error(low, high) >= 2.0); | |
| VERIFY(test_relative_error(Matrix2i::Constant(low), Matrix2i::Constant(high)) >= 2.0); | |
| VERIFY_IS_EQUAL(test_relative_error(false, false), 0.0f); | |
| VERIFY((numext::isinf)(test_relative_error(false, true))); | |
| VERIFY(test_isCwiseApprox(false, false, true)); | |
| VERIFY(!test_isCwiseApprox(false, true, false)); | |
| VERIFY_IS_EQUAL(test_relative_error(half(1), 2.0f), half(1)); | |
| VERIFY_IS_EQUAL(test_relative_error(bfloat16(1), 2.0f), bfloat16(1)); | |
| } | |
| template <typename Real> | |
| void scaled_comparison_helpers() { | |
| using MatrixType = Matrix<Real, 2, 2>; | |
| const MatrixType zero = MatrixType::Zero(); | |
| for (Index i = 0; i < zero.size(); ++i) { | |
| MatrixType value = zero; | |
| value(i) = NumTraits<Real>::quiet_NaN(); | |
| VERIFY(!verifyIsApproxScaled(value, zero, Real(1))); | |
| VERIFY(!verifyIsApproxScaled(value.array(), zero.array(), Real(1))); | |
| } | |
| VERIFY(!verifyIsApproxScaled(zero, zero, NumTraits<Real>::infinity())); | |
| VERIFY(!verifyIsApproxScaled(zero, zero, NumTraits<Real>::quiet_NaN())); | |
| const Matrix<Real, Dynamic, Dynamic> empty(0, 3); | |
| VERIFY(verifyIsApproxScaled(empty, empty, Real(1))); | |
| } | |
| void packet_comparison_helpers() { | |
| const double inf = NumTraits<double>::infinity(); | |
| const double opposite = -inf; | |
| const double one = 1, near = 1 + 1e-8; | |
| VERIFY(test::areApprox(&inf, &inf, 1)); | |
| VERIFY(!test::areApprox(&inf, &opposite, 1)); | |
| VERIFY(!test::areApprox(&inf, &opposite, 1, NumTraits<double>::epsilon())); | |
| // Packet checks retain dummy_precision(), which is tighter than the legacy test_precision(). | |
| VERIFY(!test::areApprox(&one, &near, 1)); | |
| } | |
| EIGEN_DECLARE_TEST(numerical_test_helpers) { | |
| comparison_helpers<float>(); | |
| comparison_helpers<double>(); | |
| comparison_helpers<long double>(); | |
| integer_diagnostics(); | |
| scaled_comparison_helpers<float>(); | |
| scaled_comparison_helpers<double>(); | |
| packet_comparison_helpers(); | |
| } |