26 #include "gnc-int128.hpp" 40 static const unsigned int upper_num_bits = 61;
41 static const unsigned int sublegs = GncInt128::numlegs * 2;
42 static const unsigned int sublegbits = GncInt128::legbits / 2;
43 static const uint64_t sublegmask = (UINT64_C(1) << sublegbits) - 1;
44 static const uint64_t flagmask = UINT64_C(0xe000000000000000);
45 static const uint64_t nummask = UINT64_C(0x1fffffffffffffff);
49 static inline uint64_t set_flags(uint64_t leg, uint8_t flags)
51 auto flag_part =
static_cast<uint64_t
>(flags) << upper_num_bits;
52 return flag_part + (leg & nummask);
54 static inline uint8_t get_flags(uint64_t leg)
56 return (leg & flagmask) >> upper_num_bits;
58 static inline uint64_t get_num(uint64_t leg)
67 m_hi {
static_cast<uint64_t
>(upper < 0 ? -upper : upper)},
68 m_lo {
static_cast<uint64_t
>(lower < 0 ? -lower : lower)}
70 if ((upper < 0 && lower > 0) || (upper > 0 && lower < 0))
71 m_lo = (m_hi << 63) - m_lo;
78 std::ostringstream ss;
79 ss <<
"Constructing GncInt128 with int64_t " << upper
80 <<
" which is too big.";
81 throw std::overflow_error(ss.str());
83 flags ^= (upper < 0 ? neg : upper == 0 && lower < 0 ? neg : pos);
84 m_hi = set_flags(m_hi, flags);
88 m_hi {
static_cast<uint64_t
>(upper < 0 ? -upper : upper)}, m_lo {lower}
92 std::ostringstream ss;
93 ss <<
"Constructing GncInt128 with int64_t " << upper
94 <<
" which is too big when lower is unsigned.";
95 throw std::overflow_error(ss.str());
97 flags ^= (upper < 0 ? neg : pos);
98 m_hi = set_flags(m_hi, flags);
102 m_hi {upper}, m_lo {lower}
108 if (m_hi == UINT64_MAX)
112 std::ostringstream ss;
113 ss <<
"Constructing GncInt128 with uint64_t " << upper
114 <<
" which is too big.";
115 throw std::overflow_error(ss.str());
118 m_hi = set_flags(m_hi, flags);
124 m_lo = m_hi = UINT64_C(0);
128 GncInt128::operator int64_t()
const 130 auto flags = get_flags(m_hi);
131 if ((flags & neg) && isBig())
132 throw std::underflow_error (
"Negative value too large to represent as int64_t");
133 if ((flags & (overflow | NaN)) || isBig())
134 throw std::overflow_error (
"Value too large to represent as int64_t");
135 int64_t retval =
static_cast<int64_t
>(m_lo);
136 return flags & neg ? -retval : retval;
139 GncInt128::operator uint64_t()
const 141 auto flags = get_flags(m_hi);
142 if ((flags & neg) && !isZero())
143 throw std::underflow_error (
"Can't represent negative value as uint64_t");
144 if ((flags & (overflow | NaN)) || (m_hi || m_lo > UINT64_MAX))
145 throw std::overflow_error (
"Value to large to represent as uint64_t");
153 auto flags = get_flags(m_hi);
154 if (flags & (overflow | NaN))
156 if (b.isOverflow () || b.isNan ())
158 auto hi = get_num(m_hi);
159 auto bhi = get_num(b.m_hi);
160 if (isZero() && b.isZero())
return 0;
163 if (!b.isNeg())
return -1;
164 if (hi > bhi)
return -1;
165 if (hi < bhi)
return 1;
166 if (m_lo > b.m_lo)
return -1;
167 if (m_lo < b.m_lo)
return 1;
170 if (b.isNeg())
return 1;
171 if (hi < bhi)
return -1;
172 if (hi > bhi)
return 1;
173 if (m_lo < b.m_lo)
return -1;
174 if (m_lo > b.m_lo)
return 1;
189 if (b.isOverflow() || b.isNan())
191 if (isOverflow() || isNan())
194 GncInt128 a (isNeg() ? -(*
this) : *
this);
195 if (b.isNeg()) b = -b;
198 const uint64_t one {1};
199 while (!((a & one) || (b & one)))
208 while (t && ((t & one) ^ one)) t >>= 1;
223 auto common =
gcd(b);
224 return *
this / common * b.abs();
231 if (isZero() || (m_lo == 1 && m_hi == 0) || isNan() || isOverflow())
236 while (b && !retval.isOverflow())
249 return (get_flags(m_hi) & neg);
255 return (get_num(m_hi) || m_lo > INT64_MAX);
261 return (get_flags(m_hi) & overflow);
267 return (get_flags(m_hi) & NaN);
273 return !(get_flags(m_hi) & (overflow | NaN));
279 return ((get_flags(m_hi) & (overflow | NaN)) == 0 &&
280 get_num(m_hi) == 0 && m_lo == 0);
284 GncInt128::abs() const noexcept
295 auto hi = get_num(m_hi);
296 unsigned int bits {
static_cast<unsigned int>(hi == 0 ? 0 : 64)};
297 uint64_t temp {(hi == 0 ? m_lo : hi)};
298 for (;temp > 0; temp >>= 1)
305 GncInt128::operator-() const noexcept
308 auto flags = get_flags(retval.m_hi);
313 retval.m_hi = set_flags(retval.m_hi, flags);
317 GncInt128::operator bool() const noexcept
323 GncInt128::operator++ () noexcept
325 return operator+=(UINT64_C(1));
329 GncInt128::operator++ (
int) noexcept
331 return operator+=(UINT64_C(1));
335 GncInt128::operator-- () noexcept
337 return operator-=(UINT64_C(1));
341 GncInt128::operator-- (
int) noexcept
343 return operator-=(UINT64_C(1));
347 GncInt128::operator+= (
const GncInt128& b) noexcept
349 auto flags = get_flags(m_hi);
354 m_hi = set_flags(m_hi, flags);
355 if (isOverflow() || isNan())
357 if ((isNeg () && !b.isNeg ()) || (!isNeg () && b.isNeg ()))
358 return this->operator-= (-b);
359 uint64_t result = m_lo + b.m_lo;
360 uint64_t carry =
static_cast<int64_t
>(result < m_lo);
362 auto hi = get_num(m_hi);
363 auto bhi = get_num(b.m_hi);
364 result = hi + bhi + carry;
365 if (result < hi || result & flagmask)
367 m_hi = set_flags(result, flags);
372 GncInt128::operator<<= (
unsigned int i) noexcept
374 auto flags = get_flags(m_hi);
380 m_hi = set_flags(0, flags);
384 auto hi = get_num(m_hi);
387 uint64_t carry {(m_lo & (((UINT64_C(1) << i) - 1) << (legbits - i))) >> (legbits - i)};
391 m_hi = set_flags(hi, flags);
394 hi = m_lo << (i - legbits);
395 m_hi = set_flags(hi, flags);
401 GncInt128::operator>>= (
unsigned int i) noexcept
403 auto flags = get_flags(m_hi);
407 m_hi = set_flags(0, flags);
411 auto hi = get_num(m_hi);
414 uint64_t carry {(hi & ((UINT64_C(1) << i) - 1))};
417 m_lo += (carry << (legbits - i));
418 m_hi = set_flags(hi, flags);
421 m_lo = hi >> (i - legbits);
422 m_hi = set_flags(0, flags);
427 GncInt128::operator-= (
const GncInt128& b) noexcept
429 auto flags = get_flags(m_hi);
434 m_hi = set_flags(m_hi, flags);
436 if (isOverflow() || isNan())
439 if ((!isNeg() && b.isNeg()) || (isNeg() && !b.isNeg()))
440 return this->operator+= (-b);
441 bool operand_bigger {abs().cmp (b.abs()) < 0};
442 auto hi = get_num(m_hi);
443 auto far_hi = get_num(b.m_hi);
452 m_lo = UINT64_MAX - m_lo + b.m_lo + 1;
456 m_lo = b.m_lo - m_lo;
458 m_hi = set_flags(hi, flags);
463 m_lo = UINT64_MAX - b.m_lo + m_lo + 1;
470 m_hi = set_flags(hi, flags);
475 GncInt128::operator*= (
const GncInt128& b) noexcept
478 auto flags = get_flags(m_hi);
480 flags ^= (get_flags(b.m_hi) & neg);
481 if (isZero() || b.isZero())
484 m_hi = set_flags(0, flags);
491 m_hi = set_flags(m_hi, flags);
492 if (isOverflow() || isNan())
496 auto hi = get_num(m_hi);
497 auto bhi = get_num(b.m_hi);
501 m_hi = set_flags(hi, flags);
505 unsigned int abits {bits()}, bbits {b.bits()};
511 if (abits + bbits - 1 > maxbits)
514 m_hi = set_flags(m_hi, flags);
519 if (abits + bbits <= legbits)
522 m_hi = set_flags(m_hi, flags);
538 uint64_t av[sublegs] {(m_lo & sublegmask), (m_lo >> sublegbits),
539 (hi & sublegmask), (hi >> sublegbits)};
540 uint64_t bv[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
541 (bhi & sublegmask), (bhi >> sublegbits)};
542 uint64_t rv[sublegs] {};
543 uint64_t carry {}, scratch {};
545 rv[0] = av[0] * bv[0];
547 rv[1] = av[1] * bv [0];
548 scratch = rv[1] + av[0] * bv[1];
549 carry = rv[1] > scratch ? 1 : 0;
552 rv[2] = av[2] * bv[0] + carry;
553 scratch = rv[2] + av[1] * bv[1];
554 carry = rv[2] > scratch ? 1 : 0;
555 rv[2] = scratch + av[0] * bv[2];
556 carry += scratch > rv[2] ? 1 : 0;
558 rv[3] = av[3] * bv[0] + carry;
559 scratch = rv[3] + av[2] * bv[1];
560 carry = rv[3] > scratch ? 1 : 0;
561 rv[3] = scratch + av[1] * bv[2];
562 carry += scratch > rv[3] ? 1 : 0;
563 scratch = rv[3] + av[0] * bv[3];
564 carry += rv[3] > scratch ? 1 : 0;
570 m_hi = set_flags(m_hi, flags);
574 m_lo = rv[0] + (rv[1] << sublegbits);
575 carry = rv[1] >> sublegbits;
576 carry += (rv[1] << sublegbits) > m_lo || rv[0] > m_lo ? 1 : 0;
577 hi = rv[2] + (rv[3] << sublegbits) + carry;
578 if ((rv[3] << sublegbits) > hi || rv[2] > hi || (rv[3] >> sublegbits) ||
582 m_hi = set_flags(hi, flags);
585 m_hi = set_flags(hi, flags);
596 div_multi_leg (uint64_t* u,
size_t m, uint64_t* v,
size_t n,
600 uint64_t qv[sublegs] {};
601 uint64_t d {(UINT64_C(1) << sublegbits)/(v[n - 1] + UINT64_C(1))};
602 uint64_t carry {UINT64_C(0)};
603 bool negative {q.isNeg()};
604 bool rnegative {r.isNeg()};
605 for (
size_t i = 0; i < m; ++i)
607 u[i] = u[i] * d + carry;
608 if (u[i] > sublegmask)
610 carry = u[i] >> sublegbits;
615 assert (u[i] <= sublegmask);
622 for (
size_t i = 0; i < n; ++i)
624 v[i] = v[i] * d + carry;
625 if (v[i] > sublegmask)
627 carry = v[i] >> sublegbits;
632 assert (v[i] < sublegmask);
634 assert (carry == UINT64_C(0));
635 for (
int j = m - n; j >= 0; j--)
638 qhat = ((u[j + n] << sublegbits) + u[j + n - 1]) / v[n - 1];
639 rhat = ((u[j + n] << sublegbits) + u[j + n - 1]) % v[n - 1];
641 while (qhat > sublegmask ||
642 (rhat <= sublegmask &&
643 ((qhat * v[n - 2]) > ((rhat << sublegbits) + u[j + n - 2]))))
650 for (
size_t k = 0; k < n; ++k)
652 auto subend = qhat * v[k] + carry;
653 carry = subend >> sublegbits;
654 subend &= sublegmask;
655 if (u[j + k] >= subend)
657 u[j + k] = u[j + k] - subend;
658 borrow = UINT64_C(0);
662 if (u[j + k + 1] > 0)
666 u[j + k] = u[j + k] + sublegmask + 1 - subend;
667 u[j + k] &= sublegmask;
676 for (
size_t k = 0; k < n; ++k)
678 u[j + k] += v[k] + carry;
679 if (u[j + k] > sublegmask)
681 carry = u[j + k] >> sublegbits;
682 u[j + k] &= sublegmask;
688 q =
GncInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
689 r =
GncInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
691 if (negative) q = -q;
692 if (rnegative) r = -r;
696 div_single_leg (uint64_t* u,
size_t m, uint64_t v,
699 uint64_t qv[sublegs] {};
700 bool negative {q.isNeg()};
701 bool rnegative {r.isNeg()};
702 for (
int i = m - 1; i >= 0; --i)
707 u[i - 1] += ((u[i] % v) << sublegbits);
714 q =
GncInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
715 r =
GncInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
716 if (negative) q = -q;
717 if (rnegative) r = -r;
729 auto qflags = get_flags(q.m_hi);
730 auto rflags = get_flags(r.m_hi);
731 if (isOverflow() || b.isOverflow())
735 q.m_hi = set_flags(q.m_hi, qflags);
736 r.m_hi = set_flags(r.m_hi, rflags);
740 if (isNan() || b.isNan())
744 q.m_hi = set_flags(q.m_hi, qflags);
745 r.m_hi = set_flags(r.m_hi, rflags);
759 q.m_hi = set_flags(q.m_hi, qflags);
760 r.m_hi = set_flags(r.m_hi, rflags);
773 q.m_hi = set_flags(q.m_hi, qflags);
774 r.m_hi = set_flags(r.m_hi, rflags);
781 auto hi = get_num(m_hi);
782 auto bhi = get_num(b.m_hi);
784 if (hi == 0 && bhi == 0)
786 assert (b.m_lo != 0);
787 q.m_lo = m_lo / b.m_lo;
788 r.m_lo = m_lo % b.m_lo;
792 uint64_t u[sublegs + 2] {(m_lo & sublegmask), (m_lo >> sublegbits),
793 (hi & sublegmask), (hi >> sublegbits), 0, 0};
794 uint64_t v[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
795 (bhi & sublegmask), (bhi >> sublegbits)};
796 auto m = u[3] ? 4 : u[2] ? 3 : u[1] ? 2 : u[0] ? 1 : 0;
797 auto n = v[3] ? 4 : v[2] ? 3 : v[1] ? 2 : v[0] ? 1 : 0;
798 if (m == 0 || n == 0)
801 return div_single_leg (u, m, v[0], q, r);
803 return div_multi_leg (u, m, v, n, q, r);
807 GncInt128::operator/= (
const GncInt128& b) noexcept
811 std::swap (*
this, q);
816 GncInt128::operator%= (
const GncInt128& b) noexcept
820 std::swap (*
this, r);
822 m_hi = set_flags(m_hi, (get_flags(m_hi) | NaN));
827 GncInt128::operator&= (
const GncInt128& b) noexcept
829 auto flags = get_flags(m_hi);
834 m_hi = set_flags(m_hi, flags);
835 if (isOverflow() || isNan())
837 auto hi = get_num(m_hi);
838 hi &= get_num(b.m_hi);
840 m_hi = set_flags(hi, flags);
845 GncInt128::operator|= (
const GncInt128& b) noexcept
847 auto flags = get_flags(m_hi);
848 auto hi = get_num(m_hi);
849 hi ^= get_num(b.m_hi);
850 m_hi = set_flags(hi, flags);
856 GncInt128::operator^= (
const GncInt128& b) noexcept
858 auto flags = get_flags(m_hi);
863 m_hi = set_flags(m_hi, flags);
864 if (isOverflow() || isNan())
866 auto hi = get_num(m_hi);
867 hi ^= get_num(b.m_hi);
868 m_hi = set_flags(hi, flags);
873 static const uint8_t dec_array_size {5};
879 decimal_from_binary (uint64_t d[dec_array_size], uint64_t hi, uint64_t lo)
887 const uint8_t coeff_array_size = dec_array_size - 1;
888 const uint32_t coeff_3 [coeff_array_size] {79228, 16251426, 43375935, 43950336};
889 const uint32_t coeff_2 [coeff_array_size] {0, 1844, 67440737, 9551616};
890 const uint32_t coeff_1 [coeff_array_size] {0, 0, 42, 94967296};
891 const uint32_t bin_mask {0xffffffff};
892 const uint32_t dec_div {UINT32_C(100000000)};
893 const uint8_t last {dec_array_size - 1};
895 d[0] = lo & bin_mask;
896 d[1] = (lo >> 32) & bin_mask;
897 d[2] = hi & bin_mask;
898 d[3] = (hi >> 32) & bin_mask;
900 d[0] += coeff_3[3] * d[3] + coeff_2[3] * d[2] + coeff_1[3] * d[1];
901 uint64_t q {d[0] / dec_div};
904 for (
int i {1}; i < coeff_array_size; ++i)
906 int j = coeff_array_size - i - 1;
907 d[i] = q + coeff_3[j] * d[3] + coeff_2[j] * d[2] + coeff_1[j] * d[1];
915 static const uint8_t char_buf_size {41};
922 snprintf (buf, size,
"%s",
"Overflow");
927 snprintf (buf, size,
"%s",
"NaN");
932 snprintf (buf, size,
"%d", 0);
935 uint64_t d[dec_array_size] {};
936 decimal_from_binary(d, get_num(m_hi), m_lo);
940 if (isNeg()) *(next++) = neg;
941 bool trailing {
false};
942 for (
unsigned int i {dec_array_size}; i; --i)
943 if (d[i - 1] || trailing)
945 uint32_t new_size = size - (next - buf);
947 next += snprintf (next, new_size,
"%8.8" PRIu64, d[i - 1]);
949 next += snprintf (next, new_size,
"%" PRIu64, d[i - 1]);
958 operator<< (std::ostream& stream,
const GncInt128& a) noexcept
960 char buf[char_buf_size] {};
961 stream << a.asCharBufR (buf, char_buf_size - 1);
968 return a.cmp(b) == 0;
974 return a.cmp(b) != 0;
992 return a.cmp(b) <= 0;
998 return a.cmp(b) >= 0;
1057 operator<< (
GncInt128 a,
unsigned int b) noexcept
1064 operator>> (
GncInt128 a,
unsigned int b) noexcept
bool isBig() const noexcept
GncInt128 gcd(GncInt128 b) const noexcept
Computes the Greatest Common Divisor between the object and parameter.
GncInt128 pow(unsigned int n) const noexcept
Computes the object raised to the parameter's power.
GncInt128 gcd(int64_t a, int64_t b)
Compute the greatest common denominator of two integers.
bool valid() const noexcept
GncInt128()
Default constructor.
bool isNan() const noexcept
char * asCharBufR(char *buf, uint32_t size) const noexcept
Fills a supplied buffer with a representation of the number in base 10.
bool isZero() const noexcept
GncInt128 lcm(const GncInt128 &b) const noexcept
Computes the Least Common Multiple between the object and parameter.
bool isNeg() const noexcept
void div(const GncInt128 &d, GncInt128 &q, GncInt128 &r) const noexcept
Computes a quotient and a remainder, passed as reference parameters.
int cmp(const GncInt128 &b) const noexcept
Compare function.
bool isOverflow() const noexcept
GncInt128 & zero() noexcept
Clear the object.
unsigned int bits() const noexcept