malachite_base/num/arithmetic/
extended_gcd.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5//      Copyright © 2009, 2016 William Hart
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::num::arithmetic::traits::ExtendedGcd;
14use crate::num::arithmetic::traits::UnsignedAbs;
15use crate::num::basic::signeds::PrimitiveSigned;
16use crate::num::basic::unsigneds::PrimitiveUnsigned;
17use crate::num::conversion::traits::WrappingFrom;
18use crate::rounding_modes::RoundingMode::*;
19use core::mem::swap;
20
21fn extended_gcd_signed<
22    U: ExtendedGcd<Cofactor = S> + PrimitiveUnsigned,
23    S: PrimitiveSigned + UnsignedAbs<Output = U> + WrappingFrom<U>,
24>(
25    a: S,
26    b: S,
27) -> (U, S, S) {
28    let (gcd, mut x, mut y) = a.unsigned_abs().extended_gcd(b.unsigned_abs());
29    if a < S::ZERO {
30        x = x.checked_neg().unwrap();
31    }
32    if b < S::ZERO {
33        y = y.checked_neg().unwrap();
34    }
35    (gcd, x, y)
36}
37
38// This is equivalent to `n_xgcd` from `ulong_extras/xgcd.c`, FLINT 2.7.1, with an adjustment to
39// find the minimal cofactors.
40pub_test! {extended_gcd_unsigned_binary<
41    U: WrappingFrom<S> + PrimitiveUnsigned,
42    S: PrimitiveSigned + WrappingFrom<U>,
43>(
44    mut a: U,
45    mut b: U,
46) -> (U, S, S) {
47    if a == U::ZERO && b == U::ZERO {
48        return (U::ZERO, S::ZERO, S::ZERO);
49    } else if a == b || a == U::ZERO {
50        return (b, S::ZERO, S::ONE);
51    } else if b == U::ZERO {
52        return (a, S::ONE, S::ZERO);
53    }
54    let mut swapped = false;
55    if a < b {
56        swap(&mut a, &mut b);
57        swapped = true;
58    }
59    let mut u1 = S::ONE;
60    let mut v2 = S::ONE;
61    let mut u2 = S::ZERO;
62    let mut v1 = S::ZERO;
63    let mut u3 = a;
64    let mut v3 = b;
65    let mut d;
66    let mut t2;
67    let mut t1;
68    if (a & b).get_highest_bit() {
69        d = u3 - v3;
70        t2 = v2;
71        t1 = u2;
72        u2 = u1 - u2;
73        u1 = t1;
74        u3 = v3;
75        v2 = v1 - v2;
76        v1 = t2;
77        v3 = d;
78    }
79    while v3.get_bit(U::WIDTH - 2) {
80        d = u3 - v3;
81        if d < v3 {
82            // quot = 1
83            t2 = v2;
84            t1 = u2;
85            u2 = u1 - u2;
86            u1 = t1;
87            u3 = v3;
88            v2 = v1 - v2;
89            v1 = t2;
90            v3 = d;
91        } else if d < (v3 << 1) {
92            // quot = 2
93            t1 = u2;
94            u2 = u1 - (u2 << 1);
95            u1 = t1;
96            u3 = v3;
97            t2 = v2;
98            v2 = v1 - (v2 << 1);
99            v1 = t2;
100            v3 = d - u3;
101        } else {
102            // quot = 3
103            t1 = u2;
104            u2 = u1 - S::wrapping_from(3) * u2;
105            u1 = t1;
106            u3 = v3;
107            t2 = v2;
108            v2 = v1 - S::wrapping_from(3) * v2;
109            v1 = t2;
110            v3 = d - (u3 << 1);
111        }
112    }
113    while v3 != U::ZERO {
114        d = u3 - v3;
115        // overflow not possible, top 2 bits of v3 not set
116        if u3 < (v3 << 2) {
117            if d < v3 {
118                // quot = 1
119                t2 = v2;
120                t1 = u2;
121                u2 = u1 - u2;
122                u1 = t1;
123                u3 = v3;
124                v2 = v1 - v2;
125                v1 = t2;
126                v3 = d;
127            } else if d < (v3 << 1) {
128                // quot = 2
129                t1 = u2;
130                u2 = u1.wrapping_sub(u2 << 1);
131                u1 = t1;
132                u3 = v3;
133                t2 = v2;
134                v2 = v1.wrapping_sub(v2 << 1);
135                v1 = t2;
136                v3 = d - u3;
137            } else {
138                // quot = 3
139                t1 = u2;
140                u2 = u1.wrapping_sub(S::wrapping_from(3).wrapping_mul(u2));
141                u1 = t1;
142                u3 = v3;
143                t2 = v2;
144                v2 = v1.wrapping_sub(S::wrapping_from(3).wrapping_mul(v2));
145                v1 = t2;
146                v3 = d.wrapping_sub(u3 << 1);
147            }
148        } else {
149            let (quot, rem) = u3.div_rem(v3);
150            t1 = u2;
151            u2 = u1.wrapping_sub(S::wrapping_from(quot).wrapping_mul(u2));
152            u1 = t1;
153            u3 = v3;
154            t2 = v2;
155            v2 = v1.wrapping_sub(S::wrapping_from(quot).wrapping_mul(v2));
156            v1 = t2;
157            v3 = rem;
158        }
159    }
160    // Remarkably, |u1| < x/2, thus comparison with 0 is valid
161    if u1 <= S::ZERO {
162        u1.wrapping_add_assign(S::wrapping_from(b));
163        v1.wrapping_sub_assign(S::wrapping_from(a));
164    }
165    // The cofactors at this point are not necessarily minimal, so we may need to adjust.
166    let gcd = u3;
167    let mut x = U::wrapping_from(u1);
168    let mut y = U::wrapping_from(v1);
169    let two_limit_a = a / gcd;
170    let two_limit_b = b / gcd;
171    let limit_b = two_limit_b >> 1;
172    if x > limit_b {
173        let k = (x - limit_b).div_round(two_limit_b, Ceiling).0;
174        x.wrapping_sub_assign(two_limit_b.wrapping_mul(k));
175        y.wrapping_add_assign(two_limit_a.wrapping_mul(k));
176    }
177    if swapped {
178        swap(&mut x, &mut y);
179    }
180    (gcd, S::wrapping_from(x), S::wrapping_from(y))
181}}
182
183macro_rules! impl_extended_gcd {
184    ($u:ident, $s:ident) => {
185        impl ExtendedGcd<$u> for $u {
186            type Gcd = $u;
187            type Cofactor = $s;
188
189            /// Computes the GCD (greatest common divisor) of two numbers $a$ and $b$, and also the
190            /// coefficients $x$ and $y$ in Bézout's identity $ax+by=\gcd(a,b)$.
191            ///
192            /// The are infinitely many $x$, $y$ that satisfy the identity for any $a$, $b$, so the
193            /// full specification is more detailed:
194            ///
195            /// - $f(0, 0) = (0, 0, 0)$.
196            /// - $f(a, ak) = (a, 1, 0)$ if $a > 0$ and $k \neq 1$.
197            /// - $f(bk, b) = (b, 0, 1)$ if $b > 0$.
198            /// - $f(a, b) = (g, x, y)$ if $a \neq 0$ and $b \neq 0$ and $\gcd(a, b) \neq \min(a,
199            ///   b)$, where $g = \gcd(a, b) \geq 0$, $ax + by = g$, $x \leq \lfloor b/g \rfloor$,
200            ///   and $y \leq \lfloor a/g \rfloor$.
201            ///
202            /// # Worst-case complexity
203            /// $T(n) = O(n^2)$
204            ///
205            /// $M(n) = O(n)$
206            ///
207            /// where $T$ is time, $M$ is additional memory, and $n$ is
208            /// `max(self.significant_bits(), other.significant_bits())`.
209            ///
210            /// # Examples
211            /// See [here](super::extended_gcd#extended_gcd).
212            #[inline]
213            fn extended_gcd(self, other: $u) -> ($u, $s, $s) {
214                extended_gcd_unsigned_binary(self, other)
215            }
216        }
217
218        impl ExtendedGcd<$s> for $s {
219            type Gcd = $u;
220            type Cofactor = $s;
221
222            /// Computes the GCD (greatest common divisor) of two numbers $a$ and $b$, and also the
223            /// coefficients $x$ and $y$ in Bézout's identity $ax+by=\gcd(a,b)$.
224            ///
225            /// The are infinitely many $x$, $y$ that satisfy the identity for any $a$, $b$, so the
226            /// full specification is more detailed:
227            ///
228            /// - $f(0, 0) = (0, 0, 0)$.
229            /// - $f(a, ak) = (a, 1, 0)$ if $a > 0$ and $k \neq 1$.
230            /// - $f(a, ak) = (-a, -1, 0)$ if $a < 0$ and $k \neq 1$.
231            /// - $f(bk, b) = (b, 0, 1)$ if $b > 0$.
232            /// - $f(bk, b) = (-b, 0, -1)$ if $b < 0$.
233            /// - $f(a, b) = (g, x, y)$ if $a \neq 0$ and $b \neq 0$ and $\gcd(a, b) \neq \min(|a|,
234            ///   |b|)$, where $g = \gcd(a, b) \geq 0$, $ax + by = g$, $x \leq \lfloor b/g \rfloor$,
235            ///   and $y \leq \lfloor a/g \rfloor$.
236            ///
237            /// # Worst-case complexity
238            /// $T(n) = O(n^2)$
239            ///
240            /// $M(n) = O(n)$
241            ///
242            /// where $T$ is time, $M$ is additional memory, and $n$ is
243            /// `max(self.significant_bits(), other.significant_bits())`.
244            ///
245            /// # Examples
246            /// See [here](super::extended_gcd#extended_gcd).
247            #[inline]
248            fn extended_gcd(self, other: $s) -> ($u, $s, $s) {
249                extended_gcd_signed(self, other)
250            }
251        }
252    };
253}
254apply_to_unsigned_signed_pairs!(impl_extended_gcd);