diff --git a/src/ripple/basics/Number.h b/src/ripple/basics/Number.h index 607db3ff8..50975e7d0 100644 --- a/src/ripple/basics/Number.h +++ b/src/ripple/basics/Number.h @@ -21,6 +21,7 @@ #define RIPPLE_BASICS_NUMBER_H_INCLUDED #include +#include #include #include #include @@ -51,6 +52,7 @@ public: explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; Number(IOUAmount const& x); + Number(XRPAmount const& x); constexpr rep mantissa() const noexcept; @@ -81,6 +83,8 @@ public: operator/=(Number const& x); explicit operator IOUAmount() const; + explicit operator XRPAmount() const; // round to nearest, even on tie + explicit operator rep() const; // round to nearest, even on tie friend constexpr bool operator==(Number const& x, Number const& y) noexcept @@ -184,6 +188,10 @@ inline Number::Number(IOUAmount const& x) : Number{x.mantissa(), x.exponent()} { } +inline Number::Number(XRPAmount const& x) : Number{x.drops()} +{ +} + inline constexpr Number::rep Number::mantissa() const noexcept { diff --git a/src/ripple/basics/impl/Number.cpp b/src/ripple/basics/impl/Number.cpp index 1f056a2d9..c9e9c51ce 100644 --- a/src/ripple/basics/impl/Number.cpp +++ b/src/ripple/basics/impl/Number.cpp @@ -374,6 +374,45 @@ Number::operator/=(Number const& y) return *this; } +Number::operator rep() const +{ + std::int64_t drops = mantissa_; + int offset = exponent_; + guard g; + if (drops != 0) + { + if (drops < 0) + { + g.set_negative(); + drops = -drops; + } + for (; offset < 0; ++offset) + { + g.push(drops % 10); + drops /= 10; + } + for (; offset > 0; --offset) + { + if (drops > std::numeric_limits::max() / 10) + throw std::runtime_error("Number::operator rep() overflow"); + drops *= 10; + } + auto r = g.round(); + if (r == 1 || (r == 0 && (drops & 1) == 1)) + { + ++drops; + } + if (g.is_negative()) + drops = -drops; + } + return drops; +} + +Number::operator XRPAmount() const +{ + return XRPAmount{static_cast(*this)}; +} + std::string to_string(Number const& amount) { diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index 570e16287..444095bfb 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -126,6 +126,75 @@ public: BEAST_EXPECT(x == z); } + void + test_to_integer() + { + Number x[]{ + Number{0}, + Number{1}, + Number{2}, + Number{3}, + Number{-1}, + Number{-2}, + Number{-3}, + Number{10}, + Number{99}, + Number{1155}, + Number{9'999'999'999'999'999, 0}, + Number{9'999'999'999'999'999, 1}, + Number{9'999'999'999'999'999, 2}, + Number{-9'999'999'999'999'999, 2}, + Number{15, -1}, + Number{14, -1}, + Number{16, -1}, + Number{25, -1}, + Number{6, -1}, + Number{5, -1}, + Number{4, -1}, + Number{-15, -1}, + Number{-14, -1}, + Number{-16, -1}, + Number{-25, -1}, + Number{-6, -1}, + Number{-5, -1}, + Number{-4, -1}}; + std::int64_t y[]{ + 0, + 1, + 2, + 3, + -1, + -2, + -3, + 10, + 99, + 1155, + 9'999'999'999'999'999, + 99'999'999'999'999'990, + 999'999'999'999'999'900, + -999'999'999'999'999'900, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + -2, + -1, + -2, + -2, + -1, + 0, + 0}; + static_assert(std::size(x) == std::size(y)); + for (unsigned u = 0; u < std::size(x); ++u) + { + auto j = static_cast(x[u]); + BEAST_EXPECT(j == y[u]); + } + } + void run() override { @@ -135,6 +204,7 @@ public: test_div(); test_root(); testConversions(); + test_to_integer(); } };