/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XSIMD_TRIGO_REDUCTION_HPP #define XSIMD_TRIGO_REDUCTION_HPP #include #include #include "xsimd_horner.hpp" #include "xsimd_rem_pio2.hpp" #include "xsimd_rounding.hpp" namespace xsimd { template batch_type_t quadrant(const simd_base& x); namespace detail { template struct trigo_evaluation; /* origin: boost/simd/arch/common/detail/simd/f_trig_evaluation.hpp */ /* * ==================================================== * copyright 2016 NumScale SAS * * Distributed under the Boost Software License, Version 1.0. * (See copy at http://boost.org/LICENSE_1_0.txt) * ==================================================== */ template struct trigo_evaluation { static inline B cos_eval(const B& z) { B y = horner(z); return B(1.) + fma(z, B(-0.5), y * z * z); } static inline B sin_eval(const B& z, const B& x) { B y = horner(z); return fma(y * z, x, x); } static inline B base_tancot_eval(const B& z) { B zz = z * z; B y = horner(zz); return fma(y, zz * z, z); } template static inline B tan_eval(const B& z, const BB& test) { B y = base_tancot_eval(z); return select(test, y, -B(1.) / y); } template static inline B cot_eval(const B& z, const BB& test) { B y = base_tancot_eval(z); return select(test, B(1.) / y, -y); } }; /* origin: boost/simd/arch/common/detail/simd/d_trig_evaluation.hpp */ /* * ==================================================== * copyright 2016 NumScale SAS * * Distributed under the Boost Software License, Version 1.0. * (See copy at http://boost.org/LICENSE_1_0.txt) * ==================================================== */ template struct trigo_evaluation { static inline B cos_eval(const B& z) { B y = horner(z); return B(1.) - y * z; } static inline B sin_eval(const B& z, const B& x) { B y = horner(z); return fma(y * z, x, x); } static inline B base_tancot_eval(const B& z) { B zz = z * z; B num = horner(zz); B den = horner1(zz); return fma(z, (zz * (num / den)), z); } template static inline B tan_eval(const B& z, const BB& test) { B y = base_tancot_eval(z); return select(test, y, -B(1.) / y); } template static inline B cot_eval(const B& z, const BB& test) { B y = base_tancot_eval(z); return select(test, B(1.) / y, -y); } }; /* origin: boost/simd/arch/common/detail/simd/trig_reduction.hpp */ /* * ==================================================== * copyright 2016 NumScale SAS * * Distributed under the Boost Software License, Version 1.0. * (See copy at http://boost.org/LICENSE_1_0.txt) * ==================================================== */ struct trigo_radian_tag { }; struct trigo_pi_tag { }; template struct trigo_reducer { static inline B reduce(const B& x, B& xr) { if (all(x <= pio4())) { xr = x; return B(0.); } else if (all(x <= pio2())) { auto test = x > pio4(); xr = x - pio2_1(); xr -= pio2_2(); xr -= pio2_3(); xr = select(test, xr, x); return select(test, B(1.), B(0.)); } else if (all(x <= twentypi())) { B xi = nearbyint(x * twoopi()); xr = fnma(xi, pio2_1(), x); xr -= xi * pio2_2(); xr -= xi * pio2_3(); return quadrant(xi); } else if (all(x <= mediumpi())) { B fn = nearbyint(x * twoopi()); B r = x - fn * pio2_1(); B w = fn * pio2_1t(); B t = r; w = fn * pio2_2(); r = t - w; w = fn * pio2_2t() - ((t - r) - w); t = r; w = fn * pio2_3(); r = t - w; w = fn * pio2_3t() - ((t - r) - w); xr = r - w; return quadrant(fn); } else { static constexpr std::size_t size = B::size; using value_type = typename B::value_type; alignas(B) std::array tmp; alignas(B) std::array txr; for (std::size_t i = 0; i < size; ++i) { double arg = x[i]; if (arg == std::numeric_limits::infinity()) { tmp[i] = 0.; txr[i] = std::numeric_limits::quiet_NaN(); } else { double y[2]; std::int32_t n = detail::__ieee754_rem_pio2(arg, y); tmp[i] = value_type(n & 3); txr[i] = value_type(y[0]); } } xr.load_aligned(&txr[0]); B res; res.load_aligned(&tmp[0]); return res; } } }; template struct trigo_reducer { static inline B reduce(const B& x, B& xr) { B xi = nearbyint(x * B(2.)); B x2 = x - xi * B(0.5); xr = x2 * pi(); return quadrant(xi); } }; template struct quadrant_impl { static inline B compute(const B& x) { return x & B(3); } }; template struct quadrant_impl { static inline B compute(const B& x) { return to_float(quadrant(to_int(x))); } }; template struct quadrant_impl { static inline B compute(const B& x) { B a = x * B(0.25); return (a - floor(a)) * B(4.); } }; } template inline batch_type_t quadrant(const simd_base& x) { using b_type = batch_type_t; return detail::quadrant_impl::compute(x()); } } #endif