8#include "../bitop/get_msb.hpp"
16 const uint64_t a_lo =
a & 0xffffffffULL;
17 const uint64_t a_hi =
a >> 32ULL;
18 const uint64_t b_lo =
b & 0xffffffffULL;
19 const uint64_t b_hi =
b >> 32ULL;
21 const uint64_t lo_lo = a_lo * b_lo;
22 const uint64_t hi_lo = a_hi * b_lo;
23 const uint64_t lo_hi = a_lo * b_hi;
24 const uint64_t hi_hi = a_hi * b_hi;
26 const uint64_t cross = (lo_lo >> 32ULL) + (hi_lo & 0xffffffffULL) + lo_hi;
28 return { (cross << 32ULL) | (lo_lo & 0xffffffffULL), (hi_lo >> 32ULL) + (cross >> 32ULL) + hi_hi };
34 const uint64_t
sum =
a +
b;
35 const auto carry_temp =
static_cast<uint64_t
>(
sum <
a);
36 const uint64_t r =
sum + carry_in;
37 const uint64_t carry_out = carry_temp +
static_cast<uint64_t
>(r < carry_in);
38 return { r, carry_out };
43 return a +
b + carry_in;
48 const uint64_t t_1 =
a - (borrow_in >> 63ULL);
49 const auto borrow_temp_1 =
static_cast<uint64_t
>(t_1 >
a);
50 const uint64_t t_2 = t_1 -
b;
51 const auto borrow_temp_2 =
static_cast<uint64_t
>(t_2 > t_1);
53 return { t_2, 0ULL - (borrow_temp_1 | borrow_temp_2) };
58 return a -
b - (borrow_in >> 63ULL);
65 const uint64_t carry_in)
69 const auto overflow_c =
static_cast<uint64_t
>(
result.first <
a);
71 const auto overflow_carry =
static_cast<uint64_t
>(
result.first < carry_in);
72 result.second += (overflow_c + overflow_carry);
79 const uint64_t carry_in)
81 return (
b * c +
a + carry_in);
83#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
90 const uint64_t* right_limbs,
101 result_0 += left_limb * right_limbs[0];
102 result_1 += left_limb * right_limbs[1];
103 result_2 += left_limb * right_limbs[2];
104 result_3 += left_limb * right_limbs[3];
105 result_4 += left_limb * right_limbs[4];
106 result_5 += left_limb * right_limbs[5];
107 result_6 += left_limb * right_limbs[6];
108 result_7 += left_limb * right_limbs[7];
109 result_8 += left_limb * right_limbs[8];
120 data[0] & 0x1fffffff,
121 (
data[0] >> 29) & 0x1fffffff,
122 ((
data[0] >> 58) & 0x3f) |
123 ((
data[1] & 0x7fffff) << 6),
124 (
data[1] >> 23) & 0x1fffffff,
125 ((
data[1] >> 52) & 0xfff) |
126 ((
data[2] & 0x1ffff) << 12),
127 (
data[2] >> 17) & 0x1fffffff,
128 ((
data[2] >> 46) & 0x3ffff) |
129 ((
data[3] & 0x7ff) << 18),
130 (
data[3] >> 11) & 0x1fffffff,
131 (
data[3] >> 40) & 0x1fffffff
156 uint64_t bit_difference =
get_msb() -
b.get_msb();
162 if (divisor > remainder) {
169 while (remainder >=
b) {
173 if (remainder >= divisor) {
174 remainder -= divisor;
177 quotient |= accumulator;
183 return { quotient, remainder };
205#if !defined(__wasm__)
207 uint64_t remainder = 0;
208 for (
int i = 3; i >= 0; --i) {
210 quotient.
data[i] =
static_cast<uint64_t
>(cur /
b);
211 remainder =
static_cast<uint64_t
>(cur %
b);
213 return { quotient, remainder };
217 return { q,
static_cast<uint64_t
>(r.data[0]) };
227#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
229 const auto [q0, t1] =
mac(t0,
data[0], other.
data[1], 0);
230 const auto [q1, t2] =
mac(t1,
data[0], other.
data[2], 0);
231 const auto [q2, z0] =
mac(t2,
data[0], other.
data[3], 0);
233 const auto [r1, t3] =
mac(q0,
data[1], other.
data[0], 0);
234 const auto [q3, t4] =
mac(q1,
data[1], other.
data[1], t3);
235 const auto [q4, t5] =
mac(q2,
data[1], other.
data[2], t4);
236 const auto [q5, z1] =
mac(z0,
data[1], other.
data[3], t5);
238 const auto [r2, t6] =
mac(q3,
data[2], other.
data[0], 0);
239 const auto [q6, t7] =
mac(q4,
data[2], other.
data[1], t6);
240 const auto [q7, t8] =
mac(q5,
data[2], other.
data[2], t7);
241 const auto [q8, z2] =
mac(z1,
data[2], other.
data[3], t8);
243 const auto [r3, t9] =
mac(q6,
data[3], other.
data[0], 0);
244 const auto [r4, t10] =
mac(q7,
data[3], other.
data[1], t9);
245 const auto [r5, t11] =
mac(q8,
data[3], other.
data[2], t10);
246 const auto [r6, r7] =
mac(z2,
data[3], other.
data[3], t11);
255 constexpr uint64_t mask = 0x1fffffff;
275 wasm_madd(left[0], &right[0],
temp_0,
temp_1,
temp_2,
temp_3,
temp_4,
temp_5,
temp_6,
temp_7,
temp_8);
276 wasm_madd(left[1], &right[0],
temp_1,
temp_2,
temp_3,
temp_4,
temp_5,
temp_6,
temp_7,
temp_8,
temp_9);
277 wasm_madd(left[2], &right[0],
temp_2,
temp_3,
temp_4,
temp_5,
temp_6,
temp_7,
temp_8,
temp_9,
temp_10);
278 wasm_madd(left[3], &right[0],
temp_3,
temp_4,
temp_5,
temp_6,
temp_7,
temp_8,
temp_9,
temp_10,
temp_11);
279 wasm_madd(left[4], &right[0],
temp_4,
temp_5,
temp_6,
temp_7,
temp_8,
temp_9,
temp_10,
temp_11,
temp_12);
280 wasm_madd(left[5], &right[0],
temp_5,
temp_6,
temp_7,
temp_8,
temp_9,
temp_10,
temp_11,
temp_12,
temp_13);
281 wasm_madd(left[6], &right[0],
temp_6,
temp_7,
temp_8,
temp_9,
temp_10,
temp_11,
temp_12,
temp_13,
temp_14);
282 wasm_madd(left[7], &right[0],
temp_7,
temp_8,
temp_9,
temp_10,
temp_11,
temp_12,
temp_13,
temp_14,
temp_15);
283 wasm_madd(left[8], &right[0],
temp_8,
temp_9,
temp_10,
temp_11,
temp_12,
temp_13,
temp_14,
temp_15,
temp_16);
340 assert(start <= end);
341 const uint64_t range = end - start;
343 return ((*
this) >> start) & mask;
350 const uint64_t maximum_set_bit = exponent.
get_msb();
352 for (
int i =
static_cast<int>(maximum_set_bit) - 1; i >= 0; --i) {
353 accumulator *= accumulator;
354 if (exponent.
get_bit(
static_cast<uint64_t
>(i))) {
355 accumulator *= to_mul;
368 if (bit_index > 255) {
369 return static_cast<bool>(0);
371 const auto idx =
static_cast<size_t>(bit_index >> 6);
372 const size_t shift = bit_index & 63;
373 return static_cast<bool>((
data[idx] >>
shift) & 1);
391 return { r0, r1, r2, r3 };
397 const auto [r0, t0] =
sbb(
data[0], other.
data[0], 0);
398 const auto [r1, t1] =
sbb(
data[1], other.
data[1], t0);
399 const auto [r2, t2] =
sbb(
data[2], other.
data[2], t1);
401 return { r0, r1, r2, r3 };
412#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
413 const auto [r0, t0] =
mac(0,
data[0], other.
data[0], 0ULL);
414 const auto [q0, t1] =
mac(0,
data[0], other.
data[1], t0);
415 const auto [q1, t2] =
mac(0,
data[0], other.
data[2], t1);
418 const auto [r1, t3] =
mac(q0,
data[1], other.
data[0], 0ULL);
419 const auto [q3, t4] =
mac(q1,
data[1], other.
data[1], t3);
422 const auto [r2, t5] =
mac(q3,
data[2], other.
data[0], 0ULL);
427 return { r0, r1, r2, r3 };
443 wasm_madd(left[0], &right[0],
temp_0,
temp_1,
temp_2,
temp_3,
temp_4,
temp_5,
temp_6,
temp_7,
temp_8);
445 temp_1 += left[1] * right[0];
446 temp_2 += left[1] * right[1];
447 temp_3 += left[1] * right[2];
448 temp_4 += left[1] * right[3];
449 temp_5 += left[1] * right[4];
450 temp_6 += left[1] * right[5];
451 temp_7 += left[1] * right[6];
452 temp_8 += left[1] * right[7];
454 temp_2 += left[2] * right[0];
455 temp_3 += left[2] * right[1];
456 temp_4 += left[2] * right[2];
457 temp_5 += left[2] * right[3];
458 temp_6 += left[2] * right[4];
459 temp_7 += left[2] * right[5];
460 temp_8 += left[2] * right[6];
461 temp_3 += left[3] * right[0];
462 temp_4 += left[3] * right[1];
463 temp_5 += left[3] * right[2];
464 temp_6 += left[3] * right[3];
465 temp_7 += left[3] * right[4];
466 temp_8 += left[3] * right[5];
467 temp_4 += left[4] * right[0];
468 temp_5 += left[4] * right[1];
469 temp_6 += left[4] * right[2];
470 temp_7 += left[4] * right[3];
471 temp_8 += left[4] * right[4];
472 temp_5 += left[5] * right[0];
473 temp_6 += left[5] * right[1];
474 temp_7 += left[5] * right[2];
475 temp_8 += left[5] * right[3];
476 temp_6 += left[6] * right[0];
477 temp_7 += left[6] * right[1];
478 temp_8 += left[6] * right[2];
479 temp_7 += left[7] * right[0];
480 temp_8 += left[7] * right[1];
481 temp_8 += left[8] * right[0];
484 constexpr uint64_t mask = 0x1fffffff;
512 return divmod(other).first;
517 return divmod(other).second;
537 return { ~data[0], ~data[1], ~data[2], ~data[3] };
547 return !(*
this == other);
562 return t0 || t1 || t2 || t3;
567 return (*
this > other) || (*
this == other);
572 return other > *
this;
577 return (*
this < other) || (*
this == other);
582 uint64_t total_shift = other.
data[0];
584 if (total_shift >= 256 || (other.
data[1] != 0U) || (other.
data[2] != 0U) || (other.
data[3] != 0U)) {
588 if (total_shift == 0) {
592 uint64_t num_shifted_limbs = total_shift >> 6ULL;
593 uint64_t limb_shift = total_shift & 63ULL;
597 if (limb_shift == 0) {
598 shifted_limbs[0] =
data[0];
599 shifted_limbs[1] =
data[1];
600 shifted_limbs[2] =
data[2];
601 shifted_limbs[3] =
data[3];
603 uint64_t remainder_shift = 64ULL - limb_shift;
605 shifted_limbs[3] =
data[3] >> limb_shift;
607 uint64_t remainder = (
data[3]) << remainder_shift;
609 shifted_limbs[2] = (
data[2] >> limb_shift) + remainder;
611 remainder = (
data[2]) << remainder_shift;
613 shifted_limbs[1] = (
data[1] >> limb_shift) + remainder;
615 remainder = (
data[1]) << remainder_shift;
617 shifted_limbs[0] = (
data[0] >> limb_shift) + remainder;
621 for (
size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
622 result.data[i] = shifted_limbs[
static_cast<size_t>(i + num_shifted_limbs)];
630 uint64_t total_shift = other.
data[0];
632 if (total_shift >= 256 || (other.
data[1] != 0U) || (other.
data[2] != 0U) || (other.
data[3] != 0U)) {
636 if (total_shift == 0) {
639 uint64_t num_shifted_limbs = total_shift >> 6ULL;
640 uint64_t limb_shift = total_shift & 63ULL;
644 if (limb_shift == 0) {
645 shifted_limbs[0] =
data[0];
646 shifted_limbs[1] =
data[1];
647 shifted_limbs[2] =
data[2];
648 shifted_limbs[3] =
data[3];
650 uint64_t remainder_shift = 64ULL - limb_shift;
652 shifted_limbs[0] =
data[0] << limb_shift;
654 uint64_t remainder =
data[0] >> remainder_shift;
656 shifted_limbs[1] = (
data[1] << limb_shift) + remainder;
658 remainder =
data[1] >> remainder_shift;
660 shifted_limbs[2] = (
data[2] << limb_shift) + remainder;
662 remainder =
data[2] >> remainder_shift;
664 shifted_limbs[3] = (
data[3] << limb_shift) + remainder;
668 for (
size_t i = 0; i < 4 - num_shifted_limbs; ++i) {
669 result.data[
static_cast<size_t>(i + num_shifted_limbs)] = shifted_limbs[i];
681 uint64_t bin_data[4] = { htonll(
data[3]), htonll(
data[2]), htonll(
data[1]), htonll(
data[0]) };
684 packer.pack_bin(
sizeof(bin_data));
685 packer.pack_bin_body((
const char*)bin_data,
sizeof(bin_data));
692 std::array<uint8_t,
sizeof(
data)> raw_data = o;
696 uint64_t* cast_data = (uint64_t*)&raw_data[0];
697 uint64_t reversed[] = { ntohll(cast_data[3]), ntohll(cast_data[2]), ntohll(cast_data[1]), ntohll(cast_data[0]) };
700 for (
int i = 0; i < 4; i++) {
701 data[i] = reversed[i];
constexpr std::pair< uint256_t, uint256_t > mul_extended(const uint256_t &other) const
Compute the result of multiplication modulu 2**512.
constexpr uint256_t operator^(const uint256_t &other) const
constexpr uint256_t operator~() const
constexpr uint256_t operator%(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > addc(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr uint256_t operator*(const uint256_t &other) const
constexpr uint256_t operator+(const uint256_t &other) const
static constexpr uint64_t sbb_discard_hi(uint64_t a, uint64_t b, uint64_t borrow_in)
static constexpr std::array< uint64_t, WASM_NUM_LIMBS > wasm_convert(const uint64_t *data)
Convert from 4 64-bit limbs to 9 29-bit limbs.
constexpr bool get_bit(uint64_t bit_index) const
void msgpack_unpack(auto o)
constexpr uint256_t() noexcept
constexpr uint256_t operator<<(const uint256_t &other) const
constexpr bool operator!() const
constexpr bool operator==(const uint256_t &other) const
constexpr uint256_t operator&(const uint256_t &other) const
static constexpr void wasm_madd(const uint64_t &left_limb, const uint64_t *right_limbs, uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8)
Multiply one limb by 9 limbs and add to resulting limbs.
constexpr bool operator>(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > mac(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr bool operator<(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > sbb(uint64_t a, uint64_t b, uint64_t borrow_in)
constexpr bool operator>=(const uint256_t &other) const
constexpr uint256_t operator|(const uint256_t &other) const
constexpr bool operator!=(const uint256_t &other) const
constexpr uint256_t operator-() const
static constexpr uint64_t mac_discard_hi(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr uint256_t operator/(const uint256_t &other) const
constexpr uint256_t pow(const uint256_t &exponent) const
constexpr uint256_t slice(uint64_t start, uint64_t end) const
static constexpr std::pair< uint64_t, uint64_t > mul_wide(uint64_t a, uint64_t b)
static constexpr uint64_t addc_discard_hi(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr bool operator<=(const uint256_t &other) const
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
constexpr uint256_t operator>>(const uint256_t &other) const
constexpr uint64_t get_msb() const
void msgpack_pack(auto &packer) const
constexpr T get_msb(const T in)
Inner sum(Cont< Inner, Args... > const &in)
constexpr ScalarIndex shift(ScalarIndex ctx, size_t d)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t
void throw_or_abort(std::string const &err)