diff --git a/include/xsimd/arch/common/xsimd_common_trigo.hpp b/include/xsimd/arch/common/xsimd_common_trigo.hpp index 00ad75076..1d1b2948a 100644 --- a/include/xsimd/arch/common/xsimd_common_trigo.hpp +++ b/include/xsimd/arch/common/xsimd_common_trigo.hpp @@ -870,7 +870,7 @@ namespace xsimd return batch_type(wreal, real_batch(1.)), batch_type(wreal, wimag / d); #else batch_type winf(constants::infinity(), constants::infinity()); - batch_type wres = select(isinf(wimag), batch_type(wreal, real_batch(1.)), batch_type(wreal, wimag / d)); + batch_type wres = select(isinf(wimag), batch_type(wreal, copysign(real_batch(1.), wimag)), batch_type(wreal, wimag / d)); return select(d == real_batch(0.), winf, wres); #endif } diff --git a/test/test_complex_trigonometric.cpp b/test/test_complex_trigonometric.cpp index 89fdbd4aa..ed82e74b2 100644 --- a/test/test_complex_trigonometric.cpp +++ b/test/test_complex_trigonometric.cpp @@ -229,4 +229,56 @@ TEST_CASE_TEMPLATE("[complex trigonometric]", B, BATCH_COMPLEX_TYPES) Test.test_atan(); } } + +#ifndef __FAST_MATH__ +TEST_CASE_TEMPLATE("[complex tan overflow sign]", B, BATCH_COMPLEX_TYPES) +{ + using value_type = typename B::value_type; + using real_type = typename value_type::value_type; + const real_type large = std::is_same::value ? real_type(45) : real_type(356); + const real_type largest = std::numeric_limits::max(); + const std::array samples = { { + { real_type(1), -large }, + { real_type(-1), large }, + { real_type(0), -large }, + { -real_type(0), large }, + { real_type(1), -largest }, + { real_type(-1), largest }, + { -real_type(0), -largest }, + { real_type(0), largest }, + { real_type(1), real_type(-1) }, + { real_type(-1), real_type(1) }, + { real_type(1), large }, + { real_type(-1), -large }, + } }; + + for (size_t offset = 0; offset < samples.size(); offset += B::size) + { + std::array input, output; + for (size_t lane = 0; lane < B::size; ++lane) + { + input[lane] = samples[(offset + lane) % samples.size()]; + } + xsimd::tan(B::load_unaligned(input.data())).store_unaligned(output.data()); + for (size_t lane = 0; lane < B::size; ++lane) + { + const value_type expected = std::tan(input[lane]); + const real_type actual_parts[] = { output[lane].real(), output[lane].imag() }; + const real_type expected_parts[] = { expected.real(), expected.imag() }; + for (size_t part = 0; part < 2; ++part) + { + CHECK(std::isfinite(actual_parts[part])); + if (expected_parts[part] == real_type(0)) + { + CHECK(actual_parts[part] == real_type(0)); + } + else + { + CHECK(actual_parts[part] == doctest::Approx(expected_parts[part]).epsilon(64 * std::numeric_limits::epsilon())); + } + } + } + } +} +#endif #endif