From 3934fdb658d05aeb093d182eae67eeb163341d54 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Mon, 26 Jan 2026 19:50:38 -0500 Subject: [PATCH] [WIP] Checkpoint --- include/xrpl/basics/Number.h | 47 ++++++++-------- src/libxrpl/basics/Number.cpp | 102 +++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 62 deletions(-) diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 4ae815e681..799e055575 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -157,12 +157,7 @@ private: static constexpr rep computeMin(rep max) { - auto min = max + 1; - auto const r = min % 10; - min /= 10; - if (r != 0) - ++min; - return min; + return max / 10 + 1; } static constexpr rep @@ -293,9 +288,7 @@ class Number using rep = std::int64_t; using internalrep = MantissaRange::rep; - // TODO: Get rid of negative_ and convert mantissa back to rep - bool negative_{false}; - internalrep mantissa_{0}; + rep mantissa_{0}; int exponent_{std::numeric_limits::lowest()}; public: @@ -393,7 +386,7 @@ public: friend constexpr bool operator==(Number const& x, Number const& y) noexcept { - return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ && + return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_; } @@ -408,8 +401,8 @@ public: { // 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_; + bool const lneg = x.mantissa_ < 0; + bool const rneg = y.mantissa_ < 0; if (lneg != rneg) return lneg; @@ -437,7 +430,7 @@ public: constexpr int signum() const noexcept { - return negative_ ? -1 : (mantissa_ ? 1 : 0); + return mantissa_ < 0 ? -1 : (mantissa_ ? 1 : 0); } Number @@ -620,6 +613,11 @@ private: std::tuple toInternal() const; + // Set the Number from an internal representation + template + void + fromInternal(bool negative, Rep mantissa, int exponent); + class Guard; public: @@ -631,7 +629,7 @@ inline constexpr Number::Number( internalrep mantissa, int exponent, unchecked) noexcept - : negative_(negative), mantissa_{mantissa}, exponent_{exponent} + : mantissa_{(negative ? -1 : 1) * static_cast(mantissa)}, exponent_{exponent} { } @@ -650,9 +648,10 @@ inline Number::Number( internalrep mantissa, int exponent, normalized) - : Number(negative, mantissa, exponent, unchecked{}) { - normalize(); + auto const& range = range_.get(); + normalize(negative, mantissa, exponent, range.min, range.max); + fromInternal(negative, mantissa, exponent); } inline Number::Number(internalrep mantissa, int exponent, normalized) @@ -677,8 +676,7 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0} inline constexpr Number::rep Number::mantissa() const noexcept { - auto const sign = negative_ ? -1 : 1; - return sign * static_cast(mantissa_); + return mantissa_; } /** Returns the exponent of the external view of the Number. @@ -704,7 +702,7 @@ Number::operator-() const noexcept if (mantissa_ == 0) return Number{}; auto x = *this; - x.negative_ = !x.negative_; + x.mantissa_ = -1 * x.mantissa_; return x; } @@ -798,7 +796,8 @@ inline bool Number::isnormal() const noexcept { MantissaRange const& range = range_; - auto const abs_m = mantissa_; + auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_; + return *this == Number{} || (range.min <= abs_m && abs_m <= range.max && // minExponent <= exponent_ && exponent_ <= maxExponent); @@ -808,8 +807,9 @@ template std::pair Number::normalizeToRange(T minMantissa, T maxMantissa) const { - bool negative = negative_; - internalrep mantissa = mantissa_; + bool negative = mantissa_ < 0; + auto const sign = negative ? -1 : 1; + internalrep mantissa = sign * mantissa_; int exponent = exponent_; if constexpr (std::is_unsigned_v) @@ -819,8 +819,7 @@ Number::normalizeToRange(T minMantissa, T maxMantissa) const "Number is non-negative for unsigned range."); Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa); - auto const sign = negative ? -1 : 1; - return std::make_pair(static_cast(sign * mantissa), exponent); + return std::make_pair(sign * static_cast(mantissa), exponent); } inline constexpr Number diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 8be63e4b3c..2ee55d3307 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -257,7 +257,7 @@ Number::Guard::bringIntoRange( { constexpr Number zero = Number{}; - negative = zero.negative_; + negative = false; mantissa = zero.mantissa_; exponent = zero.exponent_; } @@ -365,25 +365,54 @@ std::tuple Number::toInternal() const { auto exponent = exponent_; - Rep mantissa = mantissa_; - bool const negative = negative_; + bool const negative = mantissa_ < 0; + auto const sign = negative ? -1 : 1; + Rep mantissa = static_cast(sign * mantissa_); - auto const referenceMin = Number::range_.get().referenceMin; + auto const& range = Number::range_.get(); + auto const referenceMin = range.referenceMin; + auto const minMantissa = range.min; - if (mantissa != 0 && mantissa < referenceMin) + if (mantissa != 0 && mantissa >= minMantissa && mantissa < referenceMin) { // Ensure the mantissa has the correct number of digits mantissa *= 10; --exponent; + XRPL_ASSERT_PARTS( + mantissa >= referenceMin && mantissa < referenceMin * 10, + "ripple::Number::toInternal()", + "Number is within reference range and has 'log' digits"); } - XRPL_ASSERT_PARTS( - mantissa >= referenceMin && mantissa < referenceMin * 10, - "ripple::Number::toInternal()", - "Number is within reference range and has 'log' digits"); return {negative, mantissa, exponent}; } +template +void +Number::fromInternal(bool negative, Rep mantissa, int exponent) +{ + auto const sign = negative ? -1 : 1; + + auto const& range = Number::range_.get(); + auto const maxMantissa = range.max; + + XRPL_ASSERT_PARTS( + mantissa <= maxMantissa, + "ripple::Number::fromInternal", + "mantissa in range"); + if constexpr (std::is_signed_v) + XRPL_ASSERT_PARTS( + mantissa >= -maxMantissa, + "xrpl::Number::fromInternal", + "negative mantissa in range"); + + mantissa_ = sign * static_cast(mantissa); + exponent_ = exponent; + + XRPL_ASSERT_PARTS( + isnormal(), "ripple::Number::fromInternal", "Number is normalized"); +} + constexpr Number Number::oneSmall() { @@ -437,7 +466,7 @@ doNormalize( { mantissa = zero.mantissa_; exponent = zero.exponent_; - negative = zero.negative_; + negative = false; return; } @@ -462,7 +491,7 @@ doNormalize( { mantissa = zero.mantissa_; exponent = zero.exponent_; - negative = zero.negative_; + negative = false; return; } @@ -530,7 +559,13 @@ void Number::normalize() { auto const& range = range_.get(); - normalize(negative_, mantissa_, exponent_, range.min, range.max); + + auto [negative, mantissa, exponent] = toInternal(); + + normalize(negative, mantissa, exponent, range.min, range.max); + auto const sign = negative ? -1 : 1; + + fromInternal(negative, mantissa, exponent); } // Copy the number, but set a new exponent. Because the mantissa doesn't change, @@ -540,6 +575,9 @@ Number Number::shiftExponent(int exponentDelta) const { XRPL_ASSERT_PARTS(isnormal(), "xrpl::Number::shiftExponent", "normalized"); + + auto const [negative, mantissa, exponent] = toInternal(); + auto const newExponent = exponent_ + exponentDelta; if (newExponent >= maxExponent) throw std::overflow_error("Number::shiftExponent"); @@ -547,7 +585,9 @@ Number::shiftExponent(int exponentDelta) const { return Number{}; } - Number const result{negative_, mantissa_, newExponent, unchecked{}}; + + Number const result{negative, mantissa, newExponent, unchecked{}}; + XRPL_ASSERT_PARTS( result.isnormal(), "xrpl::Number::shiftExponent", @@ -646,10 +686,8 @@ Number::operator+=(Number const& y) g.doRoundDown(xn, xm, xe, minMantissa); } - negative_ = xn; - mantissa_ = static_cast(xm); - exponent_ = xe; - normalize(); + normalize(xn, xm, xe, minMantissa, maxMantissa); + fromInternal(xn, xm, xe); return *this; } @@ -697,15 +735,11 @@ Number::operator*=(Number const& y) // *m = mantissa // *e = exponent - bool xn = negative_; + auto [xn, xm, xe] = toInternal(); int xs = xn ? -1 : 1; - internalrep xm = mantissa_; - auto xe = exponent_; - bool yn = y.negative_; + auto [yn, ym, ye] = y.toInternal(); int ys = yn ? -1 : 1; - internalrep ym = y.mantissa_; - auto ye = y.exponent_; auto zm = uint128_t(xm) * uint128_t(ym); auto ze = xe + ye; @@ -736,11 +770,9 @@ Number::operator*=(Number const& y) minMantissa, maxMantissa, "Number::multiplication overflow : exponent is " + std::to_string(xe)); - negative_ = zn; - mantissa_ = xm; - exponent_ = xe; - normalize(); + normalize(zn, xm, xe, minMantissa, maxMantissa); + fromInternal(zn, xm, xe); return *this; } @@ -759,15 +791,11 @@ Number::operator/=(Number const& y) // *m = mantissa // *e = exponent - bool np = negative_; + auto [np, nm, ne] = toInternal(); int ns = (np ? -1 : 1); - auto nm = mantissa_; - auto ne = exponent_; - bool dp = y.negative_; + auto [dp, dm, de] = y.toInternal(); int ds = (dp ? -1 : 1); - auto dm = y.mantissa_; - auto de = y.exponent_; auto const& range = range_.get(); auto const& minMantissa = range.min; @@ -833,9 +861,7 @@ Number::operator/=(Number const& y) } } normalize(zn, zm, ze, minMantissa, maxMantissa); - negative_ = zn; - mantissa_ = static_cast(zm); - exponent_ = ze; + fromInternal(zn, zm, ze); XRPL_ASSERT_PARTS( isnormal(), "xrpl::Number::operator/=", "result is normalized"); @@ -849,7 +875,7 @@ Number::operator rep() const Guard g; if (drops != 0) { - if (negative_) + if (drops < 0) { g.set_negative(); drops = -drops; @@ -861,7 +887,7 @@ Number::operator rep() const } for (; offset > 0; --offset) { - if (drops > largeRange.max / 10) + if (drops >= largeRange.min) throw std::overflow_error("Number::operator rep() overflow"); drops *= 10; }