1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/// g = gcd(a, b), ax + by = g を満たす (x, y, g) を返します。
///
/// # Examples
/// ```
/// use ext_gcd::ext_gcd;
///
/// let (x, y, g) = ext_gcd(48, 30);
/// assert_eq!(g, 6);
/// assert_eq!(48 * x + 30 * y, g); // e.g. x = 2, y = -3
///
/// assert_eq!(ext_gcd(42, 0), (1, 0, 42));
/// assert_eq!(ext_gcd(0, 0), (0, 0, 0));
/// ```
#[allow(clippy::many_single_char_names)]
pub fn ext_gcd(a: i64, b: i64) -> (i64, i64, i64) {
    if b == 0 {
        // ax + 0y = a
        if a == 0 {
            (0, 0, 0)
        } else {
            (1, 0, a)
        }
    } else {
        let (q, r) = (a / b, a % b);
        // a = bq + r, ax + by = g
        // -> b * (qx + y) + rx = g
        let (s, t, g) = ext_gcd(b, r);
        // s = qx + y
        // t = x
        (t, s - q * t, g)
    }
}

#[cfg(test)]
mod tests {
    use crate::ext_gcd;

    #[test]
    fn test() {
        for a in -20..=20 {
            for b in -20..=20 {
                let expected_g = gcd(a, b);
                let (x, y, g) = ext_gcd(a, b);
                assert_eq!(expected_g, g.abs());
                assert_eq!(a * x + b * y, g);
            }
        }
    }

    fn gcd(a: i64, b: i64) -> i64 {
        if a == 0 && b == 0 {
            return 0;
        }
        (1..=(a.abs().max(b.abs())))
            .filter(|d| a % d == 0 && b % d == 0)
            .max()
            .unwrap()
    }
}