File indexing completed on 2025-12-13 09:41:39
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP
0009 #define BOOST_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP
0010
0011 #include <boost/charconv/detail/fast_float/float_common.hpp>
0012 #include <algorithm>
0013 #include <cstdint>
0014 #include <climits>
0015 #include <cstring>
0016
0017 namespace boost { namespace charconv { namespace detail { namespace fast_float {
0018
0019
0020
0021
0022
0023
0024
0025 #if defined(BOOST_CHARCONV_FASTFLOAT_64BIT) && !defined(__sparc)
0026 #define BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB 1
0027 typedef uint64_t limb;
0028 constexpr size_t limb_bits = 64;
0029 #else
0030 #define BOOST_CHARCONV_FASTFLOAT_32BIT_LIMB
0031 typedef uint32_t limb;
0032 constexpr size_t limb_bits = 32;
0033 #endif
0034
0035 typedef span<limb> limb_span;
0036
0037
0038
0039
0040
0041 constexpr size_t bigint_bits = 4000;
0042 constexpr size_t bigint_limbs = bigint_bits / limb_bits;
0043
0044
0045
0046 template <uint16_t size>
0047 struct stackvec {
0048 limb data[size];
0049
0050 uint16_t length{0};
0051
0052 stackvec() = default;
0053 stackvec(const stackvec &) = delete;
0054 stackvec &operator=(const stackvec &) = delete;
0055 stackvec(stackvec &&) = delete;
0056 stackvec &operator=(stackvec &&other) = delete;
0057
0058
0059 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
0060 BOOST_CHARCONV_FASTFLOAT_ASSERT(try_extend(s));
0061 }
0062
0063 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 limb& operator[](size_t index) noexcept {
0064 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length);
0065 return data[index];
0066 }
0067 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const limb& operator[](size_t index) const noexcept {
0068 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length);
0069 return data[index];
0070 }
0071
0072 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const limb& rindex(size_t index) const noexcept {
0073 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length);
0074 size_t rindex = length - index - 1;
0075 return data[rindex];
0076 }
0077
0078
0079 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
0080 length = uint16_t(len);
0081 }
0082 constexpr size_t len() const noexcept {
0083 return length;
0084 }
0085 constexpr bool is_empty() const noexcept {
0086 return length == 0;
0087 }
0088 constexpr size_t capacity() const noexcept {
0089 return size;
0090 }
0091
0092 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
0093 data[length] = value;
0094 length++;
0095 }
0096
0097 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
0098 if (len() < capacity()) {
0099 push_unchecked(value);
0100 return true;
0101 } else {
0102 return false;
0103 }
0104 }
0105
0106 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
0107 limb* ptr = data + length;
0108 std::copy_n(s.ptr, s.len(), ptr);
0109 set_len(len() + s.len());
0110 }
0111
0112 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
0113 if (len() + s.len() <= capacity()) {
0114 extend_unchecked(s);
0115 return true;
0116 } else {
0117 return false;
0118 }
0119 }
0120
0121
0122
0123 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0124 void resize_unchecked(size_t new_len, limb value) noexcept {
0125 if (new_len > len()) {
0126 size_t count = new_len - len();
0127 limb* first = data + len();
0128 limb* last = first + count;
0129 ::std::fill(first, last, value);
0130 set_len(new_len);
0131 } else {
0132 set_len(new_len);
0133 }
0134 }
0135
0136 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
0137 if (new_len > capacity()) {
0138 return false;
0139 } else {
0140 resize_unchecked(new_len, value);
0141 return true;
0142 }
0143 }
0144
0145
0146
0147 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept {
0148 while (index < len()) {
0149 if (rindex(index) != 0) {
0150 return true;
0151 }
0152 index++;
0153 }
0154 return false;
0155 }
0156
0157 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
0158 while (len() > 0 && rindex(0) == 0) {
0159 length--;
0160 }
0161 }
0162 };
0163
0164 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14
0165 uint64_t empty_hi64(bool& truncated) noexcept {
0166 truncated = false;
0167 return 0;
0168 }
0169
0170 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0171 uint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept {
0172 truncated = false;
0173 int shl = leading_zeroes(r0);
0174 return r0 << shl;
0175 }
0176
0177 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0178 uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {
0179 int shl = leading_zeroes(r0);
0180 if (shl == 0) {
0181 truncated = r1 != 0;
0182 return r0;
0183 } else {
0184 int shr = 64 - shl;
0185 truncated = (r1 << shl) != 0;
0186 return (r0 << shl) | (r1 >> shr);
0187 }
0188 }
0189
0190 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0191 uint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept {
0192 return uint64_hi64(r0, truncated);
0193 }
0194
0195 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0196 uint64_t uint32_hi64(uint32_t r0, uint32_t r1, bool& truncated) noexcept {
0197 uint64_t x0 = r0;
0198 uint64_t x1 = r1;
0199 return uint64_hi64((x0 << 32) | x1, truncated);
0200 }
0201
0202 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0203 uint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noexcept {
0204 uint64_t x0 = r0;
0205 uint64_t x1 = r1;
0206 uint64_t x2 = r2;
0207 return uint64_hi64(x0, (x1 << 32) | x2, truncated);
0208 }
0209
0210
0211
0212
0213
0214 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0215 limb scalar_add(limb x, limb y, bool& overflow) noexcept {
0216 limb z;
0217
0218 #if defined(__has_builtin)
0219 #if __has_builtin(__builtin_add_overflow)
0220 if (!cpp20_and_in_constexpr()) {
0221 overflow = __builtin_add_overflow(x, y, &z);
0222 return z;
0223 }
0224 #endif
0225 #endif
0226
0227
0228 z = x + y;
0229 overflow = z < x;
0230 return z;
0231 }
0232
0233
0234 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0235 limb scalar_mul(limb x, limb y, limb& carry) noexcept {
0236 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0237 #if defined(__SIZEOF_INT128__)
0238
0239 __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
0240 carry = limb(z >> limb_bits);
0241 return limb(z);
0242 #else
0243
0244
0245 value128 z = full_multiplication(x, y);
0246 bool overflow;
0247 z.low = scalar_add(z.low, carry, overflow);
0248 z.high += uint64_t(overflow);
0249 carry = z.high;
0250 return z.low;
0251 #endif
0252 #else
0253 uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
0254 carry = limb(z >> limb_bits);
0255 return limb(z);
0256 #endif
0257 }
0258
0259
0260
0261 template <uint16_t size>
0262 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0263 bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {
0264 size_t index = start;
0265 limb carry = y;
0266 bool overflow;
0267 while (carry != 0 && index < vec.len()) {
0268 vec[index] = scalar_add(vec[index], carry, overflow);
0269 carry = limb(overflow);
0270 index += 1;
0271 }
0272 if (carry != 0) {
0273 BOOST_CHARCONV_FASTFLOAT_TRY(vec.try_push(carry));
0274 }
0275 return true;
0276 }
0277
0278
0279 template <uint16_t size>
0280 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0281 bool small_add(stackvec<size>& vec, limb y) noexcept {
0282 return small_add_from(vec, y, 0);
0283 }
0284
0285
0286 template <uint16_t size>
0287 inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0288 bool small_mul(stackvec<size>& vec, limb y) noexcept {
0289 limb carry = 0;
0290 for (size_t index = 0; index < vec.len(); index++) {
0291 vec[index] = scalar_mul(vec[index], y, carry);
0292 }
0293 if (carry != 0) {
0294 BOOST_CHARCONV_FASTFLOAT_TRY(vec.try_push(carry));
0295 }
0296 return true;
0297 }
0298
0299
0300
0301 template <uint16_t size>
0302 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0303 bool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {
0304
0305
0306 if (x.len() < start || y.len() > x.len() - start) {
0307 BOOST_CHARCONV_FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
0308 }
0309
0310 bool carry = false;
0311 for (size_t index = 0; index < y.len(); index++) {
0312 limb xi = x[index + start];
0313 limb yi = y[index];
0314 bool c1 = false;
0315 bool c2 = false;
0316 xi = scalar_add(xi, yi, c1);
0317 if (carry) {
0318 xi = scalar_add(xi, 1, c2);
0319 }
0320 x[index + start] = xi;
0321 carry = c1 | c2;
0322 }
0323
0324
0325 if (carry) {
0326 BOOST_CHARCONV_FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
0327 }
0328 return true;
0329 }
0330
0331
0332 template <uint16_t size>
0333 BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0334 bool large_add_from(stackvec<size>& x, limb_span y) noexcept {
0335 return large_add_from(x, y, 0);
0336 }
0337
0338
0339 template <uint16_t size>
0340 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0341 bool long_mul(stackvec<size>& x, limb_span y) noexcept {
0342 limb_span xs = limb_span(x.data, x.len());
0343 stackvec<size> z(xs);
0344 limb_span zs = limb_span(z.data, z.len());
0345
0346 if (y.len() != 0) {
0347 limb y0 = y[0];
0348 BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(x, y0));
0349 for (size_t index = 1; index < y.len(); index++) {
0350 limb yi = y[index];
0351 stackvec<size> zi;
0352 if (yi != 0) {
0353
0354 zi.set_len(0);
0355 BOOST_CHARCONV_FASTFLOAT_TRY(zi.try_extend(zs));
0356 BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(zi, yi));
0357 limb_span zis = limb_span(zi.data, zi.len());
0358 BOOST_CHARCONV_FASTFLOAT_TRY(large_add_from(x, zis, index));
0359 }
0360 }
0361 }
0362
0363 x.normalize();
0364 return true;
0365 }
0366
0367
0368 template <uint16_t size>
0369 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20
0370 bool large_mul(stackvec<size>& x, limb_span y) noexcept {
0371 if (y.len() == 1) {
0372 BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(x, y[0]));
0373 } else {
0374 BOOST_CHARCONV_FASTFLOAT_TRY(long_mul(x, y));
0375 }
0376 return true;
0377 }
0378
0379 template <typename = void>
0380 struct pow5_tables {
0381 static constexpr uint32_t large_step = 135;
0382 static constexpr uint64_t small_power_of_5[] = {
0383 1UL, 5UL, 25UL, 125UL, 625UL, 3125UL, 15625UL, 78125UL, 390625UL,
0384 1953125UL, 9765625UL, 48828125UL, 244140625UL, 1220703125UL,
0385 6103515625UL, 30517578125UL, 152587890625UL, 762939453125UL,
0386 3814697265625UL, 19073486328125UL, 95367431640625UL, 476837158203125UL,
0387 2384185791015625UL, 11920928955078125UL, 59604644775390625UL,
0388 298023223876953125UL, 1490116119384765625UL, 7450580596923828125UL,
0389 };
0390 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0391 constexpr static limb large_power_of_5[] = {
0392 1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
0393 10482974169319127550UL, 198276706040285095UL};
0394 #else
0395 constexpr static limb large_power_of_5[] = {
0396 4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
0397 1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
0398 #endif
0399 };
0400
0401 template <typename T>
0402 constexpr uint32_t pow5_tables<T>::large_step;
0403
0404 template <typename T>
0405 constexpr uint64_t pow5_tables<T>::small_power_of_5[];
0406
0407 template <typename T>
0408 constexpr limb pow5_tables<T>::large_power_of_5[];
0409
0410
0411
0412
0413
0414 struct bigint : pow5_tables<> {
0415
0416 stackvec<bigint_limbs> vec;
0417
0418 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bigint(): vec() {}
0419 bigint(const bigint &) = delete;
0420 bigint &operator=(const bigint &) = delete;
0421 bigint(bigint &&) = delete;
0422 bigint &operator=(bigint &&other) = delete;
0423
0424 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bigint(uint64_t value): vec() {
0425 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0426 vec.push_unchecked(value);
0427 #else
0428 vec.push_unchecked(uint32_t(value));
0429 vec.push_unchecked(uint32_t(value >> 32));
0430 #endif
0431 vec.normalize();
0432 }
0433
0434
0435
0436 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool& truncated) const noexcept {
0437 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0438 if (vec.len() == 0) {
0439 return empty_hi64(truncated);
0440 } else if (vec.len() == 1) {
0441 return uint64_hi64(vec.rindex(0), truncated);
0442 } else {
0443 uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
0444 truncated |= vec.nonzero(2);
0445 return result;
0446 }
0447 #else
0448 if (vec.len() == 0) {
0449 return empty_hi64(truncated);
0450 } else if (vec.len() == 1) {
0451 return uint32_hi64(vec.rindex(0), truncated);
0452 } else if (vec.len() == 2) {
0453 return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
0454 } else {
0455 uint64_t result = uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
0456 truncated |= vec.nonzero(3);
0457 return result;
0458 }
0459 #endif
0460 }
0461
0462
0463
0464
0465
0466
0467
0468 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int compare(const bigint& other) const noexcept {
0469 if (vec.len() > other.vec.len()) {
0470 return 1;
0471 } else if (vec.len() < other.vec.len()) {
0472 return -1;
0473 } else {
0474 for (size_t index = vec.len(); index > 0; index--) {
0475 limb xi = vec[index - 1];
0476 limb yi = other.vec[index - 1];
0477 if (xi > yi) {
0478 return 1;
0479 } else if (xi < yi) {
0480 return -1;
0481 }
0482 }
0483 return 0;
0484 }
0485 }
0486
0487
0488
0489 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept {
0490
0491
0492
0493
0494
0495 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(n != 0);
0496 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);
0497
0498 size_t shl = n;
0499 size_t shr = limb_bits - shl;
0500 limb prev = 0;
0501 for (size_t index = 0; index < vec.len(); index++) {
0502 limb xi = vec[index];
0503 vec[index] = (xi << shl) | (prev >> shr);
0504 prev = xi;
0505 }
0506
0507 limb carry = prev >> shr;
0508 if (carry != 0) {
0509 return vec.try_push(carry);
0510 }
0511 return true;
0512 }
0513
0514
0515 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept {
0516 BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(n != 0);
0517 if (n + vec.len() > vec.capacity()) {
0518 return false;
0519 } else if (!vec.is_empty()) {
0520
0521 limb* dst = vec.data + n;
0522 const limb* src = vec.data;
0523 std::copy_backward(src, src + vec.len(), dst + vec.len());
0524
0525 limb* first = vec.data;
0526 limb* last = first + n;
0527 ::std::fill(first, last, 0);
0528 vec.set_len(n + vec.len());
0529 return true;
0530 } else {
0531 return true;
0532 }
0533 }
0534
0535
0536 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
0537 size_t rem = n % limb_bits;
0538 size_t div = n / limb_bits;
0539 if (rem != 0) {
0540 BOOST_CHARCONV_FASTFLOAT_TRY(shl_bits(rem));
0541 }
0542 if (div != 0) {
0543 BOOST_CHARCONV_FASTFLOAT_TRY(shl_limbs(div));
0544 }
0545 return true;
0546 }
0547
0548
0549 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept {
0550 if (vec.is_empty()) {
0551 return 0;
0552 } else {
0553 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0554 return leading_zeroes(vec.rindex(0));
0555 #else
0556
0557 uint64_t r0 = vec.rindex(0);
0558 return leading_zeroes(r0 << 32);
0559 #endif
0560 }
0561 }
0562
0563
0564 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept {
0565 int lz = ctlz();
0566 return int(limb_bits * vec.len()) - lz;
0567 }
0568
0569 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept {
0570 return small_mul(vec, y);
0571 }
0572
0573 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept {
0574 return small_add(vec, y);
0575 }
0576
0577
0578 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept {
0579 return shl(exp);
0580 }
0581
0582
0583 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
0584
0585 constexpr size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
0586 limb_span large = limb_span(large_power_of_5, large_length);
0587 while (exp >= large_step) {
0588 BOOST_CHARCONV_FASTFLOAT_TRY(large_mul(vec, large));
0589 exp -= large_step;
0590 }
0591 #ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB
0592 constexpr uint32_t small_step = 27;
0593 constexpr limb max_native = 7450580596923828125UL;
0594 #else
0595 constexpr uint32_t small_step = 13;
0596 constexpr limb max_native = 1220703125U;
0597 #endif
0598 while (exp >= small_step) {
0599 BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(vec, max_native));
0600 exp -= small_step;
0601 }
0602 if (exp != 0) {
0603
0604
0605
0606 BOOST_CHARCONV_FASTFLOAT_TRY(
0607 small_mul(vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))
0608 );
0609 }
0610
0611 return true;
0612 }
0613
0614
0615 BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept {
0616 BOOST_CHARCONV_FASTFLOAT_TRY(pow5(exp));
0617 return pow2(exp);
0618 }
0619 };
0620
0621 }}}}
0622
0623 #endif