diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index 0eff422b2..b0e0b2130 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -63,13 +63,16 @@ namespace detail { // See IEEE 754 section 3.5.2 BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_inf_mask {UINT64_C(0b0'11110'00000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; -BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d128_inf_mask_high_bits {UINT64_C(0b0'11110'00000000'0000000000'0000000000'0000000000'0000000000'0000000000)}; BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_nan_mask {UINT64_C(0b0'11111'00000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_snan_mask {UINT64_C(0b0'11111'10000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_comb_inf_mask {UINT64_C(0b0'11110'00000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_comb_nan_mask {UINT64_C(0b0'11111'00000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_exp_snan_mask {UINT64_C(0b0'00000'10000000'0000000000'0000000000'0000000000'0000000000'0000000000), UINT64_C(0)}; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d128_inf_mask_high_bits {UINT64_C(0b0'11110'00000000'0000000000'0000000000'0000000000'0000000000'0000000000)}; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d128_nan_mask_high_bits {UINT64_C(0b0'11111'00000000'0000000000'0000000000'0000000000'0000000000'0000000000)}; +BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d128_snan_mask_high_bits {UINT64_C(0b0'11111'10000000'0000000000'0000000000'0000000000'0000000000'0000000000)}; + // Masks to update the significand based on the combination field // In these first three 00, 01, or 10 are the leading 2 bits of the exp // and the trailing 3 bits are to be concatenated onto the significand @@ -1107,17 +1110,17 @@ constexpr auto signbit BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) constexpr auto isnan BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { - return (rhs.bits_.high & detail::d128_nan_mask.high) == detail::d128_nan_mask.high; + return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_nan_mask_high_bits; } constexpr auto isinf BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { - return ((rhs.bits_.high & detail::d128_nan_mask.high) == detail::d128_inf_mask.high); + return (rhs.bits_.high & detail::d128_nan_mask_high_bits) == detail::d128_inf_mask_high_bits; } constexpr auto issignaling BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { - return (rhs.bits_.high & detail::d128_snan_mask.high) == detail::d128_snan_mask.high; + return (rhs.bits_.high & detail::d128_snan_mask_high_bits) == detail::d128_snan_mask_high_bits; } constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool @@ -1136,12 +1139,12 @@ constexpr auto isnormal BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs) noexcept -> bool { - return ((rhs.bits_.high & detail::d128_inf_mask_high_bits) != detail::d128_inf_mask_high_bits); + return (rhs.bits_.high & detail::d128_inf_mask_high_bits) != detail::d128_inf_mask_high_bits; } constexpr auto not_finite(decimal128 rhs) noexcept -> bool { - return ((rhs.bits_.high & detail::d128_inf_mask_high_bits) == detail::d128_inf_mask_high_bits); + return (rhs.bits_.high & detail::d128_inf_mask_high_bits) == detail::d128_inf_mask_high_bits; } constexpr auto operator+(decimal128 rhs) noexcept -> decimal128 @@ -1206,27 +1209,21 @@ constexpr auto operator!=(Integer lhs, decimal128 rhs) noexcept constexpr auto operator<(decimal128 lhs, decimal128 rhs) noexcept -> bool { #ifndef BOOST_DECIMAL_FAST_MATH - 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 !rhs.isneg(); - } - #else - if (!lhs.isneg() && rhs.isneg()) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) + if (not_finite(lhs) || not_finite(rhs)) { - return true; + 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 !rhs.isneg(); + } } #endif diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 11793de13..abf5f9280 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -25,9 +25,13 @@ namespace decimal { namespace detail { -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_inf = std::numeric_limits::max() - 2; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_qnan = std::numeric_limits::max() - 1; -BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_snan = std::numeric_limits::max(); +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_inf = uint128{UINT64_MAX - 2, UINT64_MAX}; +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_qnan = uint128{UINT64_MAX - 1, UINT64_MAX}; +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_snan = uint128{UINT64_MAX, UINT64_MAX}; + +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_inf_high_bits = UINT64_MAX - 2; +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_qnan_high_bits = UINT64_MAX - 1; +BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_snan_high_bits = UINT64_MAX; struct decimal128_fast_components { @@ -460,17 +464,17 @@ constexpr auto signbit(decimal128_fast val) noexcept -> bool constexpr auto isinf(decimal128_fast val) noexcept -> bool { - return val.significand_ == detail::d128_fast_inf; + return val.significand_.high == detail::d128_fast_inf_high_bits; } constexpr auto isnan(decimal128_fast val) noexcept -> bool { - return val.significand_ >= detail::d128_fast_qnan; + return val.significand_.high >= detail::d128_fast_qnan_high_bits; } constexpr auto issignaling(decimal128_fast val) noexcept -> bool { - return val.significand_ == detail::d128_fast_snan; + return val.significand_.high == detail::d128_fast_snan_high_bits; } constexpr auto isnormal(decimal128_fast val) noexcept -> bool @@ -485,12 +489,12 @@ constexpr auto isnormal(decimal128_fast val) noexcept -> bool constexpr auto isfinite(decimal128_fast val) noexcept -> bool { - return val.significand_ < detail::d128_fast_inf; + return val.significand_.high < detail::d128_fast_inf_high_bits; } constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool { - return val.significand_ >= detail::d128_fast_inf; + return val.significand_.high >= detail::d128_fast_inf_high_bits; } constexpr auto operator==(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool @@ -542,40 +546,48 @@ 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 (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); - } -#else - if (!lhs.isneg() && rhs.isneg()) - { - return false; - } - else if (lhs.isneg() && !rhs.isneg()) + #ifndef BOOST_DECIMAL_FAST_MATH + if (not_finite(lhs) || not_finite(rhs)) { - return true; + 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 + #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_; diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 9fa0cdfee..8e10379ef 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -27,9 +27,9 @@ namespace decimal { template constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, - T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, bool> + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value || std::is_same::value, bool> { - using comp_type = std::conditional_t::value, std::uint_fast32_t, std::uint_fast64_t>; + using comp_type = typename DecimalType::significand_type; BOOST_DECIMAL_ASSERT(lhs_sig >= 0); BOOST_DECIMAL_ASSERT(rhs_sig >= 0); @@ -76,7 +76,7 @@ constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, template constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, - T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value), bool> + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value || std::is_same::value), bool> { using comp_type = std::conditional_t<(std::numeric_limits::digits10 > std::numeric_limits::digits10), T1, T2>; @@ -170,9 +170,9 @@ constexpr auto operator!=(Decimal1 lhs, Decimal2 rhs) noexcept template constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, - T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value, bool> + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value || std::is_same::value, bool> { - using comp_type = std::uint_fast64_t; + using comp_type = std::conditional_t::value, detail::uint128, std::uint_fast64_t>; BOOST_DECIMAL_ASSERT(lhs_sig >= 0); BOOST_DECIMAL_ASSERT(rhs_sig >= 0); @@ -204,7 +204,7 @@ constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, template constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, - T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value), bool> + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value || std::is_same::value || std::is_same::value), bool> { using comp_type = std::conditional_t<(std::numeric_limits::digits10 > std::numeric_limits::digits10), T1, T2>;