rippled
Loading...
Searching...
No Matches
Number.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4
5#include <cstdint>
6#include <functional>
7#include <limits>
8#include <optional>
9#include <ostream>
10#include <string>
11
12namespace xrpl {
13
14class Number;
15
17to_string(Number const& amount);
18
19template <typename T>
20constexpr std::optional<int>
21logTen(T value)
22{
23 int log = 0;
24 while (value >= 10 && value % 10 == 0)
25 {
26 value /= 10;
27 ++log;
28 }
29 if (value == 1)
30 return log;
31 return std::nullopt;
32}
33
34template <typename T>
35constexpr bool
37{
38 return logTen(value).has_value();
39}
40
71{
74
75 explicit constexpr MantissaRange(mantissa_scale scale_)
76 : min(getMin(scale_)), log(logTen(min).value_or(-1)), scale(scale_)
77 {
78 }
79
81 rep max{min * 10 - 1};
82 int log;
84
85private:
86 static constexpr rep
88 {
89 switch (scale_)
90 {
91 case small:
92 return 1'000'000'000'000'000ULL;
93 case large:
94 return 1'000'000'000'000'000'000ULL;
95 default:
96 // Since this can never be called outside a non-constexpr
97 // context, this throw assures that the build fails if an
98 // invalid scale is used.
99 throw std::runtime_error("Unknown mantissa scale");
100 }
101 }
102};
103
104// Like std::integral, but only 64-bit integral types.
105template <class T>
107
207{
210
211 bool negative_{false};
214
215public:
216 // The range for the exponent when normalized
217 constexpr static int minExponent = -32768;
218 constexpr static int maxExponent = 32768;
219
221 static_assert(maxRep == 9'223'372'036'854'775'807);
222 static_assert(-maxRep == std::numeric_limits<rep>::min() + 1);
223
224 // May need to make unchecked private
226 {
227 explicit unchecked() = default;
228 };
229
230 // Like unchecked, normalized is used with the ctors that take an
231 // internalrep mantissa. Unlike unchecked, those ctors will normalize the
232 // value.
233 // Only unit tests are expected to use this class
235 {
236 explicit normalized() = default;
237 };
238
239 explicit constexpr Number() = default;
240
242 explicit Number(rep mantissa, int exponent);
243 explicit constexpr Number(
244 bool negative,
246 int exponent,
247 unchecked) noexcept;
248 // Assume unsigned values are... unsigned. i.e. positive
249 explicit constexpr Number(internalrep mantissa, int exponent, unchecked) noexcept;
250 // Only unit tests are expected to use this ctor
251 explicit Number(bool negative, internalrep mantissa, int exponent, normalized);
252 // Assume unsigned values are... unsigned. i.e. positive
254
255 constexpr rep
256 mantissa() const noexcept;
257 constexpr int
258 exponent() const noexcept;
259
260 constexpr Number
261 operator+() const noexcept;
262 constexpr Number
263 operator-() const noexcept;
264 Number&
265 operator++();
266 Number
267 operator++(int);
268 Number&
269 operator--();
270 Number
271 operator--(int);
272
273 Number&
274 operator+=(Number const& x);
275 Number&
276 operator-=(Number const& x);
277
278 Number&
279 operator*=(Number const& x);
280 Number&
281 operator/=(Number const& x);
282
283 static Number
284 min() noexcept;
285 static Number
286 max() noexcept;
287 static Number
288 lowest() noexcept;
289
295 explicit
296 operator rep() const; // round to nearest, even on tie
297
298 friend constexpr bool
299 operator==(Number const& x, Number const& y) noexcept
300 {
301 return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ &&
302 x.exponent_ == y.exponent_;
303 }
304
305 friend constexpr bool
306 operator!=(Number const& x, Number const& y) noexcept
307 {
308 return !(x == y);
309 }
310
311 friend constexpr bool
312 operator<(Number const& x, Number const& y) noexcept
313 {
314 // If the two amounts have different signs (zero is treated as positive)
315 // then the comparison is true iff the left is negative.
316 bool const lneg = x.negative_;
317 bool const rneg = y.negative_;
318
319 if (lneg != rneg)
320 return lneg;
321
322 // Both have same sign and the left is zero: the right must be
323 // greater than 0.
324 if (x.mantissa_ == 0)
325 return y.mantissa_ > 0;
326
327 // Both have same sign, the right is zero and the left is non-zero.
328 if (y.mantissa_ == 0)
329 return false;
330
331 // Both have the same sign, compare by exponents:
332 if (x.exponent_ > y.exponent_)
333 return lneg;
334 if (x.exponent_ < y.exponent_)
335 return !lneg;
336
337 // If equal exponents, compare mantissas
338 return x.mantissa_ < y.mantissa_;
339 }
340
342 constexpr int
343 signum() const noexcept
344 {
345 return negative_ ? -1 : (mantissa_ ? 1 : 0);
346 }
347
348 Number
349 truncate() const noexcept;
350
351 friend constexpr bool
352 operator>(Number const& x, Number const& y) noexcept
353 {
354 return y < x;
355 }
356
357 friend constexpr bool
358 operator<=(Number const& x, Number const& y) noexcept
359 {
360 return !(y < x);
361 }
362
363 friend constexpr bool
364 operator>=(Number const& x, Number const& y) noexcept
365 {
366 return !(x < y);
367 }
368
370 operator<<(std::ostream& os, Number const& x)
371 {
372 return os << to_string(x);
373 }
374
375 friend std::string
376 to_string(Number const& amount);
377
378 friend Number
379 root(Number f, unsigned d);
380
381 friend Number
382 root2(Number f);
383
384 // Thread local rounding control. Default is to_nearest
386 static rounding_mode
387 getround();
388 // Returns previously set mode
389 static rounding_mode
391
402 static void
404
405 inline static internalrep
407 {
408 return range_.get().min;
409 }
410
411 inline static internalrep
413 {
414 return range_.get().max;
415 }
416
417 inline static int
419 {
420 return range_.get().log;
421 }
422
424 constexpr static Number
425 oneSmall();
427 constexpr static Number
428 oneLarge();
429
430 // And one is needed because it needs to choose between oneSmall and
431 // oneLarge based on the current range
432 static Number
433 one();
434
435 template <Integral64 T>
436 [[nodiscard]]
439
440private:
441 static thread_local rounding_mode mode_;
442 // The available ranges for mantissa
443
445 static_assert(isPowerOfTen(smallRange.min));
446 static_assert(smallRange.min == 1'000'000'000'000'000LL);
447 static_assert(smallRange.max == 9'999'999'999'999'999LL);
448 static_assert(smallRange.log == 15);
449 static_assert(smallRange.min < maxRep);
450 static_assert(smallRange.max < maxRep);
452 static_assert(isPowerOfTen(largeRange.min));
453 static_assert(largeRange.min == 1'000'000'000'000'000'000ULL);
454 static_assert(largeRange.max == internalrep(9'999'999'999'999'999'999ULL));
455 static_assert(largeRange.log == 18);
456 static_assert(largeRange.min < maxRep);
457 static_assert(largeRange.max > maxRep);
458
459 // The range for the mantissa when normalized.
460 // Use reference_wrapper to avoid making copies, and prevent accidentally
461 // changing the values inside the range.
463
464 void
465 normalize();
466
473 template <class T>
474 static void
476 bool& negative,
477 T& mantissa,
478 int& exponent,
480 internalrep const& maxMantissa);
481
482 template <class T>
483 friend void
485 bool& negative,
486 T& mantissa_,
487 int& exponent_,
490
491 bool
492 isnormal() const noexcept;
493
494 // Copy the number, but modify the exponent by "exponentDelta". Because the
495 // mantissa doesn't change, the result will be "mostly" normalized, but the
496 // exponent could go out of range, so it will be checked.
497 Number
498 shiftExponent(int exponentDelta) const;
499
500 // Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
501 // is negative, returns the positive value. This takes a little extra work
502 // because converting std::numeric_limits<std::int64_t>::min() flirts with
503 // UB, and can vary across compilers.
504 static internalrep
506
507 class Guard;
508};
509
510inline constexpr Number::Number(
511 bool negative,
513 int exponent,
514 unchecked) noexcept
516{
517}
518
519inline constexpr Number::Number(internalrep mantissa, int exponent, unchecked) noexcept
520 : Number(false, mantissa, exponent, unchecked{})
521{
522}
523
524constexpr static Number numZero{};
525
527 : Number(negative, mantissa, exponent, unchecked{})
528{
529 normalize();
530}
531
532inline Number::Number(internalrep mantissa, int exponent, normalized)
533 : Number(false, mantissa, exponent, normalized{})
534{
535}
536
537inline Number::Number(rep mantissa, int exponent)
538 : Number(mantissa < 0, externalToInternal(mantissa), exponent, normalized{})
539{
540}
541
542inline Number::Number(rep mantissa) : Number{mantissa, 0}
543{
544}
545
551inline constexpr Number::rep
552Number::mantissa() const noexcept
553{
554 auto m = mantissa_;
555 if (m > maxRep)
556 {
557 XRPL_ASSERT_PARTS(
558 !isnormal() || (m % 10 == 0 && m / 10 <= maxRep),
559 "xrpl::Number::mantissa",
560 "large normalized mantissa has no remainder");
561 m /= 10;
562 }
563 auto const sign = negative_ ? -1 : 1;
564 return sign * static_cast<Number::rep>(m);
565}
566
572inline constexpr int
573Number::exponent() const noexcept
574{
575 auto e = exponent_;
576 if (mantissa_ > maxRep)
577 {
578 XRPL_ASSERT_PARTS(
579 !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= maxRep),
580 "xrpl::Number::exponent",
581 "large normalized mantissa has no remainder");
582 ++e;
583 }
584 return e;
585}
586
587inline constexpr Number
588Number::operator+() const noexcept
589{
590 return *this;
591}
592
593inline constexpr Number
594Number::operator-() const noexcept
595{
596 if (mantissa_ == 0)
597 return Number{};
598 auto x = *this;
599 x.negative_ = !x.negative_;
600 return x;
601}
602
603inline Number&
605{
606 *this += one();
607 return *this;
608}
609
610inline Number
612{
613 auto x = *this;
614 ++(*this);
615 return x;
616}
617
618inline Number&
620{
621 *this -= one();
622 return *this;
623}
624
625inline Number
627{
628 auto x = *this;
629 --(*this);
630 return x;
631}
632
633inline Number&
635{
636 return *this += -x;
637}
638
639inline Number
640operator+(Number const& x, Number const& y)
641{
642 auto z = x;
643 z += y;
644 return z;
645}
646
647inline Number
648operator-(Number const& x, Number const& y)
649{
650 auto z = x;
651 z -= y;
652 return z;
653}
654
655inline Number
656operator*(Number const& x, Number const& y)
657{
658 auto z = x;
659 z *= y;
660 return z;
661}
662
663inline Number
664operator/(Number const& x, Number const& y)
665{
666 auto z = x;
667 z /= y;
668 return z;
669}
670
671inline Number
672Number::min() noexcept
673{
674 return Number{false, range_.get().min, minExponent, unchecked{}};
675}
676
677inline Number
678Number::max() noexcept
679{
680 return Number{false, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
681}
682
683inline Number
685{
686 return Number{true, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
687}
688
689inline bool
690Number::isnormal() const noexcept
691{
692 MantissaRange const& range = range_;
693 auto const abs_m = mantissa_;
694 return *this == Number{} ||
695 (range.min <= abs_m && abs_m <= range.max && (abs_m <= maxRep || abs_m % 10 == 0) &&
697}
698
699template <Integral64 T>
702{
703 bool negative = negative_;
705 int exponent = exponent_;
706
707 if constexpr (std::is_unsigned_v<T>)
708 XRPL_ASSERT_PARTS(
709 !negative,
710 "xrpl::Number::normalizeToRange",
711 "Number is non-negative for unsigned range.");
713
714 auto const sign = negative ? -1 : 1;
715 return std::make_pair(static_cast<T>(sign * mantissa), exponent);
716}
717
718inline constexpr Number
719abs(Number x) noexcept
720{
721 if (x < Number{})
722 x = -x;
723 return x;
724}
725
726// Returns f^n
727// Uses a log_2(n) number of multiplications
728
729Number
730power(Number const& f, unsigned n);
731
732// Returns f^(1/d)
733// Uses Newton–Raphson iterations until the result stops changing
734// to find the root of the polynomial g(x) = x^d - f
735
736Number
737root(Number f, unsigned d);
738
739Number
740root2(Number f);
741
742// Returns f^(n/d)
743
744Number
745power(Number const& f, unsigned n, unsigned d);
746
747// Return 0 if abs(x) < limit, else returns x
748
749inline constexpr Number
750squelch(Number const& x, Number const& limit) noexcept
751{
752 if (abs(x) < limit)
753 return Number{};
754 return x;
755}
756
757inline std::string
759{
760 switch (scale)
761 {
763 return "small";
765 return "large";
766 default:
767 throw std::runtime_error("Bad scale");
768 }
769}
770
787
788// saveNumberRoundMode doesn't do quite enough for us. What we want is a
789// Number::RoundModeGuard that sets the new mode and restores the old mode
790// when it leaves scope. Since Number doesn't have that facility, we'll
791// build it here.
807
834
835} // namespace xrpl
Sets the new scale and restores the old scale when it leaves scope.
Definition Number.h:814
NumberMantissaScaleGuard(MantissaRange::mantissa_scale scale) noexcept
Definition Number.h:818
MantissaRange::mantissa_scale const saved_
Definition Number.h:815
NumberMantissaScaleGuard(NumberMantissaScaleGuard const &)=delete
NumberMantissaScaleGuard & operator=(NumberMantissaScaleGuard const &)=delete
NumberRoundModeGuard & operator=(NumberRoundModeGuard const &)=delete
NumberRoundModeGuard(NumberRoundModeGuard const &)=delete
NumberRoundModeGuard(Number::rounding_mode mode) noexcept
Definition Number.h:797
saveNumberRoundMode saved_
Definition Number.h:794
Number is a floating point type that can represent a wide range of values.
Definition Number.h:207
Number & operator++()
Definition Number.h:604
friend constexpr bool operator<(Number const &x, Number const &y) noexcept
Definition Number.h:312
static constexpr Number oneSmall()
oneSmall is needed because the ranges are private
Definition Number.cpp:333
static rounding_mode getround()
Definition Number.cpp:33
internalrep mantissa_
Definition Number.h:212
static internalrep minMantissa()
Definition Number.h:406
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:552
static rounding_mode setround(rounding_mode mode)
Definition Number.cpp:39
static void normalize(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa)
Normalize Number components to an arbitrary range.
Number truncate() const noexcept
Definition Number.cpp:819
friend std::string to_string(Number const &amount)
Definition Number.cpp:837
static constexpr MantissaRange smallRange
Definition Number.h:444
std::pair< T, int > normalizeToRange(T minMantissa, T maxMantissa) const
Definition Number.h:701
friend void doNormalize(bool &negative, T &mantissa_, int &exponent_, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa)
Definition Number.cpp:361
static constexpr internalrep maxRep
Definition Number.h:220
constexpr Number operator-() const noexcept
Definition Number.h:594
MantissaRange::rep internalrep
Definition Number.h:209
static Number max() noexcept
Definition Number.h:678
static thread_local rounding_mode mode_
Definition Number.h:441
static constexpr int minExponent
Definition Number.h:217
constexpr Number operator+() const noexcept
Definition Number.h:588
Number & operator--()
Definition Number.h:619
Number shiftExponent(int exponentDelta) const
Definition Number.cpp:489
friend constexpr bool operator!=(Number const &x, Number const &y) noexcept
Definition Number.h:306
static void setMantissaScale(MantissaRange::mantissa_scale scale)
Changes which mantissa scale is used for normalization.
Definition Number.cpp:51
friend constexpr bool operator>=(Number const &x, Number const &y) noexcept
Definition Number.h:364
static internalrep externalToInternal(rep mantissa)
Definition Number.cpp:314
static internalrep maxMantissa()
Definition Number.h:412
bool isnormal() const noexcept
Definition Number.h:690
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:573
static constexpr int maxExponent
Definition Number.h:218
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition Number.h:370
static thread_local std::reference_wrapper< MantissaRange const > range_
Definition Number.h:462
friend Number root2(Number f)
Definition Number.cpp:1030
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Number.h:343
Number & operator-=(Number const &x)
Definition Number.h:634
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:45
static Number min() noexcept
Definition Number.h:672
int exponent_
Definition Number.h:213
static constexpr MantissaRange largeRange
Definition Number.h:451
void normalize()
Definition Number.cpp:479
static Number one()
Definition Number.cpp:349
constexpr Number()=default
static constexpr Number oneLarge()
oneLarge is needed because the ranges are private
Definition Number.cpp:341
static Number lowest() noexcept
Definition Number.h:684
bool negative_
Definition Number.h:211
static int mantissaLog()
Definition Number.h:418
friend constexpr bool operator<=(Number const &x, Number const &y) noexcept
Definition Number.h:358
friend Number root(Number f, unsigned d)
Definition Number.cpp:958
Number::rounding_mode mode_
Definition Number.h:773
saveNumberRoundMode(Number::rounding_mode mode) noexcept
Definition Number.h:780
saveNumberRoundMode(saveNumberRoundMode const &)=delete
saveNumberRoundMode & operator=(saveNumberRoundMode const &)=delete
T is_same_v
T lowest(T... args)
T make_pair(T... args)
T max(T... args)
T min(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static std::int64_t constexpr minMantissa
Definition IOUAmount.cpp:48
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:594
Number operator-(Number const &x, Number const &y)
Definition Number.h:648
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
static constexpr Number numZero
Definition Number.h:524
Number operator/(Number const &x, Number const &y)
Definition Number.h:664
Number root(Number f, unsigned d)
Definition Number.cpp:958
Number power(Number const &f, unsigned n)
Definition Number.cpp:935
Number operator*(Number const &x, Number const &y)
Definition Number.h:656
constexpr std::optional< int > logTen(T value)
Definition Number.h:21
static std::int64_t constexpr maxMantissa
Definition IOUAmount.cpp:49
constexpr bool isPowerOfTen(T value)
Definition Number.h:36
Number root2(Number f)
Definition Number.cpp:1030
constexpr Number abs(Number x) noexcept
Definition Number.h:719
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition Number.h:750
T has_value(T... args)
MantissaRange defines a range for the mantissa of a normalized Number.
Definition Number.h:71
std::uint64_t rep
Definition Number.h:72
mantissa_scale scale
Definition Number.h:83
constexpr MantissaRange(mantissa_scale scale_)
Definition Number.h:75
static constexpr rep getMin(mantissa_scale scale_)
Definition Number.h:87