xrpld
Loading...
Searching...
No Matches
Number.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4
5#include <algorithm>
6#include <array>
7#include <cstddef>
8#include <cstdint>
9#include <functional>
10#include <limits>
11#include <optional>
12#include <ostream>
13#include <set>
14#include <stdexcept>
15#include <string>
16#include <type_traits>
17#include <utility>
18
19namespace xrpl {
20
21class Number;
22
23std::string
24to_string(Number const& amount);
25
26template <typename T>
27constexpr std::optional<int>
28logTen(T value)
29{
30 int log = 0;
31 while (value >= 10 && value % 10 == 0)
32 {
33 value /= 10;
34 ++log;
35 }
36 if (value == 1)
37 return log;
38 return std::nullopt;
39}
40
41template <typename T>
42constexpr bool
44{
45 return logTen(value).has_value();
46}
47
48namespace detail {
49
59[[maybe_unused]] constexpr std::size_t kUint128Digits = 39;
60
61template <typename T, std::size_t Digits>
64{
65 std::array<T, Digits> result{};
66
67 T power = 1;
68 std::size_t exponent = 0;
69 // end the loop early so it doesn't overflow;
70 for (; exponent < result.size() - 1; ++exponent, power *= 10)
71 {
72 result[exponent] = power;
74 throw std::logic_error("Power of 10 table is too big");
75 }
76 result[exponent] = power;
78 throw std::logic_error("Power of 10 table is not big enough for the given type");
79
80 return result;
81}
82
83} // namespace detail
84
85template <typename T = std::uint64_t, std::size_t Digits = detail::kUint64Digits>
87
89
90static_assert(kPowerOfTen[0] == 1);
91static_assert(kPowerOfTen[1] == 10);
92static_assert(kPowerOfTen[10] == 10'000'000'000);
93static_assert(
95
130struct MantissaRange final
131{
133
134 // NOLINTBEGIN(readability-enum-initial-value)
135 // The values don't matter, except for Large
136 enum class MantissaScale {
137 // Small can be removed when either featureSingleAssetVault or featureLendingProtocol are
138 // retired
140 // LargeLegacy can be removed when fixCleanup3_2_0 is retired
142 // Large320 can be removed when fixCleanup3_3_0 is retired
144 // If Large330 is ever the only remaining "Large*" entry, it can be renamed to just "Large".
146 // Large is a de-facto alias for "the latest", and is only here for backward compatibility
147 // in the extremely unlikely case that a downstream project made use of it. Note that
148 // because the behavior changed, this may still be a breaking change.
150 };
151 // NOLINTEND(readability-enum-initial-value)
152
153 // This entire enum can be removed when the last relevant amendment is retired
155 // Disabled can be removed when fixCleanup3_2_0 is retired
157 // Enabled320 can be removed when fixCleanup3_3_0 is retired
159 // If we ever get to the point that there's only one entry, remove the entire enum
161 // Enabled is a de-facto alias for "the latest", and is only here for backward compatibility
162 // in the extremely unlikely case that a downstream project made use of it. Note that
163 // because the behavior changed, this may still be a breaking change.
165 };
166
167 explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
168 {
169 }
170
172 int const log{getExponent(scale)};
174 rep const max{(min * 10) - 1};
176
177 static std::set<MantissaScale> const&
188
189 class Access
190 {
191 static constexpr MantissaRange const&
193
194 friend Number;
195 };
196
197private:
198 static constexpr int
200 {
201 switch (scale)
202 {
204 return 15;
208 return 18;
209 // LCOV_EXCL_START
210 default:
211 // If called in a constexpr context, this throw assures that the build fails if an
212 // invalid scale is used.
213 throw std::runtime_error("Unknown mantissa scale");
214 // LCOV_EXCL_STOP
215 }
216 }
217
218 // Keep this function for future use with different ways to compute
219 // the ranges.
220 static constexpr rep
222 {
223 if (exponent < 0 || exponent >= kPowerOfTen.size())
224 throw std::runtime_error("Invalid exponent"); // LCOV_EXCL_LINE
225 return kPowerOfTen[exponent];
226 }
227
228 static constexpr CuspRoundingFix
230 {
231 switch (scale)
232 {
240 default:
241 // If called in a constexpr context, this throw assures that the build fails if an
242 // invalid scale is used.
243 throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE
244 }
245 }
246};
247
248// Like std::integral, but only 64-bit integral types.
249template <class T>
251
350class Number final
351{
354
355 bool negative_{false};
358
359public:
360 // The range for the exponent when normalized
361 static constexpr int kMinExponent = -32768;
362 static constexpr int kMaxExponent = 32768;
363
365 static_assert(kMaxRep == 9'223'372'036'854'775'807);
366 static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
367 static constexpr internalrep kMaxRepUp = ((kMaxRep / 10) + 1) * 10;
368 static_assert(kMaxRepUp == 9'223'372'036'854'775'810ULL);
369
370 // May need to make unchecked private
372 {
373 explicit Unchecked() = default;
374 };
375
376 // Like unchecked, normalized is used with the ctors that take an
377 // internalrep mantissa. Unlike unchecked, those ctors will normalize the
378 // value.
379 // Only unit tests are expected to use this class
381 {
382 explicit Normalized() = default;
383 };
384
385 explicit constexpr Number() = default;
386
388 explicit Number(rep mantissa, int exponent);
389 explicit constexpr Number(
390 bool negative,
392 int exponent,
393 Unchecked) noexcept;
394 // Assume unsigned values are... unsigned. i.e. positive
395 explicit constexpr Number(internalrep mantissa, int exponent, Unchecked) noexcept;
396 // Only unit tests are expected to use this ctor
397 explicit Number(bool negative, internalrep mantissa, int exponent, Normalized);
398 // Assume unsigned values are... unsigned. i.e. positive
400
401 [[nodiscard]] constexpr rep
402 mantissa() const noexcept;
403 [[nodiscard]] constexpr int
404 exponent() const noexcept;
405
406 constexpr Number
407 operator+() const noexcept;
408 constexpr Number
409 operator-() const noexcept;
410 Number&
411 operator++();
412 Number
413 operator++(int);
414 Number&
415 operator--();
416 Number
417 operator--(int);
418
419 Number&
420 operator+=(Number const& x);
421 Number&
422 operator-=(Number const& x);
423
424 Number&
425 operator*=(Number const& x);
426 Number&
427 operator/=(Number const& x);
428
429 static Number
430 min() noexcept;
431 static Number
432 max() noexcept;
433 static Number
434 lowest() noexcept;
435
442 explicit
443 operator rep() const; // round to nearest, even on tie
444
445 friend constexpr bool
446 operator==(Number const& x, Number const& y) noexcept
447 {
448 return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ &&
449 x.exponent_ == y.exponent_;
450 }
451
452 friend constexpr bool
453 operator<(Number const& l, Number const& r) noexcept
454 {
455 bool const lneg = l.negative_;
456 bool const rneg = r.negative_;
457
458 // If the two amounts have different signs (zero is treated as positive)
459 // then the comparison is true iff the left is negative.
460 if (lneg != rneg)
461 return lneg;
462
463 // Both have same sign and the left is zero: both must be non-negative.
464 // If the right is greater than 0, then it is larger, so the comparison is true.
465 if (l.mantissa_ == 0)
466 return r.mantissa_ > 0;
467
468 // Both have same sign, the right is zero and the left is non-zero, so the left must be
469 // positive, and thus is larger, so the comparison is false.
470 if (r.mantissa_ == 0)
471 return false;
472
473 // Both have the same sign, compare by exponents:
474 if (l.exponent_ > r.exponent_)
475 return lneg;
476 if (l.exponent_ < r.exponent_)
477 return !lneg;
478
479 // If equal signs and exponents, compare mantissas.
480 if (lneg)
481 {
482 // If negative, the operator is reversed.
483 return l.mantissa_ > r.mantissa_;
484 }
485
486 return l.mantissa_ < r.mantissa_;
487 }
488
492 [[nodiscard]] constexpr int
493 signum() const noexcept
494 {
495 if (negative_)
496 return -1;
497 return (mantissa_ != 0u) ? 1 : 0;
498 }
499
500 [[nodiscard]] Number
501 truncate() const noexcept;
502
503 friend constexpr bool
504 operator>(Number const& x, Number const& y) noexcept
505 {
506 return y < x;
507 }
508
509 friend constexpr bool
510 operator<=(Number const& x, Number const& y) noexcept
511 {
512 return !(y < x);
513 }
514
515 friend constexpr bool
516 operator>=(Number const& x, Number const& y) noexcept
517 {
518 return !(x < y);
519 }
520
522 operator<<(std::ostream& os, Number const& x)
523 {
524 return os << to_string(x);
525 }
526
527 friend std::string
528 to_string(Number const& amount);
529
530 friend Number
531 root(Number f, unsigned d);
532
533 friend Number
534 root2(Number f);
535
536 // Thread local rounding control. Default is to_nearest
538
539 static RoundingMode
540 getround();
541
542 static RoundingMode
543 setround(RoundingMode inMode);
544
552
558 static void
560
561 static internalrep
563 {
564 return kRange.get().min;
565 }
566
567 static internalrep
569 {
570 return kRange.get().max;
571 }
572
573 static int
575 {
576 return kRange.get().log;
577 }
578
579 static Number
580 one();
581
582 template <
583 auto MinMantissa,
584 auto MaxMantissa,
585 Integral64 T = std::decay_t<decltype(MinMantissa)>>
586 [[nodiscard]]
588 normalizeToRange() const;
589
590 // Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
591 // is negative, returns the positive value. This takes a little extra work
592 // because converting std::numeric_limits<std::int64_t>::min() flirts with
593 // UB, and can vary across compilers.
594 static internalrep
596
597private:
598 static thread_local RoundingMode mode;
599 // The available ranges for mantissa
600
601 // The range for the mantissa when normalized.
602 // Use reference_wrapper to avoid making copies, and prevent accidentally
603 // changing the values inside the range.
605
606 class Guard;
607
608 void
610
611 // Guard has the fields that we need, as well as MantissaRange, so if we have a guard, use that
612 void
613 normalize(Guard const& guard);
614
622 template <class T>
623 static void
625 bool& negative,
626 T& mantissa,
627 int& exponent,
630 MantissaRange::CuspRoundingFix cuspRoundingFix);
631
632 template <class T>
633 friend void
635 bool& negative,
636 T& mantissa,
637 int& exponent,
640 MantissaRange::CuspRoundingFix cuspRoundingFix,
641 bool dropped);
642
643 [[nodiscard]] bool
644 isnormal() const noexcept;
645
646 // Copy the number, but modify the exponent by "exponentDelta". Because the
647 // mantissa doesn't change, the result will be "mostly" normalized, but the
648 // exponent could go out of range, so it will be checked.
649 [[nodiscard]] Number
650 shiftExponent(int exponentDelta) const;
651};
652
653constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
655{
656}
657
659 : Number(false, mantissa, exponent, Unchecked{})
660{
661}
662
663static constexpr Number kNumZero{};
664
666 : Number(negative, mantissa, exponent, Unchecked{})
667{
669}
670
675
680
682{
683}
684
691constexpr Number::rep
692Number::mantissa() const noexcept
693{
694 auto m = mantissa_;
695 if (m > kMaxRep)
696 {
697 XRPL_ASSERT_PARTS(
698 !isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
699 "xrpl::Number::mantissa",
700 "large normalized mantissa has no remainder");
701 m /= 10;
702 }
703 auto const sign = negative_ ? -1 : 1;
704 return sign * static_cast<Number::rep>(m);
705}
706
713constexpr int
714Number::exponent() const noexcept
715{
716 auto e = exponent_;
717 if (mantissa_ > kMaxRep)
718 {
719 XRPL_ASSERT_PARTS(
720 !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
721 "xrpl::Number::exponent",
722 "large normalized mantissa has no remainder");
723 ++e;
724 }
725 return e;
726}
727
728constexpr Number
729Number::operator+() const noexcept
730{
731 return *this;
732}
733
734constexpr Number
735Number::operator-() const noexcept
736{
737 if (mantissa_ == 0)
738 return Number{};
739 auto x = *this;
740 x.negative_ = !x.negative_;
741 return x;
742}
743
744inline Number&
746{
747 *this += one();
748 return *this;
749}
750
751inline Number
753{
754 auto x = *this;
755 ++(*this);
756 return x;
757}
758
759inline Number&
761{
762 *this -= one();
763 return *this;
764}
765
766inline Number
768{
769 auto x = *this;
770 --(*this);
771 return x;
772}
773
774inline Number&
776{
777 return *this += -x;
778}
779
780inline Number
781operator+(Number const& x, Number const& y)
782{
783 auto z = x;
784 z += y;
785 return z;
786}
787
788inline Number
789operator-(Number const& x, Number const& y)
790{
791 auto z = x;
792 z -= y;
793 return z;
794}
795
796inline Number
797operator*(Number const& x, Number const& y)
798{
799 auto z = x;
800 z *= y;
801 return z;
802}
803
804inline Number
805operator/(Number const& x, Number const& y)
806{
807 auto z = x;
808 z /= y;
809 return z;
810}
811
812inline Number
813Number::min() noexcept
814{
815 return Number{false, kRange.get().min, kMinExponent, Unchecked{}};
816}
817
818inline Number
819Number::max() noexcept
820{
821 return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
822}
823
824inline Number
826{
827 return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
828}
829
830inline bool
831Number::isnormal() const noexcept
832{
833 MantissaRange const& range = kRange;
834 auto const absM = mantissa_;
835 return *this == Number{} ||
836 (range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
838}
839
840template <auto MinMantissa, auto MaxMantissa, Integral64 T>
843{
845 static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
846 static_assert(std::is_same_v<T, std::decay_t<decltype(MaxMantissa)>>);
847 auto constexpr kMIN = static_cast<T>(MinMantissa);
848 auto constexpr kMAX = static_cast<T>(MaxMantissa);
849 static_assert(kMIN > 0);
850 static_assert(kMIN % 10 == 0);
851 static_assert(isPowerOfTen(kMIN));
852 static_assert(kMAX % 10 == 9);
853 static_assert((kMAX + 1) / 10 == kMIN);
854
855 bool negative = negative_;
857 int exponent = exponent_;
858
859 if constexpr (std::is_unsigned_v<T>)
860 {
861 XRPL_ASSERT_PARTS(
862 !negative,
863 "xrpl::Number::normalizeToRange",
864 "Number is non-negative for unsigned range.");
865 }
866 // Don't need to worry about the cuspRounding fix because rounding up will never take the
867 // mantissa over maxMantissa with a ones digit value other than 0. 0 can safely be truncated.
870
871 auto const sign = negative ? -1 : 1;
872 return std::make_pair(static_cast<T>(sign * mantissa), exponent);
873}
874
875constexpr Number
876abs(Number x) noexcept
877{
878 if (x < Number{})
879 x = -x;
880 return x;
881}
882
883// Returns f^n
884// Uses a log_2(n) number of multiplications
885
886Number
887power(Number const& f, unsigned n);
888
889// Returns f^(1/d)
890// Uses Newton–Raphson iterations until the result stops changing
891// to find the root of the polynomial g(x) = x^d - f
892
893Number
894root(Number f, unsigned d);
895
896Number
897root2(Number f);
898
899// Returns f^(n/d)
900
901Number
902power(Number const& f, unsigned n, unsigned d);
903
904// Return 0 if abs(x) < limit, else returns x
905
906constexpr Number
907squelch(Number const& x, Number const& limit) noexcept
908{
909 if (abs(x) < limit)
910 return Number{};
911 return x;
912}
913
916
918to_string(Number::RoundingMode const& round);
919
936
937// saveNumberRoundMode doesn't do quite enough for us. What we want is a
938// Number::RoundModeGuard that sets the new mode and restores the old mode
939// when it leaves scope. Since Number doesn't have that facility, we'll
940// build it here.
956
983
984} // namespace xrpl
static constexpr MantissaRange const & mantissaRange(MantissaScale scale)
NumberMantissaScaleGuard(NumberMantissaScaleGuard const &)=delete
MantissaRange::MantissaScale const saved_
Definition Number.h:964
NumberMantissaScaleGuard & operator=(NumberMantissaScaleGuard const &)=delete
NumberMantissaScaleGuard(MantissaRange::MantissaScale scale) noexcept
Definition Number.h:967
NumberRoundModeGuard(Number::RoundingMode mode) noexcept
Definition Number.h:946
SaveNumberRoundMode saved_
Definition Number.h:943
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:351
Number & operator++()
Definition Number.h:745
internalrep mantissa_
Definition Number.h:356
static internalrep minMantissa()
Definition Number.h:562
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:692
std::pair< T, int > normalizeToRange() const
Definition Number.h:842
static constexpr internalrep kMaxRepUp
Definition Number.h:367
Number truncate() const noexcept
std::int64_t rep
Definition Number.h:352
friend std::string to_string(Number const &amount)
friend constexpr bool operator<(Number const &l, Number const &r) noexcept
Definition Number.h:453
static constexpr int kMinExponent
Definition Number.h:361
static RoundingMode setround(RoundingMode inMode)
static RoundingMode mode
Definition Number.h:598
friend void doNormalize(bool &negative, T &mantissa, int &exponent, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix, bool dropped)
constexpr Number operator-() const noexcept
Definition Number.h:735
MantissaRange::rep internalrep
Definition Number.h:353
static Number max() noexcept
Definition Number.h:819
static RoundingMode getround()
static void normalize(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa, MantissaRange::CuspRoundingFix cuspRoundingFix)
Normalize Number components to an arbitrary range.
static std::reference_wrapper< MantissaRange const > kRange
Definition Number.h:604
static constexpr internalrep kMaxRep
Definition Number.h:364
constexpr Number operator+() const noexcept
Definition Number.h:729
Number & operator--()
Definition Number.h:760
Number shiftExponent(int exponentDelta) const
static MantissaRange::MantissaScale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
friend constexpr bool operator>=(Number const &x, Number const &y) noexcept
Definition Number.h:516
static internalrep externalToInternal(rep mantissa)
static internalrep maxMantissa()
Definition Number.h:568
static constexpr int kMaxExponent
Definition Number.h:362
bool isnormal() const noexcept
Definition Number.h:831
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:714
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition Number.h:522
friend Number root2(Number f)
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Number.h:493
Number & operator-=(Number const &x)
Definition Number.h:775
static Number min() noexcept
Definition Number.h:813
int exponent_
Definition Number.h:357
void normalize(MantissaRange const &range)
constexpr Number()=default
static void setMantissaScale(MantissaRange::MantissaScale scale)
Changes which mantissa scale is used for normalization.
static Number lowest() noexcept
Definition Number.h:825
bool negative_
Definition Number.h:355
static int mantissaLog()
Definition Number.h:574
friend constexpr bool operator<=(Number const &x, Number const &y) noexcept
Definition Number.h:510
friend Number root(Number f, unsigned d)
SaveNumberRoundMode(SaveNumberRoundMode const &)=delete
SaveNumberRoundMode & operator=(SaveNumberRoundMode const &)=delete
SaveNumberRoundMode(Number::RoundingMode mode) noexcept
Definition Number.h:929
Number::RoundingMode mode_
Definition Number.h:922
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 kUint64Digits
Builds a table of the powers of 10.
Definition Number.h:58
consteval std::array< T, Digits > buildPowersOfTen()
Definition Number.h:63
constexpr std::size_t kUint128Digits
Definition Number.h:59
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:663
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:643
Number operator-(Number const &x, Number const &y)
Definition Number.h:789
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:37
Number operator/(Number const &x, Number const &y)
Definition Number.h:805
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
Definition STAmount.h:794
constexpr std::array< T, Digits > kPowerOfTenImpl
Definition Number.h:86
Number root(Number f, unsigned d)
Number power(Number const &f, unsigned n)
Number operator*(Number const &x, Number const &y)
Definition Number.h:797
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
constexpr std::optional< int > logTen(T value)
Definition Number.h:28
constexpr auto kPowerOfTen
Definition Number.h:88
constexpr bool isPowerOfTen(T value)
Definition Number.h:43
Number root2(Number f)
constexpr Number abs(Number x) noexcept
Definition Number.h:876
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:907
T has_value(T... args)
T size(T... args)
MantissaRange defines a range for the mantissa of a normalized Number.
Definition Number.h:131
rep const min
Definition Number.h:173
MantissaScale const scale
Definition Number.h:171
static constexpr int getExponent(MantissaScale scale)
Definition Number.h:199
std::uint64_t rep
Definition Number.h:132
int const log
Definition Number.h:172
CuspRoundingFix const cuspRoundingFix
Definition Number.h:175
constexpr MantissaRange(MantissaScale sc)
Definition Number.h:167
static constexpr rep getMin(MantissaScale scale, int exponent)
Definition Number.h:221
static constexpr CuspRoundingFix isCuspFixEnabled(MantissaScale scale)
Definition Number.h:229
static std::set< MantissaScale > const & getAllScales()
Definition Number.h:178
rep const max
Definition Number.h:174