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