1#include <xrpl/basics/Number.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/beast/utility/instrumentation.h>
18#pragma message("Using boost::multiprecision::uint128_t and int128_t")
19#include <boost/multiprecision/cpp_int.hpp>
20using uint128_t = boost::multiprecision::uint128_t;
21using int128_t = boost::multiprecision::int128_t;
23using uint128_t = __uint128_t;
24using int128_t = __int128_t;
110 std::
string location);
123 doPush(
unsigned d) noexcept;
153 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
160 doPush(
static_cast<unsigned>(d));
166 unsigned d = (
digits_ & 0xF000'0000'0000'0000) >> 60;
203 if (
digits_ > 0x5000'0000'0000'0000)
205 if (
digits_ < 0x5000'0000'0000'0000)
212template <Un
signedMantissa T>
233template <Un
signedMantissa T>
244 if (r == 1 || (r == 0 && (
mantissa & 1) == 1))
260template <Un
signedMantissa T>
265 if (r == 1 || (r == 0 && (
mantissa & 1) == 1))
282 if (r == 1 || (r == 0 && (drops & 1) == 1))
426 XRPL_ASSERT_PARTS(m <=
maxRep,
"xrpl::doNormalize",
"intermediate mantissa fits in int64");
436Number::normalize<uint128_t>(
448Number::normalize<unsigned long long>(
460Number::normalize<unsigned long>(
483 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::shiftExponent",
"normalized");
484 auto const newExponent =
exponent_ + exponentDelta;
492 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::Number::shiftExponent",
"result is normalized");
513 XRPL_ASSERT(
isnormal() && y.
isnormal(),
"xrpl::Number::operator+=(Number) : is normal");
601static inline unsigned
605 auto q = (u >> 1) + (u >> 2);
615 auto r =
static_cast<unsigned>(u - ((q << 3) + (q << 1)));
617 auto c = (r + 6) >> 4;
640 int xs = xn ? -1 : 1;
645 int ys = yn ? -1 : 1;
649 auto zm = uint128_t(xm) * uint128_t(ym);
652 bool zn = (zs == -1);
697 int ns = (np ? -1 : 1);
702 int ds = (dp ? -1 : 1);
719 uint128_t
const f = small ? 100'000'000'000'000'000 : 10'000'000'000'000'000'000ULL;
720 XRPL_ASSERT_PARTS(f >=
minMantissa * 10,
"Number::operator/=",
"factor expected size");
723 auto const dmu =
static_cast<uint128_t
>(dm);
728 uint128_t
const correctionFactor = 1'000;
730 auto const numerator = uint128_t(nm) * f;
732 auto zm = numerator / dmu;
733 auto ze = ne - de - (small ? 17 : 19);
734 bool zn = (ns * ds) < 0;
756 auto const remainder = (numerator % dmu);
759 zm *= correctionFactor;
760 auto const correction = remainder * correctionFactor / dmu;
771 XRPL_ASSERT_PARTS(
isnormal(),
"xrpl::Number::operator/=",
"result is normalized");
776Number::operator
rep()
const
788 for (; offset < 0; ++offset)
793 for (; offset > 0; --offset)
799 g.
doRound(drops,
"Number::operator rep() rounding overflow");
832 bool const negative = amount.negative_;
850 XRPL_ASSERT(
exponent + 43 > 0,
"xrpl::to_string(Number) : minimum exponent");
852 ptrdiff_t
const pad_prefix = rangeLog + 12;
853 ptrdiff_t
const pad_suffix = rangeLog + 8;
859 val.
append(pad_prefix,
'0');
861 val.
append(pad_suffix,
'0');
863 ptrdiff_t
const offset(
exponent + pad_prefix + rangeLog + 1);
865 auto pre_from(val.
begin());
866 auto const pre_to(val.
begin() + offset);
868 auto const post_from(val.
begin() + offset);
869 auto post_to(val.
end());
874 pre_from += pad_prefix;
876 XRPL_ASSERT(post_to >= post_from,
"xrpl::to_string(Number) : first distance check");
878 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
883 post_to -= pad_suffix;
885 XRPL_ASSERT(post_to >= post_from,
"xrpl::to_string(Number) : second distance check");
897 if (pre_from == pre_to)
900 ret.
append(pre_from, pre_to);
902 if (post_to != post_from)
905 ret.
append(post_from, post_to);
921 auto r =
power(f, n / 2);
943 if (f ==
one || d == 1)
953 if (f < zero && d % 2 == 0)
960 auto const di =
static_cast<int>(d);
961 auto ex = [e = e, di = di]()
963 int k = (e >= 0 ? e : e - (di - 1)) / di;
972 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root(Number, unsigned)",
"f is normalized");
981 auto const D = ((6 * di + 11) * di + 6) * di + 1;
982 auto const a0 = 3 * di * ((2 * di - 3) * di + 1);
983 auto const a1 = 24 * di * (2 * di - 1);
984 auto const a2 = -30 * (di - 1) * di;
1001 }
while (r != rm1 && r != rm2);
1005 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root(Number, unsigned)",
"result is normalized");
1027 XRPL_ASSERT_PARTS(f.
isnormal(),
"xrpl::root2(Number)",
"f is normalized");
1032 auto const a1 = 144;
1033 auto const a2 = -60;
1044 r = (r + f / r) /
Number(2);
1045 }
while (r != rm1 && r != rm2);
1049 XRPL_ASSERT_PARTS(result.isnormal(),
"xrpl::root2(Number)",
"result is normalized");
1080 if ((n % 2) == 1 && (d % 2) == 0 && f < zero)
void set_positive() noexcept
void doRoundUp(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa, std::string location)
void bringIntoRange(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
void doRound(rep &drops, std::string location)
bool is_negative() const noexcept
void doRoundDown(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
void doPush(unsigned d) noexcept
void set_negative() noexcept
Number is a floating point type that can represent a wide range of values.
static constexpr Number oneSmall()
oneSmall is needed because the ranges are private
static rounding_mode getround()
static internalrep minMantissa()
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
static rounding_mode setround(rounding_mode mode)
Number & operator/=(Number const &x)
Number & operator+=(Number const &x)
Number truncate() const noexcept
friend std::string to_string(Number const &amount)
static constexpr MantissaRange smallRange
friend void doNormalize(bool &negative, T &mantissa_, int &exponent_, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa)
static constexpr internalrep maxRep
MantissaRange::rep internalrep
static thread_local rounding_mode mode_
static constexpr int minExponent
Number shiftExponent(int exponentDelta) const
static void setMantissaScale(MantissaRange::mantissa_scale scale)
Changes which mantissa scale is used for normalization.
static internalrep externalToInternal(rep mantissa)
static internalrep maxMantissa()
bool isnormal() const noexcept
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
static constexpr int maxExponent
static thread_local std::reference_wrapper< MantissaRange const > range_
friend Number root2(Number f)
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
static constexpr MantissaRange largeRange
Number & operator*=(Number const &x)
constexpr Number()=default
static constexpr Number oneLarge()
oneLarge is needed because the ranges are private
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.
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Number power(Number const &f, unsigned n)
constexpr Number abs(Number x) noexcept
static unsigned divu10(uint128_t &u)