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