ruint/gcd.rs
1use crate::{algorithms, Uint};
2
3impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
4 /// Compute the greatest common divisor of two [`Uint`]s.
5 ///
6 /// # Examples
7 ///
8 /// ```
9 /// # use ruint::{Uint, uint, aliases::*};
10 /// # uint! {
11 /// assert_eq!(0_U128.gcd(0_U128), 0_U128);
12 /// # }
13 /// ```
14 #[inline]
15 #[must_use]
16 pub fn gcd(self, other: Self) -> Self {
17 algorithms::gcd(self, other)
18 }
19
20 /// Compute the least common multiple of two [`Uint`]s or [`None`] if the
21 /// result would be too large.
22 #[inline]
23 #[must_use]
24 pub fn lcm(self, other: Self) -> Option<Self> {
25 let other = other.checked_div(self.gcd(other)).unwrap_or_default();
26 self.checked_mul(other)
27 }
28
29 /// ⚠️ Compute the greatest common divisor and the Bézout coefficients.
30 ///
31 /// **Warning.** This is API is unstable and may change in a minor release.
32 ///
33 /// Returns $(\mathtt{gcd}, \mathtt{x}, \mathtt{y}, \mathtt{sign})$ such
34 /// that
35 ///
36 /// $$
37 /// \gcd(\mathtt{self}, \mathtt{other}) = \mathtt{gcd} = \begin{cases}
38 /// \mathtt{self} · \mathtt{x} - \mathtt{other} . \mathtt{y} &
39 /// \mathtt{sign} \\\\ \mathtt{other} · \mathtt{y} - \mathtt{self} ·
40 /// \mathtt{x} & ¬\mathtt{sign} \end{cases}
41 /// $$
42 ///
43 /// Note that the intermediate products may overflow, even though the result
44 /// after subtraction will fit in the bit size of the [`Uint`].
45 #[inline]
46 #[must_use]
47 pub fn gcd_extended(self, other: Self) -> (Self, Self, Self, bool) {
48 algorithms::gcd_extended(self, other)
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::{const_for, nlimbs};
56 use proptest::{proptest, test_runner::Config};
57
58 #[test]
59 #[allow(clippy::absurd_extreme_comparisons)] // Generated code
60 fn test_gcd_identities() {
61 const_for!(BITS in SIZES {
62 const LIMBS: usize = nlimbs(BITS);
63 type U = Uint<BITS, LIMBS>;
64 let config = Config { cases: 5, ..Default::default() };
65 proptest!(config, |(a: U, b: U)| {
66 let g = a.gcd(b);
67 assert_eq!(b.gcd(a), g);
68 if a == U::ZERO && b == U::ZERO {
69 assert_eq!(g, U::ZERO);
70 } else {
71 assert_eq!(a % g, U::ZERO);
72 assert_eq!(b % g, U::ZERO);
73 }
74
75 let l = a.lcm(b);
76 assert_eq!(b.lcm(a), l);
77 if let Some(l) = l {
78 if a == U::ZERO || b == U::ZERO {
79 assert_eq!(l, U::ZERO);
80 } else {
81 assert_eq!(l % a, U::ZERO);
82 assert_eq!(l % b, U::ZERO);
83 }
84 }
85
86 let (ge, x, y, sign) = a.gcd_extended(b);
87 assert_eq!(ge, g);
88 if sign {
89 assert_eq!(a * x - b * y, g);
90 } else {
91 assert_eq!(b * y - a * x, g);
92 }
93 });
94 });
95 }
96}