diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 520c53ac..277065a6 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -132,6 +132,15 @@ BOOST_DECIMAL_EXPORT class decimal128_fast final friend constexpr auto to_dpd_d128(DecimalType val) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, detail::uint128); + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_equality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_inequality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + public: constexpr decimal128_fast() noexcept = default; @@ -535,28 +544,7 @@ constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool constexpr auto operator==(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool { - if (lhs.exponent_ != rhs.exponent_) - { - return false; - } - if (lhs.significand_ != rhs.significand_) - { - return false; - } - - #ifndef BOOST_DECIMAL_FAST_MATH - if (isnan(lhs)) - { - return false; - } - #endif - - if (lhs.significand_ == 0) - { - return true; // -0 == +0 - } - - return lhs.sign_ == rhs.sign_; + return fast_equality_impl(lhs, rhs); } template @@ -575,7 +563,7 @@ constexpr auto operator==(Integer lhs, decimal128_fast rhs) noexcept constexpr auto operator!=(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool { - return !(lhs == rhs); + return fast_inequality_impl(lhs, rhs); } template @@ -594,54 +582,7 @@ constexpr auto operator!=(Integer lhs, decimal128_fast rhs) noexcept constexpr auto operator<(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - if (not_finite(lhs) || not_finite(rhs)) - { - if (isnan(lhs) || isnan(rhs) || - (!lhs.isneg() && rhs.isneg())) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) - { - return true; - } - else if (isfinite(lhs) && isinf(rhs)) - { - return !signbit(rhs); - } - else if (isinf(lhs) && isfinite(rhs)) - { - return signbit(rhs); - } - } - #endif - - // Needed to correctly compare signed and unsigned zeros - if (lhs.significand_ == 0 || rhs.significand_ == 0) - { - if (lhs.significand_ == 0 && rhs.significand_ == 0) - { - #ifndef BOOST_DECIMAL_FAST_MATH - return lhs.sign_ && !rhs.sign_; - #else - return false; - #endif - } - return lhs.significand_ == 0 ? !rhs.sign_ : lhs.sign_; - } - - if (lhs.sign_ != rhs.sign_) - { - return lhs.sign_; - } - - if (lhs.exponent_ != rhs.exponent_) - { - return lhs.sign_ ? lhs.exponent_ > rhs.exponent_ : lhs.exponent_ < rhs.exponent_; - } - - return lhs.sign_ ? lhs.significand_ > rhs.significand_ : lhs.significand_ < rhs.significand_; + return fast_less_impl(lhs, rhs); } template diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index ed99ff3c..a391f52b 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -114,6 +115,17 @@ BOOST_DECIMAL_EXPORT class decimal32_fast final template friend constexpr auto detail::d32_add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType; + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_equality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_inequality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + friend constexpr auto not_finite(const decimal32_fast& val) noexcept -> bool; + public: constexpr decimal32_fast() noexcept = default; @@ -492,99 +504,36 @@ constexpr auto isfinite(decimal32_fast val) noexcept -> bool return val.significand_ < detail::d32_fast_inf; } -constexpr auto operator==(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool +constexpr auto not_finite(const decimal32_fast& val) noexcept -> bool { - if (lhs.exponent_ != rhs.exponent_) - { - return false; - } - if (lhs.significand_ != rhs.significand_) - { - return false; - } - - #ifndef BOOST_DECIMAL_FAST_MATH - if (isnan(lhs)) - { - return false; - } - #endif - - if (lhs.significand_ == 0) - { - return true; // -0 == +0 - } + return val.significand_ >= detail::d32_fast_inf; +} - return lhs.sign_ == rhs.sign_; +constexpr auto operator==(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool +{ + return fast_equality_impl(lhs, rhs); } constexpr auto operator!=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool { - return - #ifndef BOOST_DECIMAL_FAST_MATH - isnan(lhs) || isnan(rhs) || - #endif - (lhs.sign_ != rhs.sign_) || - (lhs.exponent_ != rhs.exponent_) || - (lhs.significand_ != rhs.significand_); + return fast_inequality_impl(lhs, rhs); } constexpr auto operator<(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - if (!isfinite(lhs) || !isfinite(rhs)) - { - if (isnan(lhs) || isnan(rhs) || - (!lhs.isneg() && rhs.isneg())) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) - { - return true; - } - else if (isfinite(lhs) && isinf(rhs)) - { - return !signbit(rhs); - } - else if (isinf(lhs) && isfinite(rhs)) - { - return signbit(rhs); - } - } - #endif - - return fast_type_less_parts_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_, - rhs.significand_, rhs.biased_exponent(), rhs.sign_); + return fast_less_impl(lhs, rhs); } constexpr auto operator<=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH - if (!isfinite(lhs) || !isfinite(rhs)) + if (isnan(lhs) || isnan(rhs)) { - if (isnan(lhs) || isnan(rhs) || - (!lhs.isneg() && rhs.isneg())) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) - { - return true; - } - else if (isfinite(lhs) && isinf(rhs)) - { - return !signbit(rhs); - } - else if (isinf(lhs) && isfinite(rhs)) - { - return signbit(rhs); - } + return false; } #endif - return !fast_type_less_parts_impl(rhs.significand_, rhs.biased_exponent(), rhs.sign_, - lhs.significand_, lhs.biased_exponent(), lhs.sign_); + return !(rhs < lhs); } constexpr auto operator>(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool @@ -595,29 +544,13 @@ constexpr auto operator>(decimal32_fast lhs, decimal32_fast rhs) noexcept -> boo constexpr auto operator>=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH - if (!isfinite(lhs) || !isfinite(rhs)) + if (isnan(lhs) || isnan(rhs)) { - if (isnan(lhs) || isnan(rhs)) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) - { - return false; - } - else if (isfinite(lhs) && isinf(rhs)) - { - return signbit(rhs); - } - else if (isinf(lhs) && isfinite(rhs)) - { - return !signbit(lhs); - } + return false; } #endif - return !fast_type_less_parts_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_, - rhs.significand_, rhs.biased_exponent(), rhs.sign_); + return !(lhs < rhs); } template diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 5f01a608..81833fe9 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -132,6 +132,18 @@ BOOST_DECIMAL_EXPORT class decimal64_fast final template BOOST_DECIMAL_FORCE_INLINE friend constexpr auto detail::d64_mul_impl(const T& lhs, const T& rhs) noexcept -> std::enable_if_t, ReturnType>; + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_equality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_inequality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + + template + BOOST_DECIMAL_FORCE_INLINE friend constexpr auto fast_less_equal_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool; + public: constexpr decimal64_fast() noexcept = default; @@ -350,7 +362,7 @@ BOOST_DECIMAL_EXPORT class decimal64_fast final constexpr auto operator++(int) noexcept -> decimal64_fast&; constexpr auto operator--() noexcept -> decimal64_fast&; constexpr auto operator--(int) noexcept -> decimal64_fast&; - + // Cmath friend functions template friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type; @@ -523,28 +535,7 @@ constexpr auto not_finite(decimal64_fast val) noexcept -> bool constexpr auto operator==(decimal64_fast lhs, decimal64_fast rhs) noexcept -> bool { - if (lhs.exponent_ != rhs.exponent_) - { - return false; - } - if (lhs.significand_ != rhs.significand_) - { - return false; - } - - #ifndef BOOST_DECIMAL_FAST_MATH - if (isnan(lhs)) - { - return false; - } - #endif - - if (lhs.significand_ == 0) - { - return true; // -0 == +0 - } - - return lhs.sign_ == rhs.sign_; + return fast_equality_impl(lhs, rhs); } template @@ -563,7 +554,7 @@ constexpr auto operator==(Integer lhs, decimal64_fast rhs) noexcept constexpr auto operator!=(decimal64_fast lhs, decimal64_fast rhs) noexcept -> bool { - return !(lhs == rhs); + return fast_inequality_impl(lhs, rhs); } template @@ -582,54 +573,7 @@ constexpr auto operator!=(Integer lhs, decimal64_fast rhs) noexcept constexpr auto operator<(decimal64_fast lhs, decimal64_fast rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - if (not_finite(lhs) || not_finite(rhs)) - { - if (isnan(lhs) || isnan(rhs) || - (!lhs.isneg() && rhs.isneg())) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) - { - return true; - } - else if (isfinite(lhs) && isinf(rhs)) - { - return !signbit(rhs); - } - else if (isinf(lhs) && isfinite(rhs)) - { - return signbit(rhs); - } - } - #endif - - // Needed to correctly compare signed and unsigned zeros - if (lhs.significand_ == 0 || rhs.significand_ == 0) - { - if (lhs.significand_ == 0 && rhs.significand_ == 0) - { - #ifndef BOOST_DECIMAL_FAST_MATH - return lhs.sign_ && !rhs.sign_; - #else - return false; - #endif - } - return lhs.significand_ == 0 ? !rhs.sign_ : lhs.sign_; - } - - if (lhs.sign_ != rhs.sign_) - { - return lhs.sign_; - } - - if (lhs.exponent_ != rhs.exponent_) - { - return lhs.sign_ ? lhs.exponent_ > rhs.exponent_ : lhs.exponent_ < rhs.exponent_; - } - - return lhs.sign_ ? lhs.significand_ > rhs.significand_ : lhs.significand_ < rhs.significand_; + return fast_less_impl(lhs, rhs); } template diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index 43fafad7..a861de77 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 17f3e102..48746f7d 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -98,6 +98,45 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal return lhs_sig == rhs_sig; } +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_equality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool +{ + if (lhs.exponent_ != rhs.exponent_) + { + return false; + } + if (lhs.significand_ != rhs.significand_) + { + return false; + } + + #ifndef BOOST_DECIMAL_FAST_MATH + if (isnan(lhs)) + { + return false; + } + #endif + + if (lhs.significand_ == 0) + { + return true; // -0 == +0 + } + + return lhs.sign_ == rhs.sign_; +} + +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_inequality_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool +{ + return + #ifndef BOOST_DECIMAL_FAST_MATH + isnan(lhs) || isnan(rhs) || + #endif + (lhs.sign_ != rhs.sign_) || + (lhs.exponent_ != rhs.exponent_) || + (lhs.significand_ != rhs.significand_); +} + template constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, @@ -256,6 +295,59 @@ constexpr auto operator!=(Decimal1 lhs, Decimal2 rhs) noexcept return !(mixed_decimal_equality_impl(lhs, rhs)); } +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_less_impl(const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool +{ + #ifndef BOOST_DECIMAL_FAST_MATH + if (not_finite(lhs) || not_finite(rhs)) + { + if (isnan(lhs) || isnan(rhs) || + (!lhs.isneg() && rhs.isneg())) + { + return false; + } + else if (lhs.isneg() && !rhs.isneg()) + { + return true; + } + else if (isfinite(lhs) && isinf(rhs)) + { + return !signbit(rhs); + } + else if (isinf(lhs) && isfinite(rhs)) + { + return signbit(rhs); + } + } + #endif + + // Needed to correctly compare signed and unsigned zeros + if (lhs.significand_ == 0 || rhs.significand_ == 0) + { + if (lhs.significand_ == 0 && rhs.significand_ == 0) + { + #ifndef BOOST_DECIMAL_FAST_MATH + return lhs.sign_ && !rhs.sign_; + #else + return false; + #endif + } + return lhs.significand_ == 0 ? !rhs.sign_ : lhs.sign_; + } + + if (lhs.sign_ != rhs.sign_) + { + return lhs.sign_; + } + + if (lhs.exponent_ != rhs.exponent_) + { + return lhs.sign_ ? lhs.exponent_ > rhs.exponent_ : lhs.exponent_ < rhs.exponent_; + } + + return lhs.sign_ ? lhs.significand_ > rhs.significand_ : lhs.significand_ < rhs.significand_; +} + template BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_type_less_parts_impl(T lhs_sig, U lhs_exp, bool lhs_sign, T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> bool diff --git a/include/boost/decimal/detail/concepts.hpp b/include/boost/decimal/detail/concepts.hpp index 16634156..371825e0 100644 --- a/include/boost/decimal/detail/concepts.hpp +++ b/include/boost/decimal/detail/concepts.hpp @@ -228,6 +228,9 @@ concept random_access_container = is_container && template concept decimal_floating_point_type = boost::decimal::detail::is_decimal_floating_point_v; +template +concept fast_decimal_floating_point_type = boost::decimal::detail::is_fast_type_v; + } // boost::decimal::detail::concepts #define BOOST_DECIMAL_HAS_CONCEPTS 1 @@ -253,6 +256,7 @@ concept decimal_floating_point_type = boost::decimal::detail::is_decimal_floatin #define BOOST_DECIMAL_ARBITRARY_REAL_OR_COMPLEX boost::decimal::detail::concepts::arbitrary_real_or_complex_type #define BOOST_DECIMAL_ARBITRARY_NUMERICAL boost::decimal::detail::concepts::arbitrary_numerical_type #define BOOST_DECIMAL_DECIMAL_FLOATING_TYPE boost::decimal::detail::concepts::decimal_floating_point_type +#define BOOST_DECIMAL_FAST_DECIMAL_FLOATING_TYPE boost::decimal::detail::concepts::fast_decimal_floating_point_type #define BOOST_DECIMAL_CONTAINER boost::decimal::detail::concepts::is_container #define BOOST_DECIMAL_RANDOM_ACCESS_CONTAINER boost::decimal::detail::concepts::random_access_container @@ -388,6 +392,10 @@ concept execution_policy = std::is_execution_policy_v>; # define BOOST_DECIMAL_DECIMAL_FLOATING_TYPE typename #endif +#ifndef BOOST_DECIMAL_FAST_DECIMAL_FLOATING_TYPE +# define BOOST_DECIMAL_FAST_DECIMAL_FLOATING_TYPE typename +#endif + #ifndef BOOST_DECIMAL_OUTPUT_ITER # define BOOST_DECIMAL_OUTPUT_ITER(I, T) #endif