From 122befe54cc0c31273d9e1caef80b49ad834bf4c Mon Sep 17 00:00:00 2001 From: Charles Schlosser Date: Fri, 12 Apr 2024 19:35:04 +0000 Subject: [PATCH] Fix "unary minus operator applied to unsigned type, result still unsigned" on MSVC and other stupid warnings --- Eigen/src/Core/GenericPacketMath.h | 20 ++++--- Eigen/src/Core/MathFunctions.h | 24 ++++++++ Eigen/src/Core/arch/AVX512/PacketMath.h | 11 +--- Eigen/src/Core/arch/SSE/PacketMath.h | 6 +- Eigen/src/Core/functors/UnaryFunctors.h | 5 +- test/array_cwise.cpp | 8 +-- test/bfloat16_float.cpp | 2 +- test/geo_eulerangles.cpp | 74 +++++++++++++------------ test/indexed_view.cpp | 1 + test/mapstaticmethods.cpp | 57 +++++++++---------- test/numext.cpp | 55 +++++++++++++++--- test/packetmath.cpp | 38 +++++++++++-- test/packetmath_test_shared.h | 7 ++- test/sparse_vector.cpp | 28 +++++----- test/vectorization_logic.cpp | 7 ++- 15 files changed, 215 insertions(+), 128 deletions(-) diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index eab717feb..61f0eb95b 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h @@ -335,12 +335,9 @@ EIGEN_DEVICE_FUNC inline Packet psub(const Packet& a, const Packet& b) { /** \internal \returns -a (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pnegate(const Packet& a) { - return -a; -} - -template <> -EIGEN_DEVICE_FUNC inline bool pnegate(const bool& a) { - return !a; + EIGEN_STATIC_ASSERT((!is_same::type, bool>::value), + NEGATE IS NOT DEFINED FOR BOOLEAN TYPES) + return numext::negate(a); } /** \internal \returns conj(a) (coeff-wise) */ @@ -1117,8 +1114,9 @@ EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog10(const Packet& /** \internal \returns the log10 of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2(const Packet& a) { - typedef typename internal::unpacket_traits::type Scalar; - return pmul(pset1(Scalar(EIGEN_LOG2E)), plog(a)); + using Scalar = typename internal::unpacket_traits::type; + using RealScalar = typename NumTraits::Real; + return pmul(pset1(Scalar(RealScalar(EIGEN_LOG2E))), plog(a)); } /** \internal \returns the square-root of \a a (coeff-wise) */ @@ -1403,6 +1401,12 @@ EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& /*kernel*/) { template struct Selector { bool select[N]; + template + EIGEN_DEVICE_FUNC inline MaskType mask(size_t begin = 0, size_t end = N) const { + MaskType res = 0; + for (size_t i = begin; i < end; i++) res |= (static_cast(select[i]) << i); + return res; + } }; template diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index f907d1e9b..2a42b1864 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -861,6 +861,25 @@ struct sign_retval { typedef Scalar type; }; +// suppress "unary minus operator applied to unsigned type, result still unsigned" warnings on MSVC +// note: `0 - a` is distinct from `-a` when Scalar is a floating point type and `a` is zero + +template ::IsInteger> +struct negate_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar run(const Scalar& a) { return -a; } +}; + +template +struct negate_impl { + EIGEN_STATIC_ASSERT((!is_same::value), NEGATE IS NOT DEFINED FOR BOOLEAN TYPES) + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar run(const Scalar& a) { return Scalar(0) - a; } +}; + +template +struct negate_retval { + typedef Scalar type; +}; + template ::type>::IsInteger> struct nearest_integer_impl { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run_floor(const Scalar& x) { @@ -1066,6 +1085,11 @@ EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(sign, Scalar) sign(const Scalar& return EIGEN_MATHFUNC_IMPL(sign, Scalar)::run(x); } +template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(negate, Scalar) negate(const Scalar& x) { + return EIGEN_MATHFUNC_IMPL(negate, Scalar)::run(x); +} + template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); diff --git a/Eigen/src/Core/arch/AVX512/PacketMath.h b/Eigen/src/Core/arch/AVX512/PacketMath.h index c1bed8020..5c535567b 100644 --- a/Eigen/src/Core/arch/AVX512/PacketMath.h +++ b/Eigen/src/Core/arch/AVX512/PacketMath.h @@ -2147,20 +2147,13 @@ EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& kernel) { template <> EIGEN_STRONG_INLINE Packet16f pblend(const Selector<16>& ifPacket, const Packet16f& thenPacket, const Packet16f& elsePacket) { - __mmask16 m = (ifPacket.select[0]) | (ifPacket.select[1] << 1) | (ifPacket.select[2] << 2) | - (ifPacket.select[3] << 3) | (ifPacket.select[4] << 4) | (ifPacket.select[5] << 5) | - (ifPacket.select[6] << 6) | (ifPacket.select[7] << 7) | (ifPacket.select[8] << 8) | - (ifPacket.select[9] << 9) | (ifPacket.select[10] << 10) | (ifPacket.select[11] << 11) | - (ifPacket.select[12] << 12) | (ifPacket.select[13] << 13) | (ifPacket.select[14] << 14) | - (ifPacket.select[15] << 15); + __mmask16 m = ifPacket.mask<__mmask16>(); return _mm512_mask_blend_ps(m, elsePacket, thenPacket); } template <> EIGEN_STRONG_INLINE Packet8d pblend(const Selector<8>& ifPacket, const Packet8d& thenPacket, const Packet8d& elsePacket) { - __mmask8 m = (ifPacket.select[0]) | (ifPacket.select[1] << 1) | (ifPacket.select[2] << 2) | - (ifPacket.select[3] << 3) | (ifPacket.select[4] << 4) | (ifPacket.select[5] << 5) | - (ifPacket.select[6] << 6) | (ifPacket.select[7] << 7); + __mmask8 m = ifPacket.mask<__mmask8>(); return _mm512_mask_blend_pd(m, elsePacket, thenPacket); } diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index 008109adf..e91ef4d29 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -296,6 +296,7 @@ struct packet_traits : default_packet_traits { HasMax = 0, HasConj = 0, HasSqrt = 1, + HasNegate = 0, HasSign = 0 // Don't try to vectorize psign = identity. }; }; @@ -601,11 +602,6 @@ EIGEN_STRONG_INLINE Packet4i pnegate(const Packet4i& a) { return psub(pzero(a), a); } -template <> -EIGEN_STRONG_INLINE Packet16b pnegate(const Packet16b& a) { - return a; -} - template <> EIGEN_STRONG_INLINE Packet4f pconj(const Packet4f& a) { return a; diff --git a/Eigen/src/Core/functors/UnaryFunctors.h b/Eigen/src/Core/functors/UnaryFunctors.h index 2f9b920d6..8d95819b0 100644 --- a/Eigen/src/Core/functors/UnaryFunctors.h +++ b/Eigen/src/Core/functors/UnaryFunctors.h @@ -24,7 +24,7 @@ namespace internal { */ template struct scalar_opposite_op { - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return -a; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::negate(a); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pnegate(a); @@ -455,8 +455,9 @@ struct functor_traits> { */ template struct scalar_log2_op { + using RealScalar = typename NumTraits::Real; EIGEN_DEVICE_FUNC inline const Scalar operator()(const Scalar& a) const { - return Scalar(EIGEN_LOG2E) * numext::log(a); + return Scalar(RealScalar(EIGEN_LOG2E)) * numext::log(a); } template EIGEN_DEVICE_FUNC inline Packet packetOp(const Packet& a) const { diff --git a/test/array_cwise.cpp b/test/array_cwise.cpp index 543ef2e7a..9fb104cb8 100644 --- a/test/array_cwise.cpp +++ b/test/array_cwise.cpp @@ -614,9 +614,9 @@ void array_generic(const ArrayType& m) { VERIFY(o2.cols() == cols); ArrayType2 o3(rows, cols); - VERIFY(o3(0) == Scalar(rows) && o3(1) == Scalar(cols)); + VERIFY(o3(0) == RealScalar(rows) && o3(1) == RealScalar(cols)); ArrayType2 o4(static_cast(rows), static_cast(cols)); - VERIFY(o4(0) == Scalar(rows) && o4(1) == Scalar(cols)); + VERIFY(o4(0) == RealScalar(rows) && o4(1) == RealScalar(cols)); } { TwoDArrayType o1{rows, cols}; @@ -627,9 +627,9 @@ void array_generic(const ArrayType& m) { VERIFY(o2.cols() == cols); ArrayType2 o3{rows, cols}; - VERIFY(o3(0) == Scalar(rows) && o3(1) == Scalar(cols)); + VERIFY(o3(0) == RealScalar(rows) && o3(1) == RealScalar(cols)); ArrayType2 o4{int(rows), int(cols)}; - VERIFY(o4(0) == Scalar(rows) && o4(1) == Scalar(cols)); + VERIFY(o4(0) == RealScalar(rows) && o4(1) == RealScalar(cols)); } } diff --git a/test/bfloat16_float.cpp b/test/bfloat16_float.cpp index 922a6d108..5be49d910 100644 --- a/test/bfloat16_float.cpp +++ b/test/bfloat16_float.cpp @@ -82,7 +82,7 @@ void test_conversion() { // Conversion to bool VERIFY_IS_EQUAL(static_cast(bfloat16(3)), true); VERIFY_IS_EQUAL(static_cast(bfloat16(0.33333f)), true); - VERIFY_IS_EQUAL(bfloat16(-0.0), false); + VERIFY_IS_EQUAL(static_cast(bfloat16(-0.0)), false); VERIFY_IS_EQUAL(static_cast(bfloat16(0.0)), false); // Explicit conversion to float. diff --git a/test/geo_eulerangles.cpp b/test/geo_eulerangles.cpp index 3d443de43..11c044934 100644 --- a/test/geo_eulerangles.cpp +++ b/test/geo_eulerangles.cpp @@ -23,6 +23,7 @@ void verify_euler(const Matrix& ea, int i, int j, int k) { typedef AngleAxis AngleAxisx; const Matrix3 m(AngleAxisx(ea[0], Vector3::Unit(i)) * AngleAxisx(ea[1], Vector3::Unit(j)) * AngleAxisx(ea[2], Vector3::Unit(k))); + const Scalar kPi = Scalar(EIGEN_PI); // Test non-canonical eulerAngles { @@ -33,11 +34,11 @@ void verify_euler(const Matrix& ea, int i, int j, int k) { // approx_or_less_than does not work for 0 VERIFY(0 < eabis[0] || test_isMuchSmallerThan(eabis[0], Scalar(1))); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], Scalar(EIGEN_PI)); - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[1]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(EIGEN_PI)); - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[2]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], kPi); + VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[1]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], kPi); + VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[2]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], kPi); } // Test canonicalEulerAngles @@ -47,20 +48,20 @@ void verify_euler(const Matrix& ea, int i, int j, int k) { AngleAxisx(eabis[2], Vector3::Unit(k))); VERIFY_IS_APPROX(m, mbis); - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[0]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[0]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], kPi); if (i != k) { // Tait-Bryan sequence - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI / 2), eabis[1]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(EIGEN_PI / 2)); + VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(kPi / 2), eabis[1]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(kPi / 2)); } else { // Proper Euler sequence // approx_or_less_than does not work for 0 VERIFY(0 < eabis[1] || test_isMuchSmallerThan(eabis[1], Scalar(1))); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], kPi); } - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[2]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[2]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], kPi); } } @@ -100,7 +101,10 @@ void eulerangles() { typedef Quaternion Quaternionx; typedef AngleAxis AngleAxisx; - Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); + const Scalar kPi = Scalar(EIGEN_PI); + const Scalar smallVal = static_cast(0.001); + + Scalar a = internal::random(-kPi, kPi); Quaternionx q1; q1 = AngleAxisx(a, Vector3::Random().normalized()); Matrix3 m; @@ -120,65 +124,65 @@ void eulerangles() { check_all_var(ea); // Check with random angles in range [-pi:pi]x[-pi:pi]x[-pi:pi]. - ea = Array3::Random() * Scalar(EIGEN_PI); + ea = Array3::Random() * kPi; check_all_var(ea); - auto test_with_some_zeros = [](const Vector3& eaz) { + auto test_with_some_zeros = [=](const Vector3& eaz) { check_all_var(eaz); Vector3 ea_glz = eaz; ea_glz[0] = Scalar(0); check_all_var(ea_glz); - ea_glz[0] = internal::random(-0.001, 0.001); + ea_glz[0] = internal::random(-smallVal, smallVal); check_all_var(ea_glz); ea_glz[2] = Scalar(0); check_all_var(ea_glz); - ea_glz[2] = internal::random(-0.001, 0.001); + ea_glz[2] = internal::random(-smallVal, smallVal); check_all_var(ea_glz); }; // Check gimbal lock configurations and a bit noisy gimbal locks Vector3 ea_gl = ea; - ea_gl[1] = EIGEN_PI / 2; + ea_gl[1] = kPi / 2; test_with_some_zeros(ea_gl); - ea_gl[1] += internal::random(-0.001, 0.001); + ea_gl[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_gl[1] = -EIGEN_PI / 2; + ea_gl[1] = -kPi / 2; test_with_some_zeros(ea_gl); - ea_gl[1] += internal::random(-0.001, 0.001); + ea_gl[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_gl[1] = EIGEN_PI / 2; + ea_gl[1] = kPi / 2; ea_gl[2] = ea_gl[0]; test_with_some_zeros(ea_gl); - ea_gl[1] += internal::random(-0.001, 0.001); + ea_gl[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_gl[1] = -EIGEN_PI / 2; + ea_gl[1] = -kPi / 2; test_with_some_zeros(ea_gl); - ea_gl[1] += internal::random(-0.001, 0.001); + ea_gl[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); // Similar to above, but with pi instead of pi/2 Vector3 ea_pi = ea; - ea_pi[1] = EIGEN_PI; + ea_pi[1] = kPi; test_with_some_zeros(ea_gl); - ea_pi[1] += internal::random(-0.001, 0.001); + ea_pi[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_pi[1] = -EIGEN_PI; + ea_pi[1] = -kPi; test_with_some_zeros(ea_gl); - ea_pi[1] += internal::random(-0.001, 0.001); + ea_pi[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_pi[1] = EIGEN_PI; + ea_pi[1] = kPi; ea_pi[2] = ea_pi[0]; test_with_some_zeros(ea_gl); - ea_pi[1] += internal::random(-0.001, 0.001); + ea_pi[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea_pi[1] = -EIGEN_PI; + ea_pi[1] = -kPi; test_with_some_zeros(ea_gl); - ea_pi[1] += internal::random(-0.001, 0.001); + ea_pi[1] += internal::random(-smallVal, smallVal); test_with_some_zeros(ea_gl); - ea[2] = ea[0] = internal::random(0, Scalar(EIGEN_PI)); + ea[2] = ea[0] = internal::random(0, kPi); check_all_var(ea); - ea[0] = ea[1] = internal::random(0, Scalar(EIGEN_PI)); + ea[0] = ea[1] = internal::random(0, kPi); check_all_var(ea); ea[1] = 0; diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index 1f1e80861..064cc4ac7 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp @@ -790,6 +790,7 @@ void check_tutorial_examples() { VERIFY_IS_EQUAL(int(slice1.SizeAtCompileTime), 6); VERIFY_IS_EQUAL(int(slice2.SizeAtCompileTime), 6); auto slice3 = A(all, seq(fix<0>, last, fix<2>)); + TEST_SET_BUT_UNUSED_VARIABLE(slice3) VERIFY_IS_EQUAL(int(slice3.RowsAtCompileTime), kRows); VERIFY_IS_EQUAL(int(slice3.ColsAtCompileTime), (kCols + 1) / 2); } diff --git a/test/mapstaticmethods.cpp b/test/mapstaticmethods.cpp index ac90bdc3b..b18b24a76 100644 --- a/test/mapstaticmethods.cpp +++ b/test/mapstaticmethods.cpp @@ -9,21 +9,14 @@ #include "main.h" -// GCC<=4.8 has spurious shadow warnings, because `ptr` re-appears inside template instantiations -// workaround: put these in an anonymous namespace -namespace { -float* ptr; -const float* const_ptr; -} // namespace - template struct mapstaticmethods_impl {}; template struct mapstaticmethods_impl { - static void run(const PlainObjectType& m) { - mapstaticmethods_impl::run(m); + static void run(const PlainObjectType& m, float* ptr, const float* const_ptr) { + mapstaticmethods_impl::run(m, ptr, const_ptr); int i = internal::random(2, 5), j = internal::random(2, 5); @@ -66,7 +59,7 @@ struct mapstaticmethods_impl { template struct mapstaticmethods_impl { - static void run(const PlainObjectType& m) { + static void run(const PlainObjectType& m, float* ptr, const float* const_ptr) { Index rows = m.rows(), cols = m.cols(); int i = internal::random(2, 5), j = internal::random(2, 5); @@ -110,7 +103,7 @@ struct mapstaticmethods_impl { template struct mapstaticmethods_impl { - static void run(const PlainObjectType& v) { + static void run(const PlainObjectType& v, float* ptr, const float* const_ptr) { Index size = v.size(); int i = internal::random(2, 5); @@ -133,34 +126,34 @@ struct mapstaticmethods_impl { }; template -void mapstaticmethods(const PlainObjectType& m) { - mapstaticmethods_impl::run(m); +void mapstaticmethods(const PlainObjectType& m, float* ptr, const float* const_ptr) { + mapstaticmethods_impl::run(m, ptr, const_ptr); VERIFY(true); // just to avoid 'unused function' warning } EIGEN_DECLARE_TEST(mapstaticmethods) { - ptr = internal::aligned_new(1000); + float* ptr = internal::aligned_new(1000); for (int i = 0; i < 1000; i++) ptr[i] = float(i); - const_ptr = ptr; + const float* const_ptr = ptr; - CALL_SUBTEST_1((mapstaticmethods(Matrix()))); - CALL_SUBTEST_1((mapstaticmethods(Vector2f()))); - CALL_SUBTEST_2((mapstaticmethods(Vector3f()))); - CALL_SUBTEST_2((mapstaticmethods(Matrix2f()))); - CALL_SUBTEST_3((mapstaticmethods(Matrix4f()))); - CALL_SUBTEST_3((mapstaticmethods(Array4f()))); - CALL_SUBTEST_4((mapstaticmethods(Array3f()))); - CALL_SUBTEST_4((mapstaticmethods(Array33f()))); - CALL_SUBTEST_5((mapstaticmethods(Array44f()))); - CALL_SUBTEST_5((mapstaticmethods(VectorXf(1)))); - CALL_SUBTEST_5((mapstaticmethods(VectorXf(8)))); - CALL_SUBTEST_6((mapstaticmethods(MatrixXf(1, 1)))); - CALL_SUBTEST_6((mapstaticmethods(MatrixXf(5, 7)))); - CALL_SUBTEST_7((mapstaticmethods(ArrayXf(1)))); - CALL_SUBTEST_7((mapstaticmethods(ArrayXf(5)))); - CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(1, 1)))); - CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(8, 6)))); + CALL_SUBTEST_1((mapstaticmethods(Matrix(), ptr, const_ptr))); + CALL_SUBTEST_1((mapstaticmethods(Vector2f(), ptr, const_ptr))); + CALL_SUBTEST_2((mapstaticmethods(Vector3f(), ptr, const_ptr))); + CALL_SUBTEST_2((mapstaticmethods(Matrix2f(), ptr, const_ptr))); + CALL_SUBTEST_3((mapstaticmethods(Matrix4f(), ptr, const_ptr))); + CALL_SUBTEST_3((mapstaticmethods(Array4f(), ptr, const_ptr))); + CALL_SUBTEST_4((mapstaticmethods(Array3f(), ptr, const_ptr))); + CALL_SUBTEST_4((mapstaticmethods(Array33f(), ptr, const_ptr))); + CALL_SUBTEST_5((mapstaticmethods(Array44f(), ptr, const_ptr))); + CALL_SUBTEST_5((mapstaticmethods(VectorXf(1), ptr, const_ptr))); + CALL_SUBTEST_5((mapstaticmethods(VectorXf(8), ptr, const_ptr))); + CALL_SUBTEST_6((mapstaticmethods(MatrixXf(1, 1), ptr, const_ptr))); + CALL_SUBTEST_6((mapstaticmethods(MatrixXf(5, 7), ptr, const_ptr))); + CALL_SUBTEST_7((mapstaticmethods(ArrayXf(1), ptr, const_ptr))); + CALL_SUBTEST_7((mapstaticmethods(ArrayXf(5), ptr, const_ptr))); + CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(1, 1), ptr, const_ptr))); + CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(8, 6), ptr, const_ptr))); internal::aligned_delete(ptr, 1000); } diff --git a/test/numext.cpp b/test/numext.cpp index ac9b66d73..a2d511bcb 100644 --- a/test/numext.cpp +++ b/test/numext.cpp @@ -33,27 +33,47 @@ bool test_is_equal_or_nans(const T& actual, const U& expected) { #define VERIFY_IS_EQUAL_OR_NANS(a, b) VERIFY(test_is_equal_or_nans(a, b)) +template +void check_negate() { + Index size = 1000; + for (Index i = 0; i < size; i++) { + T val = i == 0 ? T(0) : internal::random(T(0), NumTraits::highest()); + T neg_val = numext::negate(val); + VERIFY_IS_EQUAL(T(val + neg_val), T(0)); + VERIFY_IS_EQUAL(numext::negate(neg_val), val); + } +} + template void check_abs() { typedef typename NumTraits::Real Real; Real zero(0); - if (NumTraits::IsSigned) VERIFY_IS_EQUAL(numext::abs(-T(1)), T(1)); + if (NumTraits::IsSigned) VERIFY_IS_EQUAL(numext::abs(numext::negate(T(1))), T(1)); VERIFY_IS_EQUAL(numext::abs(T(0)), T(0)); VERIFY_IS_EQUAL(numext::abs(T(1)), T(1)); for (int k = 0; k < 100; ++k) { T x = internal::random(); - if (!internal::is_same::value) x = x / Real(2); + x = x / Real(2); if (NumTraits::IsSigned) { - VERIFY_IS_EQUAL(numext::abs(x), numext::abs(-x)); - VERIFY(numext::abs(-x) >= zero); + VERIFY_IS_EQUAL(numext::abs(x), numext::abs(numext::negate(x))); + VERIFY(numext::abs(numext::negate(x)) >= zero); } VERIFY(numext::abs(x) >= zero); VERIFY_IS_APPROX(numext::abs2(x), numext::abs2(numext::abs(x))); } } +template <> +void check_abs() { + for (bool x : {true, false}) { + VERIFY_IS_EQUAL(numext::abs(x), x); + VERIFY(numext::abs(x) >= false); + VERIFY_IS_EQUAL(numext::abs2(x), numext::abs2(numext::abs(x))); + } +} + template void check_arg() { typedef typename NumTraits::Real Real; @@ -236,16 +256,17 @@ struct check_signbit_impl { negative_values = {static_cast(-1), static_cast(NumTraits::lowest())}; non_negative_values = {static_cast(0), static_cast(1), static_cast(NumTraits::highest())}; } else { - // has sign bit - const T neg_zero = static_cast(-0.0); - const T neg_one = static_cast(-1.0); - const T neg_inf = -std::numeric_limits::infinity(); - const T neg_nan = -std::numeric_limits::quiet_NaN(); // does not have sign bit const T pos_zero = static_cast(0.0); const T pos_one = static_cast(1.0); const T pos_inf = std::numeric_limits::infinity(); const T pos_nan = std::numeric_limits::quiet_NaN(); + // has sign bit + const T neg_zero = numext::negate(pos_zero); + const T neg_one = numext::negate(pos_one); + const T neg_inf = numext::negate(pos_inf); + const T neg_nan = numext::negate(pos_nan); + negative_values = {neg_zero, neg_one, neg_inf, neg_nan}; non_negative_values = {pos_zero, pos_one, pos_inf, pos_nan}; } @@ -273,6 +294,22 @@ void check_signbit() { EIGEN_DECLARE_TEST(numext) { for (int k = 0; k < g_repeat; ++k) { + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate()); + CALL_SUBTEST(check_negate >()); + CALL_SUBTEST(check_negate >()); + CALL_SUBTEST(check_abs()); CALL_SUBTEST(check_abs()); CALL_SUBTEST(check_abs()); diff --git a/test/packetmath.cpp b/test/packetmath.cpp index db8c9b5c5..8bfa32196 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -34,11 +34,11 @@ inline T REF_MSUB(const T& a, const T& b, const T& c) { } template inline T REF_NMADD(const T& a, const T& b, const T& c) { - return (-a * b) + c; + return c - a * b; } template inline T REF_NMSUB(const T& a, const T& b, const T& c) { - return (-a * b) - c; + return test::negate(a * b + c); } template inline T REF_DIV(const T& a, const T& b) { @@ -427,6 +427,32 @@ struct eigen_optimization_barrier_test< } }; +template ::HasNegate> +struct negate_test_impl { + static void run_negate(Scalar* data1, Scalar* data2, Scalar* ref, int PacketSize) { + CHECK_CWISE1_IF(HasNegate, test::negate, internal::pnegate); + } + static void run_nmsub(Scalar* data1, Scalar* data2, Scalar* ref, int PacketSize) { + CHECK_CWISE3_IF(HasNegate, REF_NMSUB, internal::pnmsub); + } +}; + +template +struct negate_test_impl { + static void run_negate(Scalar*, Scalar*, Scalar*, int) {} + static void run_nmsub(Scalar*, Scalar*, Scalar*, int) {} +}; + +template +void negate_test(Scalar* data1, Scalar* data2, Scalar* ref, int size) { + negate_test_impl::run_negate(data1, data2, ref, size); +} + +template +void nmsub_test(Scalar* data1, Scalar* data2, Scalar* ref, int size) { + negate_test_impl::run_negate(data1, data2, ref, size); +} + template void packetmath() { typedef internal::packet_traits PacketTraits; @@ -533,7 +559,7 @@ void packetmath() { CHECK_CWISE2_IF(PacketTraits::HasMul, REF_MUL, internal::pmul); CHECK_CWISE2_IF(PacketTraits::HasDiv, REF_DIV, internal::pdiv); - CHECK_CWISE1_IF(PacketTraits::HasNegate, test::negate, internal::pnegate); + negate_test(data1, data2, ref, PacketSize); CHECK_CWISE1_IF(PacketTraits::HasReciprocal, REF_RECIPROCAL, internal::preciprocal); CHECK_CWISE1(numext::conj, internal::pconj); CHECK_CWISE1_IF(PacketTraits::HasSign, numext::sign, internal::psign); @@ -689,7 +715,7 @@ void packetmath() { CHECK_CWISE1_IF(PacketTraits::HasRsqrt, numext::rsqrt, internal::prsqrt); CHECK_CWISE3_IF(true, REF_MADD, internal::pmadd); if (!std::is_same::value && NumTraits::IsSigned) { - CHECK_CWISE3_IF(PacketTraits::HasNegate, REF_NMSUB, internal::pnmsub); + nmsub_test(data1, data2, ref, PacketSize); } // For pmsub, pnmadd, the values can cancel each other to become near zero, @@ -698,11 +724,11 @@ void packetmath() { for (int i = 0; i < PacketSize; ++i) { data1[i] = numext::abs(internal::random()); data1[i + PacketSize] = numext::abs(internal::random()); - data1[i + 2 * PacketSize] = -numext::abs(internal::random()); + data1[i + 2 * PacketSize] = Scalar(0) - numext::abs(internal::random()); } if (!std::is_same::value && NumTraits::IsSigned) { CHECK_CWISE3_IF(true, REF_MSUB, internal::pmsub); - CHECK_CWISE3_IF(PacketTraits::HasNegate, REF_NMADD, internal::pnmadd); + CHECK_CWISE3_IF(true, REF_NMADD, internal::pnmadd); } } diff --git a/test/packetmath_test_shared.h b/test/packetmath_test_shared.h index 86a01fb99..d8de04bbb 100644 --- a/test/packetmath_test_shared.h +++ b/test/packetmath_test_shared.h @@ -22,11 +22,16 @@ namespace Eigen { namespace test { -template +template ::IsSigned, bool> = true> T negate(const T& x) { return -x; } +template ::IsSigned, bool> = true> +T negate(const T& x) { + return T(0) - x; +} + template Map > bits(const T& x) { return Map >(reinterpret_cast(&x)); diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp index 8d47fb00d..e4b196320 100644 --- a/test/sparse_vector.cpp +++ b/test/sparse_vector.cpp @@ -110,29 +110,29 @@ void sparse_vector(int rows, int cols) { // test move { - SparseVectorType v3(std::move(v1)); - VERIFY_IS_APPROX(v3, refV1); - v1 = v3; + SparseVectorType tmp(std::move(v1)); + VERIFY_IS_APPROX(tmp, refV1); + v1 = tmp; } { - SparseVectorType v3; - v3 = std::move(v1); - VERIFY_IS_APPROX(v3, refV1); - v1 = v3; + SparseVectorType tmp; + tmp = std::move(v1); + VERIFY_IS_APPROX(tmp, refV1); + v1 = tmp; } { - SparseVectorType v3(std::move(mv1)); - VERIFY_IS_APPROX(v3, refV1); - mv1 = v3; + SparseVectorType tmp(std::move(mv1)); + VERIFY_IS_APPROX(tmp, refV1); + mv1 = tmp; } { - SparseVectorType v3; - v3 = std::move(mv1); - VERIFY_IS_APPROX(v3, refV1); - mv1 = v3; + SparseVectorType tmp; + tmp = std::move(mv1); + VERIFY_IS_APPROX(tmp, refV1); + mv1 = tmp; } // test conservative resize diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp index aac7248e0..dc1a5c758 100644 --- a/test/vectorization_logic.cpp +++ b/test/vectorization_logic.cpp @@ -287,6 +287,7 @@ template ::type>::half, typename internal::packet_traits::type>::value> struct vectorization_logic_half { + using RealScalar = typename NumTraits::Real; typedef internal::packet_traits PacketTraits; typedef typename internal::unpacket_traits::type>::half PacketType; static constexpr int PacketSize = internal::unpacket_traits::size; @@ -355,10 +356,12 @@ struct vectorization_logic_half { VERIFY(test_assign(Vector1(), Vector1().template segment(0).derived(), EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal, CompleteUnrolling)); - VERIFY(test_assign(Vector1(), Scalar(2.1) * Vector1() - Vector1(), InnerVectorizedTraversal, CompleteUnrolling)); + VERIFY(test_assign(Vector1(), Scalar(RealScalar(2.1)) * Vector1() - Vector1(), InnerVectorizedTraversal, + CompleteUnrolling)); VERIFY(test_assign( Vector1(), - (Scalar(2.1) * Vector1().template segment(0) - Vector1().template segment(0)).derived(), + (Scalar(RealScalar(2.1)) * Vector1().template segment(0) - Vector1().template segment(0)) + .derived(), EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal, CompleteUnrolling)); VERIFY(test_assign(Vector1(), Vector1().cwiseProduct(Vector1()), InnerVectorizedTraversal, CompleteUnrolling)); VERIFY(test_assign(Vector1(), Vector1().template cast(), InnerVectorizedTraversal, CompleteUnrolling));