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] =
static_cast<digit_type
>(
static_cast<signed_digit_type
>(value));
99 digits[0] =
static_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 static_cast<unsigned long long>(digits[0]);
142 constexpr explicit operator signed long long() const noexcept
144 return static_cast<signed long long>(digits[0]);
146 constexpr explicit operator unsigned long() const noexcept
148 return static_cast<unsigned long>(digits[0]);
150 constexpr explicit operator signed long() const noexcept
152 return static_cast<signed long>(digits[0]);
154 constexpr explicit operator unsigned int() const noexcept
156 return static_cast<unsigned int>(digits[0]);
158 constexpr explicit operator signed int() const noexcept
160 return static_cast<signed int>(digits[0]);
162 constexpr explicit operator unsigned short() const noexcept
164 return static_cast<unsigned short>(digits[0]);
166 constexpr explicit operator signed short() const noexcept
168 return static_cast<signed short>(digits[0]);
170 constexpr explicit operator unsigned char() const noexcept
172 return static_cast<unsigned char>(digits[0]);
174 constexpr explicit operator signed char() const noexcept
176 return static_cast<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
310 for (ssize_t i =
static_cast<ssize_t>(num_digits) - 1; i >= 0; i--) {
312 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
321 static bigint from_little_endian(uint8_t
const *data)
noexcept
324 for (
int i = 0; i < num_digits; ++i) {
326 for (
std::size_t j = 0; j <
sizeof(digit_type); j++) {
327 d |=
static_cast<digit_type
>(*(data++)) << (j * 8);
334 static bigint from_big_endian(
void const *data)
noexcept
336 return from_big_endian(
static_cast<uint8_t
const *
>(data));
339 static bigint from_little_endian(
void const *data)
noexcept
341 return from_little_endian(
static_cast<uint8_t
const *
>(data));
351 hilet polynomialOrder = bsr_carry_chain(rhs.digits, rhs.num_digits);
352 hi_assert(polynomialOrder >= 0);
357 auto tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
358 while (tmp_highest_bit >= polynomialOrder) {
359 hilet divident = rhs_ << (tmp_highest_bit - polynomialOrder);
362 tmp_highest_bit = bsr_carry_chain(tmp.digits, tmp.num_digits);
365 return static_cast<bigint>(tmp);
378 r.digits[num_digits] = 1;
379 return static_cast<bigint>(r / rhs);
382 [[nodiscard]]
constexpr friend bool operator==(
bigint const &lhs,
bigint const &rhs)
noexcept
384 return eq_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
387 [[nodiscard]]
constexpr friend std::strong_ordering operator<=>(bigint
const &lhs, bigint
const &rhs)
noexcept
389 if constexpr (lhs.is_signed or rhs.is_signed) {
390 return cmp_signed_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
392 return cmp_unsigned_carry_chain(lhs.digits, rhs.digits, lhs.num_digits);
396 [[nodiscard]]
constexpr friend bigint operator<<(bigint
const &lhs,
std::size_t rhs)
noexcept
399 sll_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
403 [[nodiscard]]
constexpr friend bigint operator>>(bigint
const &lhs,
std::size_t rhs)
noexcept
406 if constexpr (lhs.is_signed) {
407 sra_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
409 srl_carry_chain(r.digits, lhs.digits, rhs, lhs.num_digits);
414 [[nodiscard]]
constexpr friend bigint operator*(bigint
const &lhs, bigint
const &rhs)
noexcept
417 mul_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
421 [[nodiscard]]
constexpr friend bigint operator+(bigint
const &lhs, bigint
const &rhs)
noexcept
424 add_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
428 [[nodiscard]]
constexpr friend bigint operator-(bigint
const &lhs, bigint
const &rhs)
noexcept
431 sub_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
435 [[nodiscard]]
constexpr friend bigint operator~(bigint
const &rhs)
noexcept
438 invert_carry_chain(r.digits, rhs.digits, rhs.num_digits);
442 [[nodiscard]]
constexpr friend bigint
operator|(bigint
const &lhs, bigint
const &rhs)
noexcept
445 or_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
449 [[nodiscard]]
constexpr friend bigint operator&(bigint
const &lhs, bigint
const &rhs)
noexcept
452 and_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
456 [[nodiscard]]
constexpr friend bigint operator^(bigint
const &lhs, bigint
const &rhs)
noexcept
459 xor_carry_chain(r.digits, lhs.digits, rhs.digits, lhs.num_digits);
465 auto quotient = bigint{};
468 if constexpr (is_signed) {
469 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
471 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
477 div(bigint
const &lhs, bigint
const &rhs, bigint<digit_type, 2 * num_digits, is_signed>
const &rhs_reciprocal)
noexcept
478 requires(not is_signed)
480 constexpr auto nr_bits = num_digits * bits_per_digit;
482 using bigint_x3_type = bigint<digit_type, 3 * num_digits, is_signed>;
484 auto quotient = bigint_x3_type{lhs} * bigint_x3_type{rhs_reciprocal};
485 quotient >>= (2 * nr_bits);
487 auto product = bigint_x3_type{quotient} * bigint_x3_type{rhs};
489 hi_axiom(product <= lhs);
493 while (remainder >= rhs) {
495 return div(lhs, rhs);
501 return std::pair{
static_cast<bigint
>(quotient),
static_cast<bigint
>(remainder)};
504 [[nodiscard]]
constexpr friend bigint operator/(bigint
const &lhs, bigint
const &rhs)
noexcept
506 auto quotient = bigint{};
509 if constexpr (is_signed) {
510 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
512 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
517 [[nodiscard]]
constexpr friend bigint operator%(bigint
const &lhs, bigint
const &rhs)
noexcept
519 auto quotient = bigint{};
522 if constexpr (is_signed) {
523 signed_div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
525 div_carry_chain(quotient.digits,
remainder.digits, lhs.digits, rhs.digits, lhs.num_digits);
532 return lhs << rhs.string();