24 using digit_type = DigitType;
25 using signed_digit_type = std::make_signed_t<digit_type>;
26 static constexpr auto num_digits = NumDigits;
27 static constexpr auto is_signed = IsSigned;
28 static constexpr auto bits_per_digit =
sizeof(digit_type) * CHAR_BIT;
30 static constexpr digit_type zero_digit = 0;
31 static constexpr digit_type min1_digit =
static_cast<digit_type
>(signed_digit_type{-1});
35 digit_type digits[num_digits];
42 digits[i] = zero_digit;
47 constexpr bigint &operator=(
bigint const &)
noexcept =
default;
49 constexpr
bigint &operator=(
bigint &&) noexcept = default;
53 template<
std::
size_t N,
bool S>
54 constexpr
bigint(
bigint<digit_type, N, S> const &rhs) noexcept requires(N < num_digits)
60 digits[i] = rhs.digits[i];
64 hilet sign = rhs.is_negative() ? min1_digit : zero_digit;
65 for (; i != num_digits; ++i) {
72 template<std::
size_t N,
bool S>
79 digits[i] = rhs.digits[i];
83 hilet sign = rhs.is_negative() ? min1_digit : zero_digit;
84 for (; i != num_digits; ++i) {
90 constexpr bigint(std::integral
auto value)
noexcept
92 static_assert(
sizeof(value) <=
sizeof(digit_type));
93 static_assert(num_digits > 0);
95 if constexpr (std::is_signed_v<
decltype(value)>) {
97 digits[0] = truncate<digit_type>(narrow_cast<signed_digit_type>(value));
99 digits[0] = narrow_cast<digit_type>(value);
103 hilet sign = value < 0 ? min1_digit : zero_digit;
109 constexpr bigint &operator=(std::integral
auto value)
noexcept
111 static_assert(
sizeof(value) <=
sizeof(digit_type));
112 static_assert(num_digits > 0);
114 if constexpr (std::is_signed_v<
decltype(value)>) {
116 digits[0] =
static_cast<digit_type
>(
static_cast<signed_digit_type
>(value));
118 digits[0] =
static_cast<digit_type
>(value);
122 hilet sign = value < 0 ? min1_digit : zero_digit;
129 constexpr explicit bigint(std::string_view str,
int base = 10) noexcept : bigint()
132 for (; i < str.size(); ++i) {
134 (*this) += base16::int_from_char<int>(str[i]);
138 constexpr explicit operator unsigned long long() const noexcept
140 return truncate<unsigned long long>(digits[0]);
142 constexpr explicit operator signed long long() const noexcept
144 return truncate<signed long long>(digits[0]);
146 constexpr explicit operator unsigned long() const noexcept
148 return truncate<unsigned long>(digits[0]);
150 constexpr explicit operator signed long() const noexcept
152 return truncate<signed long>(digits[0]);
154 constexpr explicit operator unsigned int() const noexcept
156 return truncate<unsigned int>(digits[0]);
158 constexpr explicit operator signed int() const noexcept
160 return truncate<signed int>(digits[0]);
162 constexpr explicit operator unsigned short() const noexcept
164 return truncate<unsigned short>(digits[0]);
166 constexpr explicit operator signed short() const noexcept
168 return truncate<signed short>(digits[0]);
170 constexpr explicit operator unsigned char() const noexcept
172 return truncate<unsigned char>(digits[0]);
174 constexpr explicit operator signed char() const noexcept
176 return truncate<signed char>(digits[0]);
179 constexpr explicit operator bool() const noexcept
182 if (digits[i] != 0) {
189 [[nodiscard]]
constexpr bool is_negative() const noexcept
191 if constexpr (is_signed and num_digits > 0) {
192 return static_cast<signed_digit_type
>(digits[num_digits - 1]) < 0;
198 template<std::
size_t N,
bool S>
199 constexpr explicit operator bigint<digit_type, N, S>() const noexcept
201 auto r = bigint<digit_type, N, S>{};
203 hilet sign = is_negative() ? min1_digit : zero_digit;
204 for (
auto i = 0; i != N; ++i) {
205 r.digits[i] = i < num_digits ? digits[i] : sign;
212 constexpr auto oneOver10 = reciprocal(bigint<digit_type, num_digits * 2, is_signed>{10});
223 std::tie(tmp, remainder) =
div(tmp, bigint{10}, oneOver10);
224 r += (
static_cast<unsigned char>(
remainder) +
'0');
235 std::is_same_v<digit_type, uint64_t> && num_digits == 2,
236 "uuid_string should only be called on a uuid compatible type");
238 "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
239 static_cast<uint32_t
>(digits[1] >> 32),
240 static_cast<uint16_t
>(digits[1] >> 16),
241 static_cast<uint16_t
>(digits[1]),
242 static_cast<uint16_t
>(digits[0] >> 48),
243 digits[0] & 0x0000ffff'ffffffffULL);
246 [[nodiscard]]
constexpr bigint operator-() const noexcept
249 neg_carry_chain(r.digits, digits, num_digits);
253 constexpr bigint &operator<<=(
std::size_t rhs)
noexcept
255 sll_carry_chain(digits, digits, rhs, num_digits);
259 constexpr bigint &operator>>=(
std::size_t rhs)
noexcept
261 if constexpr (is_signed) {
262 sra_carry_chain(digits, digits, rhs, num_digits);
264 srl_carry_chain(digits, digits, rhs, num_digits);
269 constexpr bigint &operator*=(bigint
const &rhs)
noexcept
272 mul_carry_chain(r.digits, digits, rhs.digits, num_digits);
277 constexpr bigint &operator+=(bigint
const &rhs)
noexcept
279 add_carry_chain(digits, digits, rhs.digits, num_digits);
283 constexpr bigint &operator-=(bigint
const &rhs)
noexcept
285 sub_carry_chain(digits, digits, rhs.digits, num_digits);
289 constexpr bigint &operator&=(bigint
const &rhs)
noexcept
291 and_carry_chain(digits, digits, rhs.digits, num_digits);
295 constexpr bigint &operator|=(bigint
const &rhs)
noexcept
297 or_carry_chain(digits, digits, rhs.digits, num_digits);
301 constexpr bigint &operator^=(bigint
const &rhs)
noexcept
303 xor_carry_chain(digits, digits, rhs.digits, num_digits);
307 static bigint from_big_endian(uint8_t
const *data)
noexcept
312 for (ssize_t i = narrow_cast<ssize_t>(num_digits) - 1; i >= 0; i--) {
314 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
323 static bigint from_little_endian(uint8_t
const *data)
noexcept
326 for (
int i = 0; i < num_digits; ++i) {
328 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
329 d |=
static_cast<digit_type
>(*(data++)) << (j * 8);
336 static bigint from_big_endian(
void const *data)
noexcept
338 return from_big_endian(
static_cast<uint8_t
const *
>(data));
341 static bigint from_little_endian(
void const *data)
noexcept
343 return from_little_endian(
static_cast<uint8_t
const *
>(data));
353 hilet polynomialOrder = bsr_carry_chain(rhs.digits, rhs.num_digits);
359 auto tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
360 while (tmp_highest_bit >= polynomialOrder) {
361 hilet divident = rhs_ << (tmp_highest_bit - polynomialOrder);
364 tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
367 return static_cast<bigint>(tmp);
380 r.digits[num_digits] = 1;
381 return static_cast<bigint>(r / rhs);
384 [[nodiscard]]
constexpr friend bool operator==(
bigint const &lhs,
bigint const &rhs)
noexcept
386 return eq_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
389 [[nodiscard]]
constexpr friend std::strong_ordering operator<=>(bigint
const &lhs, bigint
const &rhs)
noexcept
391 if constexpr (lhs.is_signed or rhs.is_signed) {
392 return cmp_signed_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
394 return cmp_unsigned_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
398 [[nodiscard]]
constexpr friend bigint operator<<(bigint
const &lhs,
std::size_t rhs)
noexcept
401 sll_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
405 [[nodiscard]]
constexpr friend bigint operator>>(bigint
const &lhs,
std::size_t rhs)
noexcept
408 if constexpr (lhs.is_signed) {
409 sra_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
411 srl_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
416 [[nodiscard]]
constexpr friend bigint operator*(bigint
const &lhs, bigint
const &rhs)
noexcept
419 mul_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
423 [[nodiscard]]
constexpr friend bigint operator+(bigint
const &lhs, bigint
const &rhs)
noexcept
426 add_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
430 [[nodiscard]]
constexpr friend bigint operator-(bigint
const &lhs, bigint
const &rhs)
noexcept
433 sub_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
437 [[nodiscard]]
constexpr friend bigint operator~(bigint
const &rhs)
noexcept
440 invert_carry_chain(r.digits, rhs.digits, rhs.num_digits);
444 [[nodiscard]]
constexpr friend bigint operator|(bigint
const &lhs, bigint
const &rhs)
noexcept
447 or_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
451 [[nodiscard]]
constexpr friend bigint operator&(bigint
const &lhs, bigint
const &rhs)
noexcept
454 and_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
458 [[nodiscard]]
constexpr friend bigint operator^(bigint
const &lhs, bigint
const &rhs)
noexcept
461 xor_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
467 auto quotient = bigint{};
470 if constexpr (is_signed) {
471 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
473 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
479 div(bigint
const &lhs, bigint
const &rhs, bigint<digit_type, 2 * num_digits, is_signed>
const &rhs_reciprocal)
noexcept
480 requires(not is_signed)
482 constexpr auto nr_bits = num_digits * bits_per_digit;
484 using bigint_x3_type = bigint<digit_type, 3 * num_digits, is_signed>;
486 auto quotient = bigint_x3_type{lhs} * bigint_x3_type{rhs_reciprocal};
487 quotient >>= (2 * nr_bits);
489 auto product = bigint_x3_type{quotient} * bigint_x3_type{rhs};
495 while (remainder >= rhs) {
497 return div(lhs, rhs);
503 return std::pair{
static_cast<bigint
>(quotient),
static_cast<bigint
>(remainder)};
506 [[nodiscard]]
constexpr friend bigint operator/(bigint
const &lhs, bigint
const &rhs)
noexcept
508 auto quotient = bigint{};
511 if constexpr (is_signed) {
512 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
514 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
519 [[nodiscard]]
constexpr friend bigint operator%(bigint
const &lhs, bigint
const &rhs)
noexcept
521 auto quotient = bigint{};
524 if constexpr (is_signed) {
525 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
527 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
534 return lhs << rhs.string();