xrpld
Loading...
Searching...
No Matches
Number.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4
5#include <array>
6#include <cstdint>
7#include <functional>
8#include <limits>
9#include <optional>
10#include <ostream>
11#include <set>
12#include <stdexcept>
13#include <string>
14#include <unordered_map>
15
16namespace xrpl {
17
18class Number;
19
20std::string
21to_string(Number const& amount);
22
23template <typename T>
24constexpr std::optional<int>
25logTen(T value)
26{
27 int log = 0;
28 while (value >= 10 && value % 10 == 0)
29 {
30 value /= 10;
31 ++log;
32 }
33 if (value == 1)
34 return log;
35 return std::nullopt;
36}
37
38template <typename T>
39constexpr bool
41{
42 return logTen(value).has_value();
43}
44
45namespace detail {
46
57{
59
61 std::size_t exponent = 0;
62 // end the loop early so it doesn't overflow;
63 for (; exponent < result.size() - 1; ++exponent, power *= 10)
64 {
65 result[exponent] = power;
67 throw std::logic_error("Power of 10 table is too big");
68 }
69 result[exponent] = power;
71 throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
72
73 return result;
74}
75
76} // namespace detail
77
79
80static_assert(kPowerOfTen[0] == 1);
81static_assert(kPowerOfTen[1] == 10);
82static_assert(kPowerOfTen[10] == 10'000'000'000);
83static_assert(
85
119struct MantissaRange final
120{
122
123 enum class MantissaScale {
125 // LargeLegacy can be removed when fixCleanup3_2_0 is retired
128 };
129
130 // This entire enum can be removed when fixCleanup3_2_0 is retired
131 enum class CuspRoundingFix : bool {
132 Disabled = false,
133 Enabled = true,
134 };
135
136 explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
137 {
138 }
139
141 int const log{getExponent(scale)};
143 rep const max{(min * 10) - 1};
145
146 static MantissaRange const&
148
149 static std::set<MantissaScale> const&
150 getAllScales();
151
152private:
153 static constexpr int
155 {
156 switch (scale)
157 {
159 return 15;
162 return 18;
163 // LCOV_EXCL_START
164 default:
165 // If called in a constexpr context, this throw assures that the build fails if an
166 // invalid scale is used.
167 throw std::runtime_error("Unknown mantissa scale");
168 // LCOV_EXCL_STOP
169 }
170 }
171
172 // Keep this function for future use with different ways to compute
173 // the ranges.
174 static constexpr rep
176 {
177 if (exponent < 0 || exponent >= kPowerOfTen.size())
178 throw std::runtime_error("Invalid exponent"); // LCOV_EXCL_LINE
179 return kPowerOfTen[exponent];
180 }
181
182 static constexpr CuspRoundingFix
184 {
185 switch (scale)
186 {
192 default:
193 // If called in a constexpr context, this throw assures that the build fails if an
194 // invalid scale is used.
195 throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE
196 }
197 }
198
200 getRanges();
201};
202
203// Like std::integral, but only 64-bit integral types.
204template <class T>
206
305class Number final
306{
309
310 bool negative_{false};
313
314public:
315 // The range for the exponent when normalized
316 static constexpr int kMinExponent = -32768;
317 static constexpr int kMaxExponent = 32768;
318
320 static_assert(kMaxRep == 9'223'372'036'854'775'807);
321 static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
322
323 // May need to make unchecked private
325 {
326 explicit Unchecked() = default;
327 };
328
329 // Like unchecked, normalized is used with the ctors that take an
330 // internalrep mantissa. Unlike unchecked, those ctors will normalize the
331 // value.
332 // Only unit tests are expected to use this class
334 {
335 explicit Normalized() = default;
336 };
337
338 explicit constexpr Number() = default;
339
341 explicit Number(rep mantissa, int exponent);
342 explicit constexpr Number(
343 bool negative,
345 int exponent,
346 Unchecked) noexcept;
347 // Assume unsigned values are... unsigned. i.e. positive
348 explicit constexpr Number(internalrep mantissa, int exponent, Unchecked) noexcept;
349 // Only unit tests are expected to use this ctor
350 explicit Number(bool negative, internalrep mantissa, int exponent, Normalized);
351 // Assume unsigned values are... unsigned. i.e. positive
353
354 [[nodiscard]] constexpr rep
355 mantissa() const noexcept;
356 [[nodiscard]] constexpr int
357 exponent() const noexcept;
358
359 constexpr Number
360 operator+() const noexcept;
361 constexpr Number
362 operator-() const noexcept;
363 Number&
364 operator++();
365 Number
366 operator++(int);
367 Number&
368 operator--();
369 Number
370 operator--(int);
371
372 Number&
373 operator+=(Number const& x);
374 Number&
375 operator-=(Number const& x);
376
377 Number&
378 operator*=(Number const& x);
379 Number&
380 operator/=(Number const& x);
381
382 static Number
383 min() noexcept;
384 static Number
385 max() noexcept;
386 static Number
387 lowest() noexcept;
388
394 explicit
395 operator rep() const; // round to nearest, even on tie
396
397 friend constexpr bool
398 operator==(Number const& x, Number const& y) noexcept
399 {
400 return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ &&
401 x.exponent_ == y.exponent_;
402 }
403
404 friend constexpr bool
405 operator!=(Number const& x, Number const& y) noexcept
406 {
407 return !(x == y);
408 }
409
410 friend constexpr bool
411 operator<(Number const& l, Number const& r) noexcept
412 {
413 bool const lneg = l.negative_;
414 bool const rneg = r.negative_;
415
416 // If the two amounts have different signs (zero is treated as positive)
417 // then the comparison is true iff the left is negative.
418 if (lneg != rneg)
419 return lneg;
420
421 // Both have same sign and the left is zero: both must be non-negative.
422 // If the right is greater than 0, then it is larger, so the comparison is true.
423 if (l.mantissa_ == 0)
424 return r.mantissa_ > 0;
425
426 // Both have same sign, the right is zero and the left is non-zero, so the left must be
427 // positive, and thus is larger, so the comparison is false.
428 if (r.mantissa_ == 0)
429 return false;
430
431 // Both have the same sign, compare by exponents:
432 if (l.exponent_ > r.exponent_)
433 return lneg;
434 if (l.exponent_ < r.exponent_)
435 return !lneg;
436
437 // If equal signs and exponents, compare mantissas.
438 if (lneg)
439 {
440 // If negative, the operator is reversed.
441 return l.mantissa_ > r.mantissa_;
442 }
443
444 return l.mantissa_ < r.mantissa_;
445 }
446
448 [[nodiscard]] constexpr int
449 signum() const noexcept
450 {
451 if (negative_)
452 return -1;
453 return (mantissa_ != 0u) ? 1 : 0;
454 }
455
456 [[nodiscard]] Number
457 truncate() const noexcept;
458
459 friend constexpr bool
460 operator>(Number const& x, Number const& y) noexcept
461 {
462 return y < x;
463 }
464
465 friend constexpr bool
466 operator<=(Number const& x, Number const& y) noexcept
467 {
468 return !(y < x);
469 }
470
471 friend constexpr bool
472 operator>=(Number const& x, Number const& y) noexcept
473 {
474 return !(x < y);
475 }
476
478 operator<<(std::ostream& os, Number const& x)
479 {
480 return os << to_string(x);
481 }
482
483 friend std::string
484 to_string(Number const& amount);
485
486 friend Number
487 root(Number f, unsigned d);
488
489 friend Number
490 root2(Number f);
491
492 // Thread local rounding control. Default is to_nearest
494
495 static RoundingMode
496 getround();
497
498 static RoundingMode
499 setround(RoundingMode inMode);
500
507
512 static void
514
515 static internalrep
517 {
518 return kRange.get().min;
519 }
520
521 static internalrep
523 {
524 return kRange.get().max;
525 }
526
527 static int
529 {
530 return kRange.get().log;
531 }
532
533 static Number
534 one();
535
536 template <
537 auto MinMantissa,
538 auto MaxMantissa,
539 Integral64 T = std::decay_t<decltype(MinMantissa)>>
540 [[nodiscard]]
542 normalizeToRange() const;
543
544private:
545 static thread_local RoundingMode mode;
546 // The available ranges for mantissa
547
548 // The range for the mantissa when normalized.
549 // Use reference_wrapper to avoid making copies, and prevent accidentally
550 // changing the values inside the range.
552
553 void
555
562 template <class T>
563 static void
565 bool& negative,
566 T& mantissa,
567 int& exponent,
570 MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
571
572 template <class T>
573 friend void
575 bool& negative,
576 T& mantissa,
577 int& exponent,
580 MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
581 bool dropped);
582
583 [[nodiscard]] bool
584 isnormal() const noexcept;
585
586 // Copy the number, but modify the exponent by "exponentDelta". Because the
587 // mantissa doesn't change, the result will be "mostly" normalized, but the
588 // exponent could go out of range, so it will be checked.
589 [[nodiscard]] Number
590 shiftExponent(int exponentDelta) const;
591
592 // Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
593 // is negative, returns the positive value. This takes a little extra work
594 // because converting std::numeric_limits<std::int64_t>::min() flirts with
595 // UB, and can vary across compilers.
596 static internalrep
598
599 class Guard;
600};
601
602constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
604{
605}
606
608 : Number(false, mantissa, exponent, Unchecked{})
609{
610}
611
612static constexpr Number kNumZero{};
613
615 : Number(negative, mantissa, exponent, Unchecked{})
616{
618}
619
624
629
631{
632}
633
639constexpr Number::rep
640Number::mantissa() const noexcept
641{
642 auto m = mantissa_;
643 if (m > kMaxRep)
644 {
645 XRPL_ASSERT_PARTS(
646 !isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
647 "xrpl::Number::mantissa",
648 "large normalized mantissa has no remainder");
649 m /= 10;
650 }
651 auto const sign = negative_ ? -1 : 1;
652 return sign * static_cast<Number::rep>(m);
653}
654
660constexpr int
661Number::exponent() const noexcept
662{
663 auto e = exponent_;
664 if (mantissa_ > kMaxRep)
665 {
666 XRPL_ASSERT_PARTS(
667 !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
668 "xrpl::Number::exponent",
669 "large normalized mantissa has no remainder");
670 ++e;
671 }
672 return e;
673}
674
675constexpr Number
676Number::operator+() const noexcept
677{
678 return *this;
679}
680
681constexpr Number
682Number::operator-() const noexcept
683{
684 if (mantissa_ == 0)
685 return Number{};
686 auto x = *this;
687 x.negative_ = !x.negative_;
688 return x;
689}
690
691inline Number&
693{
694 *this += one();
695 return *this;
696}
697
698inline Number
700{
701 auto x = *this;
702 ++(*this);
703 return x;
704}
705
706inline Number&
708{
709 *this -= one();
710 return *this;
711}
712
713inline Number
715{
716 auto x = *this;
717 --(*this);
718 return x;
719}
720
721inline Number&
723{
724 return *this += -x;
725}
726
727inline Number
728operator+(Number const& x, Number const& y)
729{
730 auto z = x;
731 z += y;
732 return z;
733}
734
735inline Number
736operator-(Number const& x, Number const& y)
737{
738 auto z = x;
739 z -= y;
740 return z;
741}
742
743inline Number
744operator*(Number const& x, Number const& y)
745{
746 auto z = x;
747 z *= y;
748 return z;
749}
750
751inline Number
752operator/(Number const& x, Number const& y)
753{
754 auto z = x;
755 z /= y;
756 return z;
757}
758
759inline Number
760Number::min() noexcept
761{
762 return Number{false, kRange.get().min, kMinExponent, Unchecked{}};
763}
764
765inline Number
766Number::max() noexcept
767{
768 return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
769}
770
771inline Number
773{
774 return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
775}
776
777inline bool
778Number::isnormal() const noexcept
779{
780 MantissaRange const& range = kRange;
781 auto const absM = mantissa_;
782 return *this == Number{} ||
783 (range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
785}
786
787template <auto MinMantissa, auto MaxMantissa, Integral64 T>
790{
792 static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
793 static_assert(std::is_same_v<T, std::decay_t<decltype(MaxMantissa)>>);
794 auto constexpr kMIN = static_cast<T>(MinMantissa);
795 auto constexpr kMAX = static_cast<T>(MaxMantissa);
796 static_assert(kMIN > 0);
797 static_assert(kMIN % 10 == 0);
798 static_assert(isPowerOfTen(kMIN));
799 static_assert(kMAX % 10 == 9);
800 static_assert((kMAX + 1) / 10 == kMIN);
801
802 bool negative = negative_;
804 int exponent = exponent_;
805
806 if constexpr (std::is_unsigned_v<T>)
807 {
808 XRPL_ASSERT_PARTS(
809 !negative,
810 "xrpl::Number::normalizeToRange",
811 "Number is non-negative for unsigned range.");
812 }
813 // Don't need to worry about the cuspRounding fix because rounding up will never take the
814 // mantissa over maxMantissa with a ones digit value other than 0. 0 can safely be truncated.
817
818 auto const sign = negative ? -1 : 1;
819 return std::make_pair(static_cast<T>(sign * mantissa), exponent);
820}
821
822constexpr Number
823abs(Number x) noexcept
824{
825 if (x < Number{})
826 x = -x;
827 return x;
828}
829
830// Returns f^n
831// Uses a log_2(n) number of multiplications
832
833Number
834power(Number const& f, unsigned n);
835
836// Returns f^(1/d)
837// Uses Newton–Raphson iterations until the result stops changing
838// to find the root of the polynomial g(x) = x^d - f
839
840Number
841root(Number f, unsigned d);
842
843Number
844root2(Number f);
845
846// Returns f^(n/d)
847
848Number
849power(Number const& f, unsigned n, unsigned d);
850
851// Return 0 if abs(x) < limit, else returns x
852
853constexpr Number
854squelch(Number const& x, Number const& limit) noexcept
855{
856 if (abs(x) < limit)
857 return Number{};
858 return x;
859}
860
861inline std::string
863{
864 switch (scale)
865 {
867 return "small";
869 return "largeLegacy";
871 return "large";
872 default:
873 throw std::runtime_error("Bad scale");
874 }
875}
876
893
894// saveNumberRoundMode doesn't do quite enough for us. What we want is a
895// Number::RoundModeGuard that sets the new mode and restores the old mode
896// when it leaves scope. Since Number doesn't have that facility, we'll
897// build it here.
913
940
941} // namespace xrpl
NumberMantissaScaleGuard(NumberMantissaScaleGuard const &)=delete
MantissaRange::MantissaScale const saved_
Definition Number.h:921
NumberMantissaScaleGuard & operator=(NumberMantissaScaleGuard const &)=delete
NumberMantissaScaleGuard(MantissaRange::MantissaScale scale) noexcept
Definition Number.h:924
NumberRoundModeGuard(Number::RoundingMode mode) noexcept
Definition Number.h:903
SaveNumberRoundMode saved_
Definition Number.h:900
NumberRoundModeGuard & operator=(NumberRoundModeGuard const &)=delete
NumberRoundModeGuard(NumberRoundModeGuard const &)=delete
Number is a floating point type that can represent a wide range of values.
Definition Number.h:306
Number & operator++()
Definition Number.h:692
internalrep mantissa_
Definition Number.h:311
static internalrep minMantissa()
Definition Number.h:516
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:640
std::pair< T, int > normalizeToRange() const
Definition Number.h:789
Number truncate() const noexcept
Definition Number.cpp:1062
std::int64_t rep
Definition Number.h:307
friend std::string to_string(Number const &amount)
Definition Number.cpp:1080
friend constexpr bool operator<(Number const &l, Number const &r) noexcept
Definition Number.h:411
static constexpr int kMinExponent
Definition Number.h:316
static RoundingMode setround(RoundingMode inMode)
Definition Number.cpp:111
static RoundingMode mode
Definition Number.h:545
constexpr Number operator-() const noexcept
Definition Number.h:682
MantissaRange::rep internalrep
Definition Number.h:308
static Number max() noexcept
Definition Number.h:766
static RoundingMode getround()
Definition Number.cpp:105
static std::reference_wrapper< MantissaRange const > kRange
Definition Number.h:551
static constexpr internalrep kMaxRep
Definition Number.h:319
constexpr Number operator+() const noexcept
Definition Number.h:676
Number & operator--()
Definition Number.h:707
Number shiftExponent(int exponentDelta) const
Definition Number.cpp:675
friend constexpr bool operator!=(Number const &x, Number const &y) noexcept
Definition Number.h:405
static MantissaRange::MantissaScale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:117
friend constexpr bool operator>=(Number const &x, Number const &y) noexcept
Definition Number.h:472
static internalrep externalToInternal(rep mantissa)
Definition Number.cpp:500
static internalrep maxMantissa()
Definition Number.h:522
static constexpr int kMaxExponent
Definition Number.h:317
bool isnormal() const noexcept
Definition Number.h:778
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:661
friend void doNormalize(bool &negative, T &mantissa, int &exponent, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFixEnabled, bool dropped)
Definition Number.cpp:527
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition Number.h:478
static void normalize(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFixEnabled)
Normalize Number components to an arbitrary range.
friend Number root2(Number f)
Definition Number.cpp:1275
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Number.h:449
Number & operator-=(Number const &x)
Definition Number.h:722
static Number min() noexcept
Definition Number.h:760
int exponent_
Definition Number.h:312
void normalize(MantissaRange const &range)
Definition Number.cpp:666
static Number one()
Definition Number.cpp:519
constexpr Number()=default
static void setMantissaScale(MantissaRange::MantissaScale scale)
Changes which mantissa scale is used for normalization.
Definition Number.cpp:123
static Number lowest() noexcept
Definition Number.h:772
bool negative_
Definition Number.h:310
static int mantissaLog()
Definition Number.h:528
friend constexpr bool operator<=(Number const &x, Number const &y) noexcept
Definition Number.h:466
friend Number root(Number f, unsigned d)
Definition Number.cpp:1201
SaveNumberRoundMode(SaveNumberRoundMode const &)=delete
SaveNumberRoundMode & operator=(SaveNumberRoundMode const &)=delete
SaveNumberRoundMode(Number::RoundingMode mode) noexcept
Definition Number.h:886
Number::RoundingMode mode_
Definition Number.h:879
T is_same_v
T is_unsigned_v
T lowest(T... args)
T make_pair(T... args)
T max(T... args)
T min(T... args)
constexpr std::size_t kInt64Digits
Builds a table of the powers of 10.
Definition Number.h:54
consteval std::array< std::uint64_t, kInt64Digits > buildPowersOfTen()
Definition Number.h:56
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static constexpr Number kNumZero
Definition Number.h:612
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:625
Number operator-(Number const &x, Number const &y)
Definition Number.h:736
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
Number operator/(Number const &x, Number const &y)
Definition Number.h:752
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
Definition STAmount.h:779
Number root(Number f, unsigned d)
Definition Number.cpp:1201
Number power(Number const &f, unsigned n)
Definition Number.cpp:1178
Number operator*(Number const &x, Number const &y)
Definition Number.h:744
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
constexpr std::array< std::uint64_t, detail::kInt64Digits > kPowerOfTen
Definition Number.h:78
constexpr std::optional< int > logTen(T value)
Definition Number.h:25
constexpr bool isPowerOfTen(T value)
Definition Number.h:40
Number root2(Number f)
Definition Number.cpp:1275
constexpr Number abs(Number x) noexcept
Definition Number.h:823
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:854
T has_value(T... args)
T size(T... args)
MantissaRange defines a range for the mantissa of a normalized Number.
Definition Number.h:120
rep const min
Definition Number.h:142
MantissaScale const scale
Definition Number.h:140
static MantissaRange const & getMantissaRange(MantissaScale scale)
Definition Number.cpp:99
static constexpr int getExponent(MantissaScale scale)
Definition Number.h:154
std::uint64_t rep
Definition Number.h:121
static std::set< MantissaScale > const & getAllScales()
Definition Number.cpp:37
int const log
Definition Number.h:141
CuspRoundingFix const cuspRoundingFixEnabled
Definition Number.h:144
static std::unordered_map< MantissaScale, MantissaRange > const & getRanges()
Definition Number.cpp:48
constexpr MantissaRange(MantissaScale sc)
Definition Number.h:136
static constexpr rep getMin(MantissaScale scale, int exponent)
Definition Number.h:175
static constexpr CuspRoundingFix isCuspFixEnabled(MantissaScale scale)
Definition Number.h:183
rep const max
Definition Number.h:143