Compare commits

...

7 Commits

Author SHA1 Message Date
Ed Hennis
bc9a058c69 Make the Relational tests way more comprehensive
- Test combinatorically with a large variety of values.
2026-06-04 13:19:02 -04:00
Ed Hennis
ee9f2fb830 clang-format complains about the equality tests 2026-06-04 12:28:48 -04:00
Ed Hennis
1af5bfc2bf Improve readability 2026-06-04 12:28:21 -04:00
Ed Hennis
09a8589182 Fix the problem 2026-06-03 23:31:07 -04:00
Ed Hennis
5c8158a0cc Add test cases to testRelationals to show the problem 2026-06-03 21:44:41 -04:00
Ed Hennis
88e2d79f45 Revert "Comment out most Number comparisons"
This reverts commit a28e5777ba.
2026-06-03 21:14:07 -04:00
Ed Hennis
a28e5777ba Comment out most Number comparisons 2026-06-03 21:13:56 -04:00
2 changed files with 106 additions and 18 deletions

View File

@@ -408,33 +408,38 @@ public:
}
friend constexpr bool
operator<(Number const& x, Number const& y) noexcept
operator<(Number const& l, Number const& r) noexcept
{
bool const lneg = l.negative_;
bool const rneg = r.negative_;
// If the two amounts have different signs (zero is treated as positive)
// then the comparison is true iff the left is negative.
bool const lneg = x.negative_;
bool const rneg = y.negative_;
if (lneg != rneg)
return lneg;
// Both have same sign and the left is zero: the right must be
// greater than 0.
if (x.mantissa_ == 0)
return y.mantissa_ > 0;
// Both have same sign and the left is zero: both must be non-negative.
// If the right is greater than 0, then it is larger, so the comparison is true.
if (l.mantissa_ == 0)
return r.mantissa_ > 0;
// Both have same sign, the right is zero and the left is non-zero.
if (y.mantissa_ == 0)
// Both have same sign, the right is zero and the left is non-zero, so the left must be
// positive, and thus is larger, so the comparison is false.
if (r.mantissa_ == 0)
return false;
// Both have the same sign, compare by exponents:
if (x.exponent_ > y.exponent_)
if (l.exponent_ > r.exponent_)
return lneg;
if (x.exponent_ < y.exponent_)
if (l.exponent_ < r.exponent_)
return !lneg;
// If equal exponents, compare mantissas
return x.mantissa_ < y.mantissa_;
// If equal signs and exponents, compare mantissas.
if (lneg)
// If negative, the operator is reversed.
return l.mantissa_ > r.mantissa_;
return l.mantissa_ < r.mantissa_;
}
/** Return the sign of the amount */

View File

@@ -10,6 +10,7 @@
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/number.hpp>
#include <algorithm>
#include <array>
#include <cctype>
#include <cstdint>
@@ -20,6 +21,7 @@
#include <stdexcept>
#include <string>
#include <tuple>
#include <utility>
namespace xrpl {
@@ -1386,10 +1388,91 @@ public:
testRelationals()
{
testcase << "test_relationals " << to_string(Number::getMantissaScale());
BEAST_EXPECT(!(Number{100} < Number{10}));
BEAST_EXPECT(Number{100} > Number{10});
BEAST_EXPECT(Number{100} >= Number{10});
BEAST_EXPECT(!(Number{100} <= Number{10}));
{
auto const nums = [this]() {
// Inequality test cases are built from a list of sorted integers
auto const values =
std::to_array<int>({-100, -50, -20, -10, -1, 0, 1, 10, 20, 50, 100});
BEAST_EXPECT(std::ranges::is_sorted(values));
std::vector<Number> result;
result.reserve(values.size() + 1);
result.emplace_back(-1, 100);
for (auto const v : values)
{
if (v == 0)
result.emplace_back(-2, -10);
result.emplace_back(v);
if (v == 0)
result.emplace_back(2, -10);
}
result.emplace_back(1, 100);
return result;
}();
BEAST_EXPECT(std::ranges::is_sorted(nums));
for (auto iter1 = nums.begin(); iter1 != nums.end(); ++iter1)
{
auto iter2 = iter1;
for (++iter2; iter2 != nums.end(); ++iter2)
{
Number const& smaller = *iter1;
Number const& larger = *iter2;
std::stringstream ss;
ss << smaller << " < " << larger;
auto const str = ss.str();
// The ==/!= operators use a completely different code path than <, etc.
// This helps detect a breakage in one but not the other. It also helps
// verify that the values are being ordered correctly.
BEAST_EXPECTS(smaller != larger, str + " (!=)");
BEAST_EXPECTS(!(smaller == larger), str + " (==)");
// true results using operator< and derived operators
BEAST_EXPECTS(smaller < larger, str + " (<)");
BEAST_EXPECTS(larger > smaller, str + " (>)");
BEAST_EXPECTS(larger >= smaller, str + " (>=)");
BEAST_EXPECTS(smaller <= larger, str + " (<=)");
// false results using operator< and derived operators
BEAST_EXPECTS(!(larger < smaller), str + " (! <)");
BEAST_EXPECTS(!(smaller > larger), str + " (! >)");
BEAST_EXPECTS(!(smaller >= larger), str + " (! >=)");
BEAST_EXPECTS(!(larger <= smaller), str + " (! <=)");
}
}
}
{
// Equality test cases are <Number, __LINE__>. Number will be compared against itself
using Case = std::pair<Number, int>;
auto const c = std::to_array<Case>({
{700, __LINE__},
{50, __LINE__},
{1, __LINE__},
{0, __LINE__},
{-1, __LINE__},
{-30, __LINE__},
{-600, __LINE__},
});
for (auto const& [n, line] : c)
{
auto const str = to_string(n);
// NOLINTBEGIN(misc-redundant-expression) Explicitly testing operators with
// equivalent values
expect(n == n, str + " ==", __FILE__, line);
expect(!(n != n), str + " !=", __FILE__, line);
expect(!(n < n), str + " < ", __FILE__, line);
expect(!(n > n), str + " >", __FILE__, line);
expect(n >= n, str + " >=", __FILE__, line);
expect(n <= n, str + " <=", __FILE__, line);
// NOLINTEND(misc-redundant-expression)
}
}
}
void