ruint/
gcd.rs

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use crate::{algorithms, Uint};

impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
    /// Compute the greatest common divisor of two [`Uint`]s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ruint::{Uint, uint, aliases::*};
    /// # uint! {
    /// assert_eq!(0_U128.gcd(0_U128), 0_U128);
    /// # }
    /// ```
    #[inline]
    #[must_use]
    pub fn gcd(self, other: Self) -> Self {
        algorithms::gcd(self, other)
    }

    /// Compute the least common multiple of two [`Uint`]s or [`None`] if the
    /// result would be too large.
    #[inline]
    #[must_use]
    pub fn lcm(self, other: Self) -> Option<Self> {
        let other = other.checked_div(self.gcd(other)).unwrap_or_default();
        self.checked_mul(other)
    }

    /// ⚠️ Compute the greatest common divisor and the Bézout coefficients.
    ///
    /// **Warning.** This is API is unstable and may change in a minor release.
    ///
    /// Returns $(\mathtt{gcd}, \mathtt{x}, \mathtt{y}, \mathtt{sign})$ such
    /// that
    ///
    /// $$
    /// \gcd(\mathtt{self}, \mathtt{other}) = \mathtt{gcd} = \begin{cases}
    ///     \mathtt{self} · \mathtt{x} - \mathtt{other} . \mathtt{y} &
    /// \mathtt{sign} \\\\     \mathtt{other} · \mathtt{y} - \mathtt{self} ·
    /// \mathtt{x} & ¬\mathtt{sign} \end{cases}
    /// $$
    ///
    /// Note that the intermediate products may overflow, even though the result
    /// after subtraction will fit in the bit size of the [`Uint`].
    #[inline]
    #[must_use]
    pub fn gcd_extended(self, other: Self) -> (Self, Self, Self, bool) {
        algorithms::gcd_extended(self, other)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{const_for, nlimbs};
    use core::cmp::min;
    use proptest::{proptest, test_runner::Config};

    #[test]
    #[allow(clippy::absurd_extreme_comparisons)] // Generated code
    fn test_gcd_identities() {
        const_for!(BITS in SIZES {
            const LIMBS: usize = nlimbs(BITS);
            type U = Uint<BITS, LIMBS>;
            // TODO: Increase cases when perf is better.
            let mut config = Config::default();
            config.cases = min(config.cases, if BITS > 500 { 3 } else { 10 });
            proptest!(config, |(a: U, b: U)| {
                let g = a.gcd(b);
                assert_eq!(b.gcd(a), g);
                if a == U::ZERO && b == U::ZERO {
                    assert_eq!(g, U::ZERO);
                } else {
                    assert_eq!(a % g, U::ZERO);
                    assert_eq!(b % g, U::ZERO);
                }

                let l = a.lcm(b);
                assert_eq!(b.lcm(a), l);
                if let Some(l) = l {
                    if a == U::ZERO || b == U::ZERO {
                        assert_eq!(l, U::ZERO);
                    } else {
                        assert_eq!(l % a, U::ZERO);
                        assert_eq!(l % b, U::ZERO);
                    }
                }

                let (ge, x, y, sign) = a.gcd_extended(b);
                assert_eq!(ge, g);
                if sign {
                    assert_eq!(a * x - b * y, g);
                } else {
                    assert_eq!(b * y - a * x, g);
                }
            });
        });
    }
}