LCOV - code coverage report
Current view: top level - third_party/fast_float - bigint.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 222 0.0 %
Date: 2024-11-21 22:18:42 Functions: 0 36 0.0 %

          Line data    Source code
       1             : #ifndef FASTFLOAT_BIGINT_H
       2             : #define FASTFLOAT_BIGINT_H
       3             : 
       4             : #include <algorithm>
       5             : #include <cstdint>
       6             : #include <climits>
       7             : #include <cstring>
       8             : 
       9             : #include "float_common.h"
      10             : 
      11             : namespace fast_float {
      12             : 
      13             : // the limb width: we want efficient multiplication of double the bits in
      14             : // limb, or for 64-bit limbs, at least 64-bit multiplication where we can
      15             : // extract the high and low parts efficiently. this is every 64-bit
      16             : // architecture except for sparc, which emulates 128-bit multiplication.
      17             : // we might have platforms where `CHAR_BIT` is not 8, so let's avoid
      18             : // doing `8 * sizeof(limb)`.
      19             : #if defined(FASTFLOAT_64BIT) && !defined(__sparc)
      20             : #define FASTFLOAT_64BIT_LIMB 1
      21             : typedef uint64_t limb;
      22             : constexpr size_t limb_bits = 64;
      23             : #else
      24             : #define FASTFLOAT_32BIT_LIMB
      25             : typedef uint32_t limb;
      26             : constexpr size_t limb_bits = 32;
      27             : #endif
      28             : 
      29             : typedef span<limb> limb_span;
      30             : 
      31             : // number of bits in a bigint. this needs to be at least the number
      32             : // of bits required to store the largest bigint, which is
      33             : // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or
      34             : // ~3600 bits, so we round to 4000.
      35             : constexpr size_t bigint_bits = 4000;
      36             : constexpr size_t bigint_limbs = bigint_bits / limb_bits;
      37             : 
      38             : // vector-like type that is allocated on the stack. the entire
      39             : // buffer is pre-allocated, and only the length changes.
      40             : template <uint16_t size> struct stackvec {
      41             :   limb data[size];
      42             :   // we never need more than 150 limbs
      43             :   uint16_t length{0};
      44             : 
      45           0 :   stackvec() = default;
      46             :   stackvec(const stackvec &) = delete;
      47             :   stackvec &operator=(const stackvec &) = delete;
      48             :   stackvec(stackvec &&) = delete;
      49             :   stackvec &operator=(stackvec &&other) = delete;
      50             : 
      51             :   // create stack vector from existing limb span.
      52           0 :   FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
      53           0 :     FASTFLOAT_ASSERT(try_extend(s));
      54           0 :   }
      55             : 
      56           0 :   FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept {
      57             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      58           0 :     return data[index];
      59             :   }
      60           0 :   FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept {
      61             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      62           0 :     return data[index];
      63             :   }
      64             :   // index from the end of the container
      65           0 :   FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept {
      66             :     FASTFLOAT_DEBUG_ASSERT(index < length);
      67           0 :     size_t rindex = length - index - 1;
      68           0 :     return data[rindex];
      69             :   }
      70             : 
      71             :   // set the length, without bounds checking.
      72           0 :   FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
      73           0 :     length = uint16_t(len);
      74           0 :   }
      75           0 :   constexpr size_t len() const noexcept { return length; }
      76           0 :   constexpr bool is_empty() const noexcept { return length == 0; }
      77           0 :   constexpr size_t capacity() const noexcept { return size; }
      78             :   // append item to vector, without bounds checking
      79           0 :   FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
      80           0 :     data[length] = value;
      81           0 :     length++;
      82           0 :   }
      83             :   // append item to vector, returning if item was added
      84           0 :   FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
      85           0 :     if (len() < capacity()) {
      86           0 :       push_unchecked(value);
      87           0 :       return true;
      88             :     } else {
      89           0 :       return false;
      90             :     }
      91             :   }
      92             :   // add items to the vector, from a span, without bounds checking
      93           0 :   FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
      94           0 :     limb *ptr = data + length;
      95           0 :     std::copy_n(s.ptr, s.len(), ptr);
      96           0 :     set_len(len() + s.len());
      97           0 :   }
      98             :   // try to add items to the vector, returning if items were added
      99           0 :   FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
     100           0 :     if (len() + s.len() <= capacity()) {
     101           0 :       extend_unchecked(s);
     102           0 :       return true;
     103             :     } else {
     104           0 :       return false;
     105             :     }
     106             :   }
     107             :   // resize the vector, without bounds checking
     108             :   // if the new size is longer than the vector, assign value to each
     109             :   // appended item.
     110             :   FASTFLOAT_CONSTEXPR20
     111           0 :   void resize_unchecked(size_t new_len, limb value) noexcept {
     112           0 :     if (new_len > len()) {
     113           0 :       size_t count = new_len - len();
     114           0 :       limb *first = data + len();
     115           0 :       limb *last = first + count;
     116           0 :       ::std::fill(first, last, value);
     117           0 :       set_len(new_len);
     118             :     } else {
     119           0 :       set_len(new_len);
     120             :     }
     121           0 :   }
     122             :   // try to resize the vector, returning if the vector was resized.
     123           0 :   FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
     124           0 :     if (new_len > capacity()) {
     125           0 :       return false;
     126             :     } else {
     127           0 :       resize_unchecked(new_len, value);
     128           0 :       return true;
     129             :     }
     130             :   }
     131             :   // check if any limbs are non-zero after the given index.
     132             :   // this needs to be done in reverse order, since the index
     133             :   // is relative to the most significant limbs.
     134           0 :   FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept {
     135           0 :     while (index < len()) {
     136           0 :       if (rindex(index) != 0) {
     137           0 :         return true;
     138             :       }
     139           0 :       index++;
     140             :     }
     141           0 :     return false;
     142             :   }
     143             :   // normalize the big integer, so most-significant zero limbs are removed.
     144           0 :   FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
     145           0 :     while (len() > 0 && rindex(0) == 0) {
     146           0 :       length--;
     147             :     }
     148           0 :   }
     149             : };
     150             : 
     151             : fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
     152             : empty_hi64(bool &truncated) noexcept {
     153           0 :   truncated = false;
     154           0 :   return 0;
     155             : }
     156             : 
     157             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
     158             : uint64_hi64(uint64_t r0, bool &truncated) noexcept {
     159           0 :   truncated = false;
     160           0 :   int shl = leading_zeroes(r0);
     161           0 :   return r0 << shl;
     162             : }
     163             : 
     164             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
     165             : uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept {
     166           0 :   int shl = leading_zeroes(r0);
     167           0 :   if (shl == 0) {
     168           0 :     truncated = r1 != 0;
     169           0 :     return r0;
     170             :   } else {
     171           0 :     int shr = 64 - shl;
     172           0 :     truncated = (r1 << shl) != 0;
     173           0 :     return (r0 << shl) | (r1 >> shr);
     174             :   }
     175             : }
     176             : 
     177             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
     178             : uint32_hi64(uint32_t r0, bool &truncated) noexcept {
     179             :   return uint64_hi64(r0, truncated);
     180             : }
     181             : 
     182             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
     183             : uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept {
     184             :   uint64_t x0 = r0;
     185             :   uint64_t x1 = r1;
     186             :   return uint64_hi64((x0 << 32) | x1, truncated);
     187             : }
     188             : 
     189             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
     190             : uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept {
     191             :   uint64_t x0 = r0;
     192             :   uint64_t x1 = r1;
     193             :   uint64_t x2 = r2;
     194             :   return uint64_hi64(x0, (x1 << 32) | x2, truncated);
     195             : }
     196             : 
     197             : // add two small integers, checking for overflow.
     198             : // we want an efficient operation. for msvc, where
     199             : // we don't have built-in intrinsics, this is still
     200             : // pretty fast.
     201             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
     202             : scalar_add(limb x, limb y, bool &overflow) noexcept {
     203             :   limb z;
     204             : // gcc and clang
     205             : #if defined(__has_builtin)
     206             : #if __has_builtin(__builtin_add_overflow)
     207             :   if (!cpp20_and_in_constexpr()) {
     208             :     overflow = __builtin_add_overflow(x, y, &z);
     209             :     return z;
     210             :   }
     211             : #endif
     212             : #endif
     213             : 
     214             :   // generic, this still optimizes correctly on MSVC.
     215           0 :   z = x + y;
     216           0 :   overflow = z < x;
     217           0 :   return z;
     218             : }
     219             : 
     220             : // multiply two small integers, getting both the high and low bits.
     221             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb
     222             : scalar_mul(limb x, limb y, limb &carry) noexcept {
     223             : #ifdef FASTFLOAT_64BIT_LIMB
     224             : #if defined(__SIZEOF_INT128__)
     225             :   // GCC and clang both define it as an extension.
     226           0 :   __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
     227           0 :   carry = limb(z >> limb_bits);
     228           0 :   return limb(z);
     229             : #else
     230             :   // fallback, no native 128-bit integer multiplication with carry.
     231             :   // on msvc, this optimizes identically, somehow.
     232             :   value128 z = full_multiplication(x, y);
     233             :   bool overflow;
     234             :   z.low = scalar_add(z.low, carry, overflow);
     235             :   z.high += uint64_t(overflow); // cannot overflow
     236             :   carry = z.high;
     237             :   return z.low;
     238             : #endif
     239             : #else
     240             :   uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
     241             :   carry = limb(z >> limb_bits);
     242             :   return limb(z);
     243             : #endif
     244             : }
     245             : 
     246             : // add scalar value to bigint starting from offset.
     247             : // used in grade school multiplication
     248             : template <uint16_t size>
     249           0 : inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec<size> &vec, limb y,
     250             :                                                  size_t start) noexcept {
     251           0 :   size_t index = start;
     252           0 :   limb carry = y;
     253             :   bool overflow;
     254           0 :   while (carry != 0 && index < vec.len()) {
     255           0 :     vec[index] = scalar_add(vec[index], carry, overflow);
     256           0 :     carry = limb(overflow);
     257           0 :     index += 1;
     258             :   }
     259           0 :   if (carry != 0) {
     260           0 :     FASTFLOAT_TRY(vec.try_push(carry));
     261             :   }
     262           0 :   return true;
     263             : }
     264             : 
     265             : // add scalar value to bigint.
     266             : template <uint16_t size>
     267             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
     268             : small_add(stackvec<size> &vec, limb y) noexcept {
     269           0 :   return small_add_from(vec, y, 0);
     270             : }
     271             : 
     272             : // multiply bigint by scalar value.
     273             : template <uint16_t size>
     274           0 : inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec<size> &vec,
     275             :                                             limb y) noexcept {
     276           0 :   limb carry = 0;
     277           0 :   for (size_t index = 0; index < vec.len(); index++) {
     278           0 :     vec[index] = scalar_mul(vec[index], y, carry);
     279             :   }
     280           0 :   if (carry != 0) {
     281           0 :     FASTFLOAT_TRY(vec.try_push(carry));
     282             :   }
     283           0 :   return true;
     284             : }
     285             : 
     286             : // add bigint to bigint starting from index.
     287             : // used in grade school multiplication
     288             : template <uint16_t size>
     289           0 : FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec<size> &x, limb_span y,
     290             :                                           size_t start) noexcept {
     291             :   // the effective x buffer is from `xstart..x.len()`, so exit early
     292             :   // if we can't get that current range.
     293           0 :   if (x.len() < start || y.len() > x.len() - start) {
     294           0 :     FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
     295             :   }
     296             : 
     297           0 :   bool carry = false;
     298           0 :   for (size_t index = 0; index < y.len(); index++) {
     299           0 :     limb xi = x[index + start];
     300           0 :     limb yi = y[index];
     301           0 :     bool c1 = false;
     302           0 :     bool c2 = false;
     303           0 :     xi = scalar_add(xi, yi, c1);
     304           0 :     if (carry) {
     305           0 :       xi = scalar_add(xi, 1, c2);
     306             :     }
     307           0 :     x[index + start] = xi;
     308           0 :     carry = c1 | c2;
     309             :   }
     310             : 
     311             :   // handle overflow
     312           0 :   if (carry) {
     313           0 :     FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
     314             :   }
     315           0 :   return true;
     316             : }
     317             : 
     318             : // add bigint to bigint.
     319             : template <uint16_t size>
     320             : fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
     321             : large_add_from(stackvec<size> &x, limb_span y) noexcept {
     322             :   return large_add_from(x, y, 0);
     323             : }
     324             : 
     325             : // grade-school multiplication algorithm
     326             : template <uint16_t size>
     327           0 : FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec<size> &x, limb_span y) noexcept {
     328           0 :   limb_span xs = limb_span(x.data, x.len());
     329           0 :   stackvec<size> z(xs);
     330           0 :   limb_span zs = limb_span(z.data, z.len());
     331             : 
     332           0 :   if (y.len() != 0) {
     333           0 :     limb y0 = y[0];
     334           0 :     FASTFLOAT_TRY(small_mul(x, y0));
     335           0 :     for (size_t index = 1; index < y.len(); index++) {
     336           0 :       limb yi = y[index];
     337           0 :       stackvec<size> zi;
     338           0 :       if (yi != 0) {
     339             :         // re-use the same buffer throughout
     340           0 :         zi.set_len(0);
     341           0 :         FASTFLOAT_TRY(zi.try_extend(zs));
     342           0 :         FASTFLOAT_TRY(small_mul(zi, yi));
     343           0 :         limb_span zis = limb_span(zi.data, zi.len());
     344           0 :         FASTFLOAT_TRY(large_add_from(x, zis, index));
     345             :       }
     346             :     }
     347             :   }
     348             : 
     349           0 :   x.normalize();
     350           0 :   return true;
     351             : }
     352             : 
     353             : // grade-school multiplication algorithm
     354             : template <uint16_t size>
     355           0 : FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec<size> &x, limb_span y) noexcept {
     356           0 :   if (y.len() == 1) {
     357           0 :     FASTFLOAT_TRY(small_mul(x, y[0]));
     358             :   } else {
     359           0 :     FASTFLOAT_TRY(long_mul(x, y));
     360             :   }
     361           0 :   return true;
     362             : }
     363             : 
     364             : template <typename = void> struct pow5_tables {
     365             :   static constexpr uint32_t large_step = 135;
     366             :   static constexpr uint64_t small_power_of_5[] = {
     367             :       1UL,
     368             :       5UL,
     369             :       25UL,
     370             :       125UL,
     371             :       625UL,
     372             :       3125UL,
     373             :       15625UL,
     374             :       78125UL,
     375             :       390625UL,
     376             :       1953125UL,
     377             :       9765625UL,
     378             :       48828125UL,
     379             :       244140625UL,
     380             :       1220703125UL,
     381             :       6103515625UL,
     382             :       30517578125UL,
     383             :       152587890625UL,
     384             :       762939453125UL,
     385             :       3814697265625UL,
     386             :       19073486328125UL,
     387             :       95367431640625UL,
     388             :       476837158203125UL,
     389             :       2384185791015625UL,
     390             :       11920928955078125UL,
     391             :       59604644775390625UL,
     392             :       298023223876953125UL,
     393             :       1490116119384765625UL,
     394             :       7450580596923828125UL,
     395             :   };
     396             : #ifdef FASTFLOAT_64BIT_LIMB
     397             :   constexpr static limb large_power_of_5[] = {
     398             :       1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
     399             :       10482974169319127550UL, 198276706040285095UL};
     400             : #else
     401             :   constexpr static limb large_power_of_5[] = {
     402             :       4279965485U, 329373468U,  4020270615U, 2137533757U, 4287402176U,
     403             :       1057042919U, 1071430142U, 2440757623U, 381945767U,  46164893U};
     404             : #endif
     405             : };
     406             : 
     407             : #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE
     408             : 
     409             : template <typename T> constexpr uint32_t pow5_tables<T>::large_step;
     410             : 
     411             : template <typename T> constexpr uint64_t pow5_tables<T>::small_power_of_5[];
     412             : 
     413             : template <typename T> constexpr limb pow5_tables<T>::large_power_of_5[];
     414             : 
     415             : #endif
     416             : 
     417             : // big integer type. implements a small subset of big integer
     418             : // arithmetic, using simple algorithms since asymptotically
     419             : // faster algorithms are slower for a small number of limbs.
     420             : // all operations assume the big-integer is normalized.
     421             : struct bigint : pow5_tables<> {
     422             :   // storage of the limbs, in little-endian order.
     423             :   stackvec<bigint_limbs> vec;
     424             : 
     425           0 :   FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
     426             :   bigint(const bigint &) = delete;
     427             :   bigint &operator=(const bigint &) = delete;
     428             :   bigint(bigint &&) = delete;
     429             :   bigint &operator=(bigint &&other) = delete;
     430             : 
     431           0 :   FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() {
     432             : #ifdef FASTFLOAT_64BIT_LIMB
     433           0 :     vec.push_unchecked(value);
     434             : #else
     435             :     vec.push_unchecked(uint32_t(value));
     436             :     vec.push_unchecked(uint32_t(value >> 32));
     437             : #endif
     438           0 :     vec.normalize();
     439           0 :   }
     440             : 
     441             :   // get the high 64 bits from the vector, and if bits were truncated.
     442             :   // this is to get the significant digits for the float.
     443           0 :   FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept {
     444             : #ifdef FASTFLOAT_64BIT_LIMB
     445           0 :     if (vec.len() == 0) {
     446           0 :       return empty_hi64(truncated);
     447           0 :     } else if (vec.len() == 1) {
     448           0 :       return uint64_hi64(vec.rindex(0), truncated);
     449             :     } else {
     450           0 :       uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
     451           0 :       truncated |= vec.nonzero(2);
     452           0 :       return result;
     453             :     }
     454             : #else
     455             :     if (vec.len() == 0) {
     456             :       return empty_hi64(truncated);
     457             :     } else if (vec.len() == 1) {
     458             :       return uint32_hi64(vec.rindex(0), truncated);
     459             :     } else if (vec.len() == 2) {
     460             :       return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
     461             :     } else {
     462             :       uint64_t result =
     463             :           uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
     464             :       truncated |= vec.nonzero(3);
     465             :       return result;
     466             :     }
     467             : #endif
     468             :   }
     469             : 
     470             :   // compare two big integers, returning the large value.
     471             :   // assumes both are normalized. if the return value is
     472             :   // negative, other is larger, if the return value is
     473             :   // positive, this is larger, otherwise they are equal.
     474             :   // the limbs are stored in little-endian order, so we
     475             :   // must compare the limbs in ever order.
     476           0 :   FASTFLOAT_CONSTEXPR20 int compare(const bigint &other) const noexcept {
     477           0 :     if (vec.len() > other.vec.len()) {
     478           0 :       return 1;
     479           0 :     } else if (vec.len() < other.vec.len()) {
     480           0 :       return -1;
     481             :     } else {
     482           0 :       for (size_t index = vec.len(); index > 0; index--) {
     483           0 :         limb xi = vec[index - 1];
     484           0 :         limb yi = other.vec[index - 1];
     485           0 :         if (xi > yi) {
     486           0 :           return 1;
     487           0 :         } else if (xi < yi) {
     488           0 :           return -1;
     489             :         }
     490             :       }
     491           0 :       return 0;
     492             :     }
     493             :   }
     494             : 
     495             :   // shift left each limb n bits, carrying over to the new limb
     496             :   // returns true if we were able to shift all the digits.
     497           0 :   FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept {
     498             :     // Internally, for each item, we shift left by n, and add the previous
     499             :     // right shifted limb-bits.
     500             :     // For example, we transform (for u8) shifted left 2, to:
     501             :     //      b10100100 b01000010
     502             :     //      b10 b10010001 b00001000
     503             :     FASTFLOAT_DEBUG_ASSERT(n != 0);
     504             :     FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);
     505             : 
     506           0 :     size_t shl = n;
     507           0 :     size_t shr = limb_bits - shl;
     508           0 :     limb prev = 0;
     509           0 :     for (size_t index = 0; index < vec.len(); index++) {
     510           0 :       limb xi = vec[index];
     511           0 :       vec[index] = (xi << shl) | (prev >> shr);
     512           0 :       prev = xi;
     513             :     }
     514             : 
     515           0 :     limb carry = prev >> shr;
     516           0 :     if (carry != 0) {
     517           0 :       return vec.try_push(carry);
     518             :     }
     519           0 :     return true;
     520             :   }
     521             : 
     522             :   // move the limbs left by `n` limbs.
     523           0 :   FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept {
     524             :     FASTFLOAT_DEBUG_ASSERT(n != 0);
     525           0 :     if (n + vec.len() > vec.capacity()) {
     526           0 :       return false;
     527           0 :     } else if (!vec.is_empty()) {
     528             :       // move limbs
     529           0 :       limb *dst = vec.data + n;
     530           0 :       const limb *src = vec.data;
     531           0 :       std::copy_backward(src, src + vec.len(), dst + vec.len());
     532             :       // fill in empty limbs
     533           0 :       limb *first = vec.data;
     534           0 :       limb *last = first + n;
     535           0 :       ::std::fill(first, last, 0);
     536           0 :       vec.set_len(n + vec.len());
     537           0 :       return true;
     538             :     } else {
     539           0 :       return true;
     540             :     }
     541             :   }
     542             : 
     543             :   // move the limbs left by `n` bits.
     544           0 :   FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
     545           0 :     size_t rem = n % limb_bits;
     546           0 :     size_t div = n / limb_bits;
     547           0 :     if (rem != 0) {
     548           0 :       FASTFLOAT_TRY(shl_bits(rem));
     549             :     }
     550           0 :     if (div != 0) {
     551           0 :       FASTFLOAT_TRY(shl_limbs(div));
     552             :     }
     553           0 :     return true;
     554             :   }
     555             : 
     556             :   // get the number of leading zeros in the bigint.
     557           0 :   FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept {
     558           0 :     if (vec.is_empty()) {
     559           0 :       return 0;
     560             :     } else {
     561             : #ifdef FASTFLOAT_64BIT_LIMB
     562           0 :       return leading_zeroes(vec.rindex(0));
     563             : #else
     564             :       // no use defining a specialized leading_zeroes for a 32-bit type.
     565             :       uint64_t r0 = vec.rindex(0);
     566             :       return leading_zeroes(r0 << 32);
     567             : #endif
     568             :     }
     569             :   }
     570             : 
     571             :   // get the number of bits in the bigint.
     572           0 :   FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept {
     573           0 :     int lz = ctlz();
     574           0 :     return int(limb_bits * vec.len()) - lz;
     575             :   }
     576             : 
     577           0 :   FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); }
     578             : 
     579           0 :   FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); }
     580             : 
     581             :   // multiply as if by 2 raised to a power.
     582           0 :   FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); }
     583             : 
     584             :   // multiply as if by 5 raised to a power.
     585           0 :   FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
     586             :     // multiply by a power of 5
     587           0 :     size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
     588           0 :     limb_span large = limb_span(large_power_of_5, large_length);
     589           0 :     while (exp >= large_step) {
     590           0 :       FASTFLOAT_TRY(large_mul(vec, large));
     591           0 :       exp -= large_step;
     592             :     }
     593             : #ifdef FASTFLOAT_64BIT_LIMB
     594           0 :     uint32_t small_step = 27;
     595           0 :     limb max_native = 7450580596923828125UL;
     596             : #else
     597             :     uint32_t small_step = 13;
     598             :     limb max_native = 1220703125U;
     599             : #endif
     600           0 :     while (exp >= small_step) {
     601           0 :       FASTFLOAT_TRY(small_mul(vec, max_native));
     602           0 :       exp -= small_step;
     603             :     }
     604           0 :     if (exp != 0) {
     605             :       // Work around clang bug https://godbolt.org/z/zedh7rrhc
     606             :       // This is similar to https://github.com/llvm/llvm-project/issues/47746,
     607             :       // except the workaround described there don't work here
     608           0 :       FASTFLOAT_TRY(small_mul(
     609             :           vec, limb(((void)small_power_of_5[0], small_power_of_5[exp]))));
     610             :     }
     611             : 
     612           0 :     return true;
     613             :   }
     614             : 
     615             :   // multiply as if by 10 raised to a power.
     616           0 :   FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept {
     617           0 :     FASTFLOAT_TRY(pow5(exp));
     618           0 :     return pow2(exp);
     619             :   }
     620             : };
     621             : 
     622             : } // namespace fast_float
     623             : 
     624             : #endif

Generated by: LCOV version 1.14