32 static_assert(N >= 0,
"bigint must have zero or more digits.");
33 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
"bigint's digit must be unsigned integers.");
36 static constexpr int nr_digits = N;
37 static constexpr int bits_per_digit =
sizeof(digit_type) * 8;
38 static constexpr int nr_bits = nr_digits * bits_per_digit;
44 bigint() noexcept = default;
51 template<
int R,
std::enable_if_t<R < N,
int> = 0>
62 template<
int R, std::enable_if_t<R < N,
int> = 0>
63 big
int &operator=(big
int<T,R> const &rhs) noexcept {
66 digits[i] = rhs.digits[i];
74 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
76 digits[0] =
static_cast<digit_type
>(value);
77 for (
auto i = 1; i < nr_digits; i++) {
82 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
83 bigint &operator=(R value)
noexcept {
85 for (
auto i = 1; i < nr_digits; i++) {
91 explicit bigint(std::string_view str,
int base=10) noexcept :
94 for (
auto i = 0; i < str.size(); i++) {
95 auto nibble = base16::int_from_char<int>(str[i]);
101 explicit operator unsigned long long () const noexcept {
return static_cast<unsigned long long>(
digits[0]); }
102 explicit operator signed long long () const noexcept {
return static_cast<signed long long>(
digits[0]); }
103 explicit operator unsigned long () const noexcept {
return static_cast<unsigned long>(
digits[0]); }
104 explicit operator signed long () const noexcept {
return static_cast<signed long>(
digits[0]); }
105 explicit operator unsigned int () const noexcept {
return static_cast<unsigned int>(
digits[0]); }
106 explicit operator signed int () const noexcept {
return static_cast<signed int>(
digits[0]); }
107 explicit operator unsigned short () const noexcept {
return static_cast<unsigned short>(
digits[0]); }
108 explicit operator signed short () const noexcept {
return static_cast<signed short>(
digits[0]); }
109 explicit operator unsigned char () const noexcept {
return static_cast<unsigned char>(
digits[0]); }
110 explicit operator signed char () const noexcept {
return static_cast<signed char>(
digits[0]); }
111 explicit operator char () const noexcept {
return static_cast<char>(
digits[0]); }
113 explicit operator bool () const noexcept {
114 for (ssize_t i = 0; i != N; ++i) {
123 explicit operator bigint<T,O> () const noexcept {
124 auto r = bigint<T,O>{};
126 for (
auto i = 0; i < O; i++) {
127 r.digits[i] = i < N ?
digits[i] : 0;
133 static auto oneOver10 = bigint_reciprocal(bigint<T,N*2>{10});
144 std::tie(tmp, remainder) =
div(tmp, 10, oneOver10);
145 r += (
static_cast<char>(
remainder) +
'0');
154 static_assert(std::is_same_v<T,uint64_t> && N == 2,
"UUIDString should only be called on a uuid compatible type");
155 return fmt::format(
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
156 static_cast<uint32_t
>(
digits[1] >> 32),
157 static_cast<uint16_t
>(
digits[1] >> 16),
158 static_cast<uint16_t
>(
digits[1]),
159 static_cast<uint16_t
>(
digits[0] >> 48),
160 digits[0] & 0x0000ffff'ffffffffULL
164 digit_type get_bit(
unsigned int count)
const noexcept {
165 ttlet digit_count =
count / bits_per_digit;
166 ttlet bit_count =
count % bits_per_digit;
168 return (
digits[digit_count] >> bit_count) & 1;
171 void set_bit(
unsigned int count, digit_type value = 1) noexcept {
172 ttlet digit_count =
count / bits_per_digit;
173 ttlet bit_count =
count % bits_per_digit;
175 digits[digit_count] |= (value << bit_count);
178 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
179 bigint &operator<<=(R rhs)
noexcept {
180 bigint_shift_left(*
this, *
this,
static_cast<int>(rhs));
184 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
185 constexpr bigint &operator>>=(R rhs)
noexcept {
186 bigint_shift_right(*
this, *
this,
static_cast<int>(rhs));
190 bigint &operator*=(bigint
const &rhs)
noexcept {
191 auto r = bigint<T,N>{0};
192 bigint_multiply(r, *
this, rhs);
197 bigint &operator+=(bigint
const &rhs)
noexcept {
198 bigint_add(*
this, *
this, rhs);
202 bigint &operator-=(bigint
const &rhs)
noexcept {
203 bigint_subtract(*
this, *
this, rhs);
207 bigint &operator&=(bigint
const &rhs)
noexcept {
208 bigint_and(*
this, *
this, rhs);
212 bigint &operator|=(bigint
const &rhs)
noexcept {
213 bigint_or(*
this, *
this, rhs);
217 bigint &operator^=(bigint
const &rhs)
noexcept {
218 bigint_xor(*
this, *
this, rhs);
222 bigint crc(bigint
const &rhs)
noexcept {
223 return bigint_crc(*
this, rhs);
226 static bigint fromBigEndian(uint8_t
const *data)
noexcept {
228 for (
int i = N - 1; i >= 0; i--) {
230 for (ssize_t j = 0; j <
sizeof(digit_type); j++) {
238 static bigint fromLittleEndian(uint8_t
const *data)
noexcept {
240 for (
int i = 0; i < N; i++) {
242 for (ssize_t j = 0; j <
sizeof(digit_type); j++) {
243 d |=
static_cast<digit_type
>(*(data++)) << (j*8);
250 static bigint fromBigEndian(
void const *data)
noexcept {
251 return fromBigEndian(
static_cast<uint8_t
const *
>(data));
254 static bigint fromLittleEndian(
void const *data)
noexcept {
255 return fromLittleEndian(
static_cast<uint8_t
const *
>(data));
258 [[nodiscard]]
friend int bigint_compare(bigint
const &lhs, bigint
const &rhs)
noexcept
260 for (
int i = N - 1; i >= 0; --i) {
261 auto lhs_digit = lhs.digits[i];
262 auto rhs_digit = rhs.digits[i];
263 if (lhs_digit != rhs_digit) {
264 return lhs_digit < rhs_digit ? -1 : 1;
270 friend void bigint_invert(bigint &o, bigint
const &rhs)
noexcept
272 for (
auto i = 0; i < N; i++) {
273 o.digits[i] = ~rhs.digits[i];
277 friend void bigint_add(bigint &o, bigint
const &lhs, bigint
const &rhs, T carry=0) noexcept
279 for (
auto i = 0; i < N; i++) {
280 std::tie(o.digits[i], carry) = add_carry(lhs.digits[i], rhs.digits[i], carry);
284 friend void bigint_multiply(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
286 for (
auto rhs_index = 0; rhs_index < N; rhs_index++) {
287 ttlet rhs_digit = rhs.digits[rhs_index];
290 for (
auto lhs_index = 0; (lhs_index + rhs_index) < N; lhs_index++) {
291 ttlet lhs_digit = lhs.digits[lhs_index];
294 T accumulator = o.digits[rhs_index + lhs_index];
295 std::tie(result, carry) = multiply_carry(lhs_digit, rhs_digit, carry, accumulator);
296 o.digits[rhs_index + lhs_index] = result;
301 friend void bigint_div(bigint "ient, bigint &remainder, bigint
const &lhs, bigint
const &rhs)
noexcept
303 for (
auto i = nr_bits - 1; i >= 0; i--) {
306 if (remainder >= rhs) {
313 friend void bigint_div(bigint &r_quotient, bigint &r_remainder, bigint
const &lhs, bigint
const &rhs, bigint<T,2*N>
const &rhs_reciprocal)
noexcept
315 auto quotient = bigint<T,3*N>{0};
316 bigint_multiply(quotient, lhs, rhs_reciprocal);
318 quotient >>= (2*nr_bits);
320 auto product = bigint<T,3*N>{0};
321 bigint_multiply(product, quotient, rhs);
323 tt_axiom(product <= lhs);
327 while (remainder >= rhs) {
330 bigint_div(r_quotient, r_remainder, lhs, rhs);
336 r_quotient =
static_cast<bigint
>(quotient);
337 r_remainder =
static_cast<bigint
>(
remainder);
343 [[nodiscard]]
friend int bigint_bsr(bigint
const &rhs)
noexcept
345 for (
auto i = N - 1; i >= 0; i--) {
346 auto tmp = bsr(rhs.digits[i]);
348 return (i * bits_per_digit) + tmp;
359 [[nodiscard]]
friend bigint bigint_crc(bigint
const &lhs, bigint
const &rhs)
noexcept
361 ttlet polynomialOrder = bigint_bsr(rhs);
362 tt_assert(polynomialOrder >= 0);
364 auto tmp =
static_cast<bigint<T,2*N>
>(lhs) << polynomialOrder;
365 auto rhs_ =
static_cast<bigint<T,2*N>
>(rhs);
367 auto tmp_highest_bit = bigint_bsr(tmp);
368 while (tmp_highest_bit >= polynomialOrder) {
369 ttlet divident = rhs_ << (tmp_highest_bit - polynomialOrder);
372 tmp_highest_bit = bigint_bsr(tmp);
375 return static_cast<bigint
>(tmp);
385 [[nodiscard]]
friend bigint bigint_reciprocal(bigint
const &rhs) {
386 auto r = bigint<T,N+1>(0);
388 return static_cast<bigint
>(r / rhs);
392 friend void bigint_and(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
394 for (
auto i = 0; i != N; ++i) {
395 o.digits[i] = lhs.digits[i] & rhs.digits[i];
399 friend void bigint_or(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
401 for (
auto i = 0; i != N; ++i) {
402 o.digits[i] = lhs.digits[i] | rhs.digits[i];
406 friend void bigint_xor(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
408 for (
auto i = 0; i != N; ++i) {
409 o.digits[i] = lhs.digits[i] ^ rhs.digits[i];
413 friend void bigint_subtract(bigint &o, bigint
const &lhs, bigint
const &rhs)
noexcept
416 bigint_invert(rhs_, rhs);
417 bigint_add(o, lhs, rhs_, T{1});
420 friend void bigint_shift_left(bigint &o, bigint
const &lhs,
int count)
noexcept
422 ttlet digit_count =
count / bits_per_digit;
423 ttlet bit_count =
count % bits_per_digit;
425 if (&o != &lhs || digit_count > 0) {
426 for (
int i = N - 1; i >= digit_count; --i) {
427 o.digits[i] = lhs.digits[i - digit_count];
429 for (
int i = digit_count - 1; i >= 0; --i) {
436 for (
auto i = 0; i != N; ++i) {
437 std::tie(o.digits[i], carry) = shift_left_carry(o.digits[i], bit_count, carry);
442 friend void bigint_shift_right(bigint &o, bigint
const &lhs,
int count)
noexcept
444 ttlet digit_count =
count / bits_per_digit;
445 ttlet bit_count =
count % bits_per_digit;
447 if (&o != &lhs || digit_count > 0) {
449 for (; i != (N - digit_count); ++i) {
450 o.digits[i] = lhs.digits[narrow_cast<size_t>(i + digit_count)];
452 for (; i != N; ++i) {
459 for (
auto i = N - 1; i >= 0; --i) {
460 std::tie(o.digits[i], carry) = shift_right_carry(o.digits[i], bit_count, carry);
465 [[nodiscard]]
friend bool operator==(bigint
const &lhs, bigint
const &rhs)
noexcept
467 return bigint_compare(lhs, rhs) == 0;
470 [[nodiscard]]
friend bool operator<(bigint
const &lhs, bigint
const &rhs)
noexcept
472 return bigint_compare(lhs, rhs) < 0;
475 [[nodiscard]]
friend bool operator>(bigint
const &lhs, bigint
const &rhs)
noexcept
477 return bigint_compare(lhs, rhs) > 0;
480 [[nodiscard]]
friend bool operator!=(bigint
const &lhs, bigint
const &rhs)
noexcept
482 return bigint_compare(lhs, rhs) != 0;
485 [[nodiscard]]
friend bool operator>=(bigint
const &lhs, bigint
const &rhs)
noexcept
487 return bigint_compare(lhs, rhs) >= 0;
490 [[nodiscard]]
friend bool operator<=(bigint
const &lhs, bigint
const &rhs)
noexcept
492 return bigint_compare(lhs, rhs) <= 0;
495 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
496 [[nodiscard]]
friend auto operator<<(bigint
const &lhs, R
const &rhs)
noexcept {
498 bigint_shift_left(o, lhs,
static_cast<int>(rhs));
502 template<
typename R, std::enable_if_t<std::is_
integral_v<R>,
int> = 0>
503 [[nodiscard]]
friend auto operator>>(bigint
const &lhs, R
const &rhs)
noexcept {
505 bigint_shift_right(o, lhs,
static_cast<int>(rhs));
509 [[nodiscard]]
friend auto operator*(bigint
const &lhs, bigint
const &rhs)
noexcept
512 bigint_multiply(o, lhs, rhs);
516 [[nodiscard]]
friend auto operator+(bigint
const &lhs, bigint
const &rhs)
noexcept
519 bigint_add(o, lhs, rhs);
523 [[nodiscard]]
friend auto operator-(bigint
const &lhs, bigint
const &rhs)
noexcept
526 bigint_subtract(o, lhs, rhs);
530 [[nodiscard]]
friend auto operator~(bigint
const &rhs)
noexcept
533 bigint_invert(o, rhs);
537 [[nodiscard]]
friend auto operator|(bigint
const &lhs, bigint
const &rhs)
noexcept
540 bigint_or(o, lhs, rhs);
544 [[nodiscard]]
friend auto operator&(bigint
const &lhs, bigint
const &rhs)
noexcept
547 bigint_and(o, lhs, rhs);
551 [[nodiscard]]
friend auto operator^(bigint
const &lhs, bigint
const &rhs)
noexcept
554 bigint_xor(o, lhs, rhs);
558 [[nodiscard]]
friend auto div(bigint
const &lhs, bigint
const &rhs)
noexcept
560 auto quotient = bigint{0};
563 bigint_div(quotient, remainder, lhs, rhs);
567 [[nodiscard]]
friend auto div(bigint
const &lhs, bigint
const &rhs, bigint<T,2*N>
const &rhs_reciprocal)
noexcept
569 auto quotient = bigint{0};
572 bigint_div(quotient, remainder, lhs, rhs, rhs_reciprocal);
577 [[nodiscard]]
friend auto operator/(bigint
const &lhs, bigint
const &rhs)
noexcept
579 auto quotient = bigint{0};
582 bigint_div(quotient, remainder, lhs, rhs);
586 [[nodiscard]]
friend auto operator%(bigint
const &lhs, bigint
const &rhs)
noexcept
588 auto quotient = bigint{0};
591 bigint_div(quotient, remainder, lhs, rhs);
596 return lhs << rhs.string();