Expand Number to support the full integer range (#6025)

- Refactor Number internals away from int64 to uint64 & a sign flag
  - ctors and accessors use `rep`. Very few things expose
    `internalrep`.
  - An exception is "unchecked" and the new "normalized", which explicitly
    take an internalrep. But with those special control flags, it's easier
    to distinguish and control when they are used.

- For now, skip the larger mantissas in AMM transactions and tests

- Remove trailing zeros from scientific notation Number strings
  - Update tests. This has the happy side effect of making some of the string
    representations _more_ consistent between the small and large
    mantissa ranges.

- Add semi-automatic rounding of STNumbers based on Asset types
  - Create a new SField metadata enum, sMD_NeedsAsset, which indicates
    the field should be associated with an Asset so it can be rounded.
  - Add a new STTakesAsset intermediate class to handle the Asset
    association to a derived ST class. Currently only used in STNumber,
    but could be used by other types in the future.
  - Add "associateAsset" which takes an SLE and an Asset, finds the
    sMD_NeedsAsset fields, and associates the Asset to them. In the case
    of STNumber, that both stores the Asset, and rounds the value
    immediately.
  - Transactors only need to add a call to associateAsset _after_ all of
    the STNumbers have been set. Unfortunately, the inner workings of
    STObject do not do the association correctly with uninitialized
    fields.
  - When serializing an STNumber that has an Asset, round it before
    serializing.
  - Add an override of roundToAsset, which rounds a Number value in place
    to an Asset, but without any additional scale.
  - Update and fix a bunch of Loan-related tests to accommodate the
    expanded Number class.

---------

Co-authored-by: Vito <5780819+Tapanito@users.noreply.github.com>
This commit is contained in:
Ed Hennis
2026-01-13 17:01:11 -04:00
committed by GitHub
parent 2601442e16
commit 33f4c92b61
52 changed files with 3151 additions and 710 deletions

View File

@@ -29,10 +29,8 @@ struct STNumber_test : public beast::unit_test::suite
}
void
run() override
doRun()
{
static_assert(!std::is_convertible_v<STNumber*, Number*>);
{
STNumber const stnum{sfNumber};
BEAST_EXPECT(stnum.getSType() == STI_NUMBER);
@@ -127,6 +125,41 @@ struct STNumber_test : public beast::unit_test::suite
BEAST_EXPECT(
numberFromJson(sfNumber, "-0.000e6") == STNumber(sfNumber, 0));
{
NumberRoundModeGuard mg(Number::towards_zero);
// maxint64 9,223,372,036,854,775,807
auto const maxInt =
std::to_string(std::numeric_limits<std::int64_t>::max());
// minint64 -9,223,372,036,854,775,808
auto const minInt =
std::to_string(std::numeric_limits<std::int64_t>::min());
if (Number::getMantissaScale() == MantissaRange::small)
{
BEAST_EXPECT(
numberFromJson(sfNumber, maxInt) ==
STNumber(sfNumber, Number{9'223'372'036'854'775, 3}));
BEAST_EXPECT(
numberFromJson(sfNumber, minInt) ==
STNumber(sfNumber, Number{-9'223'372'036'854'775, 3}));
}
else
{
BEAST_EXPECT(
numberFromJson(sfNumber, maxInt) ==
STNumber(
sfNumber, Number{9'223'372'036'854'775'807, 0}));
BEAST_EXPECT(
numberFromJson(sfNumber, minInt) ==
STNumber(
sfNumber,
Number{
true,
9'223'372'036'854'775'808ULL,
0,
Number::normalized{}}));
}
}
constexpr auto imin = std::numeric_limits<int>::min();
BEAST_EXPECT(
numberFromJson(sfNumber, imin) ==
@@ -279,15 +312,21 @@ struct STNumber_test : public beast::unit_test::suite
}
}
}
void
run() override
{
static_assert(!std::is_convertible_v<STNumber*, Number*>);
for (auto const scale : {MantissaRange::small, MantissaRange::large})
{
NumberMantissaScaleGuard sg(scale);
testcase << to_string(Number::getMantissaScale());
doRun();
}
}
};
BEAST_DEFINE_TESTSUITE(STNumber, protocol, xrpl);
void
testCompile(std::ostream& out)
{
STNumber number{sfNumber, 42};
out << number;
}
} // namespace xrpl