1#include <xrpl/basics/Number.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/beast/utility/instrumentation.h>
21#pragma message("Using boost::multiprecision::uint128_t and int128_t")
22#include <boost/multiprecision/cpp_int.hpp>
23using uint128_t = boost::multiprecision::uint128_t;
24using int128_t = boost::multiprecision::int128_t;
26using uint128_t = __uint128_t;
27using int128_t = __int128_t;
33thread_local std::reference_wrapper<MantissaRange const>
Number::kRange =
36std::set<MantissaRange::MantissaScale>
const&
50 static auto const kMap = []() {
63 static_assert(kRange.
min == 1'000'000'000'000'000LL);
64 static_assert(kRange.
max == 9'999'999'999'999'999LL);
65 static_assert(kRange.
log == 15);
74 static_assert(kRange.
min == 1'000'000'000'000'000'000ULL);
75 static_assert(kRange.
max ==
rep(9'999'999'999'999'999'999ULL));
76 static_assert(kRange.
log == 18);
85 static_assert(kRange.
min == 1'000'000'000'000'000'000ULL);
86 static_assert(kRange.
max ==
rep(9'999'999'999'999'999'999ULL));
87 static_assert(kRange.
log == 18);
119 return kRange.get().scale;
136static inline unsigned
140 auto q = (u >> 1) + (u >> 2);
150 auto r =
static_cast<unsigned>(u - ((q << 3) + (q << 1)));
152 auto c = (r + 6) >> 4;
213 round() const noexcept;
225 std::
string location);
238 doPush(
unsigned d) noexcept;
274 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
281 doPush(
static_cast<unsigned>(d));
287 unsigned const d = (
digits_ & 0xF000'0000'0000'0000) >> 60;
345 if (
digits_ > 0x5000'0000'0000'0000)
347 if (
digits_ < 0x5000'0000'0000'0000)
354template <Un
signedMantissa T>
379template <Un
signedMantissa T>
391 if (r == 1 || (r == 0 && (
mantissa & 1) == 1))
415 "xrpl::Number::Guard::doRoundUp",
416 "can't recurse more than once");
423 cuspRoundingFixEnabled,
448template <Un
signedMantissa T>
457 if (r == 1 || (r == 0 && (
mantissa & 1) == 1))
474 if (r == 1 || (r == 0 && (drops & 1) == 1))
598 XRPL_ASSERT_PARTS(m <=
kMaxRep,
"xrpl::doNormalize",
"intermediate mantissa fits in int64");
607 cuspRoundingFixEnabled,
608 "Number::normalize 2");
612 "final mantissa fits in range");
677 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::shiftExponent",
"normalized");
678 auto const newExponent =
exponent_ + exponentDelta;
686 XRPL_ASSERT_PARTS(result.
isnormal(),
"xrpl::Number::shiftExponent",
"result is normalized");
707 XRPL_ASSERT(
isnormal() && y.
isnormal(),
"xrpl::Number::operator+=(Number) : is normal");
745 auto const cuspRoundingFixEnabled =
range.cuspRoundingFixEnabled;
760 cuspRoundingFixEnabled,
761 "Number::addition overflow");
808 int const xs = xn ? -1 : 1;
813 int const ys = yn ? -1 : 1;
817 auto zm = uint128_t(xm) * uint128_t(ym);
820 bool zn = (zs == -1);
828 auto const cuspRoundingFixEnabled =
range.cuspRoundingFixEnabled;
843 cuspRoundingFixEnabled,
844 "Number::multiplication overflow : exponent is " +
std::to_string(xe));
871 int const ns = (np ? -1 : 1);
876 int const ds = (dp ? -1 : 1);
879 uint128_t
const dm =
static_cast<uint128_t
>(y.
mantissa_);
885 auto const cuspRoundingFixEnabled =
range.cuspRoundingFixEnabled;
944 auto constexpr factorExponent = 17;
946 uint128_t
constexpr f =
kPowerOfTen[factorExponent];
948 auto const numerator = uint128_t(nm) * f;
950 auto zm = numerator / dm;
951 auto ze = ne - de - factorExponent;
952 bool zp = (ns * ds) < 0;
958 bool dropped =
false;
987 auto constexpr correctionExponent = 5;
988 uint128_t
constexpr correctionFactor =
kPowerOfTen[correctionExponent];
989 static_assert(factorExponent + correctionExponent == 22);
991 auto const remainder = (numerator % dm);
994 auto const partialNumerator = remainder * correctionFactor;
995 auto const correction = partialNumerator / dm;
1003 if (correction != 0)
1005 zm *= correctionFactor;
1008 ze -= correctionExponent;
1016 bool const useTrailingRemainder =
1018 if (useTrailingRemainder)
1020 dropped = partialNumerator % dm != 0;
1028 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::operator/=",
"result is normalized");
1050 for (; offset > 0; --offset)
1056 g.
doRound(drops,
"Number::operator rep() rounding overflow");
1084 if (amount == kZero)
1107 XRPL_ASSERT(
exponent + 43 > 0,
"xrpl::to_string(Number) : minimum exponent");
1109 ptrdiff_t
const padPrefix = rangeLog + 12;
1110 ptrdiff_t
const padSuffix = rangeLog + 8;
1116 val.
append(padPrefix,
'0');
1118 val.
append(padSuffix,
'0');
1120 ptrdiff_t
const offset(
exponent + padPrefix + rangeLog + 1);
1122 auto preFrom(val.
begin());
1123 auto const preTo(val.
begin() + offset);
1125 auto const postFrom(val.
begin() + offset);
1126 auto postTo(val.
end());
1131 preFrom += padPrefix;
1133 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : first distance check");
1135 preFrom =
std::find_if(preFrom, preTo, [](
char c) {
return c !=
'0'; });
1140 postTo -= padSuffix;
1142 XRPL_ASSERT(postTo >= postFrom,
"xrpl::to_string(Number) : second distance check");
1147 [](
char c) {
return c !=
'0'; })
1156 if (preFrom == preTo)
1162 ret.
append(preFrom, preTo);
1165 if (postTo != postFrom)
1168 ret.
append(postFrom, postTo);
1184 auto r =
power(f, n / 2);
1206 if (f ==
one || d == 1)
1216 if (f < kZero && d % 2 == 0)
1223 auto const di =
static_cast<int>(d);
1224 auto ex = [e = e, di = di]()
1226 int const k = (e >= 0 ? e : e - (di - 1)) / di;
1227 int const k2 = e - (k * di);
1235 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root(Number, unsigned)",
"f is normalized");
1246 auto const D = (((((6 * di) + 11) * di) + 6) * di) + 1;
1247 auto const a0 = 3 * di * ((((2 * di) - 3) * di) + 1);
1248 auto const a1 = 24 * di * ((2 * di) - 1);
1249 auto const a2 = -30 * (di - 1) * di;
1266 }
while (r != rm1 && r != rm2);
1270 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root(Number, unsigned)",
"result is normalized");
1292 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root2(Number)",
"f is normalized");
1297 auto const a1 = 144;
1298 auto const a2 = -60;
1309 r = (r + f / r) /
Number(2);
1310 }
while (r != rm1 && r != rm2);
1314 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root2(Number)",
"result is normalized");
1345 if ((n % 2) == 1 && (d % 2) == 0 && f < kZero)
bool isNegative() const noexcept
void setPositive() noexcept
void setDropped() noexcept
void setNegative() noexcept
void bringIntoRange(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
void doDropDigit(T &mantissa, int &exponent) noexcept
Drop a digit from the mantissa, and increment the exponent, storing the dropped digit in this Guard.
void doRoundDown(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
int round() const noexcept
void doPush(unsigned d) noexcept
void doRoundUp(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFixEnabled, std::string location)
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)
Number truncate() const noexcept
friend std::string to_string(Number const &amount)
static constexpr int kMinExponent
static RoundingMode setround(RoundingMode inMode)
MantissaRange::rep internalrep
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 void doNormalize(bool &negative, T &mantissa, int &exponent, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFixEnabled, bool dropped)
friend Number root2(Number f)
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 power(Number const &f, unsigned n)
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
constexpr std::array< std::uint64_t, detail::kInt64Digits > 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
static MantissaRange const & getMantissaRange(MantissaScale scale)
static std::set< MantissaScale > const & getAllScales()
CuspRoundingFix const cuspRoundingFixEnabled
static std::unordered_map< MantissaScale, MantissaRange > const & getRanges()
constexpr MantissaRange(MantissaScale sc)