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 uint128_t = boost::multiprecision::uint128_t;
23using int128_t = boost::multiprecision::int128_t;
25using uint128_t = __uint128_t;
26using int128_t = __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;
265 empty() const noexcept;
292 doRound(
rep& drops,
std::
string location) const;
319 round() const noexcept;
322 doPush(
unsigned d) noexcept;
356 XRPL_ASSERT(d < 10,
"xrpl::Number::Guard::doPush : valid digit");
359 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
366 doPush(
static_cast<unsigned>(d));
372 unsigned const d = (
digits_ & 0xF000'0000'0000'0000) >> 60;
404template <Un
signedMantissa T>
408 XRPL_ASSERT(
mantissa <=
kMaxRepUp,
"xrpl::Number::Guard::pushOverflow : valid mantissa");
415 static_assert(spread == 3);
428 auto constexpr kMidpoint =
kMaxRep + (spread / 2);
429 static_assert(kMidpoint ==
kMaxRep + 1);
430 auto const r =
round();
453 auto const digit =
static_cast<unsigned>((diff * 10) / spread);
455 digit < 10u && digit != 5,
"xrpl::Number::Guard::pushOverflow : valid overflow digit");
501 if (
digits_ > 0x5000'0000'0000'0000)
503 if (
digits_ < 0x5000'0000'0000'0000)
510template <Un
signedMantissa T>
528 XRPL_ASSERT(
mantissa != 0,
"xrpl::Number::Guard::bringIntoRange : valid mantissa");
531 negative = kZero.negative_;
537template <Un
signedMantissa T>
543 auto const r =
round();
546 auto const safeToIncrement = [
this](
auto const&
mantissa) {
578 "xrpl::Number::Guard::doRoundUp",
579 "can't recurse more than once");
613template <Un
signedMantissa T>
626 "xrpl::Number::Guard::doRoundDown : mantissa is expected size");
671 XRPL_ASSERT(drops >= 0,
"xrpl::Number::Guard::doRound : positive magnitude");
733 negative = kZero.negative_;
757 negative = kZero.negative_;
784 XRPL_ASSERT_PARTS(m <= repLimit,
"xrpl::doNormalize",
"intermediate mantissa fits in limit");
791 "final mantissa fits in range");
865 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::shiftExponent",
"normalized");
866 auto const newExponent =
exponent_ + exponentDelta;
874 XRPL_ASSERT_PARTS(result.
isnormal(),
"xrpl::Number::shiftExponent",
"result is normalized");
895 XRPL_ASSERT(
isnormal() && y.
isnormal(),
"xrpl::Number::operator+=(Number) : is normal");
916 auto const repLimit =
922 auto const upperLimit =
static_cast<uint128_t
>(g.
minMantissa) * 1000;
929 auto const adjust = [&g, &upperLimit](
930 uint128_t& expandM,
int& expandE, uint128_t& shrinkM,
int& shrinkE) {
936 while (shrinkE < expandE && shrinkM % 10 == 0)
944 while (shrinkE < expandE && expandE >
kMinExponent && expandM < upperLimit)
953 while (shrinkE < expandE)
966 adjust(ym, ye, xm, xe);
973 adjust(xm, xe, ym, ye);
980 if ((xm < ym && xn) || (ym < xm && yn))
999 "xrpl::Number::operator+ : rounding state expected after add");
1007 g.
doRoundUp(xn, xm, xe,
"Number::addition overflow");
1033 while (xm < upperLimit && !g.
empty())
1041 "xrpl::Number::operator+ : rounding state expected after subtract");
1082 XRPL_ASSERT(
isnormal(),
"xrpl::Number::operator+= : result is normal");
1103 int const xs = xn ? -1 : 1;
1108 int const ys = yn ? -1 : 1;
1112 auto zm = uint128_t(xm) * uint128_t(ym);
1115 bool zn = (zs == -1);
1121 auto const repLimit =
1158 int const ns = (np ? -1 : 1);
1163 int const ds = (dp ? -1 : 1);
1166 auto const dm =
static_cast<uint128_t
>(y.
mantissa_);
1172 auto const cuspRoundingFix =
range.cuspRoundingFix;
1231 auto constexpr factorExponent = 17;
1233 uint128_t
constexpr f =
kPowerOfTen[factorExponent];
1235 auto const numerator = uint128_t(nm) * f;
1237 auto zm = numerator / dm;
1238 auto ze = ne - de - factorExponent;
1239 bool zp = (ns * ds) < 0;
1245 bool dropped =
false;
1274 auto constexpr correctionExponent = 5;
1275 uint128_t
constexpr correctionFactor =
kPowerOfTen[correctionExponent];
1276 static_assert(factorExponent + correctionExponent == 22);
1278 auto const remainder = (numerator % dm);
1281 auto const partialNumerator = remainder * correctionFactor;
1282 auto const correction = partialNumerator / dm;
1290 if (correction != 0)
1292 zm *= correctionFactor;
1295 ze -= correctionExponent;
1303 bool const useTrailingRemainder =
1305 if (useTrailingRemainder)
1307 dropped = partialNumerator % dm != 0;
1315 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::operator/=",
"result is normalized");
1337 for (; offset > 0; --offset)
1343 g.
doRound(drops,
"Number::operator rep() rounding overflow");
1371 if (amount == kZero)
1397 XRPL_ASSERT(
exponent + 43 > 0,
"xrpl::to_string(Number) : minimum exponent");
1399 ptrdiff_t
const padPrefix = rangeLog + 12;
1400 ptrdiff_t
const padSuffix = rangeLog + 8;
1406 val.
append(padPrefix,
'0');
1408 val.
append(padSuffix,
'0');
1410 ptrdiff_t
const offset(
exponent + padPrefix + rangeLog + 1);
1412 auto preFrom(val.
begin());
1413 auto const preTo(val.
begin() + offset);
1415 auto const postFrom(val.
begin() + offset);
1416 auto postTo(val.
end());
1421 preFrom += padPrefix;
1423 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : first distance check");
1425 preFrom =
std::find_if(preFrom, preTo, [](
char c) {
return c !=
'0'; });
1430 postTo -= padSuffix;
1432 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : second distance check");
1437 [](
char c) {
return c !=
'0'; })
1446 if (preFrom == preTo)
1452 ret.
append(preFrom, preTo);
1455 if (postTo != postFrom)
1458 ret.
append(postFrom, postTo);
1474 auto r =
power(f, n / 2);
1496 if (f ==
one || d == 1)
1506 if (f < kZero && d % 2 == 0)
1513 auto const di =
static_cast<int>(d);
1514 auto ex = [e = e, di = di]()
1516 int const k = (e >= 0 ? e : e - (di - 1)) / di;
1517 int const k2 = e - (k * di);
1525 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root(Number, unsigned)",
"f is normalized");
1536 auto const D = (((((6 * di) + 11) * di) + 6) * di) + 1;
1537 auto const a0 = 3 * di * ((((2 * di) - 3) * di) + 1);
1538 auto const a1 = 24 * di * ((2 * di) - 1);
1539 auto const a2 = -30 * (di - 1) * di;
1556 }
while (r != rm1 && r != rm2);
1560 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root(Number, unsigned)",
"result is normalized");
1582 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root2(Number)",
"f is normalized");
1587 auto const a1 = 144;
1588 auto const a2 = -60;
1599 r = (r + f / r) /
Number(2);
1600 }
while (r != rm1 && r != rm2);
1604 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root2(Number)",
"result is normalized");
1635 if ((n % 2) == 1 && (d % 2) == 0 && f < kZero)
static constexpr MantissaRange const & mantissaRange(MantissaScale scale)
bool empty() const noexcept
Guard(internalrep const &minMantissa, internalrep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix)
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.
MantissaRange::CuspRoundingFix const cuspRoundingFix
void doRoundUp(bool &negative, T &mantissa, int &exponent, std::string location)
void doPush(unsigned d) noexcept
void pushOverflow(T mantissa)
internalrep const minMantissa
void doRoundDown(bool &negative, T &mantissa, int &exponent) const
internalrep const maxMantissa
void bringIntoRange(bool &negative, T &mantissa, int &exponent) const
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.
static internalrep minMantissa()
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 constexpr internalrep kMaxRepUp
Number truncate() const noexcept
friend std::string to_string(Number const &amount)
static constexpr int kMinExponent
static RoundingMode setround(RoundingMode inMode)
friend void doNormalize(bool &negative, T &mantissa, int &exponent, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix, bool dropped)
MantissaRange::rep internalrep
static Number max() noexcept
static RoundingMode getround()
static std::reference_wrapper< MantissaRange const > kRange
static constexpr internalrep kMaxRep
Number shiftExponent(int exponentDelta) const
static MantissaRange::MantissaScale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
static internalrep externalToInternal(rep mantissa)
static internalrep maxMantissa()
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 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
constexpr bool isPowerOfTen(T value)
constexpr Number abs(Number x) noexcept
static unsigned divu10(uint128_t &u)
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()