30 static_assert(N >= 0,
"bigint must have zero or more digits.");
31 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
"bigint's digit must be unsigned integers.");
34 static constexpr int nr_digits = N;
35 static constexpr int bits_per_digit =
sizeof(digit_type) * 8;
36 static constexpr int nr_bits = nr_digits * bits_per_digit;
42 tt_force_inline
bigint() noexcept = default;
43 tt_force_inline ~
bigint() = default;
44 tt_force_inline
bigint(
bigint const &) noexcept = default;
45 tt_force_inline
bigint &operator=(
bigint const &) noexcept = default;
47 tt_force_inline
bigint &operator=(
bigint &&) noexcept = default;
49 template<
int R,
std::enable_if_t<R < N,
int> = 0>
50 tt_force_inline
bigint(
bigint<T,R> const &rhs) noexcept {
60 template<
int R, std::enable_if_t<R < N,
int> = 0>
61 tt_force_inline big
int &operator=(big
int<T,R> const &rhs) noexcept {
64 digits[i] = rhs.digits[i];
72 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
73 tt_force_inline
bigint(R value)
noexcept {
74 digits[0] =
static_cast<digit_type
>(value);
75 for (
auto i = 1; i < nr_digits; i++) {
80 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
81 tt_force_inline bigint &operator=(R value)
noexcept {
83 for (
auto i = 1; i < nr_digits; i++) {
89 tt_force_inline
explicit bigint(std::string_view str,
int base=10) noexcept :
92 for (
auto i = 0; i < str.size(); i++) {
93 auto nibble = char_to_nibble(str[i]);
99 tt_force_inline
explicit operator unsigned long long () const noexcept {
return static_cast<unsigned long long>(
digits[0]); }
100 tt_force_inline
explicit operator signed long long () const noexcept {
return static_cast<signed long long>(
digits[0]); }
101 tt_force_inline
explicit operator unsigned long () const noexcept {
return static_cast<unsigned long>(
digits[0]); }
102 tt_force_inline
explicit operator signed long () const noexcept {
return static_cast<signed long>(
digits[0]); }
103 tt_force_inline
explicit operator unsigned int () const noexcept {
return static_cast<unsigned int>(
digits[0]); }
104 tt_force_inline
explicit operator signed int () const noexcept {
return static_cast<signed int>(
digits[0]); }
105 tt_force_inline
explicit operator unsigned short () const noexcept {
return static_cast<unsigned short>(
digits[0]); }
106 tt_force_inline
explicit operator signed short () const noexcept {
return static_cast<signed short>(
digits[0]); }
107 tt_force_inline
explicit operator unsigned char () const noexcept {
return static_cast<unsigned char>(
digits[0]); }
108 tt_force_inline
explicit operator signed char () const noexcept {
return static_cast<signed char>(
digits[0]); }
109 tt_force_inline
explicit operator char () const noexcept {
return static_cast<char>(
digits[0]); }
111 tt_force_inline
explicit operator bool () const noexcept {
112 for (ssize_t i = 0; i != N; ++i) {
121 tt_force_inline
explicit operator bigint<T,O> () const noexcept {
124 for (
auto i = 0; i < O; i++) {
125 r.digits[i] = i < N ?
digits[i] : 0;
131 static auto oneOver10 = bigint_reciprocal(bigint<T,N*2>{10});
142 std::tie(tmp, remainder) =
div(tmp, 10, oneOver10);
143 r += (
static_cast<char>(
remainder) +
'0');
152 static_assert(std::is_same_v<T,uint64_t> && N == 2,
"UUIDString should only be called on a uuid compatible type");
153 return fmt::format(
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
154 static_cast<uint32_t
>(
digits[1] >> 32),
155 static_cast<uint16_t
>(
digits[1] >> 16),
156 static_cast<uint16_t
>(
digits[1]),
157 static_cast<uint16_t
>(
digits[0] >> 48),
158 digits[0] & 0x0000ffff'ffffffffULL
162 tt_force_inline digit_type get_bit(
unsigned int count)
const noexcept {
163 ttlet digit_count =
count / bits_per_digit;
164 ttlet bit_count =
count % bits_per_digit;
166 return (
digits[digit_count] >> bit_count) & 1;
169 tt_force_inline
void set_bit(
unsigned int count, digit_type value = 1) noexcept {
170 ttlet digit_count =
count / bits_per_digit;
171 ttlet bit_count =
count % bits_per_digit;
173 digits[digit_count] |= (value << bit_count);
176 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
177 tt_force_inline bigint &operator<<=(R rhs)
noexcept {
178 bigint_shift_left(*
this, *
this,
static_cast<int>(rhs));
182 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
183 tt_force_inline
constexpr bigint &operator>>=(R rhs)
noexcept {
184 bigint_shift_right(*
this, *
this,
static_cast<int>(rhs));
188 tt_force_inline bigint &operator*=(bigint
const &rhs)
noexcept {
189 auto r = bigint<T,N>{0};
190 bigint_multiply(r, *
this, rhs);
195 tt_force_inline bigint &operator+=(bigint
const &rhs)
noexcept {
196 bigint_add(*
this, *
this, rhs);
200 tt_force_inline bigint &operator-=(bigint
const &rhs)
noexcept {
201 bigint_subtract(*
this, *
this, rhs);
205 tt_force_inline bigint &operator&=(bigint
const &rhs)
noexcept {
206 bigint_and(*
this, *
this, rhs);
210 tt_force_inline bigint &operator|=(bigint
const &rhs)
noexcept {
211 bigint_or(*
this, *
this, rhs);
215 tt_force_inline bigint &operator^=(bigint
const &rhs)
noexcept {
216 bigint_xor(*
this, *
this, rhs);
220 tt_force_inline bigint crc(bigint
const &rhs)
noexcept {
221 return bigint_crc(*
this, rhs);
224 static tt_force_inline bigint fromBigEndian(uint8_t
const *data)
noexcept {
226 for (
int i = N - 1; i >= 0; i--) {
228 for (ssize_t j = 0; j <
sizeof(digit_type); j++) {
236 static tt_force_inline bigint fromLittleEndian(uint8_t
const *data)
noexcept {
238 for (
int i = 0; i < N; i++) {
240 for (ssize_t j = 0; j <
sizeof(digit_type); j++) {
241 d |=
static_cast<digit_type
>(*(data++)) << (j*8);
248 static tt_force_inline bigint fromBigEndian(
void const *data)
noexcept {
249 return fromBigEndian(
static_cast<uint8_t
const *
>(data));
252 static tt_force_inline bigint fromLittleEndian(
void const *data)
noexcept {
253 return fromLittleEndian(
static_cast<uint8_t
const *
>(data));
256 [[nodiscard]] tt_force_inline
friend int bigint_compare(bigint
const &lhs, bigint
const &rhs)
noexcept
258 for (
int i = N - 1; i >= 0; --i) {
259 auto lhs_digit = lhs.digits[i];
260 auto rhs_digit = rhs.digits[i];
261 if (lhs_digit != rhs_digit) {
262 return lhs_digit < rhs_digit ? -1 : 1;
268 tt_force_inline
friend void bigint_invert(bigint &o, bigint
const &rhs)
noexcept
270 for (
auto i = 0; i < N; i++) {
271 o.digits[i] = ~rhs.digits[i];
275 tt_force_inline
friend void bigint_add(bigint &o, bigint
const &lhs, bigint
const &rhs, T carry=0) noexcept
277 for (
auto i = 0; i < N; i++) {
278 std::tie(o.digits[i], carry) = add_carry(lhs.digits[i], rhs.digits[i], carry);
282 tt_force_inline
friend void bigint_multiply(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
284 for (
auto rhs_index = 0; rhs_index < N; rhs_index++) {
285 ttlet rhs_digit = rhs.digits[rhs_index];
288 for (
auto lhs_index = 0; (lhs_index + rhs_index) < N; lhs_index++) {
289 ttlet lhs_digit = lhs.digits[lhs_index];
292 T accumulator = o.digits[rhs_index + lhs_index];
293 std::tie(result, carry) = multiply_carry(lhs_digit, rhs_digit, carry, accumulator);
294 o.digits[rhs_index + lhs_index] = result;
299 tt_force_inline
friend void bigint_div(bigint "ient, bigint &remainder, bigint
const &lhs, bigint
const &rhs)
noexcept
301 for (
auto i = nr_bits - 1; i >= 0; i--) {
304 if (remainder >= rhs) {
311 tt_force_inline
friend void bigint_div(bigint &r_quotient, bigint &r_remainder, bigint
const &lhs, bigint
const &rhs, bigint<T,2*N>
const &rhs_reciprocal)
noexcept
313 auto quotient = bigint<T,3*N>{0};
314 bigint_multiply(quotient, lhs, rhs_reciprocal);
316 quotient >>= (2*nr_bits);
318 auto product = bigint<T,3*N>{0};
319 bigint_multiply(product, quotient, rhs);
321 tt_assume(product <= lhs);
325 while (remainder >= rhs) {
328 bigint_div(r_quotient, r_remainder, lhs, rhs);
334 r_quotient =
static_cast<bigint
>(quotient);
335 r_remainder =
static_cast<bigint
>(
remainder);
341 [[nodiscard]] tt_force_inline
friend int bigint_bsr(bigint
const &rhs)
noexcept
343 for (
auto i = N - 1; i >= 0; i--) {
344 auto tmp = bsr(rhs.digits[i]);
346 return (i * bits_per_digit) + tmp;
357 [[nodiscard]] tt_force_inline
friend bigint bigint_crc(bigint
const &lhs, bigint
const &rhs)
noexcept
359 ttlet polynomialOrder = bigint_bsr(rhs);
360 tt_assert(polynomialOrder >= 0);
362 auto tmp =
static_cast<bigint<T,2*N>
>(lhs) << polynomialOrder;
363 auto rhs_ =
static_cast<bigint<T,2*N>
>(rhs);
365 auto tmp_highest_bit = bigint_bsr(tmp);
366 while (tmp_highest_bit >= polynomialOrder) {
367 ttlet divident = rhs_ << (tmp_highest_bit - polynomialOrder);
370 tmp_highest_bit = bigint_bsr(tmp);
373 return static_cast<bigint
>(tmp);
383 [[nodiscard]] tt_force_inline
friend bigint bigint_reciprocal(bigint
const &rhs) {
384 auto r = bigint<T,N+1>(0);
386 return static_cast<bigint
>(r / rhs);
390 tt_force_inline
friend void bigint_and(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
392 for (
auto i = 0; i != N; ++i) {
393 o.digits[i] = lhs.digits[i] & rhs.digits[i];
397 tt_force_inline
friend void bigint_or(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
399 for (
auto i = 0; i != N; ++i) {
400 o.digits[i] = lhs.digits[i] | rhs.digits[i];
404 tt_force_inline
friend void bigint_xor(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
406 for (
auto i = 0; i != N; ++i) {
407 o.digits[i] = lhs.digits[i] ^ rhs.digits[i];
411 tt_force_inline
friend void bigint_subtract(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
414 bigint_invert(rhs_, rhs);
415 bigint_add(o, lhs, rhs_, T{1});
418 tt_force_inline
friend void bigint_shift_left(bigint &o, bigint
const &lhs,
int count)
noexcept
420 ttlet digit_count =
count / bits_per_digit;
421 ttlet bit_count =
count % bits_per_digit;
423 if (&o != &lhs || digit_count > 0) {
424 for (
int i = N - 1; i >= digit_count; --i) {
425 o.digits[i] = lhs.digits[i - digit_count];
427 for (
int i = digit_count - 1; i >= 0; --i) {
434 for (
auto i = 0; i != N; ++i) {
435 std::tie(o.digits[i], carry) = shift_left_carry(o.digits[i], bit_count, carry);
440 tt_force_inline
friend void bigint_shift_right(bigint &o, bigint
const &lhs,
int count)
noexcept
442 ttlet digit_count =
count / bits_per_digit;
443 ttlet bit_count =
count % bits_per_digit;
445 if (&o != &lhs || digit_count > 0) {
447 for (; i != (N - digit_count); ++i) {
448 o.digits[i] = lhs.digits[i + digit_count];
450 for (; i != N; ++i) {
457 for (
auto i = N - 1; i >= 0; --i) {
458 std::tie(o.digits[i], carry) = shift_right_carry(o.digits[i], bit_count, carry);
463 [[nodiscard]] tt_force_inline
friend bool operator==(bigint
const &lhs, bigint
const &rhs)
noexcept
465 return bigint_compare(lhs, rhs) == 0;
468 [[nodiscard]] tt_force_inline
friend bool operator<(bigint
const &lhs, bigint
const &rhs)
noexcept
470 return bigint_compare(lhs, rhs) < 0;
473 [[nodiscard]] tt_force_inline
friend bool operator>(bigint
const &lhs, bigint
const &rhs)
noexcept
475 return bigint_compare(lhs, rhs) > 0;
478 [[nodiscard]] tt_force_inline
friend bool operator!=(bigint
const &lhs, bigint
const &rhs)
noexcept
480 return bigint_compare(lhs, rhs) != 0;
483 [[nodiscard]] tt_force_inline
friend bool operator>=(bigint
const &lhs, bigint
const &rhs)
noexcept
485 return bigint_compare(lhs, rhs) >= 0;
488 [[nodiscard]] tt_force_inline
friend bool operator<=(bigint
const &lhs, bigint
const &rhs)
noexcept
490 return bigint_compare(lhs, rhs) <= 0;
493 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
494 [[nodiscard]] tt_force_inline
friend auto operator<<(bigint
const &lhs, R
const &rhs)
noexcept {
496 bigint_shift_left(o, lhs,
static_cast<int>(rhs));
500 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
501 [[nodiscard]] tt_force_inline
friend auto operator>>(bigint
const &lhs, R
const &rhs)
noexcept {
503 bigint_shift_right(o, lhs,
static_cast<int>(rhs));
507 [[nodiscard]] tt_force_inline
friend auto operator*(bigint
const &lhs, bigint
const &rhs)
noexcept
510 bigint_multiply(o, lhs, rhs);
514 [[nodiscard]] tt_force_inline
friend auto operator+(bigint
const &lhs, bigint
const &rhs)
noexcept
517 bigint_add(o, lhs, rhs);
521 [[nodiscard]] tt_force_inline
friend auto operator-(bigint
const &lhs, bigint
const &rhs)
noexcept
524 bigint_subtract(o, lhs, rhs);
528 [[nodiscard]] tt_force_inline
friend auto operator~(bigint
const &rhs)
noexcept
531 bigint_invert(o, rhs);
535 [[nodiscard]] tt_force_inline
friend auto operator|(bigint
const &lhs, bigint
const &rhs)
noexcept
538 bigint_or(o, lhs, rhs);
542 [[nodiscard]] tt_force_inline
friend auto operator&(bigint
const &lhs, bigint
const &rhs)
noexcept
545 bigint_and(o, lhs, rhs);
549 [[nodiscard]] tt_force_inline
friend auto operator^(bigint
const &lhs, bigint
const &rhs)
noexcept
552 bigint_xor(o, lhs, rhs);
556 [[nodiscard]] tt_force_inline
friend auto div(bigint
const &lhs, bigint
const &rhs)
noexcept
558 auto quotient = bigint{0};
561 bigint_div(quotient, remainder, lhs, rhs);
565 [[nodiscard]] tt_force_inline
friend auto div(bigint
const &lhs, bigint
const &rhs, bigint<T,2*N>
const &rhs_reciprocal)
noexcept
567 auto quotient = bigint{0};
570 bigint_div(quotient, remainder, lhs, rhs, rhs_reciprocal);
575 [[nodiscard]] tt_force_inline
friend auto operator/(bigint
const &lhs, bigint
const &rhs)
noexcept
577 auto quotient = bigint{0};
580 bigint_div(quotient, remainder, lhs, rhs);
584 [[nodiscard]] tt_force_inline
friend auto operator%(bigint
const &lhs, bigint
const &rhs)
noexcept
586 auto quotient = bigint{0};
589 bigint_div(quotient, remainder, lhs, rhs);
594 return lhs << rhs.string();