Skip to content

Commit

Permalink
Merge pull request #815 from cppalliance/811
Browse files Browse the repository at this point in the history
Make -0 = +0
  • Loading branch information
mborland authored Jan 21, 2025
2 parents 6aa62b9 + f25014b commit b4f8cad
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 36 deletions.
14 changes: 4 additions & 10 deletions include/boost/decimal/decimal128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ BOOST_DECIMAL_EXPORT class decimal128 final
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal>
friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType;

template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType>
friend BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool;

// Equality template between any integer type and decimal128
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal, BOOST_DECIMAL_INTEGRAL Integer>
friend constexpr auto mixed_equality_impl(Decimal lhs, Integer rhs) noexcept
Expand Down Expand Up @@ -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<decimal128>(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(),
rhs.full_significand(), rhs.biased_exponent(), rhs.isneg());
return equality_impl(lhs, rhs);
}

template <typename Integer>
Expand Down
20 changes: 16 additions & 4 deletions include/boost/decimal/decimal128_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename Integer>
Expand Down
29 changes: 22 additions & 7 deletions include/boost/decimal/decimal32_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 16 additions & 4 deletions include/boost/decimal/decimal64_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename Integer>
Expand Down
28 changes: 17 additions & 11 deletions include/boost/decimal/detail/comparison.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()};

Expand All @@ -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<DecimalType> || delta_exp < -detail::precision_v<DecimalType>)
{
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)
{
Expand Down
4 changes: 4 additions & 0 deletions test/random_decimal128_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,5 +574,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}
4 changes: 4 additions & 0 deletions test/random_decimal128_fast_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,5 +593,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}
4 changes: 4 additions & 0 deletions test/random_decimal32_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,5 +606,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}
4 changes: 4 additions & 0 deletions test/random_decimal32_fast_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,5 +593,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}
4 changes: 4 additions & 0 deletions test/random_decimal64_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,5 +571,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}
4 changes: 4 additions & 0 deletions test/random_decimal64_fast_comp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,5 +593,9 @@ int main()
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::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();
}

0 comments on commit b4f8cad

Please sign in to comment.