rippled
Loading...
Searching...
No Matches
Number.cpp
1#include <xrpl/basics/Number.h>
2// Keep Number.h first to ensure it can build without hidden dependencies
3#include <xrpl/basics/contract.h>
4#include <xrpl/beast/utility/instrumentation.h>
5
6#include <algorithm>
7#include <cstddef>
8#include <cstdint>
9#include <iterator>
10#include <limits>
11#include <numeric>
12#include <stdexcept>
13#include <string>
14#include <type_traits>
15#include <utility>
16
17#ifdef _MSC_VER
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;
22#else // !defined(_MSC_VER)
23using uint128_t = __uint128_t;
24using int128_t = __int128_t;
25#endif // !defined(_MSC_VER)
26
27namespace xrpl {
28
31
34{
35 return mode_;
36}
37
40{
41 return std::exchange(mode_, mode);
42}
43
46{
47 return range_.get().scale;
48}
49
50void
52{
53 if (scale != MantissaRange::small && scale != MantissaRange::large)
54 LogicError("Unknown mantissa scale");
56}
57
58// Guard
59
60// The Guard class is used to temporarily add extra digits of
61// precision to an operation. This enables the final result
62// to be correctly rounded to the internal precision of Number.
63
64template <class T>
66
68{
69 std::uint64_t digits_{0}; // 16 decimal guard digits
70 std::uint8_t xbit_ : 1 {0}; // has a non-zero digit been shifted off the end
71 std::uint8_t sbit_ : 1 {0}; // the sign of the guard digits
72
73public:
74 explicit Guard() = default;
75
76 // set & test the sign bit
77 void
78 set_positive() noexcept;
79 void
80 set_negative() noexcept;
81 bool
82 is_negative() const noexcept;
83
84 // add a digit
85 template <class T>
86 void
87 push(T d) noexcept;
88
89 // recover a digit
90 unsigned
91 pop() noexcept;
92
93 // Indicate round direction: 1 is up, -1 is down, 0 is even
94 // This enables the client to round towards nearest, and on
95 // tie, round towards even.
96 int
97 round() const noexcept;
98
99 // Modify the result to the correctly rounded value
100 template <UnsignedMantissa T>
101 void
102 doRoundUp(
103 bool& negative,
104 T& mantissa,
105 int& exponent,
108 std::string location);
109
110 // Modify the result to the correctly rounded value
111 template <UnsignedMantissa T>
112 void
113 doRoundDown(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa);
114
115 // Modify the result to the correctly rounded value
116 void
117 doRound(rep& drops, std::string location) const;
118
119private:
120 void
121 doPush(unsigned d) noexcept;
122
123 template <UnsignedMantissa T>
124 void
125 bringIntoRange(bool& negative, T& mantissa, int& exponent, internalrep const& minMantissa);
126};
127
128inline void
130{
131 sbit_ = 0;
132}
133
134inline void
136{
137 sbit_ = 1;
138}
139
140inline bool
142{
143 return sbit_ == 1;
144}
145
146inline void
147Number::Guard::doPush(unsigned d) noexcept
148{
149 xbit_ = xbit_ || ((digits_ & 0x0000'0000'0000'000F) != 0);
150 digits_ >>= 4;
151 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
152}
153
154template <class T>
155inline void
157{
158 doPush(static_cast<unsigned>(d));
159}
160
161inline unsigned
163{
164 unsigned const d = (digits_ & 0xF000'0000'0000'0000) >> 60;
165 digits_ <<= 4;
166 return d;
167}
168
169// Returns:
170// -1 if Guard is less than half
171// 0 if Guard is exactly half
172// 1 if Guard is greater than half
173int
174Number::Guard::round() const noexcept
175{
176 auto mode = Number::getround();
177
178 if (mode == towards_zero)
179 return -1;
180
181 if (mode == downward)
182 {
183 if (sbit_)
184 {
185 if (digits_ > 0 || xbit_)
186 return 1;
187 }
188 return -1;
189 }
190
191 if (mode == upward)
192 {
193 if (sbit_)
194 return -1;
195 if (digits_ > 0 || xbit_)
196 return 1;
197 return -1;
198 }
199
200 // assume round to nearest if mode is not one of the predefined values
201 if (digits_ > 0x5000'0000'0000'0000)
202 return 1;
203 if (digits_ < 0x5000'0000'0000'0000)
204 return -1;
205 if (xbit_)
206 return 1;
207 return 0;
208}
209
210template <UnsignedMantissa T>
211void
213 bool& negative,
214 T& mantissa,
215 int& exponent,
217{
218 // Bring mantissa back into the minMantissa / maxMantissa range AFTER
219 // rounding
220 if (mantissa < minMantissa)
221 {
222 mantissa *= 10;
223 --exponent;
224 }
225 if (exponent < minExponent)
226 {
227 constexpr Number zero = Number{};
228
229 negative = zero.negative_;
230 mantissa = zero.mantissa_;
231 exponent = zero.exponent_;
232 }
233}
234
235template <UnsignedMantissa T>
236void
238 bool& negative,
239 T& mantissa,
240 int& exponent,
243 std::string location)
244{
245 auto r = round();
246 if (r == 1 || (r == 0 && (mantissa & 1) == 1))
247 {
248 ++mantissa;
249 // Ensure mantissa after incrementing fits within both the
250 // min/maxMantissa range and is a valid "rep".
252 {
253 mantissa /= 10;
254 ++exponent;
255 }
256 }
258 if (exponent > maxExponent)
259 Throw<std::overflow_error>(std::string(location));
260}
261
262template <UnsignedMantissa T>
263void
265 bool& negative,
266 T& mantissa,
267 int& exponent,
269{
270 auto r = round();
271 if (r == 1 || (r == 0 && (mantissa & 1) == 1))
272 {
273 --mantissa;
274 if (mantissa < minMantissa)
275 {
276 mantissa *= 10;
277 --exponent;
278 }
279 }
281}
282
283// Modify the result to the correctly rounded value
284void
286{
287 auto r = round();
288 if (r == 1 || (r == 0 && (drops & 1) == 1))
289 {
290 if (drops >= maxRep)
291 {
292 static_assert(sizeof(internalrep) == sizeof(rep));
293 // This should be impossible, because it's impossible to represent
294 // "maxRep + 0.6" in Number, regardless of the scale. There aren't
295 // enough digits available. You'd either get a mantissa of "maxRep"
296 // or "(maxRep + 1) / 10", neither of which will round up when
297 // converting to rep, though the latter might overflow _before_
298 // rounding.
299 Throw<std::overflow_error>(std::string(location)); // LCOV_EXCL_LINE
300 }
301 ++drops;
302 }
303 if (is_negative())
304 drops = -drops;
305}
306
307// Number
308
309// Safely convert rep (int64) mantissa to internalrep (uint64). If the rep is
310// negative, returns the positive value. This takes a little extra work because
311// converting std::numeric_limits<std::int64_t>::min() flirts with UB, and can
312// vary across compilers.
315{
316 // If the mantissa is already positive, just return it
317 if (mantissa >= 0)
318 return mantissa;
319 // If the mantissa is negative, but fits within the positive range of rep,
320 // return it negated
322 return -mantissa;
323
324 // If the mantissa doesn't fit within the positive range, convert to
325 // int128_t, negate that, and cast it back down to the internalrep
326 // In practice, this is only going to cover the case of
327 // std::numeric_limits<rep>::min().
328 int128_t const temp = mantissa;
329 return static_cast<internalrep>(-temp);
330}
331
332constexpr Number
337
339
340constexpr Number
345
347
348Number
350{
351 if (&range_.get() == &smallRange)
352 return oneSml;
353 XRPL_ASSERT(&range_.get() == &largeRange, "Number::one() : valid range_");
354 return oneLrg;
355}
356
357// Use the member names in this static function for now so the diff is cleaner
358// TODO: Rename the function parameters to get rid of the "_" suffix
359template <class T>
360void
362 bool& negative,
363 T& mantissa_,
364 int& exponent_,
367{
368 auto constexpr minExponent = Number::minExponent;
369 auto constexpr maxExponent = Number::maxExponent;
370 auto constexpr maxRep = Number::maxRep;
371
372 using Guard = Number::Guard;
373
374 constexpr Number zero = Number{};
375 if (mantissa_ == 0)
376 {
377 mantissa_ = zero.mantissa_;
378 exponent_ = zero.exponent_;
379 negative = zero.negative_;
380 return;
381 }
382 auto m = mantissa_;
383 while ((m < minMantissa) && (exponent_ > minExponent))
384 {
385 m *= 10;
386 --exponent_;
387 }
388 Guard g;
389 if (negative)
390 g.set_negative();
391 while (m > maxMantissa)
392 {
393 if (exponent_ >= maxExponent)
394 throw std::overflow_error("Number::normalize 1");
395 g.push(m % 10);
396 m /= 10;
397 ++exponent_;
398 }
399 if ((exponent_ < minExponent) || (m < minMantissa))
400 {
401 mantissa_ = zero.mantissa_;
402 exponent_ = zero.exponent_;
403 negative = zero.negative_;
404 return;
405 }
406
407 // When using the largeRange, "m" needs fit within an int64, even if
408 // the final mantissa_ is going to end up larger to fit within the
409 // MantissaRange. Cut it down here so that the rounding will be done while
410 // it's smaller.
411 //
412 // Example: 9,900,000,000,000,123,456 > 9,223,372,036,854,775,807,
413 // so "m" will be modified to 990,000,000,000,012,345. Then that value
414 // will be rounded to 990,000,000,000,012,345 or
415 // 990,000,000,000,012,346, depending on the rounding mode. Finally,
416 // mantissa_ will be "m*10" so it fits within the range, and end up as
417 // 9,900,000,000,000,123,450 or 9,900,000,000,000,123,460.
418 // mantissa() will return mantissa_ / 10, and exponent() will return
419 // exponent_ + 1.
420 if (m > maxRep)
421 {
422 if (exponent_ >= maxExponent)
423 throw std::overflow_error("Number::normalize 1.5");
424 g.push(m % 10);
425 m /= 10;
426 ++exponent_;
427 }
428 // Before modification, m should be within the min/max range. After
429 // modification, it must be less than maxRep. In other words, the original
430 // value should have been no more than maxRep * 10.
431 // (maxRep * 10 > maxMantissa)
432 XRPL_ASSERT_PARTS(m <= maxRep, "xrpl::doNormalize", "intermediate mantissa fits in int64");
433 mantissa_ = m;
434
435 g.doRoundUp(negative, mantissa_, exponent_, minMantissa, maxMantissa, "Number::normalize 2");
436 XRPL_ASSERT_PARTS(
438 "xrpl::doNormalize",
439 "final mantissa fits in range");
440}
441
442template <>
443void
444Number::normalize<uint128_t>(
445 bool& negative,
446 uint128_t& mantissa,
447 int& exponent,
450{
452}
453
454template <>
455void
456Number::normalize<unsigned long long>(
457 bool& negative,
458 unsigned long long& mantissa,
459 int& exponent,
462{
464}
465
466template <>
467void
468Number::normalize<unsigned long>(
469 bool& negative,
470 unsigned long& mantissa,
471 int& exponent,
474{
476}
477
478void
480{
481 auto const& range = range_.get();
483}
484
485// Copy the number, but set a new exponent. Because the mantissa doesn't change,
486// the result will be "mostly" normalized, but the exponent could go out of
487// range.
488Number
489Number::shiftExponent(int exponentDelta) const
490{
491 XRPL_ASSERT_PARTS(isnormal(), "xrpl::Number::shiftExponent", "normalized");
492 auto const newExponent = exponent_ + exponentDelta;
493 if (newExponent >= maxExponent)
494 throw std::overflow_error("Number::shiftExponent");
495 if (newExponent < minExponent)
496 {
497 return Number{};
498 }
499 Number const result{negative_, mantissa_, newExponent, unchecked{}};
500 XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::Number::shiftExponent", "result is normalized");
501 return result;
502}
503
504Number&
506{
507 constexpr Number zero = Number{};
508 if (y == zero)
509 return *this;
510 if (*this == zero)
511 {
512 *this = y;
513 return *this;
514 }
515 if (*this == -y)
516 {
517 *this = zero;
518 return *this;
519 }
520
521 XRPL_ASSERT(isnormal() && y.isnormal(), "xrpl::Number::operator+=(Number) : is normal");
522 // *n = negative
523 // *s = sign
524 // *m = mantissa
525 // *e = exponent
526
527 // Need to use uint128_t, because large mantissas can overflow when added
528 // together.
529 bool xn = negative_;
530 uint128_t xm = mantissa_;
531 auto xe = exponent_;
532
533 bool const yn = y.negative_;
534 uint128_t ym = y.mantissa_;
535 auto ye = y.exponent_;
536 Guard g;
537 if (xe < ye)
538 {
539 if (xn)
540 g.set_negative();
541 do
542 {
543 g.push(xm % 10);
544 xm /= 10;
545 ++xe;
546 } while (xe < ye);
547 }
548 else if (xe > ye)
549 {
550 if (yn)
551 g.set_negative();
552 do
553 {
554 g.push(ym % 10);
555 ym /= 10;
556 ++ye;
557 } while (xe > ye);
558 }
559
560 auto const& range = range_.get();
561 auto const& minMantissa = range.min;
562 auto const& maxMantissa = range.max;
563
564 if (xn == yn)
565 {
566 xm += ym;
567 if (xm > maxMantissa || xm > maxRep)
568 {
569 g.push(xm % 10);
570 xm /= 10;
571 ++xe;
572 }
573 g.doRoundUp(xn, xm, xe, minMantissa, maxMantissa, "Number::addition overflow");
574 }
575 else
576 {
577 if (xm > ym)
578 {
579 xm = xm - ym;
580 }
581 else
582 {
583 xm = ym - xm;
584 xe = ye;
585 xn = yn;
586 }
587 while (xm < minMantissa && xm * 10 <= maxRep)
588 {
589 xm *= 10;
590 xm -= g.pop();
591 --xe;
592 }
593 g.doRoundDown(xn, xm, xe, minMantissa);
594 }
595
596 negative_ = xn;
597 mantissa_ = static_cast<internalrep>(xm);
598 exponent_ = xe;
599 normalize();
600 return *this;
601}
602
603// Optimization equivalent to:
604// auto r = static_cast<unsigned>(u % 10);
605// u /= 10;
606// return r;
607// Derived from Hacker's Delight Second Edition Chapter 10
608// by Henry S. Warren, Jr.
609static inline unsigned
610divu10(uint128_t& u)
611{
612 // q = u * 0.75
613 auto q = (u >> 1) + (u >> 2);
614 // iterate towards q = u * 0.8
615 q += q >> 4;
616 q += q >> 8;
617 q += q >> 16;
618 q += q >> 32;
619 q += q >> 64;
620 // q /= 8 approximately == u / 10
621 q >>= 3;
622 // r = u - q * 10 approximately == u % 10
623 auto r = static_cast<unsigned>(u - ((q << 3) + (q << 1)));
624 // correction c is 1 if r >= 10 else 0
625 auto c = (r + 6) >> 4;
626 u = q + c;
627 r -= c * 10;
628 return r;
629}
630
631Number&
633{
634 constexpr Number zero = Number{};
635 if (*this == zero)
636 return *this;
637 if (y == zero)
638 {
639 *this = y;
640 return *this;
641 }
642 // *n = negative
643 // *s = sign
644 // *m = mantissa
645 // *e = exponent
646
647 bool const xn = negative_;
648 int const xs = xn ? -1 : 1;
650 auto xe = exponent_;
651
652 bool const yn = y.negative_;
653 int const ys = yn ? -1 : 1;
654 internalrep const ym = y.mantissa_;
655 auto ye = y.exponent_;
656
657 auto zm = uint128_t(xm) * uint128_t(ym);
658 auto ze = xe + ye;
659 auto zs = xs * ys;
660 bool zn = (zs == -1);
661 Guard g;
662 if (zn)
663 g.set_negative();
664
665 auto const& range = range_.get();
666 auto const& minMantissa = range.min;
667 auto const& maxMantissa = range.max;
668
669 while (zm > maxMantissa || zm > maxRep)
670 {
671 // The following is optimization for:
672 // g.push(static_cast<unsigned>(zm % 10));
673 // zm /= 10;
674 g.push(divu10(zm));
675 ++ze;
676 }
677 xm = static_cast<internalrep>(zm);
678 xe = ze;
679 g.doRoundUp(
680 zn,
681 xm,
682 xe,
685 "Number::multiplication overflow : exponent is " + std::to_string(xe));
686 negative_ = zn;
687 mantissa_ = xm;
688 exponent_ = xe;
689
690 normalize();
691 return *this;
692}
693
694Number&
696{
697 constexpr Number zero = Number{};
698 if (y == zero)
699 throw std::overflow_error("Number: divide by 0");
700 if (*this == zero)
701 return *this;
702 // n* = numerator
703 // d* = denominator
704 // *p = negative (positive?)
705 // *s = sign
706 // *m = mantissa
707 // *e = exponent
708
709 bool const np = negative_;
710 int const ns = (np ? -1 : 1);
711 auto nm = mantissa_;
712 auto ne = exponent_;
713
714 bool const dp = y.negative_;
715 int const ds = (dp ? -1 : 1);
716 auto dm = y.mantissa_;
717 auto de = y.exponent_;
718
719 auto const& range = range_.get();
720 auto const& minMantissa = range.min;
721 auto const& maxMantissa = range.max;
722
723 // Shift by 10^17 gives greatest precision while not overflowing
724 // uint128_t or the cast back to int64_t
725 // TODO: Can/should this be made bigger for largeRange?
726 // log(2^128,10) ~ 38.5
727 // largeRange.log = 18, fits in 10^19
728 // f can be up to 10^(38-19) = 10^19 safely
729 static_assert(smallRange.log == 15);
730 static_assert(largeRange.log == 18);
731 bool const small = Number::getMantissaScale() == MantissaRange::small;
732 uint128_t const f = small ? 100'000'000'000'000'000 : 10'000'000'000'000'000'000ULL;
733 XRPL_ASSERT_PARTS(f >= minMantissa * 10, "Number::operator/=", "factor expected size");
734
735 // unsigned denominator
736 auto const dmu = static_cast<uint128_t>(dm);
737 // correctionFactor can be anything between 10 and f, depending on how much
738 // extra precision we want to only use for rounding with the
739 // largeRange. Three digits seems like plenty, and is more than
740 // the smallRange uses.
741 uint128_t const correctionFactor = 1'000;
742
743 auto const numerator = uint128_t(nm) * f;
744
745 auto zm = numerator / dmu;
746 auto ze = ne - de - (small ? 17 : 19);
747 bool zn = (ns * ds) < 0;
748 if (!small)
749 {
750 // Virtually multiply numerator by correctionFactor. Since that would
751 // overflow in the existing uint128_t, we'll do that part separately.
752 // The math for this would work for small mantissas, but we need to
753 // preserve existing behavior.
754 //
755 // Consider:
756 // ((numerator * correctionFactor) / dmu) / correctionFactor
757 // = ((numerator / dmu) * correctionFactor) / correctionFactor)
758 //
759 // But that assumes infinite precision. With integer math, this is
760 // equivalent to
761 //
762 // = ((numerator / dmu * correctionFactor)
763 // + ((numerator % dmu) * correctionFactor) / dmu) / correctionFactor
764 //
765 // We have already set `mantissa_ = numerator / dmu`. Now we
766 // compute `remainder = numerator % dmu`, and if it is
767 // nonzero, we do the rest of the arithmetic. If it's zero, we can skip
768 // it.
769 auto const remainder = (numerator % dmu);
770 if (remainder != 0)
771 {
772 zm *= correctionFactor;
773 auto const correction = remainder * correctionFactor / dmu;
774 zm += correction;
775 // divide by 1000 by moving the exponent, so we don't lose the
776 // integer value we just computed
777 ze -= 3;
778 }
779 }
780 normalize(zn, zm, ze, minMantissa, maxMantissa);
781 negative_ = zn;
782 mantissa_ = static_cast<internalrep>(zm);
783 exponent_ = ze;
784 XRPL_ASSERT_PARTS(isnormal(), "xrpl::Number::operator/=", "result is normalized");
785
786 return *this;
787}
788
789Number::
790operator rep() const
791{
792 rep drops = mantissa();
793 int offset = exponent();
794 Guard g;
795 if (drops != 0)
796 {
797 if (negative_)
798 {
799 g.set_negative();
800 drops = -drops;
801 }
802 for (; offset < 0; ++offset)
803 {
804 g.push(drops % 10);
805 drops /= 10;
806 }
807 for (; offset > 0; --offset)
808 {
809 if (drops > maxRep / 10)
810 throw std::overflow_error("Number::operator rep() overflow");
811 drops *= 10;
812 }
813 g.doRound(drops, "Number::operator rep() rounding overflow");
814 }
815 return drops;
816}
817
818Number
819Number::truncate() const noexcept
820{
821 if (exponent_ >= 0 || mantissa_ == 0)
822 return *this;
823
824 Number ret = *this;
825 while (ret.exponent_ < 0 && ret.mantissa_ != 0)
826 {
827 ret.exponent_ += 1;
828 ret.mantissa_ /= rep(10);
829 }
830 // We are guaranteed that normalize() will never throw an exception
831 // because exponent is either negative or zero at this point.
832 ret.normalize();
833 return ret;
834}
835
837to_string(Number const& amount)
838{
839 // keep full internal accuracy, but make more human friendly if possible
840 constexpr Number zero = Number{};
841 if (amount == zero)
842 return "0";
843
844 auto exponent = amount.exponent_;
845 auto mantissa = amount.mantissa_;
846 bool const negative = amount.negative_;
847
848 // Use scientific notation for exponents that are too small or too large
849 auto const rangeLog = Number::mantissaLog();
850 if (((exponent != 0) && ((exponent < -(rangeLog + 10)) || (exponent > -(rangeLog - 10)))))
851 {
852 while (mantissa != 0 && mantissa % 10 == 0 && exponent < Number::maxExponent)
853 {
854 mantissa /= 10;
855 ++exponent;
856 }
857 std::string ret = negative ? "-" : "";
859 ret.append(1, 'e');
861 return ret;
862 }
863
864 XRPL_ASSERT(exponent + 43 > 0, "xrpl::to_string(Number) : minimum exponent");
865
866 ptrdiff_t const pad_prefix = rangeLog + 12;
867 ptrdiff_t const pad_suffix = rangeLog + 8;
868
869 std::string const raw_value(std::to_string(mantissa));
870 std::string val;
871
872 val.reserve(raw_value.length() + pad_prefix + pad_suffix);
873 val.append(pad_prefix, '0');
874 val.append(raw_value);
875 val.append(pad_suffix, '0');
876
877 ptrdiff_t const offset(exponent + pad_prefix + rangeLog + 1);
878
879 auto pre_from(val.begin());
880 auto const pre_to(val.begin() + offset);
881
882 auto const post_from(val.begin() + offset);
883 auto post_to(val.end());
884
885 // Crop leading zeroes. Take advantage of the fact that there's always a
886 // fixed amount of leading zeroes and skip them.
887 if (std::distance(pre_from, pre_to) > pad_prefix)
888 pre_from += pad_prefix;
889
890 XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : first distance check");
891
892 pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
893
894 // Crop trailing zeroes. Take advantage of the fact that there's always a
895 // fixed amount of trailing zeroes and skip them.
896 if (std::distance(post_from, post_to) > pad_suffix)
897 post_to -= pad_suffix;
898
899 XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : second distance check");
900
901 post_to = std::find_if(
904 [](char c) { return c != '0'; })
905 .base();
906
907 std::string ret;
908
909 if (negative)
910 ret.append(1, '-');
911
912 // Assemble the output:
913 if (pre_from == pre_to)
914 {
915 ret.append(1, '0');
916 }
917 else
918 {
919 ret.append(pre_from, pre_to);
920 }
921
922 if (post_to != post_from)
923 {
924 ret.append(1, '.');
925 ret.append(post_from, post_to);
926 }
927
928 return ret;
929}
930
931// Returns f^n
932// Uses a log_2(n) number of multiplications
933
934Number
935power(Number const& f, unsigned n)
936{
937 if (n == 0)
938 return Number::one();
939 if (n == 1)
940 return f;
941 auto r = power(f, n / 2);
942 r *= r;
943 if (n % 2 != 0)
944 r *= f;
945 return r;
946}
947
948// Returns f^(1/d)
949// Uses Newton–Raphson iterations until the result stops changing
950// to find the non-negative root of the polynomial g(x) = x^d - f
951
952// This function, and power(Number f, unsigned n, unsigned d)
953// treat corner cases such as 0 roots as advised by Annex F of
954// the C standard, which itself is consistent with the IEEE
955// floating point standards.
956
957Number
958root(Number f, unsigned d)
959{
960 constexpr Number zero = Number{};
961 auto const one = Number::one();
962
963 if (f == one || d == 1)
964 return f;
965 if (d == 0)
966 {
967 if (f == -one)
968 return one;
969 if (abs(f) < one)
970 return zero;
971 throw std::overflow_error("Number::root infinity");
972 }
973 if (f < zero && d % 2 == 0)
974 throw std::overflow_error("Number::root nan");
975 if (f == zero)
976 return f;
977
978 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
979 auto e = f.exponent_ + Number::mantissaLog() + 1;
980 auto const di = static_cast<int>(d);
981 auto ex = [e = e, di = di]() // Euclidean remainder of e/d
982 {
983 int const k = (e >= 0 ? e : e - (di - 1)) / di;
984 int const k2 = e - (k * di);
985 if (k2 == 0)
986 return 0;
987 return di - k2;
988 }();
989 e += ex;
990 f = f.shiftExponent(-e); // f /= 10^e;
991
992 XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root(Number, unsigned)", "f is normalized");
993 bool neg = false;
994 if (f < zero)
995 {
996 neg = true;
997 f = -f;
998 }
999
1000 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
1001 auto const D = (((6 * di + 11) * di + 6) * di) + 1;
1002 auto const a0 = 3 * di * ((2 * di - 3) * di + 1);
1003 auto const a1 = 24 * di * (2 * di - 1);
1004 auto const a2 = -30 * (di - 1) * di;
1005 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
1006 if (neg)
1007 {
1008 f = -f;
1009 r = -r;
1010 }
1011
1012 // Newton–Raphson iteration of f^(1/d) with initial guess r
1013 // halt when r stops changing, checking for bouncing on the last iteration
1014 Number rm1{};
1015 Number rm2{};
1016 do
1017 {
1018 rm2 = rm1;
1019 rm1 = r;
1020 r = (Number(d - 1) * r + f / power(r, d - 1)) / Number(d);
1021 } while (r != rm1 && r != rm2);
1022
1023 // return r * 10^(e/d) to reverse scaling
1024 auto const result = r.shiftExponent(e / di);
1025 XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root(Number, unsigned)", "result is normalized");
1026 return result;
1027}
1028
1029Number
1031{
1032 constexpr Number zero = Number{};
1033 auto const one = Number::one();
1034
1035 if (f == one)
1036 return f;
1037 if (f < zero)
1038 throw std::overflow_error("Number::root nan");
1039 if (f == zero)
1040 return f;
1041
1042 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
1043 auto e = f.exponent_ + Number::mantissaLog() + 1;
1044 if (e % 2 != 0)
1045 ++e;
1046 f = f.shiftExponent(-e); // f /= 10^e;
1047 XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root2(Number)", "f is normalized");
1048
1049 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
1050 auto const D = 105;
1051 auto const a0 = 18;
1052 auto const a1 = 144;
1053 auto const a2 = -60;
1054 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
1055
1056 // Newton–Raphson iteration of f^(1/2) with initial guess r
1057 // halt when r stops changing, checking for bouncing on the last iteration
1058 Number rm1{};
1059 Number rm2{};
1060 do
1061 {
1062 rm2 = rm1;
1063 rm1 = r;
1064 r = (r + f / r) / Number(2);
1065 } while (r != rm1 && r != rm2);
1066
1067 // return r * 10^(e/2) to reverse scaling
1068 auto const result = r.shiftExponent(e / 2);
1069 XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root2(Number)", "result is normalized");
1070
1071 return result;
1072}
1073
1074// Returns f^(n/d)
1075
1076Number
1077power(Number const& f, unsigned n, unsigned d)
1078{
1079 constexpr Number zero = Number{};
1080 auto const one = Number::one();
1081
1082 if (f == one)
1083 return f;
1084 auto g = std::gcd(n, d);
1085 if (g == 0)
1086 throw std::overflow_error("Number::power nan");
1087 if (d == 0)
1088 {
1089 if (f == -one)
1090 return one;
1091 if (abs(f) < one)
1092 return zero;
1093 // abs(f) > one
1094 throw std::overflow_error("Number::power infinity");
1095 }
1096 if (n == 0)
1097 return one;
1098 n /= g;
1099 d /= g;
1100 if ((n % 2) == 1 && (d % 2) == 0 && f < zero)
1101 throw std::overflow_error("Number::power nan");
1102 return root(power(f, n), d);
1103}
1104
1105} // namespace xrpl
T append(T... args)
T begin(T... args)
void set_positive() noexcept
Definition Number.cpp:129
unsigned pop() noexcept
Definition Number.cpp:162
void doRoundUp(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa, internalrep const &maxMantissa, std::string location)
Definition Number.cpp:237
void bringIntoRange(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
Definition Number.cpp:212
bool is_negative() const noexcept
Definition Number.cpp:141
void doRoundDown(bool &negative, T &mantissa, int &exponent, internalrep const &minMantissa)
Definition Number.cpp:264
int round() const noexcept
Definition Number.cpp:174
void doPush(unsigned d) noexcept
Definition Number.cpp:147
void set_negative() noexcept
Definition Number.cpp:135
std::uint8_t xbit_
Definition Number.cpp:70
std::uint8_t sbit_
Definition Number.cpp:71
void doRound(rep &drops, std::string location) const
Definition Number.cpp:285
void push(T d) noexcept
Definition Number.cpp:156
std::uint64_t digits_
Definition Number.cpp:69
Number is a floating point type that can represent a wide range of values.
Definition Number.h:207
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
Number & operator/=(Number const &x)
Definition Number.cpp:695
Number & operator+=(Number const &x)
Definition Number.cpp:505
Number truncate() const noexcept
Definition Number.cpp:819
std::int64_t rep
Definition Number.h:208
friend std::string to_string(Number const &amount)
Definition Number.cpp:837
static constexpr MantissaRange smallRange
Definition Number.h:444
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
MantissaRange::rep internalrep
Definition Number.h:209
static thread_local rounding_mode mode_
Definition Number.h:441
static constexpr int minExponent
Definition Number.h:217
Number shiftExponent(int exponentDelta) const
Definition Number.cpp:489
static void setMantissaScale(MantissaRange::mantissa_scale scale)
Changes which mantissa scale is used for normalization.
Definition Number.cpp:51
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
static thread_local std::reference_wrapper< MantissaRange const > range_
Definition Number.h:462
friend Number root2(Number f)
Definition Number.cpp:1030
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:45
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
Number & operator*=(Number const &x)
Definition Number.cpp:632
constexpr Number()=default
static constexpr Number oneLarge()
oneLarge is needed because the ranges are private
Definition Number.cpp:341
bool negative_
Definition Number.h:211
static int mantissaLog()
Definition Number.h:418
friend Number root(Number f, unsigned d)
Definition Number.cpp:958
T distance(T... args)
T end(T... args)
T exchange(T... args)
T find_if(T... args)
T gcd(T... args)
T is_same_v
T make_reverse_iterator(T... args)
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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.
Definition RangeSet.h:34
Number power(Number const &f, unsigned n)
Definition Number.cpp:935
constexpr Number oneSml
Definition Number.cpp:338
constexpr Number abs(Number x) noexcept
Definition Number.h:719
static unsigned divu10(uint128_t &u)
Definition Number.cpp:610
constexpr Number oneLrg
Definition Number.cpp:346
T reserve(T... args)
T length(T... args)
T to_string(T... args)