Skip to main content

serde_json/lexical/
math.rs

1// Adapted from https://github.com/Alexhuszagh/rust-lexical.
2
3//! Building-blocks for arbitrary-precision math.
4//!
5//! These algorithms assume little-endian order for the large integer
6//! buffers, so for a `vec![0, 1, 2, 3]`, `3` is the most significant limb,
7//! and `0` is the least significant limb.
8
9use super::large_powers;
10use super::num::*;
11use super::small_powers::*;
12use alloc::vec::Vec;
13use core::{cmp, iter, mem};
14
15// ALIASES
16// -------
17
18//  Type for a single limb of the big integer.
19//
20//  A limb is analogous to a digit in base10, except, it stores 32-bit
21//  or 64-bit numbers instead.
22//
23//  This should be all-known 64-bit platforms supported by Rust.
24//      https://forge.rust-lang.org/platform-support.html
25//
26//  Platforms where native 128-bit multiplication is explicitly supported:
27//      - x86_64 (Supported via `MUL`).
28//      - mips64 (Supported via `DMULTU`, which `HI` and `LO` can be read-from).
29//
30//  Platforms where native 64-bit multiplication is supported and
31//  you can extract hi-lo for 64-bit multiplications.
32//      aarch64 (Requires `UMULH` and `MUL` to capture high and low bits).
33//      powerpc64 (Requires `MULHDU` and `MULLD` to capture high and low bits).
34//
35//  Platforms where native 128-bit multiplication is not supported,
36//  requiring software emulation.
37//      sparc64 (`UMUL` only supported double-word arguments).
38
39// 32-BIT LIMB
40#[cfg(fast_arithmetic = "32")]
41pub type Limb = u32;
42
43#[cfg(fast_arithmetic = "32")]
44pub const POW5_LIMB: &[Limb] = &POW5_32;
45
46#[cfg(fast_arithmetic = "32")]
47pub const POW10_LIMB: &[Limb] = &POW10_32;
48
49#[cfg(fast_arithmetic = "32")]
50type Wide = u64;
51
52// 64-BIT LIMB
53#[cfg(fast_arithmetic = "64")]
54pub type Limb = u64;
55
56#[cfg(fast_arithmetic = "64")]
57pub const POW5_LIMB: &[Limb] = &POW5_64;
58
59#[cfg(fast_arithmetic = "64")]
60pub const POW10_LIMB: &[Limb] = &POW10_64;
61
62#[cfg(fast_arithmetic = "64")]
63type Wide = u128;
64
65/// Cast to limb type.
66#[inline]
67pub(crate) fn as_limb<T: Integer>(t: T) -> Limb {
68    Limb::as_cast(t)
69}
70
71/// Cast to wide type.
72#[inline]
73fn as_wide<T: Integer>(t: T) -> Wide {
74    Wide::as_cast(t)
75}
76
77// SPLIT
78// -----
79
80/// Split u64 into limbs, in little-endian order.
81#[inline]
82#[cfg(fast_arithmetic = "32")]
83fn split_u64(x: u64) -> [Limb; 2] {
84    [as_limb(x), as_limb(x >> 32)]
85}
86
87/// Split u64 into limbs, in little-endian order.
88#[inline]
89#[cfg(fast_arithmetic = "64")]
90fn split_u64(x: u64) -> [Limb; 1] {
91    [as_limb(x)]
92}
93
94// HI64
95// ----
96
97// NONZERO
98
99/// Check if any of the remaining bits are non-zero.
100#[inline]
101pub fn nonzero<T: Integer>(x: &[T], rindex: usize) -> bool {
102    let len = x.len();
103    let slc = &x[..len - rindex];
104    slc.iter().rev().any(|&x| x != T::ZERO)
105}
106
107/// Shift 64-bit integer to high 64-bits.
108#[inline]
109fn u64_to_hi64_1(r0: u64) -> (u64, bool) {
110    if true {
    if !(r0 != 0) { ::core::panicking::panic("assertion failed: r0 != 0") };
};debug_assert!(r0 != 0);
111    let ls = r0.leading_zeros();
112    (r0 << ls, false)
113}
114
115/// Shift 2 64-bit integers to high 64-bits.
116#[inline]
117fn u64_to_hi64_2(r0: u64, r1: u64) -> (u64, bool) {
118    if true {
    if !(r0 != 0) { ::core::panicking::panic("assertion failed: r0 != 0") };
};debug_assert!(r0 != 0);
119    let ls = r0.leading_zeros();
120    let rs = 64 - ls;
121    let v = match ls {
122        0 => r0,
123        _ => (r0 << ls) | (r1 >> rs),
124    };
125    let n = r1 << ls != 0;
126    (v, n)
127}
128
129/// Trait to export the high 64-bits from a little-endian slice.
130trait Hi64<T>: AsRef<[T]> {
131    /// Get the hi64 bits from a 1-limb slice.
132    fn hi64_1(&self) -> (u64, bool);
133
134    /// Get the hi64 bits from a 2-limb slice.
135    fn hi64_2(&self) -> (u64, bool);
136
137    /// Get the hi64 bits from a 3-limb slice.
138    fn hi64_3(&self) -> (u64, bool);
139
140    /// High-level exporter to extract the high 64 bits from a little-endian slice.
141    #[inline]
142    fn hi64(&self) -> (u64, bool) {
143        match self.as_ref().len() {
144            0 => (0, false),
145            1 => self.hi64_1(),
146            2 => self.hi64_2(),
147            _ => self.hi64_3(),
148        }
149    }
150}
151
152impl Hi64<u32> for [u32] {
153    #[inline]
154    fn hi64_1(&self) -> (u64, bool) {
155        if true {
    {
        match (&self.len(), &1) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(self.len(), 1);
156        let r0 = self[0] as u64;
157        u64_to_hi64_1(r0)
158    }
159
160    #[inline]
161    fn hi64_2(&self) -> (u64, bool) {
162        if true {
    {
        match (&self.len(), &2) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(self.len(), 2);
163        let r0 = (self[1] as u64) << 32;
164        let r1 = self[0] as u64;
165        u64_to_hi64_1(r0 | r1)
166    }
167
168    #[inline]
169    fn hi64_3(&self) -> (u64, bool) {
170        if true {
    if !(self.len() >= 3) {
        ::core::panicking::panic("assertion failed: self.len() >= 3")
    };
};debug_assert!(self.len() >= 3);
171        let r0 = self[self.len() - 1] as u64;
172        let r1 = (self[self.len() - 2] as u64) << 32;
173        let r2 = self[self.len() - 3] as u64;
174        let (v, n) = u64_to_hi64_2(r0, r1 | r2);
175        (v, n || nonzero(self, 3))
176    }
177}
178
179impl Hi64<u64> for [u64] {
180    #[inline]
181    fn hi64_1(&self) -> (u64, bool) {
182        if true {
    {
        match (&self.len(), &1) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(self.len(), 1);
183        let r0 = self[0];
184        u64_to_hi64_1(r0)
185    }
186
187    #[inline]
188    fn hi64_2(&self) -> (u64, bool) {
189        if true {
    if !(self.len() >= 2) {
        ::core::panicking::panic("assertion failed: self.len() >= 2")
    };
};debug_assert!(self.len() >= 2);
190        let r0 = self[self.len() - 1];
191        let r1 = self[self.len() - 2];
192        let (v, n) = u64_to_hi64_2(r0, r1);
193        (v, n || nonzero(self, 2))
194    }
195
196    #[inline]
197    fn hi64_3(&self) -> (u64, bool) {
198        self.hi64_2()
199    }
200}
201
202// SCALAR
203// ------
204
205// Scalar-to-scalar operations, for building-blocks for arbitrary-precision
206// operations.
207
208mod scalar {
209    use super::*;
210
211    // ADDITION
212
213    /// Add two small integers and return the resulting value and if overflow happens.
214    #[inline]
215    pub fn add(x: Limb, y: Limb) -> (Limb, bool) {
216        x.overflowing_add(y)
217    }
218
219    /// AddAssign two small integers and return if overflow happens.
220    #[inline]
221    pub fn iadd(x: &mut Limb, y: Limb) -> bool {
222        let t = add(*x, y);
223        *x = t.0;
224        t.1
225    }
226
227    // SUBTRACTION
228
229    /// Subtract two small integers and return the resulting value and if overflow happens.
230    #[inline]
231    pub fn sub(x: Limb, y: Limb) -> (Limb, bool) {
232        x.overflowing_sub(y)
233    }
234
235    /// SubAssign two small integers and return if overflow happens.
236    #[inline]
237    pub fn isub(x: &mut Limb, y: Limb) -> bool {
238        let t = sub(*x, y);
239        *x = t.0;
240        t.1
241    }
242
243    // MULTIPLICATION
244
245    /// Multiply two small integers (with carry) (and return the overflow contribution).
246    ///
247    /// Returns the (low, high) components.
248    #[inline]
249    pub fn mul(x: Limb, y: Limb, carry: Limb) -> (Limb, Limb) {
250        // Cannot overflow, as long as wide is 2x as wide. This is because
251        // the following is always true:
252        // `Wide::MAX - (Narrow::MAX * Narrow::MAX) >= Narrow::MAX`
253        let z: Wide = as_wide(x) * as_wide(y) + as_wide(carry);
254        let bits = mem::size_of::<Limb>() * 8;
255        (as_limb(z), as_limb(z >> bits))
256    }
257
258    /// Multiply two small integers (with carry) (and return if overflow happens).
259    #[inline]
260    pub fn imul(x: &mut Limb, y: Limb, carry: Limb) -> Limb {
261        let t = mul(*x, y, carry);
262        *x = t.0;
263        t.1
264    }
265} // scalar
266
267// SMALL
268// -----
269
270// Large-to-small operations, to modify a big integer from a native scalar.
271
272mod small {
273    use super::*;
274
275    // ADDITION
276
277    /// Implied AddAssign implementation for adding a small integer to bigint.
278    ///
279    /// Allows us to choose a start-index in x to store, to allow incrementing
280    /// from a non-zero start.
281    #[inline]
282    pub fn iadd_impl(x: &mut Vec<Limb>, y: Limb, xstart: usize) {
283        if x.len() <= xstart {
284            x.push(y);
285        } else {
286            // Initial add
287            let mut carry = scalar::iadd(&mut x[xstart], y);
288
289            // Increment until overflow stops occurring.
290            let mut size = xstart + 1;
291            while carry && size < x.len() {
292                carry = scalar::iadd(&mut x[size], 1);
293                size += 1;
294            }
295
296            // If we overflowed the buffer entirely, need to add 1 to the end
297            // of the buffer.
298            if carry {
299                x.push(1);
300            }
301        }
302    }
303
304    /// AddAssign small integer to bigint.
305    #[inline]
306    pub fn iadd(x: &mut Vec<Limb>, y: Limb) {
307        iadd_impl(x, y, 0);
308    }
309
310    // SUBTRACTION
311
312    /// SubAssign small integer to bigint.
313    /// Does not do overflowing subtraction.
314    #[inline]
315    pub fn isub_impl(x: &mut Vec<Limb>, y: Limb, xstart: usize) {
316        if true {
    if !(x.len() > xstart && (x[xstart] >= y || x.len() > xstart + 1)) {
        ::core::panicking::panic("assertion failed: x.len() > xstart && (x[xstart] >= y || x.len() > xstart + 1)")
    };
};debug_assert!(x.len() > xstart && (x[xstart] >= y || x.len() > xstart + 1));
317
318        // Initial subtraction
319        let mut carry = scalar::isub(&mut x[xstart], y);
320
321        // Increment until overflow stops occurring.
322        let mut size = xstart + 1;
323        while carry && size < x.len() {
324            carry = scalar::isub(&mut x[size], 1);
325            size += 1;
326        }
327        normalize(x);
328    }
329
330    // MULTIPLICATION
331
332    /// MulAssign small integer to bigint.
333    #[inline]
334    pub fn imul(x: &mut Vec<Limb>, y: Limb) {
335        // Multiply iteratively over all elements, adding the carry each time.
336        let mut carry: Limb = 0;
337        for xi in &mut *x {
338            carry = scalar::imul(xi, y, carry);
339        }
340
341        // Overflow of value, add to end.
342        if carry != 0 {
343            x.push(carry);
344        }
345    }
346
347    /// Mul small integer to bigint.
348    #[inline]
349    pub fn mul(x: &[Limb], y: Limb) -> Vec<Limb> {
350        let mut z = Vec::<Limb>::default();
351        z.extend_from_slice(x);
352        imul(&mut z, y);
353        z
354    }
355
356    /// MulAssign by a power.
357    ///
358    /// Theoretically...
359    ///
360    /// Use an exponentiation by squaring method, since it reduces the time
361    /// complexity of the multiplication to ~`O(log(n))` for the squaring,
362    /// and `O(n*m)` for the result. Since `m` is typically a lower-order
363    /// factor, this significantly reduces the number of multiplications
364    /// we need to do. Iteratively multiplying by small powers follows
365    /// the nth triangular number series, which scales as `O(p^2)`, but
366    /// where `p` is `n+m`. In short, it scales very poorly.
367    ///
368    /// Practically....
369    ///
370    /// Exponentiation by Squaring:
371    ///     running 2 tests
372    ///     test bigcomp_f32_lexical ... bench:       1,018 ns/iter (+/- 78)
373    ///     test bigcomp_f64_lexical ... bench:       3,639 ns/iter (+/- 1,007)
374    ///
375    /// Exponentiation by Iterative Small Powers:
376    ///     running 2 tests
377    ///     test bigcomp_f32_lexical ... bench:         518 ns/iter (+/- 31)
378    ///     test bigcomp_f64_lexical ... bench:         583 ns/iter (+/- 47)
379    ///
380    /// Exponentiation by Iterative Large Powers (of 2):
381    ///     running 2 tests
382    ///     test bigcomp_f32_lexical ... bench:         671 ns/iter (+/- 31)
383    ///     test bigcomp_f64_lexical ... bench:       1,394 ns/iter (+/- 47)
384    ///
385    /// Even using worst-case scenarios, exponentiation by squaring is
386    /// significantly slower for our workloads. Just multiply by small powers,
387    /// in simple cases, and use precalculated large powers in other cases.
388    pub fn imul_pow5(x: &mut Vec<Limb>, n: u32) {
389        use super::large::KARATSUBA_CUTOFF;
390
391        let small_powers = POW5_LIMB;
392        let large_powers = large_powers::POW5;
393
394        if n == 0 {
395            // No exponent, just return.
396            // The 0-index of the large powers is `2^0`, which is 1, so we want
397            // to make sure we don't take that path with a literal 0.
398            return;
399        }
400
401        // We want to use the asymptotically faster algorithm if we're going
402        // to be using Karabatsu multiplication sometime during the result,
403        // otherwise, just use exponentiation by squaring.
404        let bit_length = 32 - n.leading_zeros() as usize;
405        if true {
    if !(bit_length != 0 && bit_length <= large_powers.len()) {
        ::core::panicking::panic("assertion failed: bit_length != 0 && bit_length <= large_powers.len()")
    };
};debug_assert!(bit_length != 0 && bit_length <= large_powers.len());
406        if x.len() + large_powers[bit_length - 1].len() < 2 * KARATSUBA_CUTOFF {
407            // We can use iterative small powers to make this faster for the
408            // easy cases.
409
410            // Multiply by the largest small power until n < step.
411            let step = small_powers.len() - 1;
412            let power = small_powers[step];
413            let mut n = n as usize;
414            while n >= step {
415                imul(x, power);
416                n -= step;
417            }
418
419            // Multiply by the remainder.
420            imul(x, small_powers[n]);
421        } else {
422            // In theory, this code should be asymptotically a lot faster,
423            // in practice, our small::imul seems to be the limiting step,
424            // and large imul is slow as well.
425
426            // Multiply by higher order powers.
427            let mut idx: usize = 0;
428            let mut bit: usize = 1;
429            let mut n = n as usize;
430            while n != 0 {
431                if n & bit != 0 {
432                    if true {
    if !(idx < large_powers.len()) {
        ::core::panicking::panic("assertion failed: idx < large_powers.len()")
    };
};debug_assert!(idx < large_powers.len());
433                    large::imul(x, large_powers[idx]);
434                    n ^= bit;
435                }
436                idx += 1;
437                bit <<= 1;
438            }
439        }
440    }
441
442    // BIT LENGTH
443
444    /// Get number of leading zero bits in the storage.
445    #[inline]
446    pub fn leading_zeros(x: &[Limb]) -> usize {
447        x.last().map_or(0, |x| x.leading_zeros() as usize)
448    }
449
450    /// Calculate the bit-length of the big-integer.
451    #[inline]
452    pub fn bit_length(x: &[Limb]) -> usize {
453        let bits = mem::size_of::<Limb>() * 8;
454        // Avoid overflowing, calculate via total number of bits
455        // minus leading zero bits.
456        let nlz = leading_zeros(x);
457        bits.checked_mul(x.len()).map_or(usize::MAX, |v| v - nlz)
458    }
459
460    // SHL
461
462    /// Shift-left bits inside a buffer.
463    ///
464    /// Assumes `n < Limb::BITS`, IE, internally shifting bits.
465    #[inline]
466    pub fn ishl_bits(x: &mut Vec<Limb>, n: usize) {
467        // Need to shift by the number of `bits % Limb::BITS)`.
468        let bits = mem::size_of::<Limb>() * 8;
469        if true {
    if !(n < bits) { ::core::panicking::panic("assertion failed: n < bits") };
};debug_assert!(n < bits);
470        if n == 0 {
471            return;
472        }
473
474        // Internally, for each item, we shift left by n, and add the previous
475        // right shifted limb-bits.
476        // For example, we transform (for u8) shifted left 2, to:
477        //      b10100100 b01000010
478        //      b10 b10010001 b00001000
479        let rshift = bits - n;
480        let lshift = n;
481        let mut prev: Limb = 0;
482        for xi in &mut *x {
483            let tmp = *xi;
484            *xi <<= lshift;
485            *xi |= prev >> rshift;
486            prev = tmp;
487        }
488
489        // Always push the carry, even if it creates a non-normal result.
490        let carry = prev >> rshift;
491        if carry != 0 {
492            x.push(carry);
493        }
494    }
495
496    /// Shift-left `n` digits inside a buffer.
497    ///
498    /// Assumes `n` is not 0.
499    #[inline]
500    pub fn ishl_limbs(x: &mut Vec<Limb>, n: usize) {
501        if true {
    if !(n != 0) { ::core::panicking::panic("assertion failed: n != 0") };
};debug_assert!(n != 0);
502        if !x.is_empty() {
503            x.reserve(n);
504            x.splice(..0, iter::repeat(0).take(n));
505        }
506    }
507
508    /// Shift-left buffer by n bits.
509    #[inline]
510    pub fn ishl(x: &mut Vec<Limb>, n: usize) {
511        let bits = mem::size_of::<Limb>() * 8;
512        // Need to pad with zeros for the number of `bits / Limb::BITS`,
513        // and shift-left with carry for `bits % Limb::BITS`.
514        let rem = n % bits;
515        let div = n / bits;
516        ishl_bits(x, rem);
517        if div != 0 {
518            ishl_limbs(x, div);
519        }
520    }
521
522    // NORMALIZE
523
524    /// Normalize the container by popping any leading zeros.
525    #[inline]
526    pub fn normalize(x: &mut Vec<Limb>) {
527        // Remove leading zero if we cause underflow. Since we're dividing
528        // by a small power, we have at max 1 int removed.
529        while x.last() == Some(&0) {
530            x.pop();
531        }
532    }
533} // small
534
535// LARGE
536// -----
537
538// Large-to-large operations, to modify a big integer from a native scalar.
539
540mod large {
541    use super::*;
542
543    // RELATIVE OPERATORS
544
545    /// Compare `x` to `y`, in little-endian order.
546    #[inline]
547    pub fn compare(x: &[Limb], y: &[Limb]) -> cmp::Ordering {
548        if x.len() > y.len() {
549            cmp::Ordering::Greater
550        } else if x.len() < y.len() {
551            cmp::Ordering::Less
552        } else {
553            let iter = x.iter().rev().zip(y.iter().rev());
554            for (&xi, &yi) in iter {
555                if xi > yi {
556                    return cmp::Ordering::Greater;
557                } else if xi < yi {
558                    return cmp::Ordering::Less;
559                }
560            }
561            // Equal case.
562            cmp::Ordering::Equal
563        }
564    }
565
566    /// Check if x is less than y.
567    #[inline]
568    pub fn less(x: &[Limb], y: &[Limb]) -> bool {
569        compare(x, y) == cmp::Ordering::Less
570    }
571
572    /// Check if x is greater than or equal to y.
573    #[inline]
574    pub fn greater_equal(x: &[Limb], y: &[Limb]) -> bool {
575        !less(x, y)
576    }
577
578    // ADDITION
579
580    /// Implied AddAssign implementation for bigints.
581    ///
582    /// Allows us to choose a start-index in x to store, so we can avoid
583    /// padding the buffer with zeros when not needed, optimized for vectors.
584    pub fn iadd_impl(x: &mut Vec<Limb>, y: &[Limb], xstart: usize) {
585        // The effective x buffer is from `xstart..x.len()`, so we need to treat
586        // that as the current range. If the effective y buffer is longer, need
587        // to resize to that, + the start index.
588        if y.len() > x.len() - xstart {
589            x.resize(y.len() + xstart, 0);
590        }
591
592        // Iteratively add elements from y to x.
593        let mut carry = false;
594        for (xi, yi) in x[xstart..].iter_mut().zip(y.iter()) {
595            // Only one op of the two can overflow, since we added at max
596            // Limb::MAX + Limb::MAX. Add the previous carry, and store the
597            // current carry for the next.
598            let mut tmp = scalar::iadd(xi, *yi);
599            if carry {
600                tmp |= scalar::iadd(xi, 1);
601            }
602            carry = tmp;
603        }
604
605        // Overflow from the previous bit.
606        if carry {
607            small::iadd_impl(x, 1, y.len() + xstart);
608        }
609    }
610
611    /// AddAssign bigint to bigint.
612    #[inline]
613    pub fn iadd(x: &mut Vec<Limb>, y: &[Limb]) {
614        iadd_impl(x, y, 0);
615    }
616
617    /// Add bigint to bigint.
618    #[inline]
619    pub fn add(x: &[Limb], y: &[Limb]) -> Vec<Limb> {
620        let mut z = Vec::<Limb>::default();
621        z.extend_from_slice(x);
622        iadd(&mut z, y);
623        z
624    }
625
626    // SUBTRACTION
627
628    /// SubAssign bigint to bigint.
629    pub fn isub(x: &mut Vec<Limb>, y: &[Limb]) {
630        // Basic underflow checks.
631        if true {
    if !greater_equal(x, y) {
        ::core::panicking::panic("assertion failed: greater_equal(x, y)")
    };
};debug_assert!(greater_equal(x, y));
632
633        // Iteratively add elements from y to x.
634        let mut carry = false;
635        for (xi, yi) in x.iter_mut().zip(y.iter()) {
636            // Only one op of the two can overflow, since we added at max
637            // Limb::MAX + Limb::MAX. Add the previous carry, and store the
638            // current carry for the next.
639            let mut tmp = scalar::isub(xi, *yi);
640            if carry {
641                tmp |= scalar::isub(xi, 1);
642            }
643            carry = tmp;
644        }
645
646        if carry {
647            small::isub_impl(x, 1, y.len());
648        } else {
649            small::normalize(x);
650        }
651    }
652
653    // MULTIPLICATION
654
655    /// Number of digits to bottom-out to asymptotically slow algorithms.
656    ///
657    /// Karatsuba tends to out-perform long-multiplication at ~320-640 bits,
658    /// so we go halfway, while Newton division tends to out-perform
659    /// Algorithm D at ~1024 bits. We can toggle this for optimal performance.
660    pub const KARATSUBA_CUTOFF: usize = 32;
661
662    /// Grade-school multiplication algorithm.
663    ///
664    /// Slow, naive algorithm, using limb-bit bases and just shifting left for
665    /// each iteration. This could be optimized with numerous other algorithms,
666    /// but it's extremely simple, and works in O(n*m) time, which is fine
667    /// by me. Each iteration, of which there are `m` iterations, requires
668    /// `n` multiplications, and `n` additions, or grade-school multiplication.
669    fn long_mul(x: &[Limb], y: &[Limb]) -> Vec<Limb> {
670        // Using the immutable value, multiply by all the scalars in y, using
671        // the algorithm defined above. Use a single buffer to avoid
672        // frequent reallocations. Handle the first case to avoid a redundant
673        // addition, since we know y.len() >= 1.
674        let mut z: Vec<Limb> = small::mul(x, y[0]);
675        z.resize(x.len() + y.len(), 0);
676
677        // Handle the iterative cases.
678        for (i, &yi) in y[1..].iter().enumerate() {
679            let zi: Vec<Limb> = small::mul(x, yi);
680            iadd_impl(&mut z, &zi, i + 1);
681        }
682
683        small::normalize(&mut z);
684
685        z
686    }
687
688    /// Split two buffers into halfway, into (lo, hi).
689    #[inline]
690    pub fn karatsuba_split(z: &[Limb], m: usize) -> (&[Limb], &[Limb]) {
691        (&z[..m], &z[m..])
692    }
693
694    /// Karatsuba multiplication algorithm with roughly equal input sizes.
695    ///
696    /// Assumes `y.len() >= x.len()`.
697    fn karatsuba_mul(x: &[Limb], y: &[Limb]) -> Vec<Limb> {
698        if y.len() <= KARATSUBA_CUTOFF {
699            // Bottom-out to long division for small cases.
700            long_mul(x, y)
701        } else if x.len() < y.len() / 2 {
702            karatsuba_uneven_mul(x, y)
703        } else {
704            // Do our 3 multiplications.
705            let m = y.len() / 2;
706            let (xl, xh) = karatsuba_split(x, m);
707            let (yl, yh) = karatsuba_split(y, m);
708            let sumx = add(xl, xh);
709            let sumy = add(yl, yh);
710            let z0 = karatsuba_mul(xl, yl);
711            let mut z1 = karatsuba_mul(&sumx, &sumy);
712            let z2 = karatsuba_mul(xh, yh);
713            // Properly scale z1, which is `z1 - z2 - zo`.
714            isub(&mut z1, &z2);
715            isub(&mut z1, &z0);
716
717            // Create our result, which is equal to, in little-endian order:
718            // [z0, z1 - z2 - z0, z2]
719            //  z1 must be shifted m digits (2^(32m)) over.
720            //  z2 must be shifted 2*m digits (2^(64m)) over.
721            let len = z0.len().max(m + z1.len()).max(2 * m + z2.len());
722            let mut result = z0;
723            result.reserve_exact(len - result.len());
724            iadd_impl(&mut result, &z1, m);
725            iadd_impl(&mut result, &z2, 2 * m);
726
727            result
728        }
729    }
730
731    /// Karatsuba multiplication algorithm where y is substantially larger than x.
732    ///
733    /// Assumes `y.len() >= x.len()`.
734    fn karatsuba_uneven_mul(x: &[Limb], mut y: &[Limb]) -> Vec<Limb> {
735        let mut result = Vec::<Limb>::default();
736        result.resize(x.len() + y.len(), 0);
737
738        // This effectively is like grade-school multiplication between
739        // two numbers, except we're using splits on `y`, and the intermediate
740        // step is a Karatsuba multiplication.
741        let mut start = 0;
742        while !y.is_empty() {
743            let m = x.len().min(y.len());
744            let (yl, yh) = karatsuba_split(y, m);
745            let prod = karatsuba_mul(x, yl);
746            iadd_impl(&mut result, &prod, start);
747            y = yh;
748            start += m;
749        }
750        small::normalize(&mut result);
751
752        result
753    }
754
755    /// Forwarder to the proper Karatsuba algorithm.
756    #[inline]
757    fn karatsuba_mul_fwd(x: &[Limb], y: &[Limb]) -> Vec<Limb> {
758        if x.len() < y.len() {
759            karatsuba_mul(x, y)
760        } else {
761            karatsuba_mul(y, x)
762        }
763    }
764
765    /// MulAssign bigint to bigint.
766    #[inline]
767    pub fn imul(x: &mut Vec<Limb>, y: &[Limb]) {
768        if y.len() == 1 {
769            small::imul(x, y[0]);
770        } else {
771            // We're not really in a condition where using Karatsuba
772            // multiplication makes sense, so we're just going to use long
773            // division. ~20% speedup compared to:
774            //      *x = karatsuba_mul_fwd(x, y);
775            *x = karatsuba_mul_fwd(x, y);
776        }
777    }
778} // large
779
780// TRAITS
781// ------
782
783/// Traits for shared operations for big integers.
784///
785/// None of these are implemented using normal traits, since these
786/// are very expensive operations, and we want to deliberately
787/// and explicitly use these functions.
788pub(crate) trait Math: Clone + Sized + Default {
789    // DATA
790
791    /// Get access to the underlying data
792    fn data(&self) -> &Vec<Limb>;
793
794    /// Get access to the underlying data
795    fn data_mut(&mut self) -> &mut Vec<Limb>;
796
797    // RELATIVE OPERATIONS
798
799    /// Compare self to y.
800    #[inline]
801    fn compare(&self, y: &Self) -> cmp::Ordering {
802        large::compare(self.data(), y.data())
803    }
804
805    // PROPERTIES
806
807    /// Get the high 64-bits from the bigint and if there are remaining bits.
808    #[inline]
809    fn hi64(&self) -> (u64, bool) {
810        self.data().as_slice().hi64()
811    }
812
813    /// Calculate the bit-length of the big-integer.
814    /// Returns usize::MAX if the value overflows,
815    /// IE, if `self.data().len() > usize::MAX / 8`.
816    #[inline]
817    fn bit_length(&self) -> usize {
818        small::bit_length(self.data())
819    }
820
821    // INTEGER CONVERSIONS
822
823    /// Create new big integer from u64.
824    #[inline]
825    fn from_u64(x: u64) -> Self {
826        let mut v = Self::default();
827        let slc = split_u64(x);
828        v.data_mut().extend_from_slice(&slc);
829        v.normalize();
830        v
831    }
832
833    // NORMALIZE
834
835    /// Normalize the integer, so any leading zero values are removed.
836    #[inline]
837    fn normalize(&mut self) {
838        small::normalize(self.data_mut());
839    }
840
841    // ADDITION
842
843    /// AddAssign small integer.
844    #[inline]
845    fn iadd_small(&mut self, y: Limb) {
846        small::iadd(self.data_mut(), y);
847    }
848
849    // MULTIPLICATION
850
851    /// MulAssign small integer.
852    #[inline]
853    fn imul_small(&mut self, y: Limb) {
854        small::imul(self.data_mut(), y);
855    }
856
857    /// Multiply by a power of 2.
858    #[inline]
859    fn imul_pow2(&mut self, n: u32) {
860        self.ishl(n as usize);
861    }
862
863    /// Multiply by a power of 5.
864    #[inline]
865    fn imul_pow5(&mut self, n: u32) {
866        small::imul_pow5(self.data_mut(), n);
867    }
868
869    /// MulAssign by a power of 10.
870    #[inline]
871    fn imul_pow10(&mut self, n: u32) {
872        self.imul_pow5(n);
873        self.imul_pow2(n);
874    }
875
876    // SHIFTS
877
878    /// Shift-left the entire buffer n bits.
879    #[inline]
880    fn ishl(&mut self, n: usize) {
881        small::ishl(self.data_mut(), n);
882    }
883}