remainder.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // (C) Copyright Matt Borland 2021 - 2022.
  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_CCMATH_REMAINDER_HPP
  6. #define BOOST_MATH_CCMATH_REMAINDER_HPP
  7. #include <boost/math/ccmath/detail/config.hpp>
  8. #ifdef BOOST_MATH_NO_CCMATH
  9. #error "The header <boost/math/remainder.hpp> can only be used in C++17 and later."
  10. #endif
  11. #include <cstdint>
  12. #include <boost/math/tools/promotion.hpp>
  13. #include <boost/math/ccmath/abs.hpp>
  14. #include <boost/math/ccmath/isinf.hpp>
  15. #include <boost/math/ccmath/isnan.hpp>
  16. #include <boost/math/ccmath/isfinite.hpp>
  17. #include <boost/math/ccmath/modf.hpp>
  18. namespace boost::math::ccmath {
  19. namespace detail {
  20. template <typename T>
  21. constexpr T remainder_impl(const T x, const T y)
  22. {
  23. T n = 0;
  24. if (T fractional_part = boost::math::ccmath::modf((x / y), &n); fractional_part > static_cast<T>(1.0/2))
  25. {
  26. ++n;
  27. }
  28. else if (fractional_part < static_cast<T>(-1.0/2))
  29. {
  30. --n;
  31. }
  32. return x - n*y;
  33. }
  34. } // Namespace detail
  35. template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
  36. constexpr Real remainder(Real x, Real y)
  37. {
  38. if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
  39. {
  40. if (boost::math::ccmath::isinf(x) && !boost::math::ccmath::isnan(y))
  41. {
  42. return std::numeric_limits<Real>::quiet_NaN();
  43. }
  44. else if (boost::math::ccmath::abs(y) == static_cast<Real>(0) && !boost::math::ccmath::isnan(x))
  45. {
  46. return std::numeric_limits<Real>::quiet_NaN();
  47. }
  48. else if (boost::math::ccmath::isnan(x))
  49. {
  50. return x;
  51. }
  52. else if (boost::math::ccmath::isnan(y))
  53. {
  54. return y;
  55. }
  56. return boost::math::ccmath::detail::remainder_impl(x, y);
  57. }
  58. else
  59. {
  60. using std::remainder;
  61. return remainder(x, y);
  62. }
  63. }
  64. template <typename T1, typename T2>
  65. constexpr auto remainder(T1 x, T2 y)
  66. {
  67. if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
  68. {
  69. using promoted_type = boost::math::tools::promote_args_t<T1, T2>;
  70. return boost::math::ccmath::remainder(promoted_type(x), promoted_type(y));
  71. }
  72. else
  73. {
  74. using std::remainder;
  75. return remainder(x, y);
  76. }
  77. }
  78. constexpr float remainderf(float x, float y)
  79. {
  80. return boost::math::ccmath::remainder(x, y);
  81. }
  82. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  83. constexpr long double remainderl(long double x, long double y)
  84. {
  85. return boost::math::ccmath::remainder(x, y);
  86. }
  87. #endif
  88. } // Namespaces
  89. #endif // BOOST_MATH_CCMATH_REMAINDER_HPP