Skip to content

Commit b4f8cad

Browse files
authored
Merge pull request #815 from cppalliance/811
Make -0 = +0
2 parents 6aa62b9 + f25014b commit b4f8cad

11 files changed

+99
-36
lines changed

include/boost/decimal/decimal128.hpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ BOOST_DECIMAL_EXPORT class decimal128 final
194194
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal>
195195
friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType;
196196

197+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType>
198+
friend BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, DecimalType rhs) noexcept -> bool;
199+
197200
// Equality template between any integer type and decimal128
198201
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal, BOOST_DECIMAL_INTEGRAL Integer>
199202
friend constexpr auto mixed_equality_impl(Decimal lhs, Integer rhs) noexcept
@@ -1202,16 +1205,7 @@ constexpr auto operator-(decimal128 rhs) noexcept-> decimal128
12021205

12031206
constexpr auto operator==(decimal128 lhs, decimal128 rhs) noexcept -> bool
12041207
{
1205-
#ifndef BOOST_DECIMAL_FAST_MATH
1206-
// Check for IEEE requirement that nan != nan
1207-
if (isnan(lhs) || isnan(rhs))
1208-
{
1209-
return false;
1210-
}
1211-
#endif
1212-
1213-
return equal_parts_impl<decimal128>(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(),
1214-
rhs.full_significand(), rhs.biased_exponent(), rhs.isneg());
1208+
return equality_impl(lhs, rhs);
12151209
}
12161210

12171211
template <typename Integer>

include/boost/decimal/decimal128_fast.hpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,16 +537,28 @@ constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool
537537

538538
constexpr auto operator==(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool
539539
{
540+
if (lhs.exponent_ != rhs.exponent_)
541+
{
542+
return false;
543+
}
544+
if (lhs.significand_ != rhs.significand_)
545+
{
546+
return false;
547+
}
548+
540549
#ifndef BOOST_DECIMAL_FAST_MATH
541-
if (isnan(lhs) || isnan(rhs))
550+
if (isnan(lhs))
542551
{
543552
return false;
544553
}
545554
#endif
546555

547-
return lhs.sign_ == rhs.sign_ &&
548-
lhs.exponent_ == rhs.exponent_ &&
549-
lhs.significand_ == rhs.significand_;
556+
if (lhs.significand_ == 0)
557+
{
558+
return true; // -0 == +0
559+
}
560+
561+
return lhs.sign_ == rhs.sign_;
550562
}
551563

552564
template <typename Integer>

include/boost/decimal/decimal32_fast.hpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -490,13 +490,28 @@ constexpr auto isfinite(decimal32_fast val) noexcept -> bool
490490

491491
constexpr auto operator==(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool
492492
{
493-
return
494-
#ifndef BOOST_DECIMAL_FAST_MATH
495-
!isnan(lhs) && !isnan(rhs) &&
496-
#endif
497-
(lhs.sign_ == rhs.sign_) &&
498-
(lhs.exponent_ == rhs.exponent_) &&
499-
(lhs.significand_ == rhs.significand_);
493+
if (lhs.exponent_ != rhs.exponent_)
494+
{
495+
return false;
496+
}
497+
if (lhs.significand_ != rhs.significand_)
498+
{
499+
return false;
500+
}
501+
502+
#ifndef BOOST_DECIMAL_FAST_MATH
503+
if (isnan(lhs))
504+
{
505+
return false;
506+
}
507+
#endif
508+
509+
if (lhs.significand_ == 0)
510+
{
511+
return true; // -0 == +0
512+
}
513+
514+
return lhs.sign_ == rhs.sign_;
500515
}
501516

502517
constexpr auto operator!=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool

include/boost/decimal/decimal64_fast.hpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -518,16 +518,28 @@ constexpr auto not_finite(decimal64_fast val) noexcept -> bool
518518

519519
constexpr auto operator==(decimal64_fast lhs, decimal64_fast rhs) noexcept -> bool
520520
{
521+
if (lhs.exponent_ != rhs.exponent_)
522+
{
523+
return false;
524+
}
525+
if (lhs.significand_ != rhs.significand_)
526+
{
527+
return false;
528+
}
529+
521530
#ifndef BOOST_DECIMAL_FAST_MATH
522-
if (isnan(lhs) || isnan(rhs))
531+
if (isnan(lhs))
523532
{
524533
return false;
525534
}
526535
#endif
527536

528-
return lhs.sign_ == rhs.sign_ &&
529-
lhs.exponent_ == rhs.exponent_ &&
530-
lhs.significand_ == rhs.significand_;
537+
if (lhs.significand_ == 0)
538+
{
539+
return true; // -0 == +0
540+
}
541+
542+
return lhs.sign_ == rhs.sign_;
531543
}
532544

533545
template <typename Integer>

include/boost/decimal/detail/comparison.hpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,21 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal
3838
}
3939
#endif
4040

41-
// Step 3: Check signs
41+
// Step 2: Fast path
42+
if (lhs.bits_ == rhs.bits_)
43+
{
44+
return true;
45+
}
46+
47+
// Step 3: Check -0 == +0
48+
auto lhs_sig {lhs.full_significand()};
49+
auto rhs_sig {rhs.full_significand()};
50+
if (lhs_sig == 0 && rhs_sig == 0)
51+
{
52+
return true;
53+
}
54+
55+
// Step 4: Check signs
4256
const auto lhs_neg {lhs.isneg()};
4357
const auto rhs_neg {rhs.isneg()};
4458

@@ -47,27 +61,19 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal
4761
return false;
4862
}
4963

50-
// Step 4: Check the exponents
64+
// Step 5: Check the exponents
5165
// If the difference is greater than we can represent in the significand than we can assume they are different
5266
const auto lhs_exp {lhs.biased_exponent()};
5367
const auto rhs_exp {rhs.biased_exponent()};
5468

55-
auto lhs_sig {lhs.full_significand()};
56-
auto rhs_sig {rhs.full_significand()};
57-
5869
const auto delta_exp {lhs_exp - rhs_exp};
5970

60-
if (lhs_sig == 0 && rhs_sig == 0)
61-
{
62-
// The difference in exponent is irrelevant here
63-
return true;
64-
}
6571
if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType>)
6672
{
6773
return false;
6874
}
6975

70-
// Step 5: Normalize the significand and compare
76+
// Step 6: Normalize the significand and compare
7177
// Instead of multiplying the larger number, divide the smaller one
7278
if (delta_exp >= 0)
7379
{

test/random_decimal128_comp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,5 +574,9 @@ int main()
574574
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::max());
575575
#endif
576576

577+
constexpr auto pos_zero = boost::decimal::decimal128{0, 0, false};
578+
constexpr auto neg_zero = boost::decimal::decimal128{0, 0, true};
579+
BOOST_TEST(pos_zero == neg_zero);
580+
577581
return boost::report_errors();
578582
}

test/random_decimal128_fast_comp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,5 +593,9 @@ int main()
593593
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::max());
594594
#endif
595595

596+
constexpr auto pos_zero = boost::decimal::decimal128_fast{0, 0, false};
597+
constexpr auto neg_zero = boost::decimal::decimal128_fast{0, 0, true};
598+
BOOST_TEST_EQ(pos_zero, neg_zero);
599+
596600
return boost::report_errors();
597601
}

test/random_decimal32_comp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,5 +606,9 @@ int main()
606606
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::max());
607607
#endif
608608

609+
constexpr auto pos_zero = boost::decimal::decimal32{0, 0, false};
610+
constexpr auto neg_zero = boost::decimal::decimal32{0, 0, true};
611+
BOOST_TEST_EQ(pos_zero, neg_zero);
612+
609613
return boost::report_errors();
610614
}

test/random_decimal32_fast_comp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,5 +593,9 @@ int main()
593593
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::max());
594594
#endif
595595

596+
constexpr auto pos_zero = boost::decimal::decimal32_fast{0, 0, false};
597+
constexpr auto neg_zero = boost::decimal::decimal32_fast{0, 0, true};
598+
BOOST_TEST_EQ(pos_zero, neg_zero);
599+
596600
return boost::report_errors();
597601
}

test/random_decimal64_comp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,5 +571,9 @@ int main()
571571
random_mixed_SPACESHIP(std::numeric_limits<unsigned long long>::min(), std::numeric_limits<unsigned long long>::max());
572572
#endif
573573

574+
constexpr auto pos_zero = boost::decimal::decimal64{0, 0, false};
575+
constexpr auto neg_zero = boost::decimal::decimal64{0, 0, true};
576+
BOOST_TEST_EQ(pos_zero, neg_zero);
577+
574578
return boost::report_errors();
575579
}

0 commit comments

Comments
 (0)