/*************************************************************************** * 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_INVTRIGO_HPP #define XSIMD_INVTRIGO_HPP #include "xsimd_fp_sign.hpp" #include "xsimd_horner.hpp" #include "xsimd_numerical_constant.hpp" namespace xsimd { namespace detail { template struct invtrigo_kernel_impl; /* origin: boost/simd/arch/common/detail/simd/f_invtrig.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 invtrigo_kernel_impl { static inline B asin(const B& a) { B x = abs(a); B sign = bitofsign(a); auto x_larger_05 = x > B(0.5); B z = select(x_larger_05, B(0.5) * (B(1.) - x), x * x); x = select(x_larger_05, sqrt(z), x); B z1 = horner(z); z1 = fma(z1, z * x, x); z = select(x_larger_05, pio2() - (z1 + z1), z1); return z ^ sign; } static inline B kernel_atan(const B& x, const B& recx) { const auto flag1 = x < tan3pio8(); const auto flag2 = (x >= B(detail::caster32_t(0x3ed413cd).f)) && flag1; B yy = select(flag1, B(0.), pio2()); yy = select(flag2, pio4(), yy); B xx = select(flag1, x, -recx); xx = select(flag2, (x - B(1.)) / (x + B(1.)), xx); const B z = xx * xx; B z1 = horner(z); z1 = fma(xx, z1 * z, xx); z1 = select(flag2, z1 + pio_4lo(), z1); z1 = select(!flag1, z1 + pio_2lo(), z1); return yy + z1; } }; /* origin: boost/simd/arch/common/detail/simd/d_invtrig.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 invtrigo_kernel_impl { static inline B asin(const B& a) { B x = abs(a); auto small_cond = x < sqrteps(); B ct1 = B(detail::caster64_t(int64_t(0x3fe4000000000000)).f); B zz1 = B(1.) - x; B vp = zz1 * horner(zz1) / horner1(zz1); zz1 = sqrt(zz1 + zz1); B z = pio4() - zz1; zz1 = fms(zz1, vp, pio_2lo()); z = z - zz1; zz1 = z + pio4(); B zz2 = a * a; z = zz2 * horner(zz2) / horner1(zz2); zz2 = fma(x, z, x); return select(x > B(1.), nan(), select(small_cond, x, select(x > ct1, zz1, zz2)) ^ bitofsign(a)); } static inline B kernel_atan(const B& x, const B& recx) { const auto flag1 = x < tan3pio8(); const auto flag2 = (x >= tanpio8()) && flag1; B yy = select(flag1, B(0.), pio2()); yy = select(flag2, pio4(), yy); B xx = select(flag1, x, -recx); xx = select(flag2, (x - B(1.)) / (x + B(1.)), xx); B z = xx * xx; z *= horner(z) / horner1(z); z = fma(xx, z, xx); z = select(flag2, z + pio_4lo(), z); z = z + select(flag1, B(0.), pio_2lo()); return yy + z; } }; template struct invtrigo_kernel { static inline B asin(const B& a) { return invtrigo_kernel_impl::asin(a); } static inline B acos(const B& a) { B x = abs(a); auto x_larger_05 = x > B(0.5); x = select(x_larger_05, sqrt(fma(B(-0.5), x, B(0.5))), a); x = asin(x); x = select(x_larger_05, x + x, x); x = select(a < B(-0.5), pi() - x, x); return select(x_larger_05, x, pio2() - x); } static inline B atan(const B& a) { const B absa = abs(a); const B x = kernel_atan(absa, B(1.) / absa); return x ^ bitofsign(a); } static inline B acot(const B& a) { const B absa = abs(a); const B x = kernel_atan(B(1.) / absa, absa); return x ^ bitofsign(a); } static inline B atan2(const B& y, const B& x) { const B q = abs(y / x); const B z = kernel_atan(q, B(1.) / q); return select(x > B(0.), z, pi() - z) * signnz(y); } static inline B kernel_atan(const B& x, const B& recx) { return invtrigo_kernel_impl::kernel_atan(x, recx); } }; } } #endif