From d7819f425e9d58ef7104046bbdfadd8e81b37a26 Mon Sep 17 00:00:00 2001 From: Demetrios Chiuratto Agourakis Date: Tue, 10 Nov 2026 23:28:35 +0000 Subject: [PATCH] Select the principal branch of complex acosh in both half-planes Take the nonnegative imaginary magnitude of acos and the sign of imag(z). Keep the signed real-axis asin branch so the cut matches std::acosh. --- .../xsimd/arch/common/xsimd_common_trigo.hpp | 8 ++--- test/test_complex_hyperbolic.cpp | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/xsimd/arch/common/xsimd_common_trigo.hpp b/include/xsimd/arch/common/xsimd_common_trigo.hpp index 00ad75076..0ad5bc2a8 100644 --- a/include/xsimd/arch/common/xsimd_common_trigo.hpp +++ b/include/xsimd/arch/common/xsimd_common_trigo.hpp @@ -80,8 +80,7 @@ namespace xsimd { using batch_type = batch, A>; batch_type w = acos(z); - w = batch_type(-w.imag(), w.real()); - return w; + return batch_type(abs(w.imag()), copysign(w.real(), z.imag())); } // asin @@ -141,8 +140,9 @@ namespace xsimd return select(y == real_batch(0.), select(fabs(x) > real_batch(1.), - batch_type(constants::pio2(), real_batch(0.)), - batch_type(asin(x), real_batch(0.))), + batch_type(copysign(constants::pio2(), x), + copysign(acosh(max(fabs(x), real_batch(1.))), y)), + batch_type(asin(x), y)), resg); } diff --git a/test/test_complex_hyperbolic.cpp b/test/test_complex_hyperbolic.cpp index 40e97ca7c..780749af8 100644 --- a/test/test_complex_hyperbolic.cpp +++ b/test/test_complex_hyperbolic.cpp @@ -121,6 +121,37 @@ struct complex_hyperbolic_test detail::load_batch(ref, expected, i); CHECK_BATCH_EQ(ref, out); } + + using R = real_value_type; + const R zero(0); + const R re[] = { -R(4), -R(2), -R(1), -R(0.5), R(0.5), R(1), R(2), R(4) }; + 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 = acosh(in); + vector_type scalar(size); + for (size_t lane = 0; lane < size; ++lane) + { + scalar[lane] = std::acosh(inputs[i + lane]); + } + detail::load_batch(ref, scalar, 0); + CHECK_BATCH_EQ(ref, out); + } } void test_atanh()