/*************************************************************************** * 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_ERROR_HPP #define XSIMD_ERROR_HPP #include "xsimd_basic_math.hpp" #include "xsimd_exponential.hpp" #include "xsimd_fp_sign.hpp" #include "xsimd_horner.hpp" namespace xsimd { /** * Computes the error function of the batch \c x. * @param x batch of floating point values. * @return the error function of \c x. */ template batch_type_t erf(const simd_base& x); /** * Computes the complementary error function of the batch \c x. * @param x batch of floating point values. * @return the error function of \c x. */ template batch_type_t erfc(const simd_base& x); /********************** * erf implementation * **********************/ namespace detail { /* origin: boost/simd/arch/common/detail/generic/erf_kernel.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 erf_kernel; template struct erf_kernel { // computes erf(a0)/a0 // x is sqr(a0) and 0 <= abs(a0) <= 2/3 static inline B erf1(const B& x) { return horner(x); } // computes erfc(x)*exp(sqr(x)) // x >= 2/3 static inline B erfc2(const B& x) { return horner(x); } static inline B erfc3(const B& x) { return (B(1.) - x) * horner(x); } }; template struct erf_kernel { // computes erf(a0)/a0 // x is sqr(a0) and 0 <= abs(a0) <= 0.65 static inline B erf1(const B& x) { return horner(x) / horner(x); } // computes erfc(x)*exp(x*x) // 0.65 <= abs(x) <= 2.2 static inline B erfc2(const B& x) { return horner(x) / horner(x); } // computes erfc(x)*exp(x*x) // 2.2 <= abs(x) <= 6 static inline B erfc3(const B& x) { return horner(x) / horner(x); } // computes erfc(rx)*exp(rx*rx) // x >= 6 rx = 1/x static inline B erfc4(const B& x) { return horner(x); } }; /* origin: boost/simd/arch/common/simd/function/erf.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 erf_impl; template struct erf_impl { static inline B compute(const B& a) { B x = abs(a); B r1 = B(0.); auto test1 = x < B(2.f / 3.f); if (any(test1)) { r1 = a * erf_kernel::erf1(x * x); if (all(test1)) return r1; } B z = x / (B(1.) + x); z -= B(0.4f); B r2 = B(1.) - exp(-x * x) * erf_kernel::erfc2(z); r2 = select(a < B(0.), -r2, r2); r1 = select(test1, r1, r2); #ifndef XSIMD_NO_INFINITIES r1 = select(xsimd::isinf(a), sign(a), r1); #endif return r1; } }; template struct erf_impl { static inline B compute(const B& a) { B x = abs(a); B xx = x * x; B lim1 = B(0.65); B lim2 = B(2.2); auto test1 = x < lim1; B r1 = B(0.); if (any(test1)) { r1 = a * erf_kernel::erf1(xx); if (all(test1)) return r1; } auto test2 = x < lim2; auto test3 = test2 && !test1; B ex = exp(-xx); if (any(test3)) { B z = B(1.) - ex * erf_kernel::erfc2(x); B r2 = select(a < B(0.), -z, z); r1 = select(test1, r1, r2); if (all(test1 || test3)) return r1; } B z = B(1.) - ex * erf_kernel::erfc3(x); z = select(a < B(0.), -z, z); #ifndef XSIMD_NO_INFINITIES z = select(xsimd::isinf(a), sign(a), z); #endif return select(test2, r1, z); } }; } template inline batch_type_t erf(const simd_base& x) { return detail::erf_impl>::compute(x()); } /*********************** * erfc implementation * ***********************/ namespace detail { template struct erfc_impl; template struct erfc_impl { static inline B compute(const B& a) { B x = abs(a); auto test0 = a < B(0.); B r1 = B(0.); auto test1 = x < B(2.f / 3.f); B z = x / (B(1.) + x); if (any(test1)) { r1 = erf_kernel::erfc3(z); if (all(test1)) return select(test0, B(2.) - r1, r1); } z -= B(0.4f); B r2 = exp(-x * x) * erf_kernel::erfc2(z); r1 = select(test1, r1, r2); #ifndef XSIMD_NO_INFINITIES r1 = select(x == infinity(), B(0.), r1); #endif return select(test0, B(2.) - r1, r1); } }; template struct erfc_impl { static inline B compute(const B& a) { B x = abs(a); B xx = x * x; B lim1 = B(0.65); B lim2 = B(2.2); auto test0 = a < B(0.); auto test1 = x < lim1; B r1 = B(0.); if (any(test1)) { r1 = B(1.) - x * erf_kernel::erf1(xx); if (all(test1)) return select(test0, B(2.) - r1, r1); } auto test2 = x < lim2; auto test3 = test2 && !test1; B ex = exp(-xx); if (any(test3)) { B z = ex * erf_kernel::erfc2(x); r1 = select(test1, r1, z); if (all(test1 || test3)) return select(test0, B(2.) - r1, r1); } B z = ex * erf_kernel::erfc3(x); r1 = select(test2, r1, z); #ifndef XSIMD_NO_INFINITIES r1 = select(x == infinity(), B(0.), r1); #endif return select(test0, B(2.) - r1, r1); } }; } template inline batch_type_t erfc(const simd_base& x) { return detail::erfc_impl>::compute(x()); } } #endif