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::
777operator rep() const
778{
779 rep drops = mantissa();
780 int offset = exponent();
781 Guard g;
782 if (drops != 0)
783 {
784 if (negative_)
785 {
786 g.set_negative();
787 drops = -drops;
788 }
789 for (; offset < 0; ++offset)
790 {
791 g.push(drops % 10);
792 drops /= 10;
793 }
794 for (; offset > 0; --offset)
795 {
796 if (drops > maxRep / 10)
797 throw std::overflow_error("Number::operator rep() overflow");
798 drops *= 10;
799 }
800 g.doRound(drops, "Number::operator rep() rounding overflow");
801 }
802 return drops;
803}
804
805Number
806Number::truncate() const noexcept
807{
808 if (exponent_ >= 0 || mantissa_ == 0)
809 return *this;
810
811 Number ret = *this;
812 while (ret.exponent_ < 0 && ret.mantissa_ != 0)
813 {
814 ret.exponent_ += 1;
815 ret.mantissa_ /= rep(10);
816 }
817 // We are guaranteed that normalize() will never throw an exception
818 // because exponent is either negative or zero at this point.
819 ret.normalize();
820 return ret;
821}
822
824to_string(Number const& amount)
825{
826 // keep full internal accuracy, but make more human friendly if possible
827 constexpr Number zero = Number{};
828 if (amount == zero)
829 return "0";
830
831 auto exponent = amount.exponent_;
832 auto mantissa = amount.mantissa_;
833 bool const negative = amount.negative_;
834
835 // Use scientific notation for exponents that are too small or too large
836 auto const rangeLog = Number::mantissaLog();
837 if (((exponent != 0) && ((exponent < -(rangeLog + 10)) || (exponent > -(rangeLog - 10)))))
838 {
839 while (mantissa != 0 && mantissa % 10 == 0 && exponent < Number::maxExponent)
840 {
841 mantissa /= 10;
842 ++exponent;
843 }
844 std::string ret = negative ? "-" : "";
846 ret.append(1, 'e');
848 return ret;
849 }
850
851 XRPL_ASSERT(exponent + 43 > 0, "xrpl::to_string(Number) : minimum exponent");
852
853 ptrdiff_t const pad_prefix = rangeLog + 12;
854 ptrdiff_t const pad_suffix = rangeLog + 8;
855
856 std::string const raw_value(std::to_string(mantissa));
857 std::string val;
858
859 val.reserve(raw_value.length() + pad_prefix + pad_suffix);
860 val.append(pad_prefix, '0');
861 val.append(raw_value);
862 val.append(pad_suffix, '0');
863
864 ptrdiff_t const offset(exponent + pad_prefix + rangeLog + 1);
865
866 auto pre_from(val.begin());
867 auto const pre_to(val.begin() + offset);
868
869 auto const post_from(val.begin() + offset);
870 auto post_to(val.end());
871
872 // Crop leading zeroes. Take advantage of the fact that there's always a
873 // fixed amount of leading zeroes and skip them.
874 if (std::distance(pre_from, pre_to) > pad_prefix)
875 pre_from += pad_prefix;
876
877 XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : first distance check");
878
879 pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
880
881 // Crop trailing zeroes. Take advantage of the fact that there's always a
882 // fixed amount of trailing zeroes and skip them.
883 if (std::distance(post_from, post_to) > pad_suffix)
884 post_to -= pad_suffix;
885
886 XRPL_ASSERT(post_to >= post_from, "xrpl::to_string(Number) : second distance check");
887
888 post_to = std::find_if(std::make_reverse_iterator(post_to), std::make_reverse_iterator(post_from), [](char c) {
889 return c != '0';
890 }).base();
891
892 std::string ret;
893
894 if (negative)
895 ret.append(1, '-');
896
897 // Assemble the output:
898 if (pre_from == pre_to)
899 ret.append(1, '0');
900 else
901 ret.append(pre_from, pre_to);
902
903 if (post_to != post_from)
904 {
905 ret.append(1, '.');
906 ret.append(post_from, post_to);
907 }
908
909 return ret;
910}
911
912// Returns f^n
913// Uses a log_2(n) number of multiplications
914
915Number
916power(Number const& f, unsigned n)
917{
918 if (n == 0)
919 return Number::one();
920 if (n == 1)
921 return f;
922 auto r = power(f, n / 2);
923 r *= r;
924 if (n % 2 != 0)
925 r *= f;
926 return r;
927}
928
929// Returns f^(1/d)
930// Uses Newton–Raphson iterations until the result stops changing
931// to find the non-negative root of the polynomial g(x) = x^d - f
932
933// This function, and power(Number f, unsigned n, unsigned d)
934// treat corner cases such as 0 roots as advised by Annex F of
935// the C standard, which itself is consistent with the IEEE
936// floating point standards.
937
938Number
939root(Number f, unsigned d)
940{
941 constexpr Number zero = Number{};
942 auto const one = Number::one();
943
944 if (f == one || d == 1)
945 return f;
946 if (d == 0)
947 {
948 if (f == -one)
949 return one;
950 if (abs(f) < one)
951 return zero;
952 throw std::overflow_error("Number::root infinity");
953 }
954 if (f < zero && d % 2 == 0)
955 throw std::overflow_error("Number::root nan");
956 if (f == zero)
957 return f;
958
959 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
960 auto e = f.exponent_ + Number::mantissaLog() + 1;
961 auto const di = static_cast<int>(d);
962 auto ex = [e = e, di = di]() // Euclidean remainder of e/d
963 {
964 int k = (e >= 0 ? e : e - (di - 1)) / di;
965 int k2 = e - k * di;
966 if (k2 == 0)
967 return 0;
968 return di - k2;
969 }();
970 e += ex;
971 f = f.shiftExponent(-e); // f /= 10^e;
972
973 XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root(Number, unsigned)", "f is normalized");
974 bool neg = false;
975 if (f < zero)
976 {
977 neg = true;
978 f = -f;
979 }
980
981 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
982 auto const D = ((6 * di + 11) * di + 6) * di + 1;
983 auto const a0 = 3 * di * ((2 * di - 3) * di + 1);
984 auto const a1 = 24 * di * (2 * di - 1);
985 auto const a2 = -30 * (di - 1) * di;
986 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
987 if (neg)
988 {
989 f = -f;
990 r = -r;
991 }
992
993 // Newton–Raphson iteration of f^(1/d) with initial guess r
994 // halt when r stops changing, checking for bouncing on the last iteration
995 Number rm1{};
996 Number rm2{};
997 do
998 {
999 rm2 = rm1;
1000 rm1 = r;
1001 r = (Number(d - 1) * r + f / power(r, d - 1)) / Number(d);
1002 } while (r != rm1 && r != rm2);
1003
1004 // return r * 10^(e/d) to reverse scaling
1005 auto const result = r.shiftExponent(e / di);
1006 XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root(Number, unsigned)", "result is normalized");
1007 return result;
1008}
1009
1010Number
1012{
1013 constexpr Number zero = Number{};
1014 auto const one = Number::one();
1015
1016 if (f == one)
1017 return f;
1018 if (f < zero)
1019 throw std::overflow_error("Number::root nan");
1020 if (f == zero)
1021 return f;
1022
1023 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
1024 auto e = f.exponent_ + Number::mantissaLog() + 1;
1025 if (e % 2 != 0)
1026 ++e;
1027 f = f.shiftExponent(-e); // f /= 10^e;
1028 XRPL_ASSERT_PARTS(f.isnormal(), "xrpl::root2(Number)", "f is normalized");
1029
1030 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
1031 auto const D = 105;
1032 auto const a0 = 18;
1033 auto const a1 = 144;
1034 auto const a2 = -60;
1035 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
1036
1037 // Newton–Raphson iteration of f^(1/2) with initial guess r
1038 // halt when r stops changing, checking for bouncing on the last iteration
1039 Number rm1{};
1040 Number rm2{};
1041 do
1042 {
1043 rm2 = rm1;
1044 rm1 = r;
1045 r = (r + f / r) / Number(2);
1046 } while (r != rm1 && r != rm2);
1047
1048 // return r * 10^(e/2) to reverse scaling
1049 auto const result = r.shiftExponent(e / 2);
1050 XRPL_ASSERT_PARTS(result.isnormal(), "xrpl::root2(Number)", "result is normalized");
1051
1052 return result;
1053}
1054
1055// Returns f^(n/d)
1056
1057Number
1058power(Number const& f, unsigned n, unsigned d)
1059{
1060 constexpr Number zero = Number{};
1061 auto const one = Number::one();
1062
1063 if (f == one)
1064 return f;
1065 auto g = std::gcd(n, d);
1066 if (g == 0)
1067 throw std::overflow_error("Number::power nan");
1068 if (d == 0)
1069 {
1070 if (f == -one)
1071 return one;
1072 if (abs(f) < one)
1073 return zero;
1074 // abs(f) > one
1075 throw std::overflow_error("Number::power infinity");
1076 }
1077 if (n == 0)
1078 return one;
1079 n /= g;
1080 d /= g;
1081 if ((n % 2) == 1 && (d % 2) == 0 && f < zero)
1082 throw std::overflow_error("Number::power nan");
1083 return root(power(f, n), d);
1084}
1085
1086} // 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:207
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
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:806
std::int64_t rep
Definition Number.h:208
friend std::string to_string(Number const &amount)
Definition Number.cpp:824
static constexpr MantissaRange smallRange
Definition Number.h:439
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
MantissaRange::rep internalrep
Definition Number.h:209
static thread_local rounding_mode mode_
Definition Number.h:436
static constexpr int minExponent
Definition Number.h:217
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: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
static thread_local std::reference_wrapper< MantissaRange const > range_
Definition Number.h:457
friend Number root2(Number f)
Definition Number.cpp:1011
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:446
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:211
static int mantissaLog()
Definition Number.h:413
friend Number root(Number f, unsigned d)
Definition Number.cpp:939
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:916
constexpr Number oneSml
Definition Number.cpp:332
constexpr Number abs(Number x) noexcept
Definition Number.h:706
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)