31 constexpr uint128_t() noexcept :
low{0},
high{0} {}
34 :
low{
static_cast<std::uint64_t
>(value)},
35 high{value < 0 ? UINT64_MAX : 0} {}
38 :
low{
static_cast<std::uint64_t
>(value)},
high{0} {}
43 :
low{
static_cast<std::uint64_t
>(value)},
44 high{value < 0 ? UINT64_MAX : 0} {}
46 constexpr uint128_t(std::uint64_t high_part, std::uint64_t low_part) noexcept
47 :
low{low_part},
high{high_part} {}
49 constexpr explicit operator std::uint64_t() const noexcept {
52 constexpr explicit operator std::int64_t() const noexcept {
53 return static_cast<std::int64_t
>(this->
low);
56 constexpr explicit operator bool() const noexcept {
57 return this->
low != 0 || this->
high != 0;
60 constexpr auto operator+=(
const uint128_t &other)
noexcept -> uint128_t & {
61 auto old_low = this->
low;
62 this->
low += other.low;
63 this->
high += other.high + (this->
low < old_low ? 1 : 0);
67 constexpr auto operator-=(
const uint128_t &other)
noexcept -> uint128_t & {
68 const auto old_low = this->
low;
69 this->
low -= other.low;
70 this->
high -= other.high + (old_low < other.low ? 1 : 0);
74 constexpr auto operator*=(
const uint128_t &other)
noexcept -> uint128_t & {
75 *
this = *
this * other;
79 constexpr auto operator%=(
const uint128_t &other)
noexcept -> uint128_t & {
80 *
this = *
this % other;
84 friend constexpr auto operator+(uint128_t left,
85 const uint128_t &right)
noexcept
91 friend constexpr auto operator-(uint128_t left,
92 const uint128_t &right)
noexcept
98 friend constexpr auto operator*(
const uint128_t &left,
99 const uint128_t &right)
noexcept
101 std::uint64_t result_high;
102 std::uint64_t result_low;
107 result_low = _umul128(left.low, right.low, &result_high);
111 const std::uint64_t left_low{left.low & 0xFFFFFFFF};
112 const std::uint64_t left_high{left.low >> 32};
113 const std::uint64_t right_low{right.low & 0xFFFFFFFF};
114 const std::uint64_t right_high{right.low >> 32};
115 const std::uint64_t cross_1{left_high * right_low};
116 const std::uint64_t cross_2{left_low * right_high};
117 const std::uint64_t mid{cross_1 + (left_low * right_low >> 32)};
118 const std::uint64_t mid_2{(mid & 0xFFFFFFFF) + cross_2};
119 result_high = left_high * right_high + (mid >> 32) + (mid_2 >> 32);
120 result_low = (mid_2 << 32) | ((left_low * right_low) & 0xFFFFFFFF);
122 result_high += left.low * right.high + left.high * right.low;
123 return {result_high, result_low};
126 friend constexpr auto operator/(
const uint128_t ÷nd,
127 std::uint64_t divisor)
noexcept -> uint128_t {
128 if (dividend.high == 0) {
129 return {0, dividend.low / divisor};
132 auto quotient_high = dividend.high / divisor;
133 auto remainder_high = dividend.high % divisor;
134 std::uint64_t quotient_low;
138 assert(remainder_high < divisor);
143 std::uint64_t remainder;
145 _udiv128(remainder_high, dividend.low, divisor, &remainder);
150 auto current_remainder = remainder_high;
151 for (
int bit = 63; bit >= 0; --bit) {
152 const auto carry = current_remainder >> 63;
154 (current_remainder << 1) | ((dividend.low >> bit) & 1);
155 if (carry || current_remainder >= divisor) {
156 current_remainder -= divisor;
157 quotient_low |=
static_cast<std::uint64_t
>(1) << bit;
161 return {quotient_high, quotient_low};
164 friend constexpr auto operator/(
const uint128_t ÷nd,
165 const uint128_t &divisor)
noexcept
167 assert(divisor.high == 0);
168 return dividend / divisor.low;
171 friend constexpr auto operator%(
const uint128_t ÷nd,
172 std::uint64_t divisor)
noexcept -> uint128_t {
173 if (dividend.high == 0) {
174 return {0, dividend.low % divisor};
177 auto remainder_high = dividend.high % divisor;
178 std::uint64_t remainder;
182 assert(remainder_high < divisor);
187 _udiv128(remainder_high, dividend.low, divisor, &remainder);
191 remainder = remainder_high;
192 for (
int bit = 63; bit >= 0; --bit) {
193 const auto carry = remainder >> 63;
194 remainder = (remainder << 1) | ((dividend.low >> bit) & 1);
195 if (carry || remainder >= divisor) {
196 remainder -= divisor;
200 return {0, remainder};
203 friend constexpr auto operator%(
const uint128_t ÷nd,
204 const uint128_t &divisor)
noexcept
206 assert(divisor.high == 0);
207 return dividend % divisor.low;
210 friend constexpr auto operator<(
const uint128_t &left,
211 const uint128_t &right)
noexcept ->
bool {
212 return left.high < right.high ||
213 (left.high == right.high && left.low < right.low);
216 friend constexpr auto operator>(
const uint128_t &left,
217 const uint128_t &right)
noexcept ->
bool {
221 friend constexpr auto operator<=(
const uint128_t &left,
222 const uint128_t &right)
noexcept ->
bool {
223 return !(right < left);
226 friend constexpr auto operator>=(
const uint128_t &left,
227 const uint128_t &right)
noexcept ->
bool {
228 return !(left < right);
231 friend constexpr auto operator==(
const uint128_t &left,
232 const uint128_t &right)
noexcept ->
bool {
233 return left.high == right.high && left.low == right.low;
236 friend constexpr auto operator!=(
const uint128_t &left,
237 const uint128_t &right)
noexcept ->
bool {
238 return !(left == right);
241 friend constexpr auto operator<<(
const uint128_t &value,
int shift)
noexcept
245 }
else if (shift >= 128) {
247 }
else if (shift >= 64) {
248 return {value.low << (shift - 64), 0};
250 return {(value.high << shift) | (value.low >> (64 - shift)),
255 friend constexpr auto operator>>(
const uint128_t &value,
int shift)
noexcept
259 }
else if (shift >= 128) {
261 }
else if (shift >= 64) {
262 return {0, value.high >> (shift - 64)};
264 return {value.high >> shift,
265 (value.low >> shift) | (value.high << (64 - shift))};
269 friend constexpr auto operator|(
const uint128_t &left,
270 const uint128_t &right)
noexcept
272 return {left.high | right.high, left.low | right.low};
275 constexpr auto operator|=(
const uint128_t &other)
noexcept -> uint128_t & {
276 this->
high |= other.high;
277 this->
low |= other.low;
281 friend constexpr auto operator&(
const uint128_t &left,
282 const uint128_t &right)
noexcept
284 return {left.high & right.high, left.low & right.low};