25 using digit_type = DigitType;
26 using signed_digit_type = std::make_signed_t<digit_type>;
27 constexpr static auto num_digits = NumDigits;
28 constexpr static auto is_signed = IsSigned;
29 constexpr static auto bits_per_digit =
sizeof(digit_type) * CHAR_BIT;
31 constexpr static digit_type zero_digit = 0;
32 constexpr static digit_type min1_digit =
static_cast<digit_type
>(signed_digit_type{-1});
36 digit_type digits[num_digits];
43 digits[i] = zero_digit;
48 constexpr bigint& operator=(
bigint const&)
noexcept =
default;
50 constexpr
bigint& operator=(
bigint&&) noexcept = default;
54 template<
std::
size_t N,
bool S>
56 requires(N < num_digits)
62 digits[i] = rhs.digits[i];
66 auto const sign = rhs.is_negative() ? min1_digit : zero_digit;
67 for (; i != num_digits; ++i) {
74 template<std::
size_t N,
bool S>
76 requires(N < num_digits)
82 digits[i] = rhs.digits[i];
86 auto const sign = rhs.is_negative() ? min1_digit : zero_digit;
87 for (; i != num_digits; ++i) {
93 constexpr bigint(std::integral
auto value)
noexcept
95 static_assert(
sizeof(value) <=
sizeof(digit_type));
96 static_assert(num_digits > 0);
98 if constexpr (std::is_signed_v<
decltype(value)>) {
100 digits[0] = truncate<digit_type>(narrow_cast<signed_digit_type>(value));
102 digits[0] = narrow_cast<digit_type>(value);
106 auto const sign = value < 0 ? min1_digit : zero_digit;
112 constexpr bigint& operator=(std::integral
auto value)
noexcept
114 static_assert(
sizeof(value) <=
sizeof(digit_type));
115 static_assert(num_digits > 0);
117 if constexpr (std::is_signed_v<
decltype(value)>) {
119 digits[0] =
static_cast<digit_type
>(
static_cast<signed_digit_type
>(value));
121 digits[0] =
static_cast<digit_type
>(value);
125 auto const sign = value < 0 ? min1_digit : zero_digit;
132 constexpr explicit bigint(std::string_view str,
int base = 10) : bigint()
134 for (
auto const c : str) {
137 if (c >=
'0' and c <=
'9') {
138 *
this += char_cast<size_t>(c -
'0');
139 }
else if (c >=
'a' and c <=
'f') {
140 *
this += char_cast<size_t>(c -
'a' + 10);
141 }
else if (c >=
'A' and c <=
'F') {
142 *
this += char_cast<size_t>(c -
'A' + 10);
144 throw parse_error(std::format(
"Unexpected character '{}' in string initializing bigint", c));
149 constexpr explicit operator unsigned long long() const noexcept
151 return truncate<unsigned long long>(digits[0]);
153 constexpr explicit operator signed long long() const noexcept
155 return truncate<signed long long>(digits[0]);
157 constexpr explicit operator unsigned long() const noexcept
159 return truncate<unsigned long>(digits[0]);
161 constexpr explicit operator signed long() const noexcept
163 return truncate<signed long>(digits[0]);
165 constexpr explicit operator unsigned int() const noexcept
167 return truncate<unsigned int>(digits[0]);
169 constexpr explicit operator signed int() const noexcept
171 return truncate<signed int>(digits[0]);
173 constexpr explicit operator unsigned short() const noexcept
175 return truncate<unsigned short>(digits[0]);
177 constexpr explicit operator signed short() const noexcept
179 return truncate<signed short>(digits[0]);
181 constexpr explicit operator unsigned char() const noexcept
183 return truncate<unsigned char>(digits[0]);
185 constexpr explicit operator signed char() const noexcept
187 return truncate<signed char>(digits[0]);
190 constexpr explicit operator bool() const noexcept
193 if (digits[i] != 0) {
200 [[nodiscard]]
constexpr bool is_negative() const noexcept
202 if constexpr (is_signed and num_digits > 0) {
203 return static_cast<signed_digit_type
>(digits[num_digits - 1]) < 0;
209 template<std::
size_t N,
bool S>
210 constexpr explicit operator bigint<digit_type, N, S>() const noexcept
212 auto r = bigint<digit_type, N, S>{};
214 auto const sign = is_negative() ? min1_digit : zero_digit;
215 for (
auto i = 0; i != N; ++i) {
216 r.digits[i] = i < num_digits ? digits[i] : sign;
223 constexpr auto oneOver10 = reciprocal(bigint<digit_type, num_digits * 2, is_signed>{10});
234 std::tie(tmp, remainder) =
div(tmp, bigint{10}, oneOver10);
235 r += (
static_cast<unsigned char>(remainder) +
'0');
246 std::is_same_v<digit_type, uint64_t> && num_digits == 2,
247 "uuid_string should only be called on a uuid compatible type");
249 "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
250 static_cast<uint32_t
>(digits[1] >> 32),
251 static_cast<uint16_t
>(digits[1] >> 16),
252 static_cast<uint16_t
>(digits[1]),
253 static_cast<uint16_t
>(digits[0] >> 48),
254 digits[0] & 0x0000ffff'ffffffffULL);
257 [[nodiscard]]
constexpr bigint operator-() const noexcept
260 neg_carry_chain(r.digits, digits, num_digits);
264 constexpr bigint& operator<<=(
std::size_t rhs)
noexcept
266 sll_carry_chain(digits, digits, rhs, num_digits);
270 constexpr bigint& operator>>=(
std::size_t rhs)
noexcept
272 if constexpr (is_signed) {
273 sra_carry_chain(digits, digits, rhs, num_digits);
275 srl_carry_chain(digits, digits, rhs, num_digits);
280 constexpr bigint&
operator*=(bigint
const& rhs)
noexcept
283 mul_carry_chain(r.digits, digits, rhs.digits, num_digits);
288 constexpr bigint& operator+=(bigint
const& rhs)
noexcept
290 add_carry_chain(digits, digits, rhs.digits, num_digits);
294 constexpr bigint& operator-=(bigint
const& rhs)
noexcept
296 sub_carry_chain(digits, digits, rhs.digits, num_digits);
300 constexpr bigint& operator&=(bigint
const& rhs)
noexcept
302 and_carry_chain(digits, digits, rhs.digits, num_digits);
306 constexpr bigint& operator|=(bigint
const& rhs)
noexcept
308 or_carry_chain(digits, digits, rhs.digits, num_digits);
312 constexpr bigint& operator^=(bigint
const& rhs)
noexcept
314 xor_carry_chain(digits, digits, rhs.digits, num_digits);
318 static bigint from_big_endian(uint8_t
const *data)
noexcept
320 hi_axiom_not_null(data);
323 for (ssize_t i = narrow_cast<ssize_t>(num_digits) - 1; i >= 0; i--) {
325 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
334 static bigint from_little_endian(uint8_t
const *data)
noexcept
337 for (
int i = 0; i < num_digits; ++i) {
339 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
340 d |=
static_cast<digit_type
>(*(data++)) << (j * 8);
347 static bigint from_big_endian(
void const *data)
noexcept
349 return from_big_endian(
static_cast<uint8_t
const *
>(data));
352 static bigint from_little_endian(
void const *data)
noexcept
354 return from_little_endian(
static_cast<uint8_t
const *
>(data));
363 requires(not is_signed)
365 auto const polynomialOrder = bsr_carry_chain(rhs.digits, rhs.num_digits);
366 hi_assert(polynomialOrder >= 0);
371 auto tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
372 while (tmp_highest_bit >= polynomialOrder) {
373 auto const divident = rhs_ << (tmp_highest_bit - polynomialOrder);
376 tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
379 return static_cast<bigint>(tmp);
392 r.digits[num_digits] = 1;
393 return static_cast<bigint>(r / rhs);
396 [[nodiscard]]
constexpr friend bool operator==(
bigint const& lhs,
bigint const& rhs)
noexcept
398 return eq_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
401 [[nodiscard]]
constexpr friend std::strong_ordering operator<=>(bigint
const& lhs, bigint
const& rhs)
noexcept
403 if constexpr (lhs.is_signed or rhs.is_signed) {
404 return cmp_signed_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
406 return cmp_unsigned_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
410 [[nodiscard]]
constexpr friend bigint operator<<(bigint
const& lhs,
std::size_t rhs)
noexcept
413 sll_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
417 [[nodiscard]]
constexpr friend bigint operator>>(bigint
const& lhs,
std::size_t rhs)
noexcept
420 if constexpr (lhs.is_signed) {
421 sra_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
423 srl_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
428 [[nodiscard]]
constexpr friend bigint
operator*(bigint
const& lhs, bigint
const& rhs)
noexcept
431 mul_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
435 [[nodiscard]]
constexpr friend bigint operator+(bigint
const& lhs, bigint
const& rhs)
noexcept
438 add_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
442 [[nodiscard]]
constexpr friend bigint operator-(bigint
const& lhs, bigint
const& rhs)
noexcept
445 sub_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
449 [[nodiscard]]
constexpr friend bigint operator~(bigint
const& rhs)
noexcept
452 invert_carry_chain(r.digits, rhs.digits, rhs.num_digits);
456 [[nodiscard]]
constexpr friend bigint operator|(bigint
const& lhs, bigint
const& rhs)
noexcept
459 or_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
463 [[nodiscard]]
constexpr friend bigint operator&(bigint
const& lhs, bigint
const& rhs)
noexcept
466 and_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
470 [[nodiscard]]
constexpr friend bigint operator^(bigint
const& lhs, bigint
const& rhs)
noexcept
473 xor_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
479 auto quotient = bigint{};
480 auto remainder = bigint{};
482 if constexpr (is_signed) {
483 signed_div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
485 div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
491 div(bigint
const& lhs, bigint
const& rhs, bigint<digit_type, 2 * num_digits, is_signed>
const& rhs_reciprocal)
noexcept
492 requires(not is_signed)
494 constexpr auto nr_bits = num_digits * bits_per_digit;
496 using bigint_x3_type = bigint<digit_type, 3 * num_digits, is_signed>;
498 auto quotient = bigint_x3_type{lhs} * bigint_x3_type{rhs_reciprocal};
499 quotient >>= (2 * nr_bits);
501 auto product = bigint_x3_type{quotient} * bigint_x3_type{rhs};
503 hi_axiom(product <= lhs);
504 auto remainder = lhs - product;
507 while (remainder >= rhs) {
509 return div(lhs, rhs);
515 return std::pair{
static_cast<bigint
>(quotient),
static_cast<bigint
>(remainder)};
518 [[nodiscard]]
constexpr friend bigint operator/(bigint
const& lhs, bigint
const& rhs)
noexcept
520 auto quotient = bigint{};
521 auto remainder = bigint{};
523 if constexpr (is_signed) {
524 signed_div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
526 div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
531 [[nodiscard]]
constexpr friend bigint operator%(bigint
const& lhs, bigint
const& rhs)
noexcept
533 auto quotient = bigint{};
534 auto remainder = bigint{};
536 if constexpr (is_signed) {
537 signed_div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
539 div_carry_chain(quotient.digits, remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
546 return lhs << rhs.string();