rsqrt.hpp 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. // (C) Copyright Nick Thompson 2020.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_SPECIAL_FUNCTIONS_RSQRT_HPP
  6. #define BOOST_MATH_SPECIAL_FUNCTIONS_RSQRT_HPP
  7. #include <cmath>
  8. #include <type_traits>
  9. #include <limits>
  10. #include <boost/math/tools/is_standalone.hpp>
  11. #ifndef BOOST_MATH_STANDALONE
  12. # include <boost/config.hpp>
  13. # ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
  14. # error "The header <boost/math/rqrt.hpp> can only be used in C++17 and later."
  15. # endif
  16. #endif
  17. namespace boost::math {
  18. template<typename Real>
  19. inline Real rsqrt(Real const & x)
  20. {
  21. using std::sqrt;
  22. if constexpr (std::is_arithmetic_v<Real> && !std::is_integral_v<Real>)
  23. {
  24. return 1/sqrt(x);
  25. }
  26. else
  27. {
  28. // if it's so tiny it rounds to 0 as long double,
  29. // no performance gains are possible:
  30. if (x < std::numeric_limits<long double>::denorm_min() || x > (std::numeric_limits<long double>::max)()) {
  31. return 1/sqrt(x);
  32. }
  33. Real x0 = 1/sqrt(static_cast<long double>(x));
  34. // Divide by 512 for leeway:
  35. Real s = sqrt(std::numeric_limits<Real>::epsilon())*x0/512;
  36. Real x1 = x0 + x0*(1-x*x0*x0)/2;
  37. while(abs(x1 - x0) > s) {
  38. x0 = x1;
  39. x1 = x0 + x0*(1-x*x0*x0)/2;
  40. }
  41. // Final iteration get ~2ULPs:
  42. return x1 + x1*(1-x*x1*x1)/2;;
  43. }
  44. }
  45. }
  46. #endif