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);