From b6bc370ecf2b6819514474ffed476cad2e9db6ea Mon Sep 17 00:00:00 2001 From: Fikret Ardal Date: Wed, 7 Oct 2026 16:48:39 -0400 Subject: [PATCH 1/4] fixed the issue of neg function in avx512f where it differed from scalar implementation in signed zero case and made it similar to avx/sse implementations --- include/xsimd/arch/xsimd_avx512f.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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 From e0eab695606495b8b510c2163ba236528b9f7f11 Mon Sep 17 00:00:00 2001 From: Fikret Ardal Date: Wed, 7 Oct 2026 16:51:07 -0400 Subject: [PATCH 2/4] Test that neg preserves signed zero The existing neg tests compare with ==, under which +0 == -0, so they pass against a kernel that evaluates 0 - x instead of flipping the sign bit. Check the sign bit explicitly: across every lane of the batch arithmetic test, and for the scalar and batch overloads in the api test. Both are guarded by __FAST_MATH__, which implies -fno-signed-zeros and makes the property untestable. Co-Authored-By: Claude Opus 5 --- test/test_batch.cpp | 17 +++++++++++++++++ test/test_xsimd_api.cpp | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) 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(); From 9ff56aad7c72536cbd40cd9545bed009a7d7663f Mon Sep 17 00:00:00 2001 From: Fikret Ardal Date: Wed, 7 Oct 2026 16:52:44 -0400 Subject: [PATCH 3/4] Add missing XSIMD_INLINE and noexcept to the avx neg kernel --- include/xsimd/arch/xsimd_avx.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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))); } From ef15a46b172b2d9d23ae37ea402a45833f1e05bc Mon Sep 17 00:00:00 2001 From: Fikret Ardal Date: Thu, 8 Oct 2026 09:34:10 -0400 Subject: [PATCH 4/4] fixed signed zero issue in neg function for vxe --- include/xsimd/arch/xsimd_vxe.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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