diff --git a/include/xsimd/arch/xsimd_avx.hpp b/include/xsimd/arch/xsimd_avx.hpp index 49bd12b90..f06a603e4 100644 --- a/include/xsimd/arch/xsimd_avx.hpp +++ b/include/xsimd/arch/xsimd_avx.hpp @@ -1368,7 +1368,7 @@ namespace xsimd return 0 - self; } template - batch neg(batch const& self, requires_arch) + XSIMD_INLINE batch neg(batch const& self, requires_arch) noexcept { return _mm256_xor_ps(self, _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000))); } diff --git a/include/xsimd/arch/xsimd_avx512f.hpp b/include/xsimd/arch/xsimd_avx512f.hpp index e5ab27813..06da6218e 100644 --- a/include/xsimd/arch/xsimd_avx512f.hpp +++ b/include/xsimd/arch/xsimd_avx512f.hpp @@ -1885,11 +1885,21 @@ namespace xsimd } // neg - template + template >> XSIMD_INLINE batch neg(batch const& self, requires_arch) noexcept { return 0 - self; } + template + XSIMD_INLINE batch neg(batch const& self, requires_arch) noexcept + { + return _mm512_castsi512_ps(_mm512_xor_si512(_mm512_castps_si512(self), _mm512_set1_epi32(0x80000000))); + } + template + XSIMD_INLINE batch neg(batch const& self, requires_arch) noexcept + { + return _mm512_castsi512_pd(_mm512_xor_si512(_mm512_castpd_si512(self), _mm512_set1_epi64(0x8000000000000000))); + } // neq template diff --git a/include/xsimd/arch/xsimd_vxe.hpp b/include/xsimd/arch/xsimd_vxe.hpp index 61e9bf8a5..1403fff90 100644 --- a/include/xsimd/arch/xsimd_vxe.hpp +++ b/include/xsimd/arch/xsimd_vxe.hpp @@ -326,7 +326,7 @@ namespace xsimd template XSIMD_INLINE batch neg(batch const& self, requires_arch) noexcept { - return (typename batch::register_type) { 0 } - self.data; + return -self.data; } // add diff --git a/test/test_batch.cpp b/test/test_batch.cpp index ed43364e0..0bee8b1fc 100644 --- a/test/test_batch.cpp +++ b/test/test_batch.cpp @@ -246,6 +246,23 @@ struct batch_test INFO("-batch"); CHECK_BATCH_EQ(res, expected); } +#ifndef __FAST_MATH__ + // -batch at signed zero, which CHECK_BATCH_EQ cannot see: it compares + // with ==, and +0 == -0. + if constexpr (std::is_floating_point_v) + { + value_type pos_zero(0.0); + value_type neg_zero(-0.0); + batch_type pos_res = -batch_type(pos_zero); + batch_type neg_res = -batch_type(neg_zero); + INFO("-batch (signed zero)"); + for (size_t i = 0; i < size; ++i) + { + CHECK(std::signbit(pos_res.get(i))); + CHECK_FALSE(std::signbit(neg_res.get(i))); + } + } +#endif // batch + batch { array_type expected; diff --git a/test/test_xsimd_api.cpp b/test/test_xsimd_api.cpp index bc8d8f6bd..61eafd15c 100644 --- a/test/test_xsimd_api.cpp +++ b/test/test_xsimd_api.cpp @@ -14,6 +14,8 @@ #include +#include + template struct scalar_type { @@ -780,6 +782,15 @@ struct xsimd_api_float_types_functions value_type val(3.1); CHECK_EQ(extract(xsimd::nearbyint_as_int(T(val))), long(std::nearbyint(val))); } +#ifndef __FAST_MATH__ + void test_neg_signed_zero() + { + value_type pos_zero(0.0); + value_type neg_zero(-0.0); + CHECK(std::signbit(extract(xsimd::neg(T(pos_zero))))); + CHECK_FALSE(std::signbit(extract(xsimd::neg(T(neg_zero))))); + } +#endif void test_nextafter() { value_type val0(3); @@ -1065,6 +1076,13 @@ TEST_CASE_TEMPLATE("[xsimd api | float types functions]", B, FLOAT_TYPES) Test.test_nearbyint_as_int(); } +#ifndef __FAST_MATH__ + SUBCASE("neg_signed_zero") + { + Test.test_neg_signed_zero(); + } +#endif + SUBCASE("nextafter") { Test.test_nextafter();