Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:45:15

0001 //  (C) Copyright Matt Borland 2021.
0002 //  Use, modification and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // Computes the nearest integer value to arg (in floating-point format), 
0026 // rounding halfway cases away from zero, regardless of the current rounding mode.
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 } // Namespace detail
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 } // Namespaces
0178 
0179 #endif // BOOST_MATH_CCMATH_ROUND_HPP