1#include <xrpl/basics/Number.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/beast/utility/instrumentation.h>
20#pragma message("Using boost::multiprecision::uint128_t and int128_t")
21#include <boost/multiprecision/cpp_int.hpp>
22using UInt128T = boost::multiprecision::uint128_t;
23using Int128T = boost::multiprecision::int128_t;
25using UInt128T = __uint128_t;
26using Int128T = __int128_t;
32thread_local std::reference_wrapper<MantissaRange const>
Number::kRange =
71constexpr MantissaRange
const&
97 static_assert(kSmall.
min == 1'000'000'000'000'000LL);
98 static_assert(kSmall.
max == 9'999'999'999'999'999LL);
99 static_assert(kSmall.
log == 15);
106 static_assert(kLegacy.
min == 1'000'000'000'000'000'000ULL);
107 static_assert(kLegacy.
max ==
rep(9'999'999'999'999'999'999ULL));
108 static_assert(kLegacy.
log == 18);
115 static_assert(kLarge320.
min == 1'000'000'000'000'000'000ULL);
116 static_assert(kLarge320.
max ==
rep(9'999'999'999'999'999'999ULL));
117 static_assert(kLarge320.
log == 18);
124 static_assert(kLarge330.
min == 1'000'000'000'000'000'000ULL);
125 static_assert(kLarge330.
max ==
rep(9'999'999'999'999'999'999ULL));
126 static_assert(kLarge330.
log == 18);
147 return kRange.get().scale;
164static inline unsigned
168 auto q = (u >> 1) + (u >> 2);
178 auto r =
static_cast<unsigned>(u - ((q << 3) + (q << 1)));
180 auto c = (r + 6) >> 4;
244 setPositive() noexcept;
246 setNegative() noexcept;
250 setDropped() noexcept;
252 isNegative() const noexcept;
266 unrecoverable() const noexcept;
270 empty() const noexcept;
294 doDropDigitWithTarget(T&
mantissa,
int&
exponent,
int const targetExponent) noexcept;
308 doRound(
rep& drops,
std::
string location) const;
335 round() const noexcept;
338 doPush(
unsigned d) noexcept;
372 XRPL_ASSERT(d < 10,
"xrpl::Number::Guard::doPush : valid digit");
375 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
382 doPush(
static_cast<unsigned>(d));
388 unsigned const d = (
digits_ & 0xF000'0000'0000'0000) >> 60;
431 exponent < targetExponent,
"xrpl::Number::Guard::doDropDigitWithTarget : something to do");
445template <Un
signedMantissa T>
449 XRPL_ASSERT(
mantissa <=
kMaxRepUp,
"xrpl::Number::Guard::pushOverflow : valid mantissa");
456 static_assert(spread == 3);
469 auto constexpr kMidpoint =
kMaxRep + (spread / 2);
470 static_assert(kMidpoint ==
kMaxRep + 1);
471 auto const r =
round();
494 auto const digit =
static_cast<unsigned>((diff * 10) / spread);
496 digit < 10u && digit != 5,
"xrpl::Number::Guard::pushOverflow : valid overflow digit");
542 if (
digits_ > 0x5000'0000'0000'0000)
544 if (
digits_ < 0x5000'0000'0000'0000)
551template <Un
signedMantissa T>
569 XRPL_ASSERT(
mantissa != 0,
"xrpl::Number::Guard::bringIntoRange : valid mantissa");
572 negative = kZero.negative_;
578template <Un
signedMantissa T>
584 auto const r =
round();
587 auto const safeToIncrement = [
this](
auto const&
mantissa) {
619 "xrpl::Number::Guard::doRoundUp",
620 "can't recurse more than once");
654template <Un
signedMantissa T>
667 "xrpl::Number::Guard::doRoundDown : mantissa is expected size");
712 XRPL_ASSERT(drops >= 0,
"xrpl::Number::Guard::doRound : positive magnitude");
774 negative = kZero.negative_;
798 negative = kZero.negative_;
825 XRPL_ASSERT_PARTS(m <= repLimit,
"xrpl::doNormalize",
"intermediate mantissa fits in limit");
832 "final mantissa fits in range");
906 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::shiftExponent",
"normalized");
907 auto const newExponent =
exponent_ + exponentDelta;
915 XRPL_ASSERT_PARTS(result.
isnormal(),
"xrpl::Number::shiftExponent",
"result is normalized");
936 XRPL_ASSERT(
isnormal() && y.
isnormal(),
"xrpl::Number::operator+=(Number) : is normal");
957 auto const repLimit =
963 auto const upperLimit =
static_cast<UInt128T
>(g.
minMantissa) * 1000;
970 auto const adjust = [&g, &upperLimit](
971 UInt128T& expandM,
int& expandE, UInt128T& shrinkM,
int& shrinkE) {
972 XRPL_ASSERT(shrinkE < expandE,
"xrpl::Number::operator+= : exponents ordered correctly");
978 while (shrinkE < expandE && shrinkM % 10 == 0)
988 while (shrinkE < expandE && expandE >
kMinExponent && expandM < upperLimit)
997 if (shrinkE < expandE)
1001 XRPL_ASSERT(shrinkE == expandE,
"xrpl::Number::operator+= : exponents are equal");
1011 adjust(ym, ye, xm, xe);
1018 adjust(xm, xe, ym, ye);
1025 if ((xm < ym && xn) || (ym < xm && yn))
1044 "xrpl::Number::operator+= : rounding state expected after add");
1052 g.
doRoundUp(xn, xm, xe,
"Number::addition overflow");
1078 while (xm < upperLimit && !g.
empty())
1086 "xrpl::Number::operator+= : rounding state expected after subtract");
1127 XRPL_ASSERT(
isnormal(),
"xrpl::Number::operator+= : result is normal");
1148 int const xs = xn ? -1 : 1;
1153 int const ys = yn ? -1 : 1;
1157 auto zm = UInt128T(xm) * UInt128T(ym);
1160 bool zn = (zs == -1);
1166 auto const repLimit =
1203 int const ns = (np ? -1 : 1);
1208 int const ds = (dp ? -1 : 1);
1211 auto const dm =
static_cast<UInt128T
>(y.
mantissa_);
1217 auto const cuspRoundingFix =
range.cuspRoundingFix;
1276 auto constexpr factorExponent = 17;
1278 UInt128T
constexpr f =
kPowerOfTen[factorExponent];
1280 auto const numerator = UInt128T(nm) * f;
1282 auto zm = numerator / dm;
1283 auto ze = ne - de - factorExponent;
1284 bool zp = (ns * ds) < 0;
1290 bool dropped =
false;
1319 auto constexpr correctionExponent = 5;
1320 UInt128T
constexpr correctionFactor =
kPowerOfTen[correctionExponent];
1321 static_assert(factorExponent + correctionExponent == 22);
1323 auto const remainder = (numerator % dm);
1326 auto const partialNumerator = remainder * correctionFactor;
1327 auto const correction = partialNumerator / dm;
1335 if (correction != 0)
1337 zm *= correctionFactor;
1340 ze -= correctionExponent;
1348 bool const useTrailingRemainder =
1350 if (useTrailingRemainder)
1352 dropped = partialNumerator % dm != 0;
1360 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::operator/=",
"result is normalized");
1381 XRPL_ASSERT(offset == 0,
"xrpl::Number::operator rep() : exponents are equal");
1383 for (; offset > 0; --offset)
1389 g.
doRound(drops,
"Number::operator rep() rounding overflow");
1417 if (amount == kZero)
1443 XRPL_ASSERT(
exponent + 43 > 0,
"xrpl::to_string(Number) : minimum exponent");
1445 ptrdiff_t
const padPrefix = rangeLog + 12;
1446 ptrdiff_t
const padSuffix = rangeLog + 8;
1452 val.
append(padPrefix,
'0');
1454 val.
append(padSuffix,
'0');
1456 ptrdiff_t
const offset(
exponent + padPrefix + rangeLog + 1);
1458 auto preFrom(val.
begin());
1459 auto const preTo(val.
begin() + offset);
1461 auto const postFrom(val.
begin() + offset);
1462 auto postTo(val.
end());
1467 preFrom += padPrefix;
1469 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : first distance check");
1471 preFrom =
std::find_if(preFrom, preTo, [](
char c) {
return c !=
'0'; });
1476 postTo -= padSuffix;
1478 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : second distance check");
1483 [](
char c) {
return c !=
'0'; })
1492 if (preFrom == preTo)
1498 ret.
append(preFrom, preTo);
1501 if (postTo != postFrom)
1504 ret.
append(postFrom, postTo);
1520 auto r =
power(f, n / 2);
1542 if (f ==
one || d == 1)
1552 if (f < kZero && d % 2 == 0)
1559 auto const di =
static_cast<int>(d);
1560 auto ex = [e = e, di = di]()
1562 int const k = (e >= 0 ? e : e - (di - 1)) / di;
1563 int const k2 = e - (k * di);
1571 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root(Number, unsigned)",
"f is normalized");
1582 auto const D = (((((6 * di) + 11) * di) + 6) * di) + 1;
1583 auto const a0 = 3 * di * ((((2 * di) - 3) * di) + 1);
1584 auto const a1 = 24 * di * ((2 * di) - 1);
1585 auto const a2 = -30 * (di - 1) * di;
1602 }
while (r != rm1 && r != rm2);
1606 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root(Number, unsigned)",
"result is normalized");
1628 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root2(Number)",
"f is normalized");
1633 auto const a1 = 144;
1634 auto const a2 = -60;
1645 r = (r + f / r) /
Number(2);
1646 }
while (r != rm1 && r != rm2);
1650 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root2(Number)",
"result is normalized");
1681 if ((n % 2) == 1 && (d % 2) == 0 && f < kZero)
static constexpr MantissaRange const & mantissaRange(MantissaScale scale)
bool empty() const noexcept
InternalRep const minMantissa
bool isNegative() const noexcept
void setPositive() noexcept
void setDropped() noexcept
void setNegative() noexcept
Guard(MantissaRange const &range)
void doDropDigit(T &mantissa, int &exponent) noexcept
Drop a digit from the mantissa, and increment the exponent, storing the dropped digit in this Guard.
bool unrecoverable() const noexcept
MantissaRange::CuspRoundingFix const cuspRoundingFix
void doRoundUp(bool &negative, T &mantissa, int &exponent, std::string location)
void doPush(unsigned d) noexcept
InternalRep const maxMantissa
void pushOverflow(T mantissa)
void doRoundDown(bool &negative, T &mantissa, int &exponent) const
Guard(InternalRep const &minMantissa, InternalRep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix)
void bringIntoRange(bool &negative, T &mantissa, int &exponent) const
void doDropDigitWithTarget(T &mantissa, int &exponent, int const targetExponent) noexcept
Drop a digit from the mantissa, and increment the exponent, storing the dropped digit in this Guard.
Round round() const noexcept
void doRound(rep &drops, std::string location) const
Number is a floating point type that can represent a wide range of values.
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Number & operator/=(Number const &x)
Number & operator+=(Number const &x)
static InternalRep maxMantissa()
MantissaRange::rep InternalRep
static constexpr InternalRep kMaxRepUp
Number truncate() const noexcept
friend std::string to_string(Number const &amount)
static constexpr int kMinExponent
static RoundingMode setround(RoundingMode inMode)
static constexpr InternalRep kMaxRep
friend void doNormalize(bool &negative, T &mantissa, int &exponent, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix, bool dropped)
static Number max() noexcept
static RoundingMode getround()
static std::reference_wrapper< MantissaRange const > kRange
Number shiftExponent(int exponentDelta) const
static MantissaRange::MantissaScale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
static InternalRep minMantissa()
static constexpr int kMaxExponent
bool isnormal() const noexcept
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
friend Number root2(Number f)
static InternalRep externalToInternal(rep mantissa)
static Number min() noexcept
void normalize(MantissaRange const &range)
Number & operator*=(Number const &x)
constexpr Number()=default
static void setMantissaScale(MantissaRange::MantissaScale scale)
Changes which mantissa scale is used for normalization.
friend Number root(Number f, unsigned d)
T make_reverse_iterator(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
Number root(Number f, unsigned d)
Number power(Number const &f, unsigned n)
std::string to_string(BaseUInt< Bits, Tag > const &a)
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
constexpr auto kPowerOfTen
static unsigned divu10(UInt128T &u)
constexpr bool isPowerOfTen(T value)
constexpr Number abs(Number x) noexcept
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
MantissaRange defines a range for the mantissa of a normalized Number.
MantissaScale const scale
CuspRoundingFix const cuspRoundingFix
constexpr MantissaRange(MantissaScale sc)
static std::set< MantissaScale > const & getAllScales()