sqrt.hpp 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // (C) Copyright Matt Borland 2021.
  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. //
  6. // Constexpr implementation of sqrt function
  7. #ifndef BOOST_MATH_CCMATH_SQRT
  8. #define BOOST_MATH_CCMATH_SQRT
  9. #include <boost/math/ccmath/detail/config.hpp>
  10. #ifdef BOOST_MATH_NO_CCMATH
  11. #error "The header <boost/math/sqrt.hpp> can only be used in C++17 and later."
  12. #endif
  13. #include <boost/math/ccmath/abs.hpp>
  14. #include <boost/math/ccmath/isnan.hpp>
  15. #include <boost/math/ccmath/isinf.hpp>
  16. #include <boost/math/tools/is_constant_evaluated.hpp>
  17. namespace boost::math::ccmath {
  18. namespace detail {
  19. template <typename Real>
  20. constexpr Real sqrt_impl_2(Real x, Real s, Real s2)
  21. {
  22. return !(s < s2) ? s2 : sqrt_impl_2(x, (x / s + s) / 2, s);
  23. }
  24. template <typename Real>
  25. constexpr Real sqrt_impl_1(Real x, Real s)
  26. {
  27. return sqrt_impl_2(x, (x / s + s) / 2, s);
  28. }
  29. template <typename Real>
  30. constexpr Real sqrt_impl(Real x)
  31. {
  32. return sqrt_impl_1(x, x > 1 ? x : Real(1));
  33. }
  34. } // namespace detail
  35. template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
  36. constexpr Real sqrt(Real x)
  37. {
  38. if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
  39. {
  40. if (boost::math::ccmath::isnan(x) ||
  41. (boost::math::ccmath::isinf(x) && x > 0) ||
  42. boost::math::ccmath::abs(x) == Real(0))
  43. {
  44. return x;
  45. }
  46. // Domain error is implementation defined so return NAN
  47. else if (boost::math::ccmath::isinf(x) && x < 0)
  48. {
  49. return std::numeric_limits<Real>::quiet_NaN();
  50. }
  51. return detail::sqrt_impl<Real>(x);
  52. }
  53. else
  54. {
  55. using std::sqrt;
  56. return sqrt(x);
  57. }
  58. }
  59. template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
  60. constexpr double sqrt(Z x)
  61. {
  62. return detail::sqrt_impl<double>(static_cast<double>(x));
  63. }
  64. } // Namespaces
  65. #endif // BOOST_MATH_CCMATH_SQRT