From f1b5cb021401d4bf596690af9f282a3b141e561f Mon Sep 17 00:00:00 2001 From: Demetrios Chiuratto Agourakis Date: Tue, 10 Nov 2026 23:28:35 +0000 Subject: [PATCH] Avoid NaN real components in complex tanh after overflow When cosh(2*real(z)) overflows, use the sign of the real part instead of an inf/inf quotient. --- .../xsimd/arch/common/xsimd_common_trigo.hpp | 6 +++- test/test_complex_hyperbolic.cpp | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/include/xsimd/arch/common/xsimd_common_trigo.hpp b/include/xsimd/arch/common/xsimd_common_trigo.hpp index 00ad75076..3c12982e6 100644 --- a/include/xsimd/arch/common/xsimd_common_trigo.hpp +++ b/include/xsimd/arch/common/xsimd_common_trigo.hpp @@ -986,7 +986,11 @@ namespace xsimd auto y = z.imag(); real_batch two(2); auto d = cosh(two * x) + cos(two * y); - return { sinh(two * x) / d, sin(two * y) / d }; + auto real_part = sinh(two * x) / d; +#ifndef __FAST_MATH__ + real_part = select(isinf(d), copysign(real_batch(1), x), real_part); +#endif + return { real_part, sin(two * y) / d }; } } diff --git a/test/test_complex_hyperbolic.cpp b/test/test_complex_hyperbolic.cpp index 40e97ca7c..d9855a12d 100644 --- a/test/test_complex_hyperbolic.cpp +++ b/test/test_complex_hyperbolic.cpp @@ -91,6 +91,41 @@ struct complex_hyperbolic_test detail::load_batch(ref, expected, i); CHECK_BATCH_EQ(ref, out); } + +#ifndef __FAST_MATH__ + // Fast-math drops overflow recovery and does not match std::tanh. + using R = real_value_type; + const R zero(0); + const R huge = std::is_same_v ? R(45) : R(356); + const R re[] = { -huge, -R(20), -R(1), -zero, zero, R(1), R(20), huge }; + const R im[] = { -R(2), -R(1), -R(0.5), -zero, zero, R(0.5), R(1), R(2) }; + vector_type inputs; + inputs.reserve(64 + size); + for (R real : re) + { + for (R imag : im) + { + inputs.push_back(value_type(real, imag)); + } + } + while (inputs.size() % size != 0) + { + inputs.push_back(inputs.front()); + } + for (size_t i = 0; i < inputs.size(); i += size) + { + batch_type in, out, ref; + detail::load_batch(in, inputs, i); + out = tanh(in); + vector_type scalar(size); + for (size_t lane = 0; lane < size; ++lane) + { + scalar[lane] = std::tanh(inputs[i + lane]); + } + detail::load_batch(ref, scalar, 0); + CHECK_BATCH_EQ(ref, out); + } +#endif } void test_asinh()