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_)), max(min * 10 - 1), log(logTen(min).value_or(-1)), scale(scale_)
77 {
78 }
79
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(bool negative, internalrep mantissa, int exponent, unchecked) noexcept;
244 // Assume unsigned values are... unsigned. i.e. positive
245 explicit constexpr Number(internalrep mantissa, int exponent, unchecked) noexcept;
246 // Only unit tests are expected to use this ctor
247 explicit Number(bool negative, internalrep mantissa, int exponent, normalized);
248 // Assume unsigned values are... unsigned. i.e. positive
250
251 constexpr rep
252 mantissa() const noexcept;
253 constexpr int
254 exponent() const noexcept;
255
256 constexpr Number
257 operator+() const noexcept;
258 constexpr Number
259 operator-() const noexcept;
260 Number&
261 operator++();
262 Number
263 operator++(int);
264 Number&
265 operator--();
266 Number
267 operator--(int);
268
269 Number&
270 operator+=(Number const& x);
271 Number&
272 operator-=(Number const& x);
273
274 Number&
275 operator*=(Number const& x);
276 Number&
277 operator/=(Number const& x);
278
279 static Number
280 min() noexcept;
281 static Number
282 max() noexcept;
283 static Number
284 lowest() noexcept;
285
291 explicit
292 operator rep() const; // round to nearest, even on tie
293
294 friend constexpr bool
295 operator==(Number const& x, Number const& y) noexcept
296 {
297 return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
298 }
299
300 friend constexpr bool
301 operator!=(Number const& x, Number const& y) noexcept
302 {
303 return !(x == y);
304 }
305
306 friend constexpr bool
307 operator<(Number const& x, Number const& y) noexcept
308 {
309 // If the two amounts have different signs (zero is treated as positive)
310 // then the comparison is true iff the left is negative.
311 bool const lneg = x.negative_;
312 bool const rneg = y.negative_;
313
314 if (lneg != rneg)
315 return lneg;
316
317 // Both have same sign and the left is zero: the right must be
318 // greater than 0.
319 if (x.mantissa_ == 0)
320 return y.mantissa_ > 0;
321
322 // Both have same sign, the right is zero and the left is non-zero.
323 if (y.mantissa_ == 0)
324 return false;
325
326 // Both have the same sign, compare by exponents:
327 if (x.exponent_ > y.exponent_)
328 return lneg;
329 if (x.exponent_ < y.exponent_)
330 return !lneg;
331
332 // If equal exponents, compare mantissas
333 return x.mantissa_ < y.mantissa_;
334 }
335
337 constexpr int
338 signum() const noexcept
339 {
340 return negative_ ? -1 : (mantissa_ ? 1 : 0);
341 }
342
343 Number
344 truncate() const noexcept;
345
346 friend constexpr bool
347 operator>(Number const& x, Number const& y) noexcept
348 {
349 return y < x;
350 }
351
352 friend constexpr bool
353 operator<=(Number const& x, Number const& y) noexcept
354 {
355 return !(y < x);
356 }
357
358 friend constexpr bool
359 operator>=(Number const& x, Number const& y) noexcept
360 {
361 return !(x < y);
362 }
363
365 operator<<(std::ostream& os, Number const& x)
366 {
367 return os << to_string(x);
368 }
369
370 friend std::string
371 to_string(Number const& amount);
372
373 friend Number
374 root(Number f, unsigned d);
375
376 friend Number
377 root2(Number f);
378
379 // Thread local rounding control. Default is to_nearest
381 static rounding_mode
382 getround();
383 // Returns previously set mode
384 static rounding_mode
386
397 static void
399
400 inline static internalrep
402 {
403 return range_.get().min;
404 }
405
406 inline static internalrep
408 {
409 return range_.get().max;
410 }
411
412 inline static int
414 {
415 return range_.get().log;
416 }
417
419 constexpr static Number
420 oneSmall();
422 constexpr static Number
423 oneLarge();
424
425 // And one is needed because it needs to choose between oneSmall and
426 // oneLarge based on the current range
427 static Number
428 one();
429
430 template <Integral64 T>
431 [[nodiscard]]
434
435private:
436 static thread_local rounding_mode mode_;
437 // The available ranges for mantissa
438
440 static_assert(isPowerOfTen(smallRange.min));
441 static_assert(smallRange.min == 1'000'000'000'000'000LL);
442 static_assert(smallRange.max == 9'999'999'999'999'999LL);
443 static_assert(smallRange.log == 15);
444 static_assert(smallRange.min < maxRep);
445 static_assert(smallRange.max < maxRep);
447 static_assert(isPowerOfTen(largeRange.min));
448 static_assert(largeRange.min == 1'000'000'000'000'000'000ULL);
449 static_assert(largeRange.max == internalrep(9'999'999'999'999'999'999ULL));
450 static_assert(largeRange.log == 18);
451 static_assert(largeRange.min < maxRep);
452 static_assert(largeRange.max > maxRep);
453
454 // The range for the mantissa when normalized.
455 // Use reference_wrapper to avoid making copies, and prevent accidentally
456 // changing the values inside the range.
458
459 void
460 normalize();
461
468 template <class T>
469 static void
471 bool& negative,
472 T& mantissa,
473 int& exponent,
475 internalrep const& maxMantissa);
476
477 template <class T>
478 friend void
480 bool& negative,
481 T& mantissa_,
482 int& exponent_,
485
486 bool
487 isnormal() const noexcept;
488
489 // Copy the number, but modify the exponent by "exponentDelta". Because the
490 // mantissa doesn't change, the result will be "mostly" normalized, but the
491 // exponent could go out of range, so it will be checked.
492 Number
493 shiftExponent(int exponentDelta) const;
494
495 // Safely convert rep (int64) mantissa to internalrep (uint64). If the rep
496 // is negative, returns the positive value. This takes a little extra work
497 // because converting std::numeric_limits<std::int64_t>::min() flirts with
498 // UB, and can vary across compilers.
499 static internalrep
501
502 class Guard;
503};
504
505inline constexpr Number::Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept
507{
508}
509
510inline constexpr Number::Number(internalrep mantissa, int exponent, unchecked) noexcept
511 : Number(false, mantissa, exponent, unchecked{})
512{
513}
514
515constexpr static Number numZero{};
516
518 : Number(negative, mantissa, exponent, unchecked{})
519{
520 normalize();
521}
522
523inline Number::Number(internalrep mantissa, int exponent, normalized) : Number(false, mantissa, exponent, normalized{})
524{
525}
526
527inline Number::Number(rep mantissa, int exponent)
528 : Number(mantissa < 0, externalToInternal(mantissa), exponent, normalized{})
529{
530}
531
532inline Number::Number(rep mantissa) : Number{mantissa, 0}
533{
534}
535
541inline constexpr Number::rep
542Number::mantissa() const noexcept
543{
544 auto m = mantissa_;
545 if (m > maxRep)
546 {
547 XRPL_ASSERT_PARTS(
548 !isnormal() || (m % 10 == 0 && m / 10 <= maxRep),
549 "xrpl::Number::mantissa",
550 "large normalized mantissa has no remainder");
551 m /= 10;
552 }
553 auto const sign = negative_ ? -1 : 1;
554 return sign * static_cast<Number::rep>(m);
555}
556
562inline constexpr int
563Number::exponent() const noexcept
564{
565 auto e = exponent_;
566 if (mantissa_ > maxRep)
567 {
568 XRPL_ASSERT_PARTS(
569 !isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= maxRep),
570 "xrpl::Number::exponent",
571 "large normalized mantissa has no remainder");
572 ++e;
573 }
574 return e;
575}
576
577inline constexpr Number
578Number::operator+() const noexcept
579{
580 return *this;
581}
582
583inline constexpr Number
584Number::operator-() const noexcept
585{
586 if (mantissa_ == 0)
587 return Number{};
588 auto x = *this;
589 x.negative_ = !x.negative_;
590 return x;
591}
592
593inline Number&
595{
596 *this += one();
597 return *this;
598}
599
600inline Number
602{
603 auto x = *this;
604 ++(*this);
605 return x;
606}
607
608inline Number&
610{
611 *this -= one();
612 return *this;
613}
614
615inline Number
617{
618 auto x = *this;
619 --(*this);
620 return x;
621}
622
623inline Number&
625{
626 return *this += -x;
627}
628
629inline Number
630operator+(Number const& x, Number const& y)
631{
632 auto z = x;
633 z += y;
634 return z;
635}
636
637inline Number
638operator-(Number const& x, Number const& y)
639{
640 auto z = x;
641 z -= y;
642 return z;
643}
644
645inline Number
646operator*(Number const& x, Number const& y)
647{
648 auto z = x;
649 z *= y;
650 return z;
651}
652
653inline Number
654operator/(Number const& x, Number const& y)
655{
656 auto z = x;
657 z /= y;
658 return z;
659}
660
661inline Number
662Number::min() noexcept
663{
664 return Number{false, range_.get().min, minExponent, unchecked{}};
665}
666
667inline Number
668Number::max() noexcept
669{
670 return Number{false, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
671}
672
673inline Number
675{
676 return Number{true, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
677}
678
679inline bool
680Number::isnormal() const noexcept
681{
682 MantissaRange const& range = range_;
683 auto const abs_m = mantissa_;
684 return *this == Number{} ||
685 (range.min <= abs_m && abs_m <= range.max && (abs_m <= maxRep || abs_m % 10 == 0) && minExponent <= exponent_ &&
687}
688
689template <Integral64 T>
692{
693 bool negative = negative_;
695 int exponent = exponent_;
696
697 if constexpr (std::is_unsigned_v<T>)
698 XRPL_ASSERT_PARTS(!negative, "xrpl::Number::normalizeToRange", "Number is non-negative for unsigned range.");
700
701 auto const sign = negative ? -1 : 1;
702 return std::make_pair(static_cast<T>(sign * mantissa), exponent);
703}
704
705inline constexpr Number
706abs(Number x) noexcept
707{
708 if (x < Number{})
709 x = -x;
710 return x;
711}
712
713// Returns f^n
714// Uses a log_2(n) number of multiplications
715
716Number
717power(Number const& f, unsigned n);
718
719// Returns f^(1/d)
720// Uses Newton–Raphson iterations until the result stops changing
721// to find the root of the polynomial g(x) = x^d - f
722
723Number
724root(Number f, unsigned d);
725
726Number
727root2(Number f);
728
729// Returns f^(n/d)
730
731Number
732power(Number const& f, unsigned n, unsigned d);
733
734// Return 0 if abs(x) < limit, else returns x
735
736inline constexpr Number
737squelch(Number const& x, Number const& limit) noexcept
738{
739 if (abs(x) < limit)
740 return Number{};
741 return x;
742}
743
744inline std::string
746{
747 switch (scale)
748 {
750 return "small";
752 return "large";
753 default:
754 throw std::runtime_error("Bad scale");
755 }
756}
757
774
775// saveNumberRoundMode doesn't do quite enough for us. What we want is a
776// Number::RoundModeGuard that sets the new mode and restores the old mode
777// when it leaves scope. Since Number doesn't have that facility, we'll
778// build it here.
793
819
820} // namespace xrpl
Sets the new scale and restores the old scale when it leaves scope.
Definition Number.h:800
NumberMantissaScaleGuard(MantissaRange::mantissa_scale scale) noexcept
Definition Number.h:804
MantissaRange::mantissa_scale const saved_
Definition Number.h:801
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:784
saveNumberRoundMode saved_
Definition Number.h:781
Number is a floating point type that can represent a wide range of values.
Definition Number.h:207
Number & operator++()
Definition Number.h:594
friend constexpr bool operator<(Number const &x, Number const &y) noexcept
Definition Number.h:307
static constexpr Number oneSmall()
oneSmall is needed because the ranges are private
Definition Number.cpp:327
static rounding_mode getround()
Definition Number.cpp:33
internalrep mantissa_
Definition Number.h:212
static internalrep minMantissa()
Definition Number.h:401
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:542
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:805
friend std::string to_string(Number const &amount)
Definition Number.cpp:823
static constexpr MantissaRange smallRange
Definition Number.h:439
std::pair< T, int > normalizeToRange(T minMantissa, T maxMantissa) const
Definition Number.h:691
friend void doNormalize(bool &negative, T &mantissa_, int &exponent_, MantissaRange::rep const &minMantissa, MantissaRange::rep const &maxMantissa)
Definition Number.cpp:355
static constexpr internalrep maxRep
Definition Number.h:220
constexpr Number operator-() const noexcept
Definition Number.h:584
MantissaRange::rep internalrep
Definition Number.h:209
static Number max() noexcept
Definition Number.h:668
static thread_local rounding_mode mode_
Definition Number.h:436
static constexpr int minExponent
Definition Number.h:217
constexpr Number operator+() const noexcept
Definition Number.h:578
Number & operator--()
Definition Number.h:609
Number shiftExponent(int exponentDelta) const
Definition Number.cpp:481
friend constexpr bool operator!=(Number const &x, Number const &y) noexcept
Definition Number.h:301
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:359
static internalrep externalToInternal(rep mantissa)
Definition Number.cpp:308
static internalrep maxMantissa()
Definition Number.h:407
bool isnormal() const noexcept
Definition Number.h:680
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
Definition Number.h:563
static constexpr int maxExponent
Definition Number.h:218
friend std::ostream & operator<<(std::ostream &os, Number const &x)
Definition Number.h:365
static thread_local std::reference_wrapper< MantissaRange const > range_
Definition Number.h:457
friend Number root2(Number f)
Definition Number.cpp:1010
constexpr int signum() const noexcept
Return the sign of the amount.
Definition Number.h:338
Number & operator-=(Number const &x)
Definition Number.h:624
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:662
int exponent_
Definition Number.h:213
static constexpr MantissaRange largeRange
Definition Number.h:446
void normalize()
Definition Number.cpp:471
static Number one()
Definition Number.cpp:343
constexpr Number()=default
static constexpr Number oneLarge()
oneLarge is needed because the ranges are private
Definition Number.cpp:335
static Number lowest() noexcept
Definition Number.h:674
bool negative_
Definition Number.h:211
static int mantissaLog()
Definition Number.h:413
friend constexpr bool operator<=(Number const &x, Number const &y) noexcept
Definition Number.h:353
friend Number root(Number f, unsigned d)
Definition Number.cpp:938
Number::rounding_mode mode_
Definition Number.h:760
saveNumberRoundMode(Number::rounding_mode mode) noexcept
Definition Number.h:767
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:589
Number operator-(Number const &x, Number const &y)
Definition Number.h:638
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:597
static constexpr Number numZero
Definition Number.h:515
Number operator/(Number const &x, Number const &y)
Definition Number.h:654
Number root(Number f, unsigned d)
Definition Number.cpp:938
Number power(Number const &f, unsigned n)
Definition Number.cpp:915
Number operator*(Number const &x, Number const &y)
Definition Number.h:646
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:1010
constexpr Number abs(Number x) noexcept
Definition Number.h:706
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:737
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