Skip to main content

a/math/numbers/
gcd.rs

1//! Greatest common divisors of [`Number`]s: [`Number::gcd`], [`Number::lcm`],
2//! [`Number::gcd_ext`] and [`Number::mod_inverse`].
3//!
4//! Operands whose vectors both hold at most 16 bytes take short paths in registers: the binary
5//! method for the greatest common divisor, and for the cofactors Euclid's algorithm on two limbs,
6//! with the steps that Lehmer's method finds from the top limbs, then on one.
7//!
8//! Longer operands are read into limbs of eight bytes, native `u64`s, the least significant first,
9//! in working memory on the stack, or on the heap for the longest (see [`limbs`]). A much longer
10//! operand is first divided by the shorter one, and the remainder takes its place. From there the
11//! numbers are reduced by Lehmer's method: the quotients of many of Euclid's steps are found from
12//! the top two limbs of the numbers by Möller's hgcd2, and their matrix is applied to the whole
13//! numbers in one pass, two limbs read and two written a position. The greatest common divisor
14//! alone shifts the zero bits at the low end out of both numbers first, which keeps it odd, and
15//! finishes on two limbs by the binary method; the extended algorithm keeps a row of the matrices'
16//! product, the cofactor of one number, and finishes on one limb by Euclid's divisions. Numbers of
17//! [`GCD_DC_THRESHOLD`] limbs and more (of [`GCDEXT_DC_THRESHOLD`] for the cofactors) are first
18//! reduced by Möller's subquadratic half gcd on the multiplication (see [`hgcd`]).
19//!
20//! `lcm` divides the shorter operand exactly by the greatest common divisor and multiplies the
21//! quotient by the longer one; `mod_inverse` takes the extended algorithm on the operand modulo
22//! the modulus and the modulus, and keeps the cofactor of the operand.
23
24// The kernels under the name `kernels`, chosen as those of the multiplication are: assembly on
25// 64-bit little-endian aarch64 where the system allows unaligned accesses, and portable Rust
26// elsewhere and under Miri.
27mod hgcd;
28#[cfg(all(
29    target_arch = "aarch64",
30    target_endian = "little",
31    target_pointer_width = "64",
32    any(
33        target_vendor = "apple",
34        target_os = "linux",
35        target_os = "android",
36        target_os = "windows",
37        target_os = "freebsd",
38        target_os = "netbsd",
39        target_os = "openbsd",
40        target_os = "fuchsia"
41    ),
42    not(miri)
43))]
44#[path = "gcd/aarch64.rs"]
45mod kernels;
46#[cfg(not(all(
47    target_arch = "aarch64",
48    target_endian = "little",
49    target_pointer_width = "64",
50    any(
51        target_vendor = "apple",
52        target_os = "linux",
53        target_os = "android",
54        target_os = "windows",
55        target_os = "freebsd",
56        target_os = "netbsd",
57        target_os = "openbsd",
58        target_os = "fuchsia"
59    ),
60    not(miri)
61)))]
62#[path = "gcd/portable.rs"]
63mod kernels;
64mod limbs;
65
66use super::add::{read_small, significant_len, small, write_small};
67use super::mul::limbs::mul;
68use super::mul::{Operand, Product, STACK_LIMBS, on_heap, on_stack, to_limbs};
69use super::{ByteOrder, Number};
70use core::mem::MaybeUninit;
71use core::ptr;
72use hgcd::{GCD_DC_THRESHOLD, GCDEXT_DC_THRESHOLD, gcd_dc, gcd_dc_itch, gcdext, gcdext_dc_itch};
73use limbs::{
74    Row, Step, add_to, divexact, divexact_itch, gcd_11, gcd_lehmer, gcd_u128, gcdext_1, hgcd2,
75    lehmer_ext_itch, lshift, mul_bound, normalized, rem_1, rshift, sub_from, tdiv_itch, tdiv_qr,
76    with_scratch,
77};
78
79impl Number {
80    /// Returns the greatest common divisor of `self` and `other`, in the byte order of `self`, in
81    /// the shortest form: the largest number that divides both, never negative.
82    ///
83    /// As for GMP's `mpz_gcd`, `gcd(x, 0) = |x|`, and `gcd(0, 0) = 0`. Signs do not count. Both
84    /// operands are left as they were, and the result is built in one new vector.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use a::math::numbers::{ByteOrder, Number};
90    ///
91    /// let a = Number::new_from_i32(-84, ByteOrder::BigEndian);
92    /// let b = Number::new_from_i32(36, ByteOrder::LittleEndian);
93    /// let g = a.gcd(&b);
94    /// assert_eq!(g.value, [12]);
95    /// assert!(!g.is_negative());
96    /// assert!(g.byte_order() == ByteOrder::BigEndian);
97    /// ```
98    pub fn gcd(&self, other: &Number) -> Number {
99        if small(self, other) {
100            // SAFETY: both vectors hold at most 16 bytes.
101            let (x, y) = unsafe {
102                (
103                    read_small(&self.value, self.byte_order),
104                    read_small(&other.value, other.byte_order),
105                )
106            };
107            return small_number(self.byte_order, gcd_u128(x, y), false);
108        }
109        gcd_general(self, other)
110    }
111
112    /// Returns the least common multiple of `self` and `other`, in the byte order of `self`, in
113    /// the shortest form: the smallest number that both divide, never negative, and zero when
114    /// either is zero, as GMP's `mpz_lcm` gives it.
115    ///
116    /// It is computed as `|a| / gcd(a, b) · |b|`, the shorter operand divided exactly by the
117    /// greatest common divisor, and the quotient multiplied by the longer one.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use a::math::numbers::{ByteOrder, Number};
123    ///
124    /// let a = Number::new_from_i32(-4, ByteOrder::LittleEndian);
125    /// let b = Number::new_from_i32(6, ByteOrder::BigEndian);
126    /// let l = a.lcm(&b);
127    /// assert_eq!(l.value, [12]);
128    /// assert!(!l.is_negative());
129    /// ```
130    pub fn lcm(&self, other: &Number) -> Number {
131        if small(self, other) {
132            // SAFETY: both vectors hold at most 16 bytes.
133            let (x, y) = unsafe {
134                (
135                    read_small(&self.value, self.byte_order),
136                    read_small(&other.value, other.byte_order),
137                )
138            };
139            return small_lcm(self.byte_order, x, y);
140        }
141        lcm_general(self, other)
142    }
143
144    /// Returns `(g, x, y)`: the greatest common divisor `g` of `self` and `other`, never negative,
145    /// and cofactors with `g = self · x + other · y`, all three in the byte order of `self` and in
146    /// the shortest form.
147    ///
148    /// The cofactors are those of GMP's `mpz_gcdext`: `|x| < |other| / 2g` and `|y| < |self| / 2g`,
149    /// which define them uniquely, but for a few cases. When `|self| = |other|`, `x = 0` and `y =
150    /// sgn(other)`; otherwise `x = sgn(self)` when `other = 0` or `|other| = 2g`, and `y =
151    /// sgn(other)` when `self = 0` or `|self| = 2g`. So `x = 0` exactly when `g = |other|`, and
152    /// `gcd_ext(0, 0) = (0, 0, 0)`.
153    ///
154    /// # Examples
155    ///
156    /// ```
157    /// use a::math::numbers::{ByteOrder, Number};
158    ///
159    /// // gcd(240, -46) = 2 = 240 · (-9) + (-46) · (-47).
160    /// let a = Number::new_from_i32(240, ByteOrder::BigEndian);
161    /// let b = Number::new_from_i32(-46, ByteOrder::BigEndian);
162    /// let (g, x, y) = a.gcd_ext(&b);
163    /// assert_eq!(g.value, [2]);
164    /// assert_eq!((x.is_negative(), x.value), (true, vec![9]));
165    /// assert_eq!((y.is_negative(), y.value), (true, vec![47]));
166    /// ```
167    pub fn gcd_ext(&self, other: &Number) -> (Number, Number, Number) {
168        if small(self, other) {
169            // SAFETY: both vectors hold at most 16 bytes.
170            let (x, y) = unsafe {
171                (
172                    read_small(&self.value, self.byte_order),
173                    read_small(&other.value, other.byte_order),
174                )
175            };
176            return small_gcd_ext(self.byte_order, x, self.negative, y, other.negative);
177        }
178        gcd_ext_general(self, other)
179    }
180
181    /// Returns the inverse of `self` modulo `|modulus|`: the `r` with `0 <= r < |modulus|` and
182    /// `self · r = 1` modulo `|modulus|`, in the byte order of `self` and in the shortest form, or
183    /// `None` when there is none, which is when `self` and `modulus` have a common divisor besides
184    /// 1. As for GMP's `mpz_invert`, every number has the inverse 0 modulo 1.
185    ///
186    /// # Panics
187    ///
188    /// When `modulus` is zero, with the message of `%`.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use a::math::numbers::{ByteOrder, Number};
194    ///
195    /// // 3 · 4 = 12 = 1 modulo 11, and -3 · 7 = -21 = 1 modulo 11.
196    /// let m = Number::new_from_i32(11, ByteOrder::BigEndian);
197    /// let r = Number::new_from_i32(3, ByteOrder::BigEndian).mod_inverse(&m).unwrap();
198    /// assert_eq!(r.value, [4]);
199    /// let r = Number::new_from_i32(-3, ByteOrder::BigEndian).mod_inverse(&m).unwrap();
200    /// assert_eq!(r.value, [7]);
201    ///
202    /// // 6 and 9 have the common divisor 3.
203    /// let m = Number::new_from_i32(9, ByteOrder::BigEndian);
204    /// assert!(Number::new_from_i32(6, ByteOrder::BigEndian).mod_inverse(&m).is_none());
205    /// ```
206    #[track_caller]
207    pub fn mod_inverse(&self, modulus: &Number) -> Option<Number> {
208        if small(self, modulus) {
209            // SAFETY: both vectors hold at most 16 bytes.
210            let (x, n) = unsafe {
211                (
212                    read_small(&self.value, self.byte_order),
213                    read_small(&modulus.value, modulus.byte_order),
214                )
215            };
216            if n == 0 {
217                by_zero();
218            }
219            return small_inverse(x, self.negative, n)
220                .map(|r| small_number(self.byte_order, r, false));
221        }
222        inverse_general(self, modulus)
223    }
224}
225
226/// Panics for a modulus of zero, with the message of `%`.
227#[cold]
228#[inline(never)]
229#[track_caller]
230fn by_zero() -> ! {
231    panic!("attempt to calculate the remainder with a divisor of zero")
232}
233
234// Numbers of up to 16 bytes
235
236/// The magnitude `m` with the sign `negative`, which zero does not keep, as a number in one new
237/// vector of exactly its length in the byte order `order`.
238#[inline]
239fn small_number(order: ByteOrder, m: u128, negative: bool) -> Number {
240    let len = 16 - (m | 1).leading_zeros() as usize / 8;
241    let mut v = Vec::with_capacity(len);
242    // SAFETY: the new vector has room for the `len` bytes, from 1 to 16, all of which
243    // `write_small` writes before the length is set.
244    unsafe {
245        write_small(v.as_mut_ptr(), order, m as u64, (m >> 64) as u64, len);
246        v.set_len(len);
247    }
248    Number {
249        value: v,
250        negative: negative && m != 0,
251        byte_order: order,
252    }
253}
254
255/// The least common multiple of the magnitudes `x` and `y`, of up to 16 bytes each, as a number in
256/// the byte order `order`: the one divided by the greatest common divisor, by the hardware's
257/// division when both fit in a limb, and the quotient times the other, in four limbs.
258fn small_lcm(order: ByteOrder, x: u128, y: u128) -> Number {
259    let g = gcd_u128(x, y);
260    if g == 0 {
261        return small_number(order, 0, false);
262    }
263    let q = if (x | g) >> 64 == 0 {
264        u128::from(x as u64 / g as u64)
265    } else {
266        x / g
267    };
268    let (q0, q1, y0, y1) = (q as u64, (q >> 64) as u64, y as u64, (y >> 64) as u64);
269    let mul = |a: u64, b: u64| u128::from(a) * u128::from(b);
270    let (p00, p01, p10, p11) = (mul(q0, y0), mul(q0, y1), mul(q1, y0), mul(q1, y1));
271    let c1 = (p00 >> 64) + u128::from(p01 as u64) + u128::from(p10 as u64);
272    let c2 = (c1 >> 64) + (p01 >> 64) + (p10 >> 64) + u128::from(p11 as u64);
273    let c3 = (c2 >> 64) + (p11 >> 64);
274    let limbs = [p00 as u64, c1 as u64, c2 as u64, c3 as u64];
275    // SAFETY: the four limbs are valid for reads while the number is written.
276    unsafe { limbs_number(limbs.as_ptr(), 4, false, order) }
277}
278
279/// A cofactor of up to two limbs: its magnitude and whether it is negative.
280type Signed = (u128, bool);
281
282/// `x - q y` for cofactors held as `i128`s, whose values all fit.
283#[inline(always)]
284fn less_times(x: i128, q: u128, y: i128) -> i128 {
285    x.wrapping_sub((q as i128).wrapping_mul(y))
286}
287
288/// The greatest common divisor `g` of the magnitudes `x` and `y`, of up to two limbs each and not
289/// zero, and the cofactors `s` and `t` of `g = s x + t y` that [`Number::gcd_ext`] promises:
290/// Euclid's algorithm on two limbs, with the steps that [`hgcd2`] finds from the numbers shifted
291/// together applied at once, then on one limb by [`gcdext_1`], keeping the cofactors of both
292/// numbers.
293fn gcdext_u128(x: u128, y: u128) -> (u128, i128, i128) {
294    let (mut a, mut b) = (x, y);
295    // a = sa x + ta y and b = sb x + tb y; every cofactor fits in an `i128`, as each is at most
296    // half the other number.
297    let (mut sa, mut ta, mut sb, mut tb) = (1i128, 0i128, 0i128, 1i128);
298    while (a | b) >> 64 != 0 {
299        let s = (a | b).leading_zeros();
300        let (ah, bh) = (a << s, b << s);
301        if let Some(m) = hgcd2((ah >> 64) as u64, ah as u64, (bh >> 64) as u64, bh as u64) {
302            // The reduced numbers fit in two limbs, so they are right modulo 2^128, as are the
303            // cofactors, which fit as well.
304            let (u00, u01, u10, u11) = (
305                u128::from(m.u00),
306                u128::from(m.u01),
307                u128::from(m.u10),
308                u128::from(m.u11),
309            );
310            (a, b) = (
311                u11.wrapping_mul(a).wrapping_sub(u01.wrapping_mul(b)),
312                u00.wrapping_mul(b).wrapping_sub(u10.wrapping_mul(a)),
313            );
314            let (i00, i01, i10, i11) = (u00 as i128, u01 as i128, u10 as i128, u11 as i128);
315            (sa, sb) = (
316                i11.wrapping_mul(sa).wrapping_sub(i01.wrapping_mul(sb)),
317                i00.wrapping_mul(sb).wrapping_sub(i10.wrapping_mul(sa)),
318            );
319            (ta, tb) = (
320                i11.wrapping_mul(ta).wrapping_sub(i01.wrapping_mul(tb)),
321                i00.wrapping_mul(tb).wrapping_sub(i10.wrapping_mul(ta)),
322            );
323            continue;
324        }
325        // One step of Euclid's: the larger number modulo the smaller.
326        if a == b {
327            return smaller_pair(a, (sa, ta), (sb, tb));
328        }
329        if a > b {
330            let q = a / b;
331            a -= q * b;
332            if a == 0 {
333                return (b, sb, tb);
334            }
335            sa = less_times(sa, q, sb);
336            ta = less_times(ta, q, tb);
337        } else {
338            let q = b / a;
339            b -= q * a;
340            if b == 0 {
341                return (a, sa, ta);
342            }
343            sb = less_times(sb, q, sa);
344            tb = less_times(tb, q, ta);
345        }
346    }
347    if a == b {
348        return smaller_pair(a, (sa, ta), (sb, tb));
349    }
350    let (g, u, v) = gcdext_1(a as u64, b as u64);
351    let (u, v) = (i128::from(u), i128::from(v));
352    (
353        u128::from(g),
354        u.wrapping_mul(sa).wrapping_add(v.wrapping_mul(sb)),
355        u.wrapping_mul(ta).wrapping_add(v.wrapping_mul(tb)),
356    )
357}
358
359/// The greatest common divisor `g` when both numbers of [`gcdext_u128`] are `g`, with the pair of
360/// cofactors of the two whose first cofactor is the smaller, or the positive one when they are
361/// equal in magnitude: Euclid's.
362#[inline]
363fn smaller_pair(g: u128, a: (i128, i128), b: (i128, i128)) -> (u128, i128, i128) {
364    let (ua, ub) = (a.0.unsigned_abs(), b.0.unsigned_abs());
365    let pick_b = ub < ua || (ub == ua && b.0 > 0);
366    let (s, t) = if pick_b { b } else { a };
367    (g, s, t)
368}
369
370/// [`Number::gcd_ext`] of operands of up to 16 bytes, magnitudes `x` and `y` with their signs, in
371/// the byte order `order`.
372fn small_gcd_ext(
373    order: ByteOrder,
374    x: u128,
375    negative_x: bool,
376    y: u128,
377    negative_y: bool,
378) -> (Number, Number, Number) {
379    let sgn = |m: u128, negative: bool| -> Signed { (u128::from(m != 0), negative) };
380    let (g, s, t) = if y == 0 {
381        (x, sgn(x, negative_x), (0, false))
382    } else if x == 0 {
383        (y, (0, false), sgn(y, negative_y))
384    } else if x == y {
385        (x, (0, false), (1, negative_y))
386    } else {
387        let (g, s, t) = gcdext_u128(x, y);
388        (
389            g,
390            (s.unsigned_abs(), (s < 0) != negative_x),
391            (t.unsigned_abs(), (t < 0) != negative_y),
392        )
393    };
394    (
395        small_number(order, g, false),
396        small_number(order, s.0, s.1),
397        small_number(order, t.0, t.1),
398    )
399}
400
401/// The inverse of `x`, of sign `negative`, modulo `n`, not zero, of up to two limbs each, or
402/// `None`.
403fn small_inverse(x: u128, negative: bool, n: u128) -> Option<u128> {
404    if n == 1 {
405        return Some(0);
406    }
407    let x = x % n;
408    if x == 0 {
409        return None;
410    }
411    let (g, s, _) = gcdext_u128(x, n);
412    if g != 1 {
413        return None;
414    }
415    let r = if s < 0 {
416        n - s.unsigned_abs()
417    } else {
418        s as u128
419    };
420    Some(if negative && r != 0 { n - r } else { r })
421}
422
423// Writing results
424
425/// The `n` limbs at `r` as a number of sign `negative` in the byte order `order`, in one new vector
426/// of exactly its length; zero, which is never negative, when they are all zero.
427///
428/// # Safety
429///
430/// The limbs must be valid for reads.
431unsafe fn limbs_number(r: *const u64, n: usize, negative: bool, order: ByteOrder) -> Number {
432    // SAFETY: as the caller guarantees.
433    unsafe {
434        let top = normalized(r, n);
435        let p = if top == 0 {
436            Product {
437                r: ptr::null(),
438                len: 1,
439                negative: false,
440            }
441        } else {
442            Product {
443                r,
444                len: 8 * top - (*r.add(top - 1)).leading_zeros() as usize / 8,
445                negative,
446            }
447        };
448        let mut v = Vec::with_capacity(p.len);
449        p.write(v.as_mut_ptr(), order);
450        v.set_len(p.len);
451        Number {
452            value: v,
453            negative: p.negative,
454            byte_order: order,
455        }
456    }
457}
458
459/// The magnitude of `n` with the sign `negative`, which zero does not keep, in the byte order
460/// `order`, in the shortest form, in one new vector.
461fn magnitude(n: &Number, negative: bool, order: ByteOrder) -> Number {
462    let be = n.byte_order == ByteOrder::BigEndian;
463    let len = if be {
464        significant_len::<true>(&n.value)
465    } else {
466        significant_len::<false>(&n.value)
467    };
468    let bytes = if be {
469        &n.value[n.value.len() - len..]
470    } else {
471        &n.value[..len]
472    };
473    let value = if len == 0 {
474        vec![0]
475    } else if n.byte_order == order {
476        bytes.to_vec()
477    } else {
478        bytes.iter().rev().copied().collect()
479    };
480    Number {
481        value,
482        negative: negative && len != 0,
483        byte_order: order,
484    }
485}
486
487/// The sign of a number of sign `negative` and magnitude not zero when `nonzero`, as a number:
488/// -1, 0 or 1, in the byte order `order`.
489fn sign(nonzero: bool, negative: bool, order: ByteOrder) -> Number {
490    small_number(order, u128::from(nonzero), negative)
491}
492
493// Working memory
494
495/// Runs `f` on `need` limbs of working memory, on the stack up to [`STACK_LIMBS`], aligned to 16
496/// bytes.
497#[inline(always)]
498fn working<R>(need: usize, f: impl FnOnce(*mut u64) -> R) -> R {
499    let run = |s: *mut MaybeUninit<u64>| f(s.cast());
500    if need <= STACK_LIMBS {
501        on_stack(run)
502    } else {
503        on_heap(need, run)
504    }
505}
506
507/// Shifts the zero bits at the low end out of the `n` limbs at `p`, not all zero, in place, and
508/// returns the limbs left without those at the top that become zero, and the number of bits.
509///
510/// # Safety
511///
512/// The limbs must be valid for reads and writes.
513unsafe fn strip(p: *mut u64, n: usize) -> (usize, usize) {
514    // SAFETY: as the caller guarantees: a limb that is not zero comes before the end.
515    unsafe {
516        let mut skip = 0;
517        while *p.add(skip) == 0 {
518            skip += 1;
519        }
520        let bits = (*p.add(skip)).trailing_zeros();
521        let m = n - skip;
522        if skip > 0 {
523            ptr::copy(p.add(skip), p, m);
524        }
525        if bits > 0 {
526            rshift(p, p, m, bits);
527        }
528        (normalized(p, m), 64 * skip + bits as usize)
529    }
530}
531
532// The greatest common divisor
533
534/// `a.gcd(b)` for operands of which at least one has more than 16 bytes.
535#[inline(never)]
536fn gcd_general(a: &Number, b: &Number) -> Number {
537    let order = a.byte_order;
538    let (x, y) = (Operand::of(a), Operand::of(b));
539    if x.significant == 0 {
540        return magnitude(b, false, order);
541    }
542    if y.significant == 0 {
543        return magnitude(a, false, order);
544    }
545    let (nx, ny) = (x.significant.div_ceil(8), y.significant.div_ceil(8));
546    let (long, short) = (nx.max(ny), nx.min(ny));
547    // Both numbers with a limb to spare, the result shifted with a limb above it and its zero
548    // limbs, and the scratch of the first division and of the steps.
549    let need = (nx + 1) + (ny + 1) + (long + 2) + gcd_itch(long, short);
550    working(need, |s| {
551        // SAFETY: the working memory holds the limbs counted above; the operands are borrowed.
552        unsafe {
553            let (pa, pb) = (s, s.add(nx + 1));
554            let r = pb.add(ny + 1);
555            let t = r.add(long + 2);
556            to_limbs(x, pa);
557            to_limbs(y, pb);
558            let (na, za) = strip(pa, nx);
559            let (nb, zb) = strip(pb, ny);
560            let k = za.min(zb);
561            let (pa, na, pb, nb) = if na >= nb {
562                (pa, na, pb, nb)
563            } else {
564                (pb, nb, pa, na)
565            };
566            // The result's zero limbs, then the odd greatest common divisor shifted by the bits.
567            let (zl, zbits) = (k / 64, (k % 64) as u32);
568            let g = r.add(zl);
569            let gn = gcd_limbs(g, pa, na, pb, nb, t, gcd_itch(long, short));
570            ptr::write_bytes(r, 0, zl);
571            *g.add(gn) = lshift(g, g, gn, zbits);
572            limbs_number(r, zl + gn + 1, false, order)
573        }
574    })
575}
576
577/// The limbs of scratch space that [`gcd_limbs`] needs for numbers of `na >= nb` limbs.
578fn gcd_itch(na: usize, nb: usize) -> usize {
579    let lehmer = (na - nb + 1) + tdiv_itch(na, nb).max(nb + 1 + tdiv_itch(nb, 1));
580    if nb >= GCD_DC_THRESHOLD {
581        lehmer.max(gcd_dc_itch(nb))
582    } else {
583        lehmer
584    }
585}
586
587/// The greatest common divisor of the odd numbers of `na >= nb` limbs at `a` and `b`, whose top
588/// limbs are not zero, written at `g`; returns its number of limbs. The numbers are clobbered.
589///
590/// # Safety
591///
592/// The limbs at `a` and `b` must be valid for reads and writes, the `nb` at `g` for writes, and
593/// the `avail` limbs at `t` for reads and writes, at least [`gcd_itch`] of them, all apart.
594unsafe fn gcd_limbs(
595    g: *mut u64,
596    a: *mut u64,
597    na: usize,
598    b: *mut u64,
599    nb: usize,
600    t: *mut u64,
601    avail: usize,
602) -> usize {
603    // SAFETY: as the caller guarantees.
604    unsafe {
605        if nb == 1 {
606            let d = *b;
607            let r = if na == 1 && *a < d {
608                *a
609            } else {
610                rem_1(a, na, d, t)
611            };
612            *g = if r == 0 {
613                d
614            } else {
615                gcd_11(r >> r.trailing_zeros(), d)
616            };
617            return 1;
618        }
619        if na > nb {
620            // The scratch was planned for the lengths before the zero bits at the low end were
621            // shifted out, which can leave the divisor much shorter: a longer quotient and a
622            // division that needs more scratch take it from `with_scratch`.
623            let qn = na - nb + 1;
624            with_scratch(t, avail, qn + tdiv_itch(na, nb), |t| {
625                tdiv_qr(t, a, na, b, nb, t.add(qn));
626            });
627            if normalized(a, nb) == 0 {
628                ptr::copy_nonoverlapping(b, g, nb);
629                return nb;
630            }
631        }
632        let (mut a, mut b, mut n) = (a, b, nb);
633        if n >= GCD_DC_THRESHOLD {
634            match gcd_dc(&mut a, &mut b, n, t, avail) {
635                Step::Size(k) => n = k,
636                Step::Gcd(p, k) => {
637                    ptr::copy(p, g, k);
638                    return k;
639                }
640            }
641        }
642        gcd_lehmer(g, a, b, n, t, avail)
643    }
644}
645
646// The least common multiple
647
648/// `a.lcm(b)` for operands of which at least one has more than 16 bytes: the shorter one divided
649/// exactly by the greatest common divisor, times the longer one.
650#[inline(never)]
651fn lcm_general(a: &Number, b: &Number) -> Number {
652    let order = a.byte_order;
653    let (x, y) = (Operand::of(a), Operand::of(b));
654    if x.significant == 0 || y.significant == 0 {
655        return small_number(order, 0, false);
656    }
657    let g = a.gcd(b);
658    let one = g.value == [1];
659    let mut l = if x.significant <= y.significant {
660        let q = if one {
661            magnitude(a, false, order)
662        } else {
663            a.div_exact(&g)
664        };
665        q * b
666    } else {
667        let q = if one {
668            magnitude(b, false, b.byte_order)
669        } else {
670            b.div_exact(&g)
671        };
672        a * q
673    };
674    l.negative = false;
675    l
676}
677
678// The extended algorithm
679
680/// The scratch of the half gcd for the extended algorithm on numbers of `n` limbs: none below its
681/// threshold, so that the shorter numbers keep their working memory on the stack.
682fn ext_dc_itch(n: usize) -> usize {
683    if n >= GCDEXT_DC_THRESHOLD {
684        gcdext_dc_itch(n)
685    } else {
686        0
687    }
688}
689
690/// `a.gcd_ext(b)` for operands of which at least one has more than 16 bytes.
691#[inline(never)]
692fn gcd_ext_general(a: &Number, b: &Number) -> (Number, Number, Number) {
693    let order = a.byte_order;
694    let (x, y) = (Operand::of(a), Operand::of(b));
695    if y.significant == 0 {
696        return (
697            magnitude(a, false, order),
698            sign(x.significant != 0, a.negative, order),
699            sign(false, false, order),
700        );
701    }
702    if x.significant == 0 {
703        return (
704            magnitude(b, false, order),
705            sign(false, false, order),
706            sign(true, b.negative, order),
707        );
708    }
709    let (nx, ny) = (x.significant.div_ceil(8), y.significant.div_ceil(8));
710    // The cofactor of the longer operand is the one computed, as GMP's `mpz_gcdext` does: it is
711    // the shorter of the two.
712    let swap = nx < ny;
713    let (p, q, negative_p, negative_q) = if swap {
714        (y, x, b.negative, a.negative)
715    } else {
716        (x, y, a.negative, b.negative)
717    };
718    let (np, nq) = if swap { (ny, nx) } else { (nx, ny) };
719    let (g, cp, cq) = cofactors(p, np, q, nq, order);
720    let cp = Number {
721        negative: cp.negative != negative_p && cp.value != [0],
722        ..cp
723    };
724    let cq = Number {
725        negative: cq.negative != negative_q && cq.value != [0],
726        ..cq
727    };
728    if swap { (g, cq, cp) } else { (g, cp, cq) }
729}
730
731/// The greatest common divisor of the magnitudes of the operands `p` and `q`, not zero, of `np >=
732/// nq` limbs, and their cofactors, in the byte order `order`: the cofactor of `p` by Lehmer's
733/// method on `p` modulo `q` and `q`, and the one of `q` from it, `(g - cp p) / q`, an exact
734/// division.
735fn cofactors(
736    p: Operand,
737    np: usize,
738    q: Operand,
739    nq: usize,
740    order: ByteOrder,
741) -> (Number, Number, Number) {
742    let ualloc = nq + 4;
743    // The numbers; the row; the greatest common divisor and the cofactor; the product of the
744    // cofactor and `p`, the other cofactor; and the scratch.
745    let scratch = lehmer_ext_itch(nq)
746        .max(ext_dc_itch(nq))
747        .max((np - nq + 1) + tdiv_itch(np, nq))
748        .max(mul_bound(np, ualloc))
749        .max(divexact_itch(np + ualloc + 1, nq));
750    let need = (np + 1)
751        + (nq + 1)
752        + 2 * ualloc
753        + nq
754        + (ualloc + 1)
755        + (np + ualloc + 1)
756        + (np + 2)
757        + scratch;
758    working(need, |s| {
759        // SAFETY: the working memory holds the limbs counted above, in that order; the operands are
760        // borrowed.
761        unsafe {
762            let pa = s;
763            let pb = pa.add(np + 1);
764            let u0 = pb.add(nq + 1);
765            let u1 = u0.add(ualloc);
766            let g = u1.add(ualloc);
767            let c = g.add(nq);
768            let prod = c.add(ualloc + 1);
769            let v = prod.add(np + ualloc + 1);
770            let t = v.add(np + 2);
771            to_limbs(p, pa);
772            to_limbs(q, pb);
773            if np > nq {
774                let qn = np - nq + 1;
775                tdiv_qr(t, pa, np, pb, nq, t.add(qn));
776                if normalized(pa, nq) == 0 {
777                    // `q` divides `p`: g = |q| = 0 |p| + 1 |q|.
778                    let gq = limbs_number(pb, nq, false, order);
779                    return (gq, sign(false, false, order), sign(true, false, order));
780                }
781            }
782            ptr::write_bytes(u0, 0, 2 * ualloc);
783            *u1 = 1;
784            let mut row = Row { u0, u1, un: 1 };
785            let (gn, cn, negative) = gcdext(g, c, pa, pb, nq, &mut row, t, scratch);
786            let gq = limbs_number(g, gn, false, order);
787            let cp = limbs_number(c, cn, negative, order);
788            // The cofactor of `q`: (g - c |p|) / |q|, whose sign is the opposite of `c`'s.
789            if cn == 0 {
790                // g = |q|.
791                return (gq, cp, sign(true, false, order));
792            }
793            to_limbs(p, pa);
794            to_limbs(q, pb);
795            let (long, short) = if np >= cn {
796                ((pa, np), (c, cn))
797            } else {
798                ((c, cn), (pa, np))
799            };
800            let pn = np + cn;
801            mul(prod, long.0, long.1, short.0, short.1, t);
802            if negative {
803                add_to(prod, prod, pn, g, gn);
804            } else {
805                sub_from(prod, prod, pn, g, gn);
806            }
807            let pn = normalized(prod, pn);
808            if pn == 0 {
809                return (gq, cp, sign(false, false, order));
810            }
811            divexact(v, prod, pn, pb, nq, t, scratch);
812            let cq = limbs_number(v, pn - nq + 1, !negative, order);
813            (gq, cp, cq)
814        }
815    })
816}
817
818// The inverse
819
820/// `a.mod_inverse(n)` for operands of which at least one has more than 16 bytes.
821#[inline(never)]
822#[track_caller]
823fn inverse_general(a: &Number, modulus: &Number) -> Option<Number> {
824    let order = a.byte_order;
825    let (x, m) = (Operand::of(a), Operand::of(modulus));
826    if m.significant == 0 {
827        by_zero();
828    }
829    let nm = m.significant.div_ceil(8);
830    let nx = x.significant.div_ceil(8);
831    let ualloc = nm + 4;
832    let scratch = lehmer_ext_itch(nm)
833        .max(ext_dc_itch(nm))
834        .max((nx.max(nm) - nm + 1) + tdiv_itch(nx.max(nm), nm));
835    let need = (nx.max(nm) + 1) + (nm + 1) + 2 * ualloc + nm + (ualloc + 1) + scratch;
836    working(need, |s| {
837        // SAFETY: the working memory holds the limbs counted above, in that order; the operands are
838        // borrowed.
839        unsafe {
840            let pa = s;
841            let pm = pa.add(nx.max(nm) + 1);
842            let u0 = pm.add(nm + 1);
843            let u1 = u0.add(ualloc);
844            let g = u1.add(ualloc);
845            let c = g.add(nm);
846            let t = c.add(ualloc + 1);
847            to_limbs(m, pm);
848            if nm == 1 && *pm == 1 {
849                return Some(small_number(order, 0, false));
850            }
851            if x.significant == 0 {
852                return None;
853            }
854            to_limbs(x, pa);
855            let mut na = nx;
856            if nx >= nm {
857                let qn = nx - nm + 1;
858                tdiv_qr(t, pa, nx, pm, nm, t.add(qn));
859                na = normalized(pa, nm);
860                if na == 0 {
861                    return None;
862                }
863            }
864            ptr::write_bytes(pa.add(na), 0, nm - na);
865            ptr::write_bytes(u0, 0, 2 * ualloc);
866            *u1 = 1;
867            let mut row = Row { u0, u1, un: 1 };
868            let (gn, cn, negative) = gcdext(g, c, pa, pm, nm, &mut row, t, scratch);
869            if gn != 1 || *g != 1 {
870                return None;
871            }
872            // The inverse of |a| is c, of a it is c with the sign of a; below zero, |m| more.
873            let negative = negative != a.negative;
874            if negative {
875                to_limbs(m, pm);
876                sub_from(pm, pm, nm, c, cn);
877                return Some(limbs_number(pm, nm, false, order));
878            }
879            Some(limbs_number(c, cn, false, order))
880        }
881    })
882}