rippled
Loading...
Searching...
No Matches
Number.cpp
1#include <xrpl/basics/Number.h>
2#include <xrpl/beast/utility/instrumentation.h>
3
4#include <algorithm>
5#include <cstddef>
6#include <cstdint>
7#include <iterator>
8#include <limits>
9#include <numeric>
10#include <stdexcept>
11#include <string>
12#include <type_traits>
13#include <utility>
14
15#ifdef _MSC_VER
16#pragma message("Using boost::multiprecision::uint128_t")
17#include <boost/multiprecision/cpp_int.hpp>
18using uint128_t = boost::multiprecision::uint128_t;
19#else // !defined(_MSC_VER)
20using uint128_t = __uint128_t;
21#endif // !defined(_MSC_VER)
22
23namespace xrpl {
24
26
29{
30 return mode_;
31}
32
35{
36 return std::exchange(mode_, mode);
37}
38
39// Guard
40
41// The Guard class is used to temporarily add extra digits of
42// precision to an operation. This enables the final result
43// to be correctly rounded to the internal precision of Number.
44
46{
47 std::uint64_t digits_; // 16 decimal guard digits
48 std::uint8_t xbit_ : 1; // has a non-zero digit been shifted off the end
49 std::uint8_t sbit_ : 1; // the sign of the guard digits
50
51public:
52 explicit Guard() : digits_{0}, xbit_{0}, sbit_{0}
53 {
54 }
55
56 // set & test the sign bit
57 void
58 set_positive() noexcept;
59 void
60 set_negative() noexcept;
61 bool
62 is_negative() const noexcept;
63
64 // add a digit
65 void
66 push(unsigned d) noexcept;
67
68 // recover a digit
69 unsigned
70 pop() noexcept;
71
72 // Indicate round direction: 1 is up, -1 is down, 0 is even
73 // This enables the client to round towards nearest, and on
74 // tie, round towards even.
75 int
76 round() noexcept;
77
78 // Modify the result to the correctly rounded value
79 void
80 doRoundUp(rep& mantissa, int& exponent, std::string location);
81
82 // Modify the result to the correctly rounded value
83 void
85
86 // Modify the result to the correctly rounded value
87 void
88 doRound(rep& drops);
89};
90
91inline void
93{
94 sbit_ = 0;
95}
96
97inline void
99{
100 sbit_ = 1;
101}
102
103inline bool
105{
106 return sbit_ == 1;
107}
108
109inline void
110Number::Guard::push(unsigned d) noexcept
111{
112 xbit_ = xbit_ || (digits_ & 0x0000'0000'0000'000F) != 0;
113 digits_ >>= 4;
114 digits_ |= (d & 0x0000'0000'0000'000FULL) << 60;
115}
116
117inline unsigned
119{
120 unsigned d = (digits_ & 0xF000'0000'0000'0000) >> 60;
121 digits_ <<= 4;
122 return d;
123}
124
125// Returns:
126// -1 if Guard is less than half
127// 0 if Guard is exactly half
128// 1 if Guard is greater than half
129int
131{
132 auto mode = Number::getround();
133
134 if (mode == towards_zero)
135 return -1;
136
137 if (mode == downward)
138 {
139 if (sbit_)
140 {
141 if (digits_ > 0 || xbit_)
142 return 1;
143 }
144 return -1;
145 }
146
147 if (mode == upward)
148 {
149 if (sbit_)
150 return -1;
151 if (digits_ > 0 || xbit_)
152 return 1;
153 return -1;
154 }
155
156 // assume round to nearest if mode is not one of the predefined values
157 if (digits_ > 0x5000'0000'0000'0000)
158 return 1;
159 if (digits_ < 0x5000'0000'0000'0000)
160 return -1;
161 if (xbit_)
162 return 1;
163 return 0;
164}
165
166void
168{
169 auto r = round();
170 if (r == 1 || (r == 0 && (mantissa & 1) == 1))
171 {
172 ++mantissa;
173 if (mantissa > maxMantissa)
174 {
175 mantissa /= 10;
176 ++exponent;
177 }
178 }
179 if (exponent < minExponent)
180 {
181 mantissa = 0;
183 }
184 if (exponent > maxExponent)
185 throw std::overflow_error(location);
186}
187
188void
190{
191 auto r = round();
192 if (r == 1 || (r == 0 && (mantissa & 1) == 1))
193 {
194 --mantissa;
195 if (mantissa < minMantissa)
196 {
197 mantissa *= 10;
198 --exponent;
199 }
200 }
201 if (exponent < minExponent)
202 {
203 mantissa = 0;
205 }
206}
207
208// Modify the result to the correctly rounded value
209void
211{
212 auto r = round();
213 if (r == 1 || (r == 0 && (drops & 1) == 1))
214 {
215 ++drops;
216 }
217 if (is_negative())
218 drops = -drops;
219}
220
221// Number
222
223constexpr Number one{1000000000000000, -15, Number::unchecked{}};
224
225void
227{
228 if (mantissa_ == 0)
229 {
230 *this = Number{};
231 return;
232 }
233 bool const negative = (mantissa_ < 0);
234 auto m = static_cast<std::make_unsigned_t<rep>>(mantissa_);
235 if (negative)
236 m = -m;
237 while ((m < minMantissa) && (exponent_ > minExponent))
238 {
239 m *= 10;
240 --exponent_;
241 }
242 Guard g;
243 if (negative)
244 g.set_negative();
245 while (m > maxMantissa)
246 {
247 if (exponent_ >= maxExponent)
248 throw std::overflow_error("Number::normalize 1");
249 g.push(m % 10);
250 m /= 10;
251 ++exponent_;
252 }
253 mantissa_ = m;
255 {
256 *this = Number{};
257 return;
258 }
259
260 g.doRoundUp(mantissa_, exponent_, "Number::normalize 2");
261
262 if (negative)
264}
265
266Number&
268{
269 if (y == Number{})
270 return *this;
271 if (*this == Number{})
272 {
273 *this = y;
274 return *this;
275 }
276 if (*this == -y)
277 {
278 *this = Number{};
279 return *this;
280 }
281 XRPL_ASSERT(
282 isnormal() && y.isnormal(),
283 "xrpl::Number::operator+=(Number) : is normal");
284 auto xm = mantissa();
285 auto xe = exponent();
286 int xn = 1;
287 if (xm < 0)
288 {
289 xm = -xm;
290 xn = -1;
291 }
292 auto ym = y.mantissa();
293 auto ye = y.exponent();
294 int yn = 1;
295 if (ym < 0)
296 {
297 ym = -ym;
298 yn = -1;
299 }
300 Guard g;
301 if (xe < ye)
302 {
303 if (xn == -1)
304 g.set_negative();
305 do
306 {
307 g.push(xm % 10);
308 xm /= 10;
309 ++xe;
310 } while (xe < ye);
311 }
312 else if (xe > ye)
313 {
314 if (yn == -1)
315 g.set_negative();
316 do
317 {
318 g.push(ym % 10);
319 ym /= 10;
320 ++ye;
321 } while (xe > ye);
322 }
323 if (xn == yn)
324 {
325 xm += ym;
326 if (xm > maxMantissa)
327 {
328 g.push(xm % 10);
329 xm /= 10;
330 ++xe;
331 }
332 g.doRoundUp(xm, xe, "Number::addition overflow");
333 }
334 else
335 {
336 if (xm > ym)
337 {
338 xm = xm - ym;
339 }
340 else
341 {
342 xm = ym - xm;
343 xe = ye;
344 xn = yn;
345 }
346 while (xm < minMantissa)
347 {
348 xm *= 10;
349 xm -= g.pop();
350 --xe;
351 }
352 g.doRoundDown(xm, xe);
353 }
354 mantissa_ = xm * xn;
355 exponent_ = xe;
356 return *this;
357}
358
359// Optimization equivalent to:
360// auto r = static_cast<unsigned>(u % 10);
361// u /= 10;
362// return r;
363// Derived from Hacker's Delight Second Edition Chapter 10
364// by Henry S. Warren, Jr.
365static inline unsigned
366divu10(uint128_t& u)
367{
368 // q = u * 0.75
369 auto q = (u >> 1) + (u >> 2);
370 // iterate towards q = u * 0.8
371 q += q >> 4;
372 q += q >> 8;
373 q += q >> 16;
374 q += q >> 32;
375 q += q >> 64;
376 // q /= 8 approximately == u / 10
377 q >>= 3;
378 // r = u - q * 10 approximately == u % 10
379 auto r = static_cast<unsigned>(u - ((q << 3) + (q << 1)));
380 // correction c is 1 if r >= 10 else 0
381 auto c = (r + 6) >> 4;
382 u = q + c;
383 r -= c * 10;
384 return r;
385}
386
387Number&
389{
390 if (*this == Number{})
391 return *this;
392 if (y == Number{})
393 {
394 *this = y;
395 return *this;
396 }
397 XRPL_ASSERT(
398 isnormal() && y.isnormal(),
399 "xrpl::Number::operator*=(Number) : is normal");
400 auto xm = mantissa();
401 auto xe = exponent();
402 int xn = 1;
403 if (xm < 0)
404 {
405 xm = -xm;
406 xn = -1;
407 }
408 auto ym = y.mantissa();
409 auto ye = y.exponent();
410 int yn = 1;
411 if (ym < 0)
412 {
413 ym = -ym;
414 yn = -1;
415 }
416 auto zm = uint128_t(xm) * uint128_t(ym);
417 auto ze = xe + ye;
418 auto zn = xn * yn;
419 Guard g;
420 if (zn == -1)
421 g.set_negative();
422 while (zm > maxMantissa)
423 {
424 // The following is optimization for:
425 // g.push(static_cast<unsigned>(zm % 10));
426 // zm /= 10;
427 g.push(divu10(zm));
428 ++ze;
429 }
430 xm = static_cast<rep>(zm);
431 xe = ze;
432 g.doRoundUp(
433 xm,
434 xe,
435 "Number::multiplication overflow : exponent is " + std::to_string(xe));
436 mantissa_ = xm * zn;
437 exponent_ = xe;
438 XRPL_ASSERT(
439 isnormal() || *this == Number{},
440 "xrpl::Number::operator*=(Number) : result is normal");
441 return *this;
442}
443
444Number&
446{
447 if (y == Number{})
448 throw std::overflow_error("Number: divide by 0");
449 if (*this == Number{})
450 return *this;
451 int np = 1;
452 auto nm = mantissa();
453 auto ne = exponent();
454 if (nm < 0)
455 {
456 nm = -nm;
457 np = -1;
458 }
459 int dp = 1;
460 auto dm = y.mantissa();
461 auto de = y.exponent();
462 if (dm < 0)
463 {
464 dm = -dm;
465 dp = -1;
466 }
467 // Shift by 10^17 gives greatest precision while not overflowing uint128_t
468 // or the cast back to int64_t
469 uint128_t const f = 100'000'000'000'000'000;
470 mantissa_ = static_cast<std::int64_t>(uint128_t(nm) * f / uint128_t(dm));
471 exponent_ = ne - de - 17;
472 mantissa_ *= np * dp;
473 normalize();
474 return *this;
475}
476
477Number::operator rep() const
478{
479 rep drops = mantissa_;
480 int offset = exponent_;
481 Guard g;
482 if (drops != 0)
483 {
484 if (drops < 0)
485 {
486 g.set_negative();
487 drops = -drops;
488 }
489 for (; offset < 0; ++offset)
490 {
491 g.push(drops % 10);
492 drops /= 10;
493 }
494 for (; offset > 0; --offset)
495 {
496 if (drops > std::numeric_limits<decltype(drops)>::max() / 10)
497 throw std::overflow_error("Number::operator rep() overflow");
498 drops *= 10;
499 }
500 g.doRound(drops);
501 }
502 return drops;
503}
504
505Number
506Number::truncate() const noexcept
507{
508 if (exponent_ >= 0 || mantissa_ == 0)
509 return *this;
510
511 Number ret = *this;
512 while (ret.exponent_ < 0 && ret.mantissa_ != 0)
513 {
514 ret.exponent_ += 1;
515 ret.mantissa_ /= rep(10);
516 }
517 // We are guaranteed that normalize() will never throw an exception
518 // because exponent is either negative or zero at this point.
519 ret.normalize();
520 return ret;
521}
522
524to_string(Number const& amount)
525{
526 // keep full internal accuracy, but make more human friendly if possible
527 if (amount == Number{})
528 return "0";
529
530 auto const exponent = amount.exponent();
531 auto mantissa = amount.mantissa();
532
533 // Use scientific notation for exponents that are too small or too large
534 if (((exponent != 0) && ((exponent < -25) || (exponent > -5))))
535 {
537 ret.append(1, 'e');
539 return ret;
540 }
541
542 bool negative = false;
543
544 if (mantissa < 0)
545 {
547 negative = true;
548 }
549
550 XRPL_ASSERT(
551 exponent + 43 > 0, "xrpl::to_string(Number) : minimum exponent");
552
553 ptrdiff_t const pad_prefix = 27;
554 ptrdiff_t const pad_suffix = 23;
555
556 std::string const raw_value(std::to_string(mantissa));
557 std::string val;
558
559 val.reserve(raw_value.length() + pad_prefix + pad_suffix);
560 val.append(pad_prefix, '0');
561 val.append(raw_value);
562 val.append(pad_suffix, '0');
563
564 ptrdiff_t const offset(exponent + 43);
565
566 auto pre_from(val.begin());
567 auto const pre_to(val.begin() + offset);
568
569 auto const post_from(val.begin() + offset);
570 auto post_to(val.end());
571
572 // Crop leading zeroes. Take advantage of the fact that there's always a
573 // fixed amount of leading zeroes and skip them.
574 if (std::distance(pre_from, pre_to) > pad_prefix)
575 pre_from += pad_prefix;
576
577 XRPL_ASSERT(
578 post_to >= post_from, "xrpl::to_string(Number) : first distance check");
579
580 pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
581
582 // Crop trailing zeroes. Take advantage of the fact that there's always a
583 // fixed amount of trailing zeroes and skip them.
584 if (std::distance(post_from, post_to) > pad_suffix)
585 post_to -= pad_suffix;
586
587 XRPL_ASSERT(
588 post_to >= post_from,
589 "xrpl::to_string(Number) : second distance check");
590
591 post_to = std::find_if(
594 [](char c) { return c != '0'; })
595 .base();
596
597 std::string ret;
598
599 if (negative)
600 ret.append(1, '-');
601
602 // Assemble the output:
603 if (pre_from == pre_to)
604 ret.append(1, '0');
605 else
606 ret.append(pre_from, pre_to);
607
608 if (post_to != post_from)
609 {
610 ret.append(1, '.');
611 ret.append(post_from, post_to);
612 }
613
614 return ret;
615}
616
617// Returns f^n
618// Uses a log_2(n) number of multiplications
619
620Number
621power(Number const& f, unsigned n)
622{
623 if (n == 0)
624 return one;
625 if (n == 1)
626 return f;
627 auto r = power(f, n / 2);
628 r *= r;
629 if (n % 2 != 0)
630 r *= f;
631 return r;
632}
633
634// Returns f^(1/d)
635// Uses Newton–Raphson iterations until the result stops changing
636// to find the non-negative root of the polynomial g(x) = x^d - f
637
638// This function, and power(Number f, unsigned n, unsigned d)
639// treat corner cases such as 0 roots as advised by Annex F of
640// the C standard, which itself is consistent with the IEEE
641// floating point standards.
642
643Number
644root(Number f, unsigned d)
645{
646 if (f == one || d == 1)
647 return f;
648 if (d == 0)
649 {
650 if (f == -one)
651 return one;
652 if (abs(f) < one)
653 return Number{};
654 throw std::overflow_error("Number::root infinity");
655 }
656 if (f < Number{} && d % 2 == 0)
657 throw std::overflow_error("Number::root nan");
658 if (f == Number{})
659 return f;
660
661 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
662 auto e = f.exponent() + 16;
663 auto const di = static_cast<int>(d);
664 auto ex = [e = e, di = di]() // Euclidean remainder of e/d
665 {
666 int k = (e >= 0 ? e : e - (di - 1)) / di;
667 int k2 = e - k * di;
668 if (k2 == 0)
669 return 0;
670 return di - k2;
671 }();
672 e += ex;
673 f = Number{f.mantissa(), f.exponent() - e}; // f /= 10^e;
674 bool neg = false;
675 if (f < Number{})
676 {
677 neg = true;
678 f = -f;
679 }
680
681 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
682 auto const D = ((6 * di + 11) * di + 6) * di + 1;
683 auto const a0 = 3 * di * ((2 * di - 3) * di + 1);
684 auto const a1 = 24 * di * (2 * di - 1);
685 auto const a2 = -30 * (di - 1) * di;
686 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
687 if (neg)
688 {
689 f = -f;
690 r = -r;
691 }
692
693 // Newton–Raphson iteration of f^(1/d) with initial guess r
694 // halt when r stops changing, checking for bouncing on the last iteration
695 Number rm1{};
696 Number rm2{};
697 do
698 {
699 rm2 = rm1;
700 rm1 = r;
701 r = (Number(d - 1) * r + f / power(r, d - 1)) / Number(d);
702 } while (r != rm1 && r != rm2);
703
704 // return r * 10^(e/d) to reverse scaling
705 return Number{r.mantissa(), r.exponent() + e / di};
706}
707
708Number
710{
711 if (f == one)
712 return f;
713 if (f < Number{})
714 throw std::overflow_error("Number::root nan");
715 if (f == Number{})
716 return f;
717
718 // Scale f into the range (0, 1) such that f's exponent is a multiple of d
719 auto e = f.exponent() + 16;
720 if (e % 2 != 0)
721 ++e;
722 f = Number{f.mantissa(), f.exponent() - e}; // f /= 10^e;
723
724 // Quadratic least squares curve fit of f^(1/d) in the range [0, 1]
725 auto const D = 105;
726 auto const a0 = 18;
727 auto const a1 = 144;
728 auto const a2 = -60;
729 Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D};
730
731 // Newton–Raphson iteration of f^(1/2) with initial guess r
732 // halt when r stops changing, checking for bouncing on the last iteration
733 Number rm1{};
734 Number rm2{};
735 do
736 {
737 rm2 = rm1;
738 rm1 = r;
739 r = (r + f / r) / Number(2);
740 } while (r != rm1 && r != rm2);
741
742 // return r * 10^(e/2) to reverse scaling
743 return Number{r.mantissa(), r.exponent() + e / 2};
744}
745
746// Returns f^(n/d)
747
748Number
749power(Number const& f, unsigned n, unsigned d)
750{
751 if (f == one)
752 return f;
753 auto g = std::gcd(n, d);
754 if (g == 0)
755 throw std::overflow_error("Number::power nan");
756 if (d == 0)
757 {
758 if (f == -one)
759 return one;
760 if (abs(f) < one)
761 return Number{};
762 // abs(f) > one
763 throw std::overflow_error("Number::power infinity");
764 }
765 if (n == 0)
766 return one;
767 n /= g;
768 d /= g;
769 if ((n % 2) == 1 && (d % 2) == 0 && f < Number{})
770 throw std::overflow_error("Number::power nan");
771 return root(power(f, n), d);
772}
773
774} // namespace xrpl
T append(T... args)
T begin(T... args)
int round() noexcept
Definition Number.cpp:130
void set_positive() noexcept
Definition Number.cpp:92
unsigned pop() noexcept
Definition Number.cpp:118
void push(unsigned d) noexcept
Definition Number.cpp:110
void doRoundDown(rep &mantissa, int &exponent)
Definition Number.cpp:189
bool is_negative() const noexcept
Definition Number.cpp:104
void set_negative() noexcept
Definition Number.cpp:98
std::uint8_t xbit_
Definition Number.cpp:48
void doRound(rep &drops)
Definition Number.cpp:210
void doRoundUp(rep &mantissa, int &exponent, std::string location)
Definition Number.cpp:167
std::uint8_t sbit_
Definition Number.cpp:49
std::uint64_t digits_
Definition Number.cpp:47
static rounding_mode getround()
Definition Number.cpp:28
constexpr rep mantissa() const noexcept
Definition Number.h:209
static rounding_mode setround(rounding_mode mode)
Definition Number.cpp:34
Number & operator/=(Number const &x)
Definition Number.cpp:445
constexpr bool isnormal() const noexcept
Definition Number.h:321
Number & operator+=(Number const &x)
Definition Number.cpp:267
Number truncate() const noexcept
Definition Number.cpp:506
std::int64_t rep
Definition Number.h:27
static thread_local rounding_mode mode_
Definition Number.h:181
static constexpr Number max() noexcept
Definition Number.h:309
static constexpr int minExponent
Definition Number.h:39
static constexpr std::int64_t maxMantissa
Definition Number.h:35
constexpr int exponent() const noexcept
Definition Number.h:215
static constexpr int maxExponent
Definition Number.h:40
rep mantissa_
Definition Number.h:28
int exponent_
Definition Number.h:29
static constexpr std::int64_t minMantissa
Definition Number.h:33
void normalize()
Definition Number.cpp:226
Number & operator*=(Number const &x)
Definition Number.cpp:388
constexpr Number()=default
T distance(T... args)
T end(T... args)
T exchange(T... args)
T find_if(T... args)
T gcd(T... args)
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
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
Number root(Number f, unsigned d)
Definition Number.cpp:644
Number power(Number const &f, unsigned n)
Definition Number.cpp:621
constexpr Number one
Definition Number.cpp:223
Number root2(Number f)
Definition Number.cpp:709
constexpr Number abs(Number x) noexcept
Definition Number.h:329
static unsigned divu10(uint128_t &u)
Definition Number.cpp:366
T reserve(T... args)
T length(T... args)
T to_string(T... args)