/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 |