bi
An arbitrary precision integer library for C++.
Loading...
Searching...
No Matches
h_.hpp
1/*
2Copyright 2024 Owain Davies
3SPDX-License-Identifier: Apache-2.0
4*/
5
6#ifndef BI_SRC_H__HPP_
7#define BI_SRC_H__HPP_
8
9#include <algorithm>
10#include <array>
11#include <cassert>
12#include <cmath>
13#include <limits>
14#include <random>
15#include <string>
16#include <utility>
17
18#include "bi.hpp"
19#include "bi.inl"
20#include "bi_exceptions.hpp"
21#include "constants.hpp"
22#include "uints.hpp"
23
25
26namespace bi {
27
29struct h_ {
30 // increment/decrement
31 static void increment_abs(bi_t& x);
32 static void decrement_abs(bi_t& x);
33
34 // additive
35 static void add_abs(bi_t& result, const bi_t& a, const bi_t& b);
36 static void add(bi_t& result, const bi_t& a, const bi_t& b);
37 static void sub_abs_gt(bi_t& result, const bi_t& a, const bi_t& b);
38 static void sub_abs(bi_t& result, const bi_t& a, const bi_t& b);
39 static void sub(bi_t& result, const bi_t& a, const bi_t& b);
40
41 // multiplicative
42 static void imul1add1(bi_t& x, digit v, digit k);
43 static void mul_algo_square(bi_t& result, const bi_t& a, const size_t m);
44 static void mul_algo_knuth(bi_t& result, const bi_t& a, const bi_t& b,
45 const size_t m, const size_t n);
46 static void mul_karatsuba(bi_t& result, const bi_t& a, const bi_t& b);
47 static void mul_standard(bi_t& result, const bi_t& a, const bi_t& b);
48 static void mul(bi_t& result, const bi_t& a, const bi_t& b);
49 static digit div_algo_digit(bi_t& q, const bi_t& u, digit v) noexcept;
50 static void div_algo_single(bi_t& q, bi_t& r, const bi_t& n,
51 const bi_t& d) noexcept;
52 static void div_algo_binary(bi_t& q, bi_t& r, const bi_t& n, const bi_t& d);
53 static void div_algo_knuth(bi_t& q, bi_t& r, const bi_t& n, const bi_t& d);
54 static void divide(bi_t& q, bi_t& r, const bi_t& n, const bi_t& d);
55
56 // bits
57 static void left_shift(bi_t& result, const bi_t& a, bi_bitcount_t shift);
58 static void right_shift(bi_t& result, const bi_t& a, bi_bitcount_t shift);
59 enum class BitwiseOperation { AND, OR, XOR };
60 template <BitwiseOperation Op>
61 static void bitwise_operation_impl(bi_t& res, const bi_t& a, const bi_t& b);
62 template <BitwiseOperation Op>
63 static bi_t bitwise_operation(const bi_t& a, const bi_t& b);
64 template <BitwiseOperation Op>
65 static bi_t& ibitwise_operation(bi_t&, const bi_t& other);
66
67 // comparisons
68 static int cmp_abs(const bi_t&, const bi_t&) noexcept;
69 static int cmp(const bi_t&, const bi_t&) noexcept;
70 template <std::integral T>
71 static int cmp(const bi_t& a, T b) noexcept;
72
73 // to_string()
74 static uint8_t idiv10(bi_t& x) noexcept;
75 static size_t base_length(const bi_t& x, int base);
76
77 // initializing
78 template <std::integral T>
79 static void init_one_digit(bi_t& x, T value);
80 template <std::integral T>
81 static void init_atleast_one_digit(bi_t& x, T value);
82 // NOLINTNEXTLINE
83 static void init_string(bi_t& x, const std::string& str, int base = 10);
84
85 // misc.
86 static dvector to_twos_complement(const dvector& vec);
87 static void to_twos_complement_in_place(dvector& vec) noexcept;
88 static void bisect(const bi_t&, bi_t&, bi_t&, size_t m);
89
90 // double
91 static void assign_from_double(bi_t&, double);
92 static int cmp_abs(const bi_t&, double) noexcept;
93 static int cmp(const bi_t&, double) noexcept;
94
95 // exponentiation
96 template <std::unsigned_integral T>
97 static bi_t expo_left_to_right(const bi_t& base, T exp);
98
99 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
100 static thread_local std::mt19937 rng_;
101 static bi_t random_(bi_bitcount_t z);
102};
103
104thread_local std::mt19937 h_::rng_{std::random_device{}()}; // NOLINT
105
106void h_::increment_abs(bi_t& x) {
107 if (x.size() == 0 || x[x.size() - 1] == std::numeric_limits<digit>::max()) {
108 x.reserve_(x.size() + 1);
109 }
110
111 if (x.size() == 0) {
112 x.resize_(1);
113 x[0] = 1;
114 return;
115 }
116
117 size_t i = 0;
118 bool carry = true;
119
120 while (carry && i < x.size()) {
121 if (x[i] == std::numeric_limits<digit>::max()) {
122 x[i] = 0;
123 } else {
124 ++x[i];
125 carry = false;
126 }
127 ++i;
128 }
129
130 if (carry) {
131 x.vec_.push_back(1);
132 }
133}
134
135void h_::decrement_abs(bi_t& x) {
136 if (x.size() == 0) {
137 x.resize_(1);
138 x[0] = 1;
139 x.negative_ = true;
140 return;
141 }
142
143 size_t i = 0;
144 bool borrow = true;
145
146 while (borrow && i < x.size()) {
147 if (x[i] == 0) {
148 // Borrow from the next more significant digit
149 x[i] = std::numeric_limits<digit>::max();
150 } else {
151 --x[i];
152 borrow = false;
153 }
154 ++i;
155 }
156
157 x.trim();
158}
159
222
224void h_::add_abs(bi_t& r, const bi_t& x, const bi_t& y) {
225 // Algorithm assumes x.size() >= y.size()
226 const bi_t& large = x.size() >= y.size() ? x : y;
227 const bi_t& small = x.size() >= y.size() ? y : x;
228
229 r.reserve_(large.size() + 1);
230
231 digit temp{};
232 bool carry = 0;
233 size_t i = 0;
234 for (; i < small.size(); ++i) {
235 uints::uaddc(temp, large[i], small[i], carry);
236 r[i] = temp;
237 }
238
239 while (i < large.size()) {
240 temp = large[i] + carry;
241 carry = temp < static_cast<uint8_t>(carry); // MSVC warning C4804
242 r[i++] = temp;
243 }
244
245 r[i] = carry;
246 r.resize_(large.size() + 1);
247 r.trim();
248 r.negative_ = false;
249}
250
252void h_::add(bi_t& r, const bi_t& x, const bi_t& y) {
253 if (x.negative()) {
254 if (y.negative()) {
255 // x < 0, y < 0 ==> x = -|x|, y = -|y|. ==> x + y = -(|x| + |y|)
256 add_abs(r, x, y);
257 r.negative_ = true;
258 } else {
259 // x < 0, y >= 0 ==> x = -|x|, y = |y| ==> x + y = |y| - |x|
260 sub_abs(r, y, x);
261 }
262 } else {
263 if (y.negative()) {
264 // x >= 0, y < 0 ==> x = |x|, y = -|y| ==> x + y = |x| - |y|
265 sub_abs(r, x, y);
266 } else {
267 // x >= 0, y >= 0 ==> x = |x|, y = |y| ==> x + y = |x| + |y|
268 add_abs(r, x, y);
269 }
270 }
271}
272
274void h_::sub_abs_gt(bi_t& r, const bi_t& x, const bi_t& y) {
275 assert(x.size() >= y.size());
276
277 r.reserve_(x.size());
278
279 digit temp{};
280 bool borrow = 0;
281 size_t i = 0;
282 for (; i < y.size(); ++i) {
283 uints::usubb(temp, x[i], y[i], borrow);
284 r[i] = temp;
285 }
286 while (i < x.size()) {
287 temp = x[i] - borrow;
288 borrow = temp > x[i];
289 r[i++] = temp;
290 }
291
292 r.resize_(x.size());
293 r.trim();
294 r.negative_ = false;
295}
296
298void h_::sub_abs(bi_t& r, const bi_t& x, const bi_t& y) {
299 if (x.size() == y.size()) {
300 const auto [it_x, it_y] = std::mismatch(x.rbegin(), x.rend(), y.rbegin());
301
302 if (it_x == x.rend()) {
303 // x, y have the same digits (or both are zero)
304 r.resize_(0);
305 r.negative_ = false;
306 return;
307 }
308
309 if (*it_y > *it_x) {
310 sub_abs_gt(r, y, x);
311 r.negative_ = true;
312 } else {
313 sub_abs_gt(r, x, y);
314 }
315 } else if (x.size() > y.size()) {
316 sub_abs_gt(r, x, y);
317 } else {
318 sub_abs_gt(r, y, x);
319 r.negative_ = true;
320 }
321}
322
324void h_::sub(bi_t& r, const bi_t& x, const bi_t& y) {
325 if (x.negative()) {
326 if (y.negative()) {
327 // x < 0, y < 0 ==> x = -|x|, y = -|y| ==> x - y = |y| - |x|
328 sub_abs(r, y, x);
329 } else {
330 // x < 0, y >= 0 ==> x = -|x|, y = |y| ==> x - y = -(|x| + |y|)
331 add_abs(r, x, y);
332 r.negative_ = true;
333 }
334 } else {
335 if (y.negative()) {
336 // x >= 0, y < 0 ==> x = |x|, y = -|y| ==> x - y = |x| + |y|
337 add_abs(r, x, y);
338 } else {
339 // x >= 0, y >= 0 ==> x = |x|, y = |y| ==> x - y = |x| - |y|
340 sub_abs(r, x, y);
341 }
342 }
343}
344
346
392inline void h_::imul1add1(bi_t& x, digit v, digit k = 0) {
393 for (auto& d : x.vec_) {
394 const ddigit t = static_cast<ddigit>(d) * v + k;
395 k = t >> bi_dwidth; // floor(t / 2^{bi_dwidth})
396 d = static_cast<digit>(t); // t mod 2^{bi_dwidth}
397 }
398
399 if (k) {
400 x.vec_.push_back(k);
401 }
402}
403
416void h_::mul_algo_square(bi_t& w, const bi_t& a, const size_t t) {
417 std::fill(w.begin(), w.end(), 0);
418
419 for (size_t i = 0; i < t; ++i) {
420 ddigit uv = w[2 * i] + static_cast<ddigit>(a[i]) * a[i];
421 w[2 * i] = static_cast<digit>(uv); // set w[2 * i] <- v
422 ddigit c = uv >> bi_dwidth; // set c <- u
423
424 for (size_t j = i + 1; j < t; ++j) {
425 // (hi, lo) represents a quadruple digit
426 ddigit hi{0};
427 ddigit lo = static_cast<ddigit>(a[j]) * a[i];
428
429 // Multiply product by two
430 hi = lo >> (std::numeric_limits<ddigit>::digits - 1);
431 lo <<= 1;
432
433 // Now add w[i + j] and c to (hi, lo)
434 hi += uints::uadd_overflow(lo, lo, static_cast<ddigit>(w[i + j]));
435 hi += uints::uadd_overflow(lo, lo, c);
436
437 w[i + j] = static_cast<digit>(lo); // set w[i + j] <- v
438 c = (hi << bi_dwidth) | (lo >> bi_dwidth); // set c <- u
439 }
440
441 for (size_t k = i + t; c > 0; ++k) {
442 c += w[k];
443 w[k] = static_cast<digit>(c);
444 c >>= bi_dwidth;
445 }
446 }
447}
448
449void h_::mul_algo_knuth(bi_t& w, const bi_t& a, const bi_t& b, const size_t m,
450 const size_t n) {
451 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
452 std::fill(w.begin(), w.begin() + m, 0);
453
454 for (size_t j = 0; j < n; ++j) {
455 digit k = 0;
456 for (size_t i = 0; i < m; ++i) {
457 const ddigit t =
458 static_cast<ddigit>(a[i]) * b[j] + static_cast<ddigit>(w[i + j]) + k;
459 k = t >> bi_dwidth; // floor(t / 2^{bi_dwidth})
460 w[i + j] = static_cast<digit>(t); // t mod 2^{bi_dwidth}
461 }
462 w[j + m] = k;
463 }
464}
465
497void h_::bisect(const bi::bi_t& x, bi::bi_t& lower, bi::bi_t& upper, size_t n) {
498 const size_t bisect_point = std::min(n, x.size());
499
500 lower.vec_ = dvector(x.vec_.begin(), x.vec_.begin() + bisect_point);
501 upper.vec_ = dvector(x.vec_.begin() + bisect_point, x.vec_.end());
502
503 lower.trim();
504 upper.trim();
505}
506
507void h_::mul_karatsuba(bi_t& w, const bi_t& u, const bi_t& v) {
508 const size_t n = std::min(u.size(), v.size()) >> 1;
509
510 bi_t u0, u1, v0, v1;
511 bisect(u, u0, u1, n);
512 bisect(v, v0, v1, n);
513
514 bi_t a, b, c;
515 mul(a, u1, v1); // a = u1 * v1
516 mul(b, u0, v0); // b = u0 * v0
517
518 u1 += u0;
519 v1 += v0;
520 mul(c, u1, v1);
521 c -= a + b; // c = (u1 + u0)(v1 + v0) - (u0v0 + u1v1)
522
523 a <<= (2 * n * bi_dbits);
524 c <<= (n * bi_dbits);
525 w = a + c + b; // w = (bi_base ** 2n) * a + (bi_base ** n) * c + b
526}
527
535void h_::mul_standard(bi_t& result, const bi_t& a, const bi_t& b) {
536 if (a.size() == 0 || b.size() == 0) {
537 result.resize_(0);
538 result.negative_ = false;
539 return;
540 }
541
542 const size_t m = a.size();
543 const size_t n = b.size();
544
545 const bool overlap = &result == &a || &result == &b;
546
547 bi_t temp;
548 bi_t& target = overlap ? temp : result;
549
550 target.resize_(m + n);
551
552 if (&a != &b) {
553 h_::mul_algo_knuth(target, a, b, m, n);
554 } else {
555 h_::mul_algo_square(target, a, m);
556 }
557
558 target.trim();
559
560 if (overlap) {
561 result.swap(target);
562 }
563}
564
565void h_::mul(bi_t& w, const bi_t& u, const bi_t& v) {
566 if (u.size() < karatsuba_threshold || v.size() < karatsuba_threshold) {
567 h_::mul_standard(w, u, v);
568 } else {
569 h_::mul_karatsuba(w, u, v);
570 }
571
572 w.negative_ = u.negative() != v.negative();
573}
574
605digit h_::div_algo_digit(bi_t& q, const bi_t& u, digit v) noexcept {
606 ddigit rem{0};
607
608 for (size_t j = u.size() - 1; j < std::numeric_limits<size_t>::max(); --j) {
609 const ddigit temp = (rem << bi_dwidth) | u[j]; // rem * bi_base + u[j]
610 q[j] = temp / v;
611 rem = temp % v;
612 }
613
614 q.trim();
615 return static_cast<digit>(rem);
616}
617
618void h_::div_algo_single(bi_t& q, bi_t& r, const bi_t& u,
619 const bi_t& v) noexcept {
620 ddigit rem{0};
621
622 for (size_t j = u.size() - 1; j < std::numeric_limits<size_t>::max(); --j) {
623 const ddigit temp = (rem << bi_dwidth) | u[j]; // rem * bi_base + u[j]
624 q[j] = temp / v[0];
625 rem = temp % v[0];
626 }
627
628 r[0] = static_cast<digit>(rem);
629
630 q.trim();
631 r.trim();
632}
633
661void h_::div_algo_binary(bi_t& q, bi_t& r, const bi_t& u, const bi_t& v) {
662 // (2)
663 q = 0;
664 r = 0;
665
666 // (3)
667 for (unsigned long i = u.bit_length() - 1; i < ULONG_MAX; --i) {
668 // (3)(I)
669 r <<= 1;
670
671 // (3)(II)
672 if (u.test_bit(i)) {
673 r.set_bit(0);
674 }
675
676 // (3)(III)
677 if (h_::cmp_abs(r, v) >= 0) {
678 // (3)(III)(a)
679 h_::sub_abs(r, r, v);
680 // (3)(III)(b)
681 q.set_bit(i);
682 }
683 }
684}
685
748void h_::div_algo_knuth(bi_t& q, bi_t& r, const bi_t& u, const bi_t& v) {
749#if defined(BI_DIGIT_64_BIT)
750 using sddigit = __int128;
751#else
752 using sddigit = int64_t;
753#endif
754
755 const size_t m = u.size();
756 const size_t n = v.size();
757
758 /* (1) Normalize */
759 // Find e such that b > 2^{e} * v_{n-1} >= b / 2
760 constexpr digit b_half = bi_base >> 1;
761 const digit v_msd = v[n - 1];
762 int e = 0;
763 while ((v_msd << e) < b_half) {
764 ++e;
765 }
766 const unsigned compl_e = bi_dwidth - e;
767
768 bi_t u_norm, v_norm;
769 u_norm.resize_(m + 1);
770 v_norm.resize_(n);
771
772 // u_norm set to u * 2^{e}. Cast to ddigit as e may be 0 which would be UB
773 u_norm[0] = u[0] << e;
774 for (size_t i = 1; i < m; ++i) {
775 u_norm[i] = (u[i] << e) | (static_cast<ddigit>(u[i - 1]) >> compl_e);
776 }
777 u_norm[m] = static_cast<ddigit>(u[m - 1]) >> compl_e;
778
779 // v_norm set to v * 2^{e}
780 v_norm[0] = v[0] << e;
781 for (size_t i = 1; i < n; ++i) {
782 v_norm[i] = (v[i] << e) | (static_cast<ddigit>(v[i - 1]) >> compl_e);
783 }
784
785 const digit vp = v_norm[n - 1], vpp = v_norm[n - 2];
786 /* (2) Initialize j. Also (7) Loop on j */
787 for (size_t j = m - n; j < std::numeric_limits<size_t>::max(); --j) {
788 /* (3) Calculate q_hat */
789 const ddigit tmp = u_norm[j + n] * bi_base + u_norm[j + n - 1];
790 ddigit q_hat = tmp / vp;
791 ddigit r_hat = tmp % vp;
792
793 while (q_hat == bi_base ||
794 q_hat * vpp > bi_base * r_hat + u_norm[j + n - 2]) {
795 --q_hat;
796 r_hat += vp;
797 if (r_hat >= bi_base)
798 break;
799 }
800
801 /* (4) Multiply and subtract */
802 sddigit b{};
803 for (size_t i = 0; i < n; ++i) {
804 const ddigit product = q_hat * v_norm[i];
805 const sddigit stmp =
806 static_cast<sddigit>(u_norm[j + i]) - static_cast<digit>(product) - b;
807 u_norm[j + i] = static_cast<digit>(stmp);
808 b = static_cast<sddigit>(product >> bi_dbits) - (stmp >> bi_dbits);
809 }
810 const bool neg{u_norm[j + n] < b};
811 u_norm[j + n] = static_cast<digit>(u_norm[j + n] - b);
812
813 /* (5) Test remainder */
814 q[j] = q_hat;
815
816 if (neg) {
817 /* (6) Add back */
818 // Decrease q_{j} by 1
819 --q[j];
820
821 // Add (0v_{n-1}...v_{0})_{b} to (u_{j+n}...u_{j})_{b}
822 digit c = 0;
823 for (size_t i = 0; i < n; ++i) {
824 const ddigit tmp = (static_cast<ddigit>(u_norm[j + i]) + v_norm[i]) + c;
825 u_norm[j + i] = tmp;
826 c = tmp >> bi_dwidth;
827 }
828 // A carry will occur to the left of u_{j+n} and it should be ignored
829 u_norm[j + n] += c;
830 assert(u_norm[j + n] == 0);
831 }
832 }
833
834 /* (8) Unnormalize */
835 // (u_{n-1}...u_{0})_{b} / 2^e
836 const size_t last_idx = n - 1;
837 r[last_idx] = u_norm[last_idx] >> e;
838 for (size_t i = last_idx; i-- > 0;) {
839 r[i] = (static_cast<ddigit>(u_norm[i + 1]) << compl_e) | (u_norm[i] >> e);
840 }
841
842 q.trim();
843 r.trim();
844}
845
859void h_::divide(bi_t& Q, bi_t& R, const bi_t& N, const bi_t& D) {
860 if (D.size() == 0) {
861 throw division_by_zero("Division by zero attempt.");
862 }
863
864 const size_t size_N = N.size();
865 const size_t size_D = D.size();
866
867 // |N| < |D| case
868 if ((size_N == size_D && N[size_N - 1] < D[size_D - 1]) || size_N < size_D) {
869 Q = 0; // |N| < |D| ==> |N| / |D| < 1 ==> Q computes to 0
870 R = N; // Computation (a/b)*b + a%b should equal a ==> a%b is a
871 return;
872 }
873
874 // TRUE: size_N >= size_D > 0
875
876 // Ensure enough space in Q and R
877 const size_t size_Q = size_N - size_D + 1;
878 Q.resize_(size_Q);
879 R.resize_(size_D);
880
881 // Unsigned integer division algorithms
882 if (size_D == 1) {
883 // Knuth (Vol. 2, 4.3.1, p. 272) recommends using the algorithm used in
884 // div_algo_single() when size_D is 1.
885 div_algo_single(Q, R, N, D);
886 } else {
887 div_algo_knuth(Q, R, N, D);
888 }
889
890 Q.negative_ = D.negative() ^ N.negative();
891 R.negative_ = R.size() > 0 && N.negative();
892}
893
900
907void h_::left_shift(bi_t& result, const bi_t& x, bi_bitcount_t n_bits) {
908 if (x.size() == 0) {
909 result.resize_unsafe_(0);
910 result.negative_ = false;
911 return;
912 }
913
914 if (n_bits == 0) {
915 result = x; // Copy assignment avoids copying if &result == &x
916 return;
917 }
918
919 const size_t size_x = x.size();
920 const bi_bitcount_t digit_shift = n_bits / bi_dwidth;
921 const unsigned bit_shift = n_bits % bi_dwidth;
922
923 const size_t size_result = size_x + digit_shift + (bit_shift ? 1 : 0);
924 if (size_result < size_x) {
925 throw overflow_error("Result size exceeds SIZE_MAX.");
926 }
927
928 // Create a temporary vector if `result` and `x` overlap
929 dvector temp_vec;
930 dvector& target_vec = (&result == &x) ? temp_vec : result.vec_;
931
932 target_vec.resize(size_result);
933
934 size_t i = 0;
935 // Zero-fill vacated digits
936 for (; i < digit_shift; ++i) {
937 target_vec[i] = 0;
938 }
939
940 const auto compl_bit_shift = bi_dwidth - bit_shift;
941
942 digit carry = 0;
943 for (size_t j = 0; j < size_x; ++j, ++i) {
944 const digit current = x[j];
945 target_vec[i] = (current << bit_shift) | carry;
946 carry = bit_shift ? (current >> compl_bit_shift) : 0;
947 }
948
949 if (bit_shift) {
950 target_vec[i] = carry;
951 }
952
953 if (&result == &x) {
954 result.vec_ = std::move(temp_vec);
955 }
956
957 result.trim();
958 result.negative_ = x.negative();
959}
960
969void h_::right_shift(bi_t& result, const bi_t& x, bi_bitcount_t n_bits) {
970 // TODO: maybe set `result = x` for special cases x.size() == 0 || n_bits == 0
971 const size_t size_x = x.size();
972
973 const bi_bitcount_t digit_shift = n_bits / bi_dwidth;
974 const unsigned bit_shift = n_bits % bi_dwidth;
975
976 if (size_x <= digit_shift) {
977 if (x.negative()) {
978 // Set result to -1
979 result.resize_(1);
980 result[0] = 1;
981 result.negative_ = true;
982 } else {
983 // Set result to 0
984 result.resize_unsafe_(0);
985 result.negative_ = false;
986 }
987 return;
988 }
989
990 result.resize_(size_x - digit_shift);
991
992 if (bit_shift == 0) {
993 for (size_t i = 0; i < result.size(); ++i) {
994 result[i] = x[i + digit_shift];
995 }
996 } else {
997 const unsigned compl_bit_shift = bi_dwidth - bit_shift;
998
999 for (size_t i = 0, k = digit_shift + 1; i < result.size(); ++i, ++k) {
1000 result[i] = x[k - 1] >> bit_shift;
1001 if (k < size_x) {
1002 result[i] |= x[k] << compl_bit_shift;
1003 }
1004 }
1005 }
1006
1007 result.trim();
1008 result.negative_ = x.negative();
1009
1010 // At this point, the result is trunc(x / 2^{n_bits}) for all x
1011
1012 // Adjust for floor division for negative numbers
1013 if (x.negative()) {
1014 bool subtract_one = false;
1015 if (bit_shift > 0) {
1016 const digit mask = (static_cast<digit>(1) << bit_shift) - 1;
1017 if ((x[digit_shift] & mask) != 0) {
1018 subtract_one = true;
1019 }
1020 }
1021 if (!subtract_one && digit_shift > 0) {
1022 for (size_t i = 0; i < digit_shift; ++i) {
1023 if (x[i] != 0) {
1024 subtract_one = true;
1025 break;
1026 }
1027 }
1028 }
1029 if (subtract_one) {
1030 --result;
1031 }
1032 }
1033}
1034
1036
1038template <h_::BitwiseOperation Op>
1039void h_::bitwise_operation_impl(bi_t& result, const bi_t& x, const bi_t& y) {
1040 size_t max_size = std::max(x.size(), y.size());
1041
1042 const dvector& lhs_digits = x.negative_ ? to_twos_complement(x.vec_) : x.vec_;
1043 const dvector& rhs_digits = y.negative_ ? to_twos_complement(y.vec_) : y.vec_;
1044
1045 bool result_negative; // NOLINT(cppcoreguidelines-init-variables)
1046 if constexpr (Op == BitwiseOperation::AND) {
1047 result_negative = x.negative_ && y.negative_;
1048 } else if constexpr (Op == BitwiseOperation::OR) {
1049 result_negative = x.negative_ || y.negative_;
1050 } else if constexpr (Op == BitwiseOperation::XOR) {
1051 result_negative = x.negative_ != y.negative_;
1052 ++max_size;
1053 }
1054
1055 result.resize_(max_size);
1056
1057 for (size_t i = 0; i < result.size(); ++i) {
1058 const digit lhs_digit =
1059 i < lhs_digits.size() ? lhs_digits[i] : (x.negative_ ? bi_dmax : 0);
1060 const digit rhs_digit =
1061 i < rhs_digits.size() ? rhs_digits[i] : (y.negative_ ? bi_dmax : 0);
1062
1063 if constexpr (Op == BitwiseOperation::AND) {
1064 result[i] = lhs_digit & rhs_digit;
1065 } else if constexpr (Op == BitwiseOperation::OR) {
1066 result[i] = lhs_digit | rhs_digit;
1067 } else if constexpr (Op == BitwiseOperation::XOR) {
1068 result[i] = lhs_digit ^ rhs_digit;
1069 }
1070 }
1071
1072 result.negative_ = result_negative;
1073
1074 if (result.negative_) {
1075 to_twos_complement_in_place(result.vec_);
1076 }
1077
1078 result.trim();
1079}
1080
1082template <h_::BitwiseOperation Op>
1083bi_t h_::bitwise_operation(const bi_t& a, const bi_t& b) {
1084 bi_t result;
1085 bitwise_operation_impl<Op>(result, a, b);
1086 return result;
1087}
1088
1090template <h_::BitwiseOperation Op>
1091bi_t& h_::ibitwise_operation(bi_t& x, const bi_t& other) {
1092 bitwise_operation_impl<Op>(x, x, other);
1093 return x;
1094}
1095
1096// Assumes x, y >= 0
1097int h_::cmp_abs(const bi_t& x, const bi_t& y) noexcept {
1098 if (x.size() > y.size()) {
1099 return 1;
1100 } else if (x.size() < y.size()) {
1101 return -1;
1102 } else {
1103 for (size_t i = x.size(); i-- > 0;) {
1104 if (x.vec_[i] > y.vec_[i]) {
1105 return 1;
1106 } else if (x.vec_[i] < y.vec_[i]) {
1107 return -1;
1108 }
1109 }
1110 return 0;
1111 }
1112}
1113
1115int h_::cmp(const bi_t& x, const bi_t& y) noexcept {
1116 if (!x.negative() && y.negative()) {
1117 // x >= 0, y < 0
1118 return 1;
1119 } else if (x.negative() && !y.negative()) {
1120 // x < 0, y >= 0
1121 return -1;
1122 } else if (x.negative() && y.negative()) {
1123 // x, y < 0
1124 if (x.size() > y.size()) {
1125 return -1;
1126 } else if (x.size() < y.size()) {
1127 return 1;
1128 } else {
1129 for (size_t i = x.size(); i-- > 0;) {
1130 if (x.vec_[i] < y.vec_[i]) {
1131 return 1;
1132 } else if (x.vec_[i] > y.vec_[i]) {
1133 return -1;
1134 }
1135 }
1136 return 0;
1137 }
1138 } else {
1139 // x, y >= 0
1140 return h_::cmp_abs(x, y);
1141 }
1142}
1143
1144template <std::integral T>
1145int h_::cmp(const bi_t& a, T b) noexcept {
1146 if (b == 0) {
1147 if (a.size() == 0) {
1148 return 0; // a
1149 }
1150 return a.negative() ? -1 : 1; // b
1151 }
1152
1153 using UnsignedT = typename std::make_unsigned<T>::type;
1154 const bool b_negative = b < 0;
1155 const UnsignedT unsigned_b =
1156 b_negative ? -static_cast<UnsignedT>(b) : static_cast<UnsignedT>(b);
1157
1158 if (a.negative() && !b_negative) {
1159 return -1; // c
1160 }
1161 if (!a.negative() && b_negative) {
1162 return 1; // d
1163 }
1164
1165 size_t n_b_digits = 0;
1166 if constexpr (std::numeric_limits<UnsignedT>::max() <= bi_dmax) {
1167 n_b_digits = (unsigned_b != 0) ? 1 : 0;
1168 } else {
1169 UnsignedT temp_b = unsigned_b;
1170 while (temp_b != 0) {
1171 temp_b >>= bi_dwidth;
1172 n_b_digits++;
1173 }
1174 }
1175
1176 const size_t a_size = a.size();
1177 if (a_size < n_b_digits) {
1178 return a.negative() ? 1 : -1; // e
1179 }
1180
1181 if (a_size > n_b_digits) {
1182 return a.negative() ? -1 : 1; // f
1183 }
1184
1185 for (size_t i = n_b_digits; i-- > 0;) {
1186 const digit a_digit = a[i];
1187 const digit b_digit = static_cast<digit>(unsigned_b >> (bi_dwidth * i));
1188
1189 if (a_digit < b_digit) {
1190 return a.negative() ? 1 : -1; // g
1191 }
1192 if (a_digit > b_digit) {
1193 return a.negative() ? -1 : 1; // h
1194 }
1195 }
1196 return 0; // i
1197}
1198
1203
1205uint8_t h_::idiv10(bi_t& x) noexcept {
1206 constexpr ddigit base = static_cast<ddigit>(bi_dmax) + 1;
1207 uint8_t carry = 0;
1208
1209 // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
1210 for (size_t i = x.size(); i-- > 0;) {
1211 const ddigit current = (base * carry) + x.vec_[i];
1212 x.vec_[i] = static_cast<digit>(current / 10);
1213 carry = static_cast<uint8_t>(current % 10);
1214 }
1215 // NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
1216
1217 x.trim();
1218 return carry;
1219}
1220
1256// log_base_2[base] gives log_{base}(2) (with some rounding up)
1257constexpr std::array<double, 37> log_base_2 = {
1258 0, 0, 1.0, 0.631, 0.5, 0.431, 0.387, 0.357, 0.334, 0.316,
1259 0.302, 0.290, 0.279, 0.271, 0.263, 0.256, 0.25, 0.245, 0.240, 0.236,
1260 0.232, 0.228, 0.225, 0.222, 0.219, 0.216, 0.213, 0.211, 0.209, 0.206,
1261 0.204, 0.202, 0.200, 0.199, 0.197, 0.195, 0.194};
1262
1263size_t h_::base_length(const bi_t& x, int base) {
1264 // TODO: a different exception is probably more appropriate in this func
1265 constexpr const char* s = "Digit estimation exceeds practical limit.";
1266
1267 const bi_bitcount_t bitlen = x.bit_length();
1268 if (bitlen > dbl_max_int) {
1269 throw overflow_error(s);
1270 }
1271
1272 const bi_bitcount_t r = static_cast<bi_bitcount_t>(
1273 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1274 std::floor(static_cast<double>(bitlen) * log_base_2[base]) + 1);
1275 if (r > std::numeric_limits<size_t>::max() - 2) {
1276 throw overflow_error(s);
1277 }
1278
1279 return r;
1280}
1281
1283
1284template <std::integral T>
1285void h_::init_one_digit(bi_t& x, T value) {
1286 x.resize_(1);
1287
1288 if (value >= 0) {
1289 x[0] = static_cast<digit>(value);
1290 x.negative_ = false;
1291 } else {
1292 x[0] = static_cast<digit>(0) - static_cast<digit>(value);
1293 x.negative_ = true;
1294 }
1295}
1296
1297template <std::integral T>
1298void h_::init_atleast_one_digit(bi_t& x, T value) {
1299 using UnsignedT = typename std::make_unsigned<T>::type;
1300
1301 size_t size = 1;
1302 UnsignedT temp, uvalue;
1303
1304 if (value >= 0) {
1305 uvalue = value;
1306 x.negative_ = false;
1307 } else {
1308 uvalue = static_cast<UnsignedT>(0) - static_cast<UnsignedT>(value);
1309 x.negative_ = true;
1310 }
1311
1312 temp = uvalue;
1313
1314 while (temp >>= bi_dwidth) {
1315 ++size;
1316 }
1317
1318 x.resize_(size);
1319
1320 for (size_t i = 0; uvalue != 0; ++i) {
1321 x[i] = static_cast<digit>(uvalue);
1322 uvalue >>= bi_dwidth;
1323 }
1324}
1325
1326// TODO: move this somewhere else.
1538
1539
1540constexpr auto pow2_8 = 1 << 8;
1541
1542constexpr std::array<uint8_t, pow2_8> create_char_to_b36_map() {
1543 // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
1544 constexpr auto n_digits = 10;
1545 constexpr auto n_letters = 26;
1546 constexpr std::array<char, n_letters> lowercase{
1547 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
1548 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
1549 constexpr std::array<char, n_letters> uppercase{
1550 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
1551 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
1552
1553 std::array<uint8_t, pow2_8> map{};
1554 map.fill(0xFF);
1555
1556 for (uint8_t i = 0; i < n_digits; ++i) {
1557 map.at(static_cast<uint8_t>('0') + i) = i;
1558 }
1559
1560 for (uint8_t i = 0; i < n_letters; ++i) {
1561 map.at(static_cast<uint8_t>(lowercase.at(i))) = 10 + i;
1562 map.at(static_cast<uint8_t>(uppercase.at(i))) = 10 + i;
1563 }
1564
1565 return map;
1566 // NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
1567}
1568
1569constexpr auto char_to_int_map = create_char_to_b36_map();
1570
1571constexpr uint8_t char_to_b36(char ch) {
1572 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1573 return char_to_int_map[static_cast<uint8_t>(ch)];
1574}
1575
1576// Calculate base ** n
1577constexpr digit pow(int base, size_t n) {
1578 digit result = 1;
1579 for (size_t i = 0; i < n; ++i) {
1580 result *= base;
1581 }
1582 return result;
1583}
1584
1585constexpr int calculate_max_batch_size(digit base) {
1586 int n = 0;
1587
1588 ddigit b = base;
1589 while (b < bi_dmax) {
1590 b *= base;
1591 ++n;
1592 }
1593
1594 return n;
1595}
1596
1597struct BaseMBS {
1598 // max batch size
1599 unsigned mbs;
1600 // base ** mbs
1601 digit base_pow_mbs;
1602};
1603
1604// For example, if digit <==> uint32_t (uint64_t), 10^{9} (10^{19}) is the
1605// highest power of 10 that fits in it.
1606// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
1607constexpr std::array<BaseMBS, 37> create_base_mbs_array() {
1608 std::array<BaseMBS, 37> base_mbs{};
1609 for (int base = 2; base <= 36; ++base) {
1610 unsigned max_batch_size = calculate_max_batch_size(base);
1611 base_mbs.at(base) = {max_batch_size, pow(base, max_batch_size)};
1612 }
1613 return base_mbs;
1614}
1615// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
1616
1617constexpr auto base_mbs = create_base_mbs_array();
1618
1619void h_::init_string(bi_t& x, const std::string& s, int base) {
1620 // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
1621 if (base <= 1 || base > 36) {
1622 throw std::invalid_argument("base argument must be in [2, 36]");
1623 }
1624
1625 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1626 const auto [max_batch_size, base_pow_max_batch_size] = base_mbs[base];
1627
1628 // std::stoi and company allow leading whitespace and a plus/minus sign. We
1629 // follow suit.
1630
1631 // Allow leading whitespace
1632 auto it = std::find_if_not(s.begin(), s.end(),
1633 [](char ch) { return std::isspace(ch); });
1634
1635 // Allow plus/minus sign to precede first base-`base` digit
1636 x.negative_ = false;
1637 if (it != s.end()) {
1638 if (*it == '-') {
1639 x.negative_ = true;
1640 ++it;
1641 } else if (*it == '+') {
1642 ++it;
1643 }
1644 }
1645
1646 const auto start_digit = it;
1647 // TODO: isalnum() is too broad!
1648 it = std::find_if_not(start_digit, s.end(),
1649 [](char ch) { return std::isalnum(ch); });
1650
1651 if (start_digit == it) {
1652 throw std::invalid_argument("Invalid string format.");
1653 }
1654
1655 size_t n_base = std::distance(start_digit, it); // it - start_digit
1656 const size_t n_digits = uints::div_ceil(n_base, max_batch_size);
1657
1658 x.reserve_(n_digits);
1659 x.resize_unsafe_(0);
1660
1661 auto dec_it = start_digit;
1662 const size_t rem_batch_size = n_base % max_batch_size;
1663
1664 // Initialize batch value
1665 digit batch = 0;
1666 // Convert batch substring to integer value
1667 for (size_t j = 0; j < rem_batch_size; ++j, ++dec_it) {
1668 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1669 batch = char_to_int_map[*dec_it] + batch * base;
1670 }
1671 // x is initially zero, so multiplication is zero in h_::imul1add1()
1672 if (batch) {
1673 x.vec_.push_back(batch);
1674 }
1675
1676 while (dec_it < it) {
1677 // Initialize batch value
1678 batch = 0;
1679 // Convert batch substring to integer value
1680 for (size_t j = 0; j < max_batch_size; ++j, ++dec_it) {
1681 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
1682 batch = char_to_int_map[*dec_it] + batch * base;
1683 }
1684 h_::imul1add1(x, base_pow_max_batch_size, batch);
1685 }
1686
1687 x.trim();
1688}
1689
1691
1693inline dvector h_::to_twos_complement(const dvector& vec) {
1694 const size_t vec_size = vec.size();
1695 dvector result;
1696 result.resize(vec_size);
1697
1698 bool carry = true;
1699 for (size_t i = 0; i < vec_size; ++i) {
1700 const digit sum = ~vec[i] + carry;
1701 carry = sum < static_cast<uint8_t>(carry);
1702 result[i] = sum;
1703 }
1704
1705 return result;
1706}
1707
1709inline void h_::to_twos_complement_in_place(dvector& vec) noexcept {
1710 const size_t vec_size = vec.size();
1711
1712 bool carry = true;
1713 for (size_t i = 0; i < vec_size; ++i) {
1714 const digit sum = ~vec[i] + carry;
1715 carry = sum < static_cast<uint8_t>(carry);
1716 vec[i] = sum;
1717 }
1718}
1719
1726void h_::assign_from_double(bi_t& x, double d) {
1727 if (std::isnan(d) || std::isinf(d)) {
1728 throw from_float(
1729 "Conversion error: NaN or infinity cannot be converted to an integer.");
1730 }
1731
1732 if (d > -1 && d < 1) {
1733 x = 0;
1734 return;
1735 }
1736
1737 const bool neg = d < 0;
1738 if (neg) {
1739 d = -d;
1740 }
1741
1742 size_t n_digits{1};
1743 while (bi_base_dbl <= d) {
1744 // Equiv. to `d /= bi_base_dbl;`, but multiplication is generally cheaper
1745 d *= bi_base_dbl_reciprocal;
1746 ++n_digits;
1747 }
1748
1749 x.resize_(n_digits);
1750
1751 for (size_t i = n_digits; i-- > 0;) {
1752 x[i] = static_cast<digit>(d);
1753 d = (d - static_cast<double>(x[i])) * bi_base_dbl;
1754 }
1755
1756 x.negative_ = neg;
1757 x.trim();
1758}
1759
1760int h_::cmp_abs(const bi_t& z, double dbl) noexcept {
1761 if (z.size() == 0) {
1762 return dbl > 0 ? -1 : 0;
1763 }
1764
1765 if (z.size() >= bi_cmp_dbl_size_upper) {
1766 return 1;
1767 }
1768
1769 // Same as dbl = std::ldexp(dbl, -static_cast<int>(bi_dbits) *
1770 // static_cast<int>(z.size() - 1));
1771 for (size_t j = 1; j < z.size(); ++j) {
1772 // Equiv. to `dbl /= bi_base_dbl;`, but multiplication is generally cheaper
1773 dbl *= bi_base_dbl_reciprocal;
1774 }
1775
1776 if (bi_base_dbl <= dbl) {
1777 return -1;
1778 }
1779
1780 for (auto it = z.rbegin(); it != z.rend(); ++it) {
1781 const digit cur = static_cast<digit>(dbl);
1782
1783 if (*it < cur) {
1784 return -1;
1785 } else if (*it > cur) {
1786 return 1;
1787 } else {
1788 dbl = (dbl - static_cast<double>(cur)) * bi_base_dbl;
1789 }
1790 }
1791
1792 return dbl > 0 ? -1 : 0;
1793}
1794
1795int h_::cmp(const bi_t& z, double dbl) noexcept {
1796 if (!z.negative()) {
1797 return dbl < 0 ? 1 : h_::cmp_abs(z, dbl);
1798 } else {
1799 return dbl < 0 ? -h_::cmp_abs(z, -dbl) : -1;
1800 }
1801}
1802
1807
1808template <std::unsigned_integral T>
1809bi_t h_::expo_left_to_right(const bi_t& base, T exp) {
1810 assert(exp > 0);
1811
1812 // (1)
1813 bi_t ret{1};
1814
1815 // (2)
1816 for (int j = uints::bit_length(exp); j-- > 0;) {
1817 ret *= ret;
1818 // Test if j-th bit of exp is set
1819 if (exp & (static_cast<T>(1) << j)) {
1820 ret *= base;
1821 }
1822 }
1823
1824 // (3)
1825 return ret;
1826}
1827
1829
1830bi_t h_::random_(bi_bitcount_t z) {
1831 bi_t result{};
1832
1833 if (z == 0) {
1834 return result;
1835 }
1836
1837 size_t num_digits = z / bi_dbits;
1838 size_t remainder = z % bi_dbits;
1839
1840 if (remainder != 0) {
1841 num_digits += 1;
1842 }
1843
1844 result.resize_(num_digits);
1845
1846 std::uniform_int_distribution<digit> dist(0, bi_dmax);
1847
1848 for (size_t i = 0; i < num_digits - 1; ++i) {
1849 result[i] = dist(rng_);
1850 }
1851
1852 if (remainder != 0) {
1853 const digit mask = (static_cast<digit>(1) << remainder) - 1;
1854 result[num_digits - 1] = dist(rng_) & mask;
1855 } else {
1856 result[num_digits - 1] = dist(rng_);
1857 }
1858
1859 result.trim();
1860 return result;
1861}
1862
1863} // namespace bi
1864
1865#endif // BI_SRC_H__HPP_
Arbitrary-precision integer type and related functions.
Definition bi.hpp:52
size_t size() const noexcept
Return the number of digits used. Instance represents 0 iff size() == 0.