File indexing completed on 2025-01-30 09:45:15
0001
0002
0003
0004
0005
0006 #ifndef BOOST_MATH_CCMATH_ROUND_HPP
0007 #define BOOST_MATH_CCMATH_ROUND_HPP
0008
0009 #include <stdexcept>
0010 #include <boost/math/ccmath/detail/config.hpp>
0011
0012 #ifdef BOOST_MATH_NO_CCMATH
0013 #error "The header <boost/math/round.hpp> can only be used in C++17 and later."
0014 #endif
0015
0016 #include <boost/math/ccmath/abs.hpp>
0017 #include <boost/math/ccmath/isinf.hpp>
0018 #include <boost/math/ccmath/isnan.hpp>
0019 #include <boost/math/ccmath/modf.hpp>
0020
0021 namespace boost::math::ccmath {
0022
0023 namespace detail {
0024
0025
0026
0027 template <typename T>
0028 inline constexpr T round_impl(T arg) noexcept
0029 {
0030 T iptr = 0;
0031 const T x = boost::math::ccmath::modf(arg, &iptr);
0032 constexpr T half = T(1)/2;
0033
0034 if(x >= half && iptr > 0)
0035 {
0036 return iptr + 1;
0037 }
0038 else if(boost::math::ccmath::abs(x) >= half && iptr < 0)
0039 {
0040 return iptr - 1;
0041 }
0042 else
0043 {
0044 return iptr;
0045 }
0046 }
0047
0048 template <typename ReturnType, typename T>
0049 inline constexpr ReturnType int_round_impl(T arg)
0050 {
0051 const T rounded_arg = round_impl(arg);
0052
0053 if(rounded_arg > static_cast<T>((std::numeric_limits<ReturnType>::max)()))
0054 {
0055 if constexpr (std::is_same_v<ReturnType, long long>)
0056 {
0057 throw std::domain_error("Rounded value cannot be represented by a long long type without overflow");
0058 }
0059 else
0060 {
0061 throw std::domain_error("Rounded value cannot be represented by a long type without overflow");
0062 }
0063 }
0064 else
0065 {
0066 return static_cast<ReturnType>(rounded_arg);
0067 }
0068 }
0069
0070 }
0071
0072 template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
0073 inline constexpr Real round(Real arg) noexcept
0074 {
0075 if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
0076 {
0077 return boost::math::ccmath::abs(arg) == Real(0) ? arg :
0078 boost::math::ccmath::isinf(arg) ? arg :
0079 boost::math::ccmath::isnan(arg) ? arg :
0080 boost::math::ccmath::detail::round_impl(arg);
0081 }
0082 else
0083 {
0084 using std::round;
0085 return round(arg);
0086 }
0087 }
0088
0089 template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
0090 inline constexpr double round(Z arg) noexcept
0091 {
0092 return boost::math::ccmath::round(static_cast<double>(arg));
0093 }
0094
0095 inline constexpr float roundf(float arg) noexcept
0096 {
0097 return boost::math::ccmath::round(arg);
0098 }
0099
0100 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0101 inline constexpr long double roundl(long double arg) noexcept
0102 {
0103 return boost::math::ccmath::round(arg);
0104 }
0105 #endif
0106
0107 template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
0108 inline constexpr long lround(Real arg)
0109 {
0110 if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
0111 {
0112 return boost::math::ccmath::abs(arg) == Real(0) ? 0l :
0113 boost::math::ccmath::isinf(arg) ? 0l :
0114 boost::math::ccmath::isnan(arg) ? 0l :
0115 boost::math::ccmath::detail::int_round_impl<long>(arg);
0116 }
0117 else
0118 {
0119 using std::lround;
0120 return lround(arg);
0121 }
0122 }
0123
0124 template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
0125 inline constexpr long lround(Z arg)
0126 {
0127 return boost::math::ccmath::lround(static_cast<double>(arg));
0128 }
0129
0130 inline constexpr long lroundf(float arg)
0131 {
0132 return boost::math::ccmath::lround(arg);
0133 }
0134
0135 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0136 inline constexpr long lroundl(long double arg)
0137 {
0138 return boost::math::ccmath::lround(arg);
0139 }
0140 #endif
0141
0142 template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
0143 inline constexpr long long llround(Real arg)
0144 {
0145 if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
0146 {
0147 return boost::math::ccmath::abs(arg) == Real(0) ? 0ll :
0148 boost::math::ccmath::isinf(arg) ? 0ll :
0149 boost::math::ccmath::isnan(arg) ? 0ll :
0150 boost::math::ccmath::detail::int_round_impl<long long>(arg);
0151 }
0152 else
0153 {
0154 using std::llround;
0155 return llround(arg);
0156 }
0157 }
0158
0159 template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
0160 inline constexpr long llround(Z arg)
0161 {
0162 return boost::math::ccmath::llround(static_cast<double>(arg));
0163 }
0164
0165 inline constexpr long long llroundf(float arg)
0166 {
0167 return boost::math::ccmath::llround(arg);
0168 }
0169
0170 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0171 inline constexpr long long llroundl(long double arg)
0172 {
0173 return boost::math::ccmath::llround(arg);
0174 }
0175 #endif
0176
0177 }
0178
0179 #endif