Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions include/xsimd/arch/common/xsimd_common_trigo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,22 @@ namespace xsimd
const batch_type q = abs(self / other);
const batch_type q_p = abs(other / self);
#else
const batch_type q = abs(self / other);
const auto both_zero = (self == batch_type(0.)) && (other == batch_type(0.));
auto use_unit_ratio = both_zero;
#ifndef XSIMD_NO_INFINITIES
use_unit_ratio = use_unit_ratio || (isinf(self) && isinf(other));
#endif
const batch_type q = abs(select(use_unit_ratio, batch_type(1.), self)
/ select(use_unit_ratio, batch_type(1.), other));
const batch_type q_p = 1. / q;
#endif
const batch_type z = detail::kernel_atan(q, q_p);
return select(other > batch_type(0.), z, constants::pi<batch_type>() - z) * signnz(self);
batch_type result = select(other > batch_type(0.), z, constants::pi<batch_type>() - z) * signnz(self);
#ifndef __FAST_MATH__
const auto zero_angle = select(signnz(other) < batch_type(0.), constants::pi<batch_type>(), batch_type(0.));
result = select(both_zero, copysign(zero_angle, self), result);
#endif
return result;
}

// cos
Expand Down
34 changes: 34 additions & 0 deletions test/test_complex_exponential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,38 @@ TEST_CASE_TEMPLATE("[complex exponential]", B, BATCH_COMPLEX_TYPES)
Test.test_sign();
}
}
#ifndef __FAST_MATH__
TEST_CASE_TEMPLATE("[complex log zero angle]", B, BATCH_COMPLEX_TYPES)
{
using value_type = typename B::value_type;
using real_type = typename value_type::value_type;
const real_type zero(0);
const std::array<value_type, 4> samples = {
value_type(zero, zero), value_type(zero, -zero),
value_type(-zero, zero), value_type(-zero, -zero)
};
std::array<value_type, B::size> inputs;
std::array<value_type, B::size> results;
for (size_t start = 0; start < samples.size(); ++start)
{
for (size_t lane = 0; lane < B::size; ++lane)
{
inputs[lane] = samples[(start + lane) % samples.size()];
}
xsimd::log(B::load_unaligned(inputs.data())).store_unaligned(results.data());
for (size_t lane = 0; lane < B::size; ++lane)
{
const auto expected = std::log(inputs[lane]);
CHECK(std::isinf(results[lane].real()));
CHECK(std::signbit(results[lane].real()));
CHECK_EQ(results[lane].imag(), doctest::Approx(expected.imag()).epsilon(real_type(4) * std::numeric_limits<real_type>::epsilon()));
CHECK_EQ(std::signbit(results[lane].imag()), std::signbit(expected.imag()));
if (expected.imag() == zero)
{
CHECK_EQ(results[lane].imag(), zero);
}
}
}
}
#endif
#endif
90 changes: 90 additions & 0 deletions test/test_trigonometric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,94 @@ TEST_CASE_TEMPLATE("[trigonometric]", B, BATCH_FLOAT_TYPES)
Test.test_reciprocal_functions();
}
}
#ifndef __FAST_MATH__
TEST_CASE_TEMPLATE("[atan2 signed zero pairs]", B, BATCH_FLOAT_TYPES)
{
using value_type = typename B::value_type;
const value_type zero(0);
const std::array<std::pair<value_type, value_type>, 20> samples = {
std::pair { zero, zero }, std::pair { -zero, zero },
std::pair { zero, -zero }, std::pair { -zero, -zero },
std::pair { zero, value_type(1) }, std::pair { -zero, value_type(1) },
std::pair { zero, value_type(-1) }, std::pair { -zero, value_type(-1) },
std::pair { value_type(1), zero }, std::pair { value_type(-1), zero },
std::pair { value_type(1), -zero }, std::pair { value_type(-1), -zero },
std::pair { value_type(1), value_type(1) }, std::pair { value_type(-1), value_type(1) },
std::pair { value_type(1), value_type(-1) }, std::pair { value_type(-1), value_type(-1) },
std::pair { value_type(3), value_type(4) }, std::pair { value_type(-3), value_type(4) },
std::pair { value_type(3), value_type(-4) }, std::pair { value_type(-3), value_type(-4) }
};
std::array<value_type, B::size> ys, xs, results;
const auto tolerance = value_type(64) * std::numeric_limits<value_type>::epsilon();
for (size_t start = 0; start < samples.size(); ++start)
{
for (size_t lane = 0; lane < B::size; ++lane)
{
const auto sample = samples[(start + lane) % samples.size()];
ys[lane] = sample.first;
xs[lane] = sample.second;
}
xsimd::atan2(B::load_unaligned(ys.data()), B::load_unaligned(xs.data())).store_unaligned(results.data());
for (size_t lane = 0; lane < B::size; ++lane)
{
const auto expected = std::atan2(ys[lane], xs[lane]);
CHECK_EQ(results[lane], doctest::Approx(expected).epsilon(tolerance).scale(1));
CHECK_EQ(std::signbit(results[lane]), std::signbit(expected));
if (expected == zero)
{
CHECK_EQ(results[lane], expected);
}
}
}
}
#if !defined(XSIMD_NO_INFINITIES) && !defined(XSIMD_NO_NANS)
TEST_CASE_TEMPLATE("[atan2 infinite argument pairs]", B, BATCH_FLOAT_TYPES)
{
using value_type = typename B::value_type;
const value_type zero(0);
const auto inf = std::numeric_limits<value_type>::infinity();
const auto nan = std::numeric_limits<value_type>::quiet_NaN();
const std::array<std::pair<value_type, value_type>, 20> samples = {
std::pair { inf, inf }, std::pair { -inf, inf },
std::pair { inf, -inf }, std::pair { -inf, -inf },
std::pair { inf, value_type(1) }, std::pair { -inf, value_type(1) },
std::pair { inf, value_type(-1) }, std::pair { -inf, value_type(-1) },
std::pair { value_type(1), inf }, std::pair { value_type(-1), inf },
std::pair { value_type(1), -inf }, std::pair { value_type(-1), -inf },
std::pair { zero, inf }, std::pair { -zero, inf },
std::pair { zero, -inf }, std::pair { -zero, -inf },
std::pair { nan, value_type(1) }, std::pair { value_type(1), nan },
std::pair { value_type(1), value_type(1) }, std::pair { value_type(-1), value_type(-1) }
};
std::array<value_type, B::size> ys, xs, results;
const auto tolerance = value_type(64) * std::numeric_limits<value_type>::epsilon();
for (size_t start = 0; start < samples.size(); ++start)
{
for (size_t lane = 0; lane < B::size; ++lane)
{
const auto sample = samples[(start + lane) % samples.size()];
ys[lane] = sample.first;
xs[lane] = sample.second;
}
xsimd::atan2(B::load_unaligned(ys.data()), B::load_unaligned(xs.data())).store_unaligned(results.data());
for (size_t lane = 0; lane < B::size; ++lane)
{
const auto expected = std::atan2(ys[lane], xs[lane]);
if (std::isnan(expected))
{
CHECK(std::isnan(results[lane]));
continue;
}
CHECK(std::isfinite(results[lane]));
CHECK_EQ(results[lane], doctest::Approx(expected).epsilon(tolerance).scale(1));
CHECK_EQ(std::signbit(results[lane]), std::signbit(expected));
if (expected == zero)
{
CHECK_EQ(results[lane], zero);
}
}
}
}
#endif
#endif
#endif