Coverage Report

Created: 2026-08-14 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/s2geometry/src/s2/util/math/exactfloat/bignum.cc
Line
Count
Source
1
// Copyright 2025 Google LLC
2
// Author: smcallis@google.com (Sean McAllister)
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//     http://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
16
#include "s2/util/math/exactfloat/bignum.h"
17
18
#ifdef __x86_64__
19
#include <immintrin.h>
20
#endif
21
22
#include <algorithm>
23
#include <array>
24
#include <charconv>
25
#include <cstddef>
26
#include <cstdint>
27
#include <limits>
28
#include <optional>
29
#include <utility>
30
31
#include "absl/algorithm/container.h"
32
#include "absl/base/nullability.h"
33
#include "absl/log/absl_check.h"
34
#include "absl/numeric/bits.h"
35
#include "absl/numeric/int128.h"
36
#include "absl/strings/string_view.h"
37
#include "absl/types/span.h"
38
39
namespace exactfloat_internal {
40
41
// Number of bigits in smaller of the two operands before we fall back to simple
42
// multiplication in the Karatsuba recursion. Determined empirically.
43
static constexpr int kSimpleMulThreshold = 24;
44
45
// Computes dst[i] = a[i]*b + c
46
//
47
// Returns the final carry, if any.
48
inline Bigit MulWithCarry(absl::Span<Bigit> dst, absl::Span<const Bigit> a,
49
                          Bigit b, Bigit carry);
50
51
// Compares magnitude magnitude of two bigit vectors, returning -1, 0, or +1.
52
//
53
// Magnitudes are compared lexicographically from the most significant bigit
54
// to the least significant.
55
0
int CmpAbs(absl::Span<const Bigit> a, absl::Span<const Bigit> b) {
56
0
  if (a.size() != b.size()) {
57
0
    return a.size() < b.size() ? -1 : +1;
58
0
  }
59
60
0
  for (int i = a.size() - 1; i >= 0; --i) {
61
0
    if (a[i] != b[i]) {
62
0
      return a[i] < b[i] ? -1 : +1;
63
0
    }
64
0
  }
65
66
0
  return 0;
67
0
}
68
69
0
int Bignum::Compare(const Bignum& b) const {
70
0
  if (is_negative() != b.is_negative()) {
71
0
    return is_negative() ? -1 : +1;
72
0
  }
73
74
  // Signs are equal, are they both zero?
75
0
  if (is_zero() && b.is_zero()) {
76
0
    return 0;
77
0
  }
78
79
  // Signs are equal and non-zero, compare magnitude.
80
0
  const int compare = CmpAbs(bigits_, b.bigits_);
81
0
  return is_negative() ? -compare : compare;
82
0
}
83
84
0
std::optional<Bignum> Bignum::FromString(absl::string_view s) {
85
  // A chunk is up to 19 decimal digits, which can always fit into a Bigit.
86
0
  static constexpr size_t kMaxChunkDigits = std::numeric_limits<Bigit>::digits10;
87
88
  // NOTE: We use a simple multiply-and-add (aka Horner's) method here for the
89
  // sake of simplicity. This isn't the fastest algorithm, being quadratic in
90
  // the number of chunks the input has. If we use divide and conquer approach
91
  // or an FFT based multiply we could probably make this ~O(n^1.5) or
92
  // semi-linear.
93
94
  // Precomputed powers of 10.
95
0
  static constexpr auto kPow10 = []() {
96
0
    std::array<Bigit, kMaxChunkDigits + 1> out = {1};
97
0
    for (size_t i = 1; i < out.size(); ++i) {
98
0
      out[i] = 10 * out[i - 1];
99
0
    }
100
0
    return out;
101
0
  }();
102
103
0
  Bignum out;
104
0
  if (s.empty()) {
105
0
    return out;
106
0
  }
107
108
0
  out.bigits_.reserve((s.size() + kMaxChunkDigits - 1) / kMaxChunkDigits);
109
110
0
  bool negative = false;
111
112
  // Consume optional +/- at the front.
113
0
  const char* begin = s.data();  // std::from_chars needs pointers, not iterators
114
0
  if ((*begin == '+' || *begin == '-')) {
115
0
    negative = (s[0] == '-');
116
0
    ++begin;
117
0
  }
118
119
0
  const char* end = s.data() + s.size();
120
0
  while (begin < end) {
121
0
    size_t chunk_len =
122
0
        std::min(static_cast<size_t>(end - begin), kMaxChunkDigits);
123
0
    Bigit chunk = 0;
124
0
    auto result = std::from_chars(begin, begin + chunk_len, chunk);
125
0
    if (result.ec != std::errc() ||
126
0
        static_cast<size_t>(result.ptr - begin) != chunk_len) {
127
0
      return std::nullopt;
128
0
    }
129
0
    begin += chunk_len;
130
131
    // Shift left by chunk_len digits and add the chunk to it.
132
0
    auto outspan = absl::MakeSpan(out.bigits_);
133
0
    Bigit carry = MulWithCarry(outspan, outspan, kPow10[chunk_len], chunk);
134
0
    if (carry) {
135
0
      out.bigits_.emplace_back(carry);
136
0
    }
137
0
  }
138
139
0
  out.negative_ = negative;
140
0
  out.Normalize();
141
0
  return out;
142
0
}
143
144
0
int bit_width(const Bignum& a) {
145
0
  ABSL_DCHECK(a.bigits_.empty() || a.bigits_.back() != 0);
146
0
  if (a.is_zero()) {
147
0
    return 0;
148
0
  }
149
150
  // Bit width is the bits in the least significant bigits + bit width of
151
  // the most significant word.
152
0
  const int msw_width = absl::bit_width(a.bigits_.back());
153
0
  const int lsw_width = (a.bigits_.size() - 1) * Bignum::kBigitBits;
154
0
  return msw_width + lsw_width;
155
0
}
156
157
0
int countr_zero(const Bignum& a) {
158
0
  int nzero = 0;
159
0
  for (Bigit bigit : a.bigits_) {
160
0
    if (bigit == 0) {
161
0
      nzero += Bignum::kBigitBits;
162
0
    } else {
163
0
      nzero += absl::countr_zero(bigit);
164
0
      break;
165
0
    }
166
0
  }
167
0
  return nzero;
168
0
}
169
170
0
bool Bignum::is_bit_set(int nbit) const {
171
0
  ABSL_DCHECK_GE(nbit, 0);
172
0
  const size_t digit = nbit / kBigitBits;
173
0
  const size_t shift = nbit % kBigitBits;
174
175
0
  if (digit >= bigits_.size()) {
176
0
    return false;
177
0
  }
178
179
0
  return ((bigits_[digit] >> shift) & 0x1) != 0;
180
0
}
181
182
0
Bignum Bignum::operator-() const {
183
0
  Bignum result = *this;
184
0
  result.negate();
185
0
  return result;
186
0
}
187
188
0
Bignum& Bignum::operator<<=(int nbit) {
189
0
  ABSL_DCHECK_GE(nbit, 0);
190
0
  if (is_zero() || nbit == 0) {
191
0
    return *this;
192
0
  }
193
194
0
  const int nbigit = nbit / kBigitBits;
195
0
  const int nrem = nbit % kBigitBits;
196
197
  // First, handle the whole-bigit shift by inserting zeros.
198
0
  bigits_.insert(bigits_.begin(), nbigit, 0);
199
200
  // Then, handle the within-bigit shift, if any.
201
0
  if (nrem != 0) {
202
0
    Bigit carry = 0;
203
0
    for (size_t i = 0; i < bigits_.size(); ++i) {
204
0
      const Bigit old_val = bigits_[i];
205
0
      bigits_[i] = (old_val << nrem) | carry;
206
0
      carry = old_val >> (kBigitBits - nrem);
207
0
    }
208
209
0
    if (carry) {
210
0
      bigits_.push_back(carry);
211
0
    }
212
0
  }
213
214
0
  return *this;
215
0
}
216
217
0
Bignum& Bignum::operator>>=(int nbit) {
218
0
  ABSL_DCHECK_GE(nbit, 0);
219
0
  if (is_zero() || nbit == 0) {
220
0
    return *this;
221
0
  }
222
223
  // Shifting by more than the bit width results in zero.
224
0
  if (nbit >= bit_width(*this)) {
225
0
    return set_zero();
226
0
  }
227
228
0
  const int nbigit = nbit / kBigitBits;
229
0
  const int nrem = nbit % kBigitBits;
230
231
  // First, handle the whole-bigit shift by removing bigits.
232
0
  bigits_.erase(bigits_.begin(), bigits_.begin() + nbigit);
233
234
  // Then, handle the within-bigit shift, if any.
235
0
  if (nrem != 0) {
236
0
    Bigit carry = 0;
237
0
    for (int64_t i = static_cast<int64_t>(bigits_.size()) - 1; i >= 0; --i) {
238
0
      const Bigit old_val = bigits_[i];
239
0
      bigits_[i] = (old_val >> nrem) | carry;
240
0
      carry = old_val << (kBigitBits - nrem);
241
0
    }
242
0
  }
243
244
  // Result might be smaller or zero, so normalize.
245
0
  Normalize();
246
0
  return *this;
247
0
}
248
249
// Raise this value to the given power, which must be non-negative.
250
0
Bignum Bignum::Pow(int32_t pow) const {
251
0
  ABSL_DCHECK_GE(pow, 0);
252
253
  // Anything to the zero-th power is 1 (including zero).
254
0
  if (pow == 0) {
255
0
    return Bignum(1);
256
0
  }
257
258
0
  if (is_zero()) {
259
0
    return Bignum(0);
260
0
  }
261
262
  // Core algorithm: Exponentiation by squaring.
263
0
  Bignum result(1);
264
0
  Bignum base = *this;  // A mutable copy of the base.
265
0
  uint32_t upow = static_cast<uint32_t>(pow);
266
267
0
  while (upow > 0) {
268
0
    if (upow & 1) {  // If current exponent bit is 1, multiply into result.
269
0
      result *= base;
270
0
    }
271
0
    base *= base;
272
0
    upow >>= 1;
273
0
  }
274
275
0
  return result;
276
0
}
277
278
// Computes a + b + carry and updates the carry.
279
0
inline Bigit AddBigit(Bigit a, Bigit b, Bigit* absl_nonnull carry) {
280
// Compilers such as GCC and Clang are known to be terrible at generating good
281
// code for long carry chains on Intel. Using the _addcarry_u64 intrinsic (which
282
// maps to the add/adc instructions produces a tight series of add/adc/adc/adc
283
// instructions, whereas writing the loop manually often generates many add/adc
284
// pairs with spurious bit twiddling.
285
//
286
// Using the intrinsic here improves benchmarks by ~30% when summing larger
287
// Bignums together.
288
//
289
// See this SO discussion for more information:
290
//   https://stackoverflow.com/questions/33690791
291
//
292
// Godbolt link for comparison:
293
//   https://godbolt.org/z/cGnnfMbMn  (no intrinsics)
294
//   https://godbolt.org/z/jnM1Y3Tjs  (intrinsics)
295
0
#ifdef __x86_64__
296
0
  static_assert(sizeof(Bigit) == sizeof(unsigned long long));
297
0
  Bigit out;
298
0
  *carry =
299
0
      _addcarry_u64(*carry, a, b, reinterpret_cast<unsigned long long*>(&out));
300
0
  return out;
301
#else
302
  absl::uint128 sum = absl::uint128(a) + b + *carry;
303
  *carry = absl::Uint128High64(sum);
304
  return static_cast<Bigit>(sum);
305
#endif
306
0
}
307
308
// Computes a - b - borrow  and updates the borrow.
309
//
310
// NOTE: Borrow must be one or zero.
311
0
inline Bigit SubBigit(Bigit a, Bigit b, Bigit* absl_nonnull borrow) {
312
0
  ABSL_DCHECK_LE(*borrow, Bigit(1));
313
  // See notes in AddBigit on why using an intrinsic is the right choice here.
314
0
#ifdef __x86_64__
315
0
  Bigit out;
316
0
  *borrow = _subborrow_u64(static_cast<char>(*borrow), a, b,
317
0
                           reinterpret_cast<unsigned long long*>(&out));
318
0
  return out;
319
#else
320
  Bigit diff = a - b - *borrow;
321
  *borrow = (a < b) || (*borrow && (a == b));
322
  return diff;
323
#endif
324
0
}
325
326
// Computes a * b + carry and updates the carry.
327
0
inline Bigit MulBigit(Bigit a, Bigit b, Bigit* absl_nonnull carry) {
328
0
  absl::uint128 sum = absl::uint128(a) * b + *carry;
329
0
  *carry = absl::Uint128High64(sum);
330
0
  return static_cast<Bigit>(sum);
331
0
}
332
333
// Computes sum += a * b + carry and updates the carry.
334
//
335
// NOTE: Will not overflow even if a, b, and c are their maximum values.
336
inline void MulAddBigit(Bigit* absl_nonnull sum, Bigit a, Bigit b,
337
0
                        Bigit* absl_nonnull carry) {
338
  // Similar to the comment in AddBigit, and just for completeness, it's worth
339
  // noting that the "best" way to implement this is with the Intel MULX, ADCQ,
340
  // and ADOQ instructions (i.e. the _mulx_u64, _addcarry_u64, and
341
  // _addcarryx_u64 intrinsics), but GCC and Clang do not support _addcarryx_u64
342
  // properly (and have no plans to do so). The issue is that gcc doesn't
343
  // support reasoning about separate dependency chains for the carry and
344
  // overflow flags, because all the flags are considered to be one
345
  // register. (The ADOX instructions were added specifically for this use case,
346
  // i.e. high-precision integer multiplies. They propagate carries using the
347
  // overflow flag rather than the carry flag, which lets you do two
348
  // extended-precision add operations in parallel without having them stomp on
349
  // each other's carry flags. )
350
0
  absl::uint128 term = absl::uint128(a) * b + *carry + *sum;
351
0
  *carry = absl::Uint128High64(term);
352
0
  *sum = static_cast<Bigit>(term);
353
0
}
354
355
// Computes a += b in place. Returns the final carry (if any).
356
//
357
// A operand must be at least as large as B. When adding two same-sized values,
358
// the result may overflow and be larger than either of them, in which case we
359
// will return the final carry value.
360
//
361
// This allows a work flow like this:
362
//    Bigit carry = AddInPlace(a, b);
363
//    if (carry) {
364
//      a.bigits_.emplace_back(carry);
365
//    }
366
//
367
// Rather than having to expand A to B.bigits_.size() + 1, and popping off the
368
// top bigit if it's unused (which is the most common case).
369
ABSL_ATTRIBUTE_NOINLINE inline Bigit AddInPlace(absl::Span<Bigit> a,
370
0
                                                absl::Span<const Bigit> b) {
371
0
  ABSL_DCHECK_GE(a.size(), b.size());
372
373
0
  Bigit carry = 0;
374
375
  // Dispatch four at a time to help loop unrolling.
376
0
  size_t i = 0;
377
0
  while (i + 4 <= b.size()) {
378
0
    for (int j = 0; j < 4; ++j, ++i) {
379
0
      a[i] = AddBigit(a[i], b[i], &carry);
380
0
    }
381
0
  }
382
383
  // Finish remainder.
384
0
  for (; i < b.size(); ++i) {
385
0
    a[i] = AddBigit(a[i], b[i], &carry);
386
0
  }
387
388
  // Propagate carry through the rest of a.
389
0
  for (; carry && i < a.size(); ++i) {
390
0
    a[i] = AddBigit(a[i], 0, &carry);
391
0
  }
392
393
0
  return carry;
394
0
}
395
396
// Computes dst = a + b out of place. Returns the number of bigits actually
397
// written into dst.
398
//
399
// NOTE: dst must be sized to be larger than max(a.size(), b.size()) + 1 (i.e.
400
// it must be able to hold the carry bigit, if any.
401
//
402
// This allows for using a pre-allocated buffer to store the result of an
403
// addition followed by trimming down to size:
404
//
405
//     absl::Span<Bigit> out = arena.Alloc(std::max(a.size(), b.size()) + 1);
406
//     out = out.first(AddInto(out, a, b));
407
//
408
// Which is used in the Karatsuba multiplication, where we don't have the option
409
// to expand the allocate space on demand.
410
inline size_t Add(absl::Span<Bigit> dst, absl::Span<const Bigit> a,
411
0
                  absl::Span<const Bigit> b) {
412
0
  const size_t max_size = std::max(a.size(), b.size());
413
0
  const size_t min_size = std::min(a.size(), b.size());
414
0
  ABSL_DCHECK_GE(dst.size(), max_size + 1);
415
416
  // Add common parts.
417
0
  Bigit carry = 0;
418
419
  // Dispatch four at a time to help loop unrolling.
420
0
  size_t i = 0;
421
0
  while (i + 4 < min_size) {
422
0
    for (int j = 0; j < 4; ++j, ++i) {
423
0
      dst[i] = AddBigit(a[i], b[i], &carry);
424
0
    }
425
0
  }
426
427
  // Finish remainder of the parts common to A and B.
428
0
  for (; i < min_size; ++i) {
429
0
    dst[i] = AddBigit(a[i], b[i], &carry);
430
0
  }
431
432
  // Copy remaining digits from the longer operand and propagate carry.
433
0
  absl::Span<const Bigit> longer = (a.size() > b.size()) ? a : b;
434
435
  // Dispatch four at a time for the remaining part.
436
0
  const size_t size = longer.size();
437
0
  while (i + 4 < size) {
438
0
    for (int j = 0; j < 4; ++j, ++i) {
439
0
      dst[i] = AddBigit(longer[i], 0, &carry);
440
0
    }
441
0
  }
442
443
  // Propagate carry through the longer operand.
444
0
  for (; i < size; ++i) {
445
0
    dst[i] = AddBigit(longer[i], 0, &carry);
446
0
  }
447
448
0
  if (carry) {
449
0
    dst[i++] = carry;
450
0
    return max_size + 1;
451
0
  }
452
453
0
  return max_size;
454
0
}
455
456
// Computes a -= b.
457
//
458
// REQUIRES: |a| >= |b|.
459
0
inline void SubInPlace(absl::Span<Bigit> a, absl::Span<const Bigit> b) {
460
0
  ABSL_DCHECK_GE(a.size(), b.size());
461
0
  ABSL_DCHECK_GE(CmpAbs(a, b), 0);
462
463
0
  Bigit borrow = 0;
464
465
  // Dispatch four at a time to help loop unrolling.
466
0
  size_t size = b.size();
467
0
  size_t i = 0;
468
0
  while (i + 4 <= size) {
469
0
    for (int j = 0; j < 4; ++j, ++i) {
470
0
      a[i] = SubBigit(a[i], b[i], &borrow);
471
0
    }
472
0
  }
473
474
  // Finish remainder of subtraction.
475
0
  for (; i < size; ++i) {
476
0
    a[i] = SubBigit(a[i], b[i], &borrow);
477
0
  }
478
479
  // Propagate the borrow through a.
480
0
  for (; borrow && i < a.size(); ++i) {
481
0
    borrow = (a[i] == 0);
482
0
    a[i]--;
483
0
  }
484
0
}
485
486
// Computes a = b - a.
487
//
488
// NOTE: Requires |b| >= |a|.
489
//
490
// Since we write the result to a, but b is larger, a must be expanded with
491
// enough leading zeros to fit the result.
492
0
inline void SubReverseInPlace(absl::Span<Bigit> a, absl::Span<const Bigit> b) {
493
0
  ABSL_DCHECK_GE(a.size(), b.size());
494
0
  ABSL_DCHECK_GE(CmpAbs(b, a), 0);
495
496
0
  Bigit borrow = 0;
497
498
  // Dispatch four at a time to help loop unrolling.
499
0
  size_t size = a.size();
500
0
  size_t i = 0;
501
0
  while (i + 4 <= size) {
502
0
    for (int j = 0; j < 4; ++j, ++i) {
503
0
      a[i] = SubBigit(b[i], a[i], &borrow);
504
0
    }
505
0
  }
506
507
  // Finish remainder.
508
0
  for (; i < size; ++i) {
509
0
    a[i] = SubBigit(b[i], a[i], &borrow);
510
0
  }
511
0
}
512
513
inline Bigit MulWithCarry(absl::Span<Bigit> dst, absl::Span<const Bigit> a,
514
0
                          Bigit b, Bigit carry) {
515
0
  ABSL_DCHECK_GE(dst.size(), a.size());
516
517
  // Dispatch four at a time to help loop unrolling.
518
0
  size_t i = 0;
519
0
  while (i + 4 <= a.size()) {
520
0
    for (int j = 0; j < 4; ++j, ++i) {
521
0
      dst[i] = MulBigit(a[i], b, &carry);
522
0
    }
523
0
  }
524
525
0
  for (; i < a.size(); ++i) {
526
0
    dst[i] = MulBigit(a[i], b, &carry);
527
0
  }
528
529
0
  return carry;
530
0
}
531
532
// Computes sum[i] += a[i]*b in place.
533
//
534
// Returns the final carry, if any.
535
inline Bigit MulAddInPlace(absl::Span<Bigit> sum, absl::Span<const Bigit> a,
536
0
                           Bigit b) {
537
  // Dispatch four at a time to help loop unrolling.
538
0
  Bigit carry = 0;
539
0
  size_t i = 0;
540
0
  while (i + 4 <= a.size()) {
541
0
    for (int j = 0; j < 4; ++j, ++i) {
542
0
      MulAddBigit(&sum[i], a[i], b, &carry);
543
0
    }
544
0
  }
545
546
  // Finish remainder.
547
0
  for (; i < a.size(); ++i) {
548
0
    MulAddBigit(&sum[i], a[i], b, &carry);
549
0
  }
550
551
0
  return carry;
552
0
}
553
554
// Implements the standard grade school long multiplication algorithm. The
555
// output is computed by multiplying A by each digit of B and summing the
556
// results as we go. This is a quadratic algorithm and only serves as the base
557
// case for the recursive Karatsuba algorithm below.
558
//
559
// NOTE: out must be at least as large as the sums of the sizes of A and B.
560
inline void MulQuadratic(absl::Span<Bigit> dst, absl::Span<const Bigit> a,
561
0
                         absl::Span<const Bigit> b) {
562
0
  ABSL_DCHECK_GE(dst.size(), a.size() + b.size());
563
564
  // Make sure A is the longer of the two arguments.
565
0
  if (a.size() < b.size()) {
566
0
    using std::swap;
567
0
    swap(a, b);
568
0
  }
569
570
0
  if (b.empty()) {
571
0
    absl::c_fill(dst, 0);
572
0
    return;
573
0
  }
574
575
  // Each call to MulAdd and MulAddInPlace only updates a.size() elements of out
576
  // so we manually set the carries as we go. We grab a span to the upper half
577
  // of out starting at a.size() to facilitate this.
578
0
  absl::Span<Bigit> upper = dst.subspan(a.size());
579
0
  upper[0] = MulWithCarry(dst, a, b[0], 0);
580
581
0
  const size_t size = b.size();
582
0
  size_t i = 1;
583
0
  for (; i < size; ++i) {
584
0
    upper[i] = MulAddInPlace(dst.subspan(i), a, b[i]);
585
0
  }
586
587
  // Finish zeroing out the upper half.
588
0
  for (; i < upper.size(); ++i) {
589
0
    upper[i] = 0;
590
0
  }
591
0
}
592
593
// Split a span into two contiguous spans of length at most a and b.
594
//
595
// If span.size() <= a, the second span is empty, otherwise the second span
596
// has length at most b. If span.size() > a + b, then the two spans only cover
597
// part of the input span.
598
template <typename T>
599
inline std::pair<absl::Span<T>, absl::Span<T>> Split(absl::Span<T> span,
600
0
                                                     size_t a, size_t b) {
601
0
  if (a < span.size()) {
602
0
    return {span.subspan(0, a), span.subspan(a, b)};
603
0
  }
604
0
  return {span.subspan(0, a), {}};
605
0
};
Unexecuted instantiation: std::__1::pair<absl::lts_20260526::Span<unsigned long const>, absl::lts_20260526::Span<unsigned long const> > exactfloat_internal::Split<unsigned long const>(absl::lts_20260526::Span<unsigned long const>, unsigned long, unsigned long)
Unexecuted instantiation: std::__1::pair<absl::lts_20260526::Span<unsigned long>, absl::lts_20260526::Span<unsigned long> > exactfloat_internal::Split<unsigned long>(absl::lts_20260526::Span<unsigned long>, unsigned long, unsigned long)
606
607
// A simple bump allocator to allow us to very efficiently allocate temporary
608
// space when recursing in the Karatsuba multiply. The arena is pre-sized and
609
// returns spans of memory via Alloc() which are then returned to the arena via
610
// Release.
611
//
612
// NOTE: We use std::unique_ptr here instead of std::vector because we don't
613
// want to initialize the memory unnecessarily and using std::vector without
614
// resizing (and thus initializing) the container leads to false positives with
615
// ASAN.
616
class Arena {
617
 public:
618
  // TODO: Use make_unique_for_overwrite when on C++20.
619
0
  explicit Arena(size_t size) : size_(size), data_(new Bigit[size]) {}
620
621
  // Allocates a span of length n from the arena.
622
0
  absl::Span<Bigit> Alloc(size_t n) {
623
0
    ABSL_DCHECK_LE(used_ + n, size_);
624
0
    size_t start = used_;
625
0
    used_ += n;
626
0
    return absl::Span<Bigit>(data_.get() + start, n);
627
0
  }
628
629
0
  size_t Available() const { return size_ - used_; }
630
631
0
  size_t Used() const { return used_; }
632
633
  // Resets the arena to the given position which must be < Used().
634
0
  void Reset(size_t to) {
635
0
    ABSL_DCHECK_LE(to, used_);
636
0
    used_ = to;
637
0
  }
638
639
 private:
640
  size_t size_ = 0;
641
  size_t used_ = 0;
642
  std::unique_ptr<Bigit[]> data_;
643
};
644
645
// Returns the total arena size needed to multiply two number of a_size and
646
// b_size bigits using the recursive Karatsuba implementation. This is enough
647
// space for all the required recursive calls of KaratsubaMulRecursive.
648
0
inline size_t ArenaSize(size_t a_size, size_t b_size) {
649
  // Each step of Karatsuba splits at:
650
  //   N = (std::max(a.size() + b.size() + 1) / 2
651
  //
652
  // We have to hold a total of 4*(N + 1) bigits as temporaries at each step.
653
  //
654
  // Simulate the recursion (log(n) steps) and compute the arena size.
655
0
  int peak = 0;
656
0
  while (std::min(a_size, b_size) > kSimpleMulThreshold) {
657
0
    int half = (std::max(a_size, b_size) + 1) / 2;
658
0
    int next = half + 1;
659
0
    peak += 4 * next;
660
0
    a_size = next;
661
0
    b_size = next;
662
0
  };
663
0
  return peak;
664
0
}
665
666
// Recursive step in the Karatsuba multiplication. dst must be large enough to
667
// hold the product of a and b (i.e. it must be at least as large as a.size() +
668
// b.size()). The product is computed and stored in-place in dst.
669
//
670
// Additionally an arena must be provided for temporary storage for intermediate
671
// products. The arena must have at least ArenaSize(a.size(), b.size()) space
672
// available.
673
inline void KaratsubaMulRecursive(absl::Span<Bigit> dst,
674
                                  absl::Span<const Bigit> a,
675
                                  absl::Span<const Bigit> b,
676
0
                                  Arena* absl_nonnull arena) {
677
0
  ABSL_DCHECK_GE(dst.size(), a.size() + b.size());
678
0
  ABSL_DCHECK_GE(arena->Available(), ArenaSize(a.size(), b.size()));
679
0
  if (a.empty() || b.empty()) {
680
0
    absl::c_fill(dst, 0);
681
0
    return;
682
0
  }
683
684
0
  int arena_start = arena->Used();
685
686
  // Karatsuba lets us represent two numbers of M bigits each, A and B, as:
687
  //
688
  //   A = a1*10^(M/2) + a0
689
  //   B = b1*10^(M/2) + b0
690
  //
691
  // Which we can multiply out:
692
  //   AB = (a1*10^(M/2) + a0)*(b1*10^(M/2) + b0);
693
  //      = a1*b1*10^M + (a1*b0 + a0*b1)*10^(M/2) + a0*b0
694
  //      = z2 * 10^M  + z1*10^(M/2)            + z0
695
  //
696
  // Where:
697
  //   z0 = a0*b0
698
  //   z1 = a1*b0 + a0*b1
699
  //   z2 = a1*b1
700
  //
701
  // We can replace the multiplications in z1 by computing:
702
  //
703
  //   z3 = (a0 + a1)*(b0 + b1)
704
  //
705
  // And noting z1 = z3 - z2 - z0
706
  //
707
  // This lets us compute a 2M digit multiply with three M digit multiplies,
708
  // with those individual multiplies able to be recursively divided.
709
710
  // Fall back to long multiplication when we're small enough.
711
0
  if (std::min(a.size(), b.size()) <= kSimpleMulThreshold) {
712
0
    MulQuadratic(dst, a, b);
713
0
    return;
714
0
  }
715
716
0
  const size_t half = (std::max(a.size(), b.size()) + 1) / 2;
717
718
  // Split the inputs into contiguous subspans.
719
0
  auto [a0, a1] = Split(a, half, half);
720
0
  auto [b0, b1] = Split(b, half, half);
721
722
  // Make space to hold results in the output and multiply sub-terms.
723
  //   z0 = a0 * b0
724
  //   z2 = a1 * b1
725
0
  auto [z0, z2] = Split(dst, a0.size() + b0.size(), a1.size() + b1.size());
726
0
  KaratsubaMulRecursive(z0, a0, b0, arena);
727
0
  KaratsubaMulRecursive(z2, a1, b1, arena);
728
729
  // Compute (a0 + a1) and (b0 + b1)
730
  //
731
  // If the upper terms are zero we can just re-use the terms we have, otherwise
732
  // we compute the sum and pop off the MSB bigit if no carry occurred.
733
0
  absl::Span<const Bigit> asum = a0;
734
0
  if (!a1.empty()) {
735
0
    absl::Span<Bigit> tmp = arena->Alloc(half + 1);
736
0
    asum = tmp.first(Add(tmp, a0, a1));
737
0
  }
738
739
0
  absl::Span<const Bigit> bsum = b0;
740
0
  if (!b1.empty()) {
741
0
    absl::Span<Bigit> tmp = arena->Alloc(half + 1);
742
0
    bsum = tmp.first(Add(tmp, b0, b1));
743
0
  }
744
745
  // Compute z1 = asum*bsum - z0 - z2 = (a0 + a1)*(b0 + b1) - z0 - z2
746
0
  absl::Span<Bigit> z1 = arena->Alloc(asum.size() + bsum.size());
747
748
  // Compute asum * bsum into the beginning of z1
749
0
  KaratsubaMulRecursive(z1, asum, bsum, arena);
750
751
  // NOTE: (a0 + a1) * (b0 + b1) >= a0*b0 + a1*b1 so this never underflows.
752
0
  SubInPlace(z1, z0);
753
0
  if (!a1.empty() && !b1.empty()) {
754
0
    SubInPlace(z1, z2);
755
0
  }
756
757
  // We need to add z1*10^half, which we can do by simply adding z1 at a shifted
758
  // position in the output.
759
0
  absl::Span<Bigit> dst_z1 = dst.subspan(half);
760
761
  // Although the value of z1 is guaranteed to fit in the available space of
762
  // dst, it may have one or more high-order zero bigits because it was sized
763
  // conservatively to hold the intermediate result (asum * bsum). We trim these
764
  // leading zeros if necessary to ensure that the Add() operation below does
765
  // not attempt to write zero bigits past the end of dst.
766
0
  AddInPlace(dst_z1, z1.first(std::min(z1.size(), dst_z1.size())));
767
768
  // Release temporary memory we used.
769
0
  arena->Reset(arena_start);
770
0
}
771
772
// Multiplies two unsigned bigit vectors together using Karatsuba's algorithm.
773
//
774
// This algorithm recursively subdivides the inputs until one or both is below
775
// some threshold, and then falls back to standard long multiplication.
776
void KaratsubaMul(absl::Span<Bigit> dst, absl::Span<const Bigit> a,
777
0
                  absl::Span<const Bigit> b) {
778
0
  ABSL_DCHECK_GE(dst.size(), a.size() + b.size());
779
0
  if (a.empty() || b.empty()) {
780
0
    absl::c_fill(dst, 0);
781
0
    return;
782
0
  }
783
784
0
  Arena arena(ArenaSize(a.size(), b.size()));
785
0
  KaratsubaMulRecursive(dst, a, b, &arena);
786
0
}
787
788
0
Bignum& Bignum::operator+=(const Bignum& b) {
789
0
  if (b.is_zero()) {
790
0
    return *this;
791
0
  }
792
793
0
  if (is_zero()) {
794
0
    *this = b;
795
0
    return *this;
796
0
  }
797
798
0
  if (is_negative() == b.is_negative()) {
799
    // Same sign:
800
    //   +|a| + +|b| == +(|a| + |b|)
801
    //   -|a| + -|b| == -(|a| + |b|)
802
    //
803
    // So we can just sum magnitudes, final sign is the same as A.
804
0
    bigits_.resize(std::max(bigits_.size(), b.bigits_.size()), 0);
805
0
    Bigit carry = AddInPlace(absl::MakeSpan(bigits_), b.bigits_);
806
0
    if (carry) {
807
0
      bigits_.emplace_back(carry);
808
0
    }
809
0
  } else {
810
    // We know the signs are different, so there's two options:
811
    //   -|a| + +|b| = ?(|b| - |a|)
812
    //   +|a| + -|b| = ?(|a| - |b|)
813
    //
814
    // With the final sign being dependent on how |a| and |b| relate.
815
0
    if (CmpAbs(bigits_, b.bigits_) >= 0) {
816
      // |a| >= |b|
817
      //   -|a| + +|b| --> -(|a| - |b|)
818
      //   +|a| + -|b| --> +(|a| - |b|)
819
      //
820
      // So we can subtract magnitudes, final sign is the same as A.
821
0
      SubInPlace(absl::MakeSpan(bigits_), b.bigits_);
822
0
    } else {
823
      // |a| < |b|
824
      //   -|a| + +|b| --> +(|b| - |a|)
825
      //   +|a| + -|b| --> -(|b| - |a|)
826
      //
827
      // So we can compute |b| - |a| and the final sign is the same as B.
828
0
      bigits_.resize(b.bigits_.size());
829
0
      SubReverseInPlace(absl::MakeSpan(bigits_), b.bigits_);
830
0
      negative_ = b.is_negative();
831
0
    }
832
0
  }
833
834
0
  Normalize();
835
0
  return *this;
836
0
}
837
838
0
Bignum& Bignum::operator-=(const Bignum& b) {
839
0
  if (this == &b) {
840
0
    set_zero();
841
0
    return *this;
842
0
  }
843
844
  // Compute -(-a + b) == a - b
845
0
  negate();
846
0
  *this += b;
847
0
  negate();
848
0
  return *this;
849
0
}
850
851
0
Bignum& Bignum::operator*=(const Bignum& b) {
852
0
  if (is_zero() || b.is_zero()) {
853
0
    return set_zero();
854
0
  }
855
856
  // Result is only negative if signs are different.
857
0
  const bool negative = (is_negative() != b.is_negative());
858
859
  // Fast path for single-bigit multiplication.
860
0
  if (bigits_.size() == 1 && b.bigits_.size() == 1) {
861
0
    absl::uint128 prod = absl::uint128(bigits_[0]) * b.bigits_[0];
862
0
    const uint64_t lo = absl::Uint128Low64(prod);
863
0
    const uint64_t hi = absl::Uint128High64(prod);
864
0
    if (hi == 0) {
865
0
      bigits_ = {lo};
866
0
    } else {
867
0
      bigits_ = {lo, hi};
868
0
    }
869
0
    set_negative(negative);
870
0
    return *this;
871
0
  }
872
873
  // Use Karatsuba multiplication.
874
  // If the inputs are small enough this will just do long multiplication.
875
0
  BigitVector result;
876
0
  result.resize(bigits_.size() + b.bigits_.size());
877
0
  KaratsubaMul(absl::MakeSpan(result), bigits_, b.bigits_);
878
0
  bigits_ = std::move(result);
879
880
0
  negative_ = negative;
881
0
  Normalize();
882
0
  return *this;
883
0
}
884
885
}  // namespace exactfloat_internal