diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index ab1df71a9..125dd58f5 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -194,6 +194,9 @@ BOOST_DECIMAL_EXPORT class decimal128 final template friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType; + template + friend BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool; + // Equality template between any integer type and decimal128 template friend constexpr auto mixed_equality_impl(Decimal lhs, Integer rhs) noexcept @@ -1202,16 +1205,7 @@ constexpr auto operator-(decimal128 rhs) noexcept-> decimal128 constexpr auto operator==(decimal128 lhs, decimal128 rhs) noexcept -> bool { - #ifndef BOOST_DECIMAL_FAST_MATH - // Check for IEEE requirement that nan != nan - if (isnan(lhs) || isnan(rhs)) - { - return false; - } - #endif - - return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()); + return equality_impl(lhs, rhs); } template diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index 57920d613..0e12d320f 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -537,16 +537,28 @@ 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) || isnan(rhs)) + if (isnan(lhs)) { return false; } #endif - return lhs.sign_ == rhs.sign_ && - lhs.exponent_ == rhs.exponent_ && - lhs.significand_ == rhs.significand_; + if (lhs.significand_ == 0) + { + return true; // -0 == +0 + } + + return lhs.sign_ == rhs.sign_; } template diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 1841bf15e..5e8b34b92 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -490,13 +490,28 @@ constexpr auto isfinite(decimal32_fast val) noexcept -> bool 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_); + 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_; } constexpr auto operator!=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 26cc32bbf..f15a278a5 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -518,16 +518,28 @@ 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) || isnan(rhs)) + if (isnan(lhs)) { return false; } #endif - return lhs.sign_ == rhs.sign_ && - lhs.exponent_ == rhs.exponent_ && - lhs.significand_ == rhs.significand_; + if (lhs.significand_ == 0) + { + return true; // -0 == +0 + } + + return lhs.sign_ == rhs.sign_; } template diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 41bec656e..2ec308ec9 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -38,7 +38,21 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal } #endif - // Step 3: Check signs + // Step 2: Fast path + if (lhs.bits_ == rhs.bits_) + { + return true; + } + + // Step 3: Check -0 == +0 + auto lhs_sig {lhs.full_significand()}; + auto rhs_sig {rhs.full_significand()}; + if (lhs_sig == 0 && rhs_sig == 0) + { + return true; + } + + // Step 4: Check signs const auto lhs_neg {lhs.isneg()}; const auto rhs_neg {rhs.isneg()}; @@ -47,27 +61,19 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal return false; } - // Step 4: Check the exponents + // Step 5: Check the exponents // If the difference is greater than we can represent in the significand than we can assume they are different const auto lhs_exp {lhs.biased_exponent()}; const auto rhs_exp {rhs.biased_exponent()}; - auto lhs_sig {lhs.full_significand()}; - auto rhs_sig {rhs.full_significand()}; - const auto delta_exp {lhs_exp - rhs_exp}; - if (lhs_sig == 0 && rhs_sig == 0) - { - // The difference in exponent is irrelevant here - return true; - } if (delta_exp > detail::precision_v || delta_exp < -detail::precision_v) { return false; } - // Step 5: Normalize the significand and compare + // Step 6: Normalize the significand and compare // Instead of multiplying the larger number, divide the smaller one if (delta_exp >= 0) { diff --git a/test/random_decimal128_comp.cpp b/test/random_decimal128_comp.cpp index 735b22b77..b7a24e159 100644 --- a/test/random_decimal128_comp.cpp +++ b/test/random_decimal128_comp.cpp @@ -574,5 +574,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal128{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal128{0, 0, true}; + BOOST_TEST(pos_zero == neg_zero); + return boost::report_errors(); } diff --git a/test/random_decimal128_fast_comp.cpp b/test/random_decimal128_fast_comp.cpp index 84711e2b1..78eed0f73 100644 --- a/test/random_decimal128_fast_comp.cpp +++ b/test/random_decimal128_fast_comp.cpp @@ -593,5 +593,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal128_fast{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal128_fast{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + return boost::report_errors(); } diff --git a/test/random_decimal32_comp.cpp b/test/random_decimal32_comp.cpp index ad68386f3..01182eace 100644 --- a/test/random_decimal32_comp.cpp +++ b/test/random_decimal32_comp.cpp @@ -606,5 +606,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal32{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal32{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + return boost::report_errors(); } diff --git a/test/random_decimal32_fast_comp.cpp b/test/random_decimal32_fast_comp.cpp index 4a7f5c381..a33f30d29 100644 --- a/test/random_decimal32_fast_comp.cpp +++ b/test/random_decimal32_fast_comp.cpp @@ -593,5 +593,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal32_fast{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal32_fast{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + return boost::report_errors(); } diff --git a/test/random_decimal64_comp.cpp b/test/random_decimal64_comp.cpp index 9b568f418..4b6d94e0e 100644 --- a/test/random_decimal64_comp.cpp +++ b/test/random_decimal64_comp.cpp @@ -571,5 +571,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal64{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal64{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + return boost::report_errors(); } diff --git a/test/random_decimal64_fast_comp.cpp b/test/random_decimal64_fast_comp.cpp index ea24b9fa3..614638bf6 100644 --- a/test/random_decimal64_fast_comp.cpp +++ b/test/random_decimal64_fast_comp.cpp @@ -593,5 +593,9 @@ int main() random_mixed_SPACESHIP(std::numeric_limits::min(), std::numeric_limits::max()); #endif + constexpr auto pos_zero = boost::decimal::decimal64_fast{0, 0, false}; + constexpr auto neg_zero = boost::decimal::decimal64_fast{0, 0, true}; + BOOST_TEST_EQ(pos_zero, neg_zero); + return boost::report_errors(); }