@@ -240,15 +240,30 @@ struct uint128 {
240240 uint64_t hi;
241241 uint64_t lo;
242242
243- [[ZMIJ_MAYBE_UNUSED]] explicit constexpr operator uint64_t () const noexcept {
244- return lo;
245- }
243+ uint128 () = default ;
244+ constexpr uint128 (uint64_t hi, uint64_t lo) noexcept : hi(hi), lo(lo) {}
245+ constexpr uint128 (uint64_t lo) noexcept : hi(0 ), lo(lo) {}
246+
247+ explicit constexpr operator uint64_t () const noexcept { return lo; }
246248
247- [[ZMIJ_MAYBE_UNUSED]] constexpr auto operator >>(int shift) const noexcept
248- -> uint128 {
249- if (shift == 32 ) return {hi >> 32 , (hi << 32 ) | (lo >> 32 )};
250- assert (shift >= 64 && shift < 128 );
251- return {0 , hi >> (shift - 64 )};
249+ constexpr auto operator <<(int s) const noexcept -> uint128 {
250+ if (s == 0 ) return *this ;
251+ if (s < 64 ) return {hi << s | lo >> (64 - s), lo << s};
252+ if (s < 128 ) return {lo << (s - 64 ), 0 };
253+ return {0 , 0 };
254+ }
255+ constexpr auto operator >>(int s) const noexcept -> uint128 {
256+ if (s == 0 ) return *this ;
257+ if (s < 64 ) return {hi >> s, lo >> s | hi << (64 - s)};
258+ if (s < 128 ) return {0 , hi >> (s - 64 )};
259+ return {0 , 0 };
260+ }
261+ constexpr auto operator <(uint128 o) const noexcept -> bool {
262+ return hi != o.hi ? hi < o.hi : lo < o.lo ;
263+ }
264+ auto operator ++() noexcept -> uint128& {
265+ if (++lo == 0 ) ++hi;
266+ return *this ;
252267 }
253268};
254269
@@ -1370,29 +1385,6 @@ struct bigint {
13701385 while (num_limbs > 0 && limbs[num_limbs - 1 ] == 0 ) --num_limbs;
13711386 }
13721387
1373- auto bit (int pos) const noexcept -> uint32_t {
1374- int limb_index = pos >> 5 ;
1375- return limb_index < num_limbs ? (limbs[limb_index] >> (pos & 31 )) & 1 : 0 ;
1376- }
1377-
1378- // Returns true if any bit strictly below `pos` is set.
1379- auto any_below (int pos) const noexcept -> bool {
1380- int limb_index = pos >> 5 , b = pos & 31 ;
1381- for (int i = 0 ; i < limb_index && i < num_limbs; ++i) {
1382- if (limbs[i] != 0 ) return true ;
1383- }
1384- return limb_index < num_limbs &&
1385- (limbs[limb_index] & ((uint32_t (1 ) << b) - 1 )) != 0 ;
1386- }
1387-
1388- void increment () noexcept {
1389- for (int i = 0 ; i < num_limbs; ++i) {
1390- if (++limbs[i] != 0 ) return ; // No carry out of this limb.
1391- }
1392- assert (num_limbs < max_limbs);
1393- limbs[num_limbs++] = 1 ; // Carry into a new top limb.
1394- }
1395-
13961388 // Shifts left by `n`; requires enough spare limbs.
13971389 void shift_left (int n) noexcept {
13981390 assert (n >= 0 );
@@ -1415,33 +1407,6 @@ struct bigint {
14151407 trim ();
14161408 }
14171409
1418- // Shifts right by `n`, rounding to nearest with ties to even.
1419- void shift_right_round (int n) noexcept {
1420- assert (n >= 0 );
1421- if (n == 0 ) return ;
1422- bool round_bit = bit (n - 1 ) != 0 ;
1423- bool sticky = any_below (n - 1 );
1424- int limb_shift = n >> 5 , bit_shift = n & 31 ;
1425- if (limb_shift >= num_limbs) {
1426- num_limbs = 0 ;
1427- } else if (bit_shift == 0 ) {
1428- for (int i = 0 ; i < num_limbs - limb_shift; ++i)
1429- limbs[i] = limbs[i + limb_shift];
1430- num_limbs -= limb_shift;
1431- } else {
1432- int new_size = num_limbs - limb_shift;
1433- for (int i = 0 ; i < new_size - 1 ; ++i) {
1434- uint32_t hi = limbs[i + limb_shift + 1 ] << (32 - bit_shift);
1435- limbs[i] = limbs[i + limb_shift] >> bit_shift | hi;
1436- }
1437- limbs[new_size - 1 ] = limbs[num_limbs - 1 ] >> bit_shift;
1438- num_limbs = new_size;
1439- trim ();
1440- }
1441- bool lsb = num_limbs > 0 && (limbs[0 ] & 1 ) != 0 ;
1442- if (round_bit && (sticky || lsb)) increment ();
1443- }
1444-
14451410 // Divides by 10**9 in place and returns the remainder.
14461411 auto divmod_1e9 () noexcept -> uint32_t {
14471412 uint64_t rem = 0 ;
@@ -1482,6 +1447,20 @@ struct bigint {
14821447 }
14831448};
14841449
1450+ // Returns the 128-bit `value` shifted right by `n` bits (n >= 1), rounded to
1451+ // nearest with ties to even.
1452+ auto shift_right_round (uint128_t value, int n) noexcept -> uint128_t {
1453+ if (n >= 128 ) { // everything shifts out; 2**127 is the only in-range tie
1454+ uint128_t half = uint128_t (1 ) << 127 ;
1455+ return n == 128 && half < value ? uint128_t (1 ) : uint128_t (0 );
1456+ }
1457+ uint128_t q = value >> n;
1458+ uint128_t rem = (value << (128 - n)) >> (128 - n); // discarded low n bits
1459+ uint128_t half = uint128_t (1 ) << (n - 1 );
1460+ if (half < rem || ((uint64_t (q) & 1 ) && !(rem < half))) ++q;
1461+ return q;
1462+ }
1463+
14851464// Emits n's decimal digits (most significant first) ending at `end`, consuming
14861465// n, and returns a pointer to the first (most significant) digit.
14871466auto write_digits (bigint& n, char * end) noexcept -> char* {
@@ -1501,11 +1480,9 @@ auto write_digits(bigint& n, char* end) noexcept -> char* {
15011480// digits, correctly rounded (ties to even) via exact big-integer arithmetic.
15021481auto write_fixed_big (char * buffer, uint64_t bin_sig, int bin_exp,
15031482 int precision) noexcept -> char* {
1504- bigint n (umul128 (bin_sig, pow10s[precision]));
1505- if (bin_exp >= 0 )
1506- n.shift_left (bin_exp);
1507- else
1508- n.shift_right_round (-bin_exp);
1483+ uint128_t product = umul128 (bin_sig, pow10s[precision]);
1484+ bigint n (bin_exp < 0 ? shift_right_round (product, -bin_exp) : product);
1485+ if (bin_exp >= 0 ) n.shift_left (bin_exp);
15091486
15101487 // n <= round(DBL_MAX * 10**18): DBL_MAX has 309 integer digits and precision
15111488 // adds at most 18 more.
0 commit comments