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