[WIP] Checkpoint

This commit is contained in:
Ed Hennis
2026-01-26 19:50:38 -05:00
parent df1e354e32
commit 3934fdb658
2 changed files with 87 additions and 62 deletions

View File

@@ -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<int>::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<bool, Rep, int>
toInternal() const;
// Set the Number from an internal representation
template <class Rep = internalrep>
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<rep>(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<Number::rep>(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 <Integral64 T>
std::pair<T, int>
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<T>)
@@ -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<T>(sign * mantissa), exponent);
return std::make_pair(sign * static_cast<T>(mantissa), exponent);
}
inline constexpr Number

View File

@@ -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<bool, Rep, int>
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<Rep>(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 <class Rep>
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<Rep>)
XRPL_ASSERT_PARTS(
mantissa >= -maxMantissa,
"xrpl::Number::fromInternal",
"negative mantissa in range");
mantissa_ = sign * static_cast<rep>(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<internalrep>(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<internalrep>(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;
}