mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-06 02:07:07 +00:00
Compare commits
13 Commits
pratik/Ret
...
vvysokikh/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1670f5614 | ||
|
|
6056045f2e | ||
|
|
a489708326 | ||
|
|
8b6b075397 | ||
|
|
cdcae49fdb | ||
|
|
763bba2aba | ||
|
|
35521e1065 | ||
|
|
7f2d18f99e | ||
|
|
4ca1c6d97f | ||
|
|
52c6652a56 | ||
|
|
7ed000495c | ||
|
|
89c38e6220 | ||
|
|
00d46c5423 |
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <array>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
@@ -401,40 +402,41 @@ public:
|
||||
x.exponent_ == y.exponent_;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator!=(Number const& x, Number const& y) noexcept
|
||||
// operator!=, >, <=, >= are synthesized from operator== and operator<=>.
|
||||
friend constexpr std::strong_ordering
|
||||
operator<=>(Number const& l, Number const& r) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
bool const lneg = l.negative_;
|
||||
bool const rneg = r.negative_;
|
||||
|
||||
friend constexpr bool
|
||||
operator<(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
// 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_;
|
||||
|
||||
// then the negative one is smaller.
|
||||
if (lneg != rneg)
|
||||
return lneg;
|
||||
{
|
||||
return lneg ? std::strong_ordering::less : std::strong_ordering::greater;
|
||||
}
|
||||
|
||||
// Both have same sign and the left is zero: the right must be
|
||||
// greater than 0.
|
||||
if (x.mantissa_ == 0)
|
||||
return y.mantissa_ > 0;
|
||||
// Same sign: compare the unsigned magnitudes |a| <=> |b|. For negative
|
||||
// values the order is reversed (larger magnitude == smaller value), so
|
||||
// swap the operands. A negative value is never zero, so the zero checks
|
||||
// below only ever fire for the non-negative case.
|
||||
Number const& a = lneg ? r : l;
|
||||
Number const& b = lneg ? l : r;
|
||||
|
||||
// Both have same sign, the right is zero and the left is non-zero.
|
||||
if (y.mantissa_ == 0)
|
||||
return false;
|
||||
// A zero mantissa carries a sentinel exponent, so zero has to be handled
|
||||
// before the exponents can be compared.
|
||||
if (a.mantissa_ == 0)
|
||||
{
|
||||
return b.mantissa_ == 0 ? std::strong_ordering::equal : std::strong_ordering::less;
|
||||
}
|
||||
if (b.mantissa_ == 0)
|
||||
return std::strong_ordering::greater;
|
||||
|
||||
// Both have the same sign, compare by exponents:
|
||||
if (x.exponent_ > y.exponent_)
|
||||
return lneg;
|
||||
if (x.exponent_ < y.exponent_)
|
||||
return !lneg;
|
||||
|
||||
// If equal exponents, compare mantissas
|
||||
return x.mantissa_ < y.mantissa_;
|
||||
// Both are non-zero and normalized, so the exponent dominates and the
|
||||
// mantissa breaks ties.
|
||||
if (auto const cmp = a.exponent_ <=> b.exponent_; cmp != 0)
|
||||
return cmp;
|
||||
return a.mantissa_ <=> b.mantissa_;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
@@ -449,24 +451,6 @@ public:
|
||||
[[nodiscard]] Number
|
||||
truncate() const noexcept;
|
||||
|
||||
friend constexpr bool
|
||||
operator>(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator<=(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator>=(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, Number const& x)
|
||||
{
|
||||
|
||||
@@ -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,8 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -1386,10 +1389,103 @@ 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 test = [this](auto const& nums) {
|
||||
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 + " (! <=)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto const intNums = [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});
|
||||
// Check this list is sorted before converting it to Numbers.
|
||||
// That way if any of the other tests fail, we know it's because of code and not the
|
||||
// source data.
|
||||
BEAST_EXPECT(std::ranges::is_sorted(values));
|
||||
|
||||
std::vector<Number> result;
|
||||
result.reserve(values.size());
|
||||
for (auto const v : values)
|
||||
result.emplace_back(v);
|
||||
return result;
|
||||
}();
|
||||
|
||||
auto const otherNums = std::to_array<Number>({
|
||||
Number{-5, 100},
|
||||
Number{-1, 100},
|
||||
Number{-7, -10},
|
||||
Number{-2, -10},
|
||||
Number{0},
|
||||
Number{2, -10},
|
||||
Number{7, -10},
|
||||
Number{1, 100},
|
||||
Number{5, 100},
|
||||
});
|
||||
|
||||
test(intNums);
|
||||
test(otherNums);
|
||||
}
|
||||
|
||||
{
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user