gcd.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //! Greatest common divisor.
  2. use crate::ibig::IBig;
  3. use crate::ops::DivRem;
  4. use crate::ubig::UBig;
  5. use core::mem;
  6. impl UBig {
  7. /// Greatest common divisor.
  8. ///
  9. /// # Example
  10. ///
  11. /// ```
  12. /// # use ibig::ubig;
  13. /// assert_eq!(ubig!(12).gcd(&ubig!(18)), ubig!(6));
  14. /// ```
  15. ///
  16. /// # Panics
  17. ///
  18. /// `ubig!(0).gcd(&ubig!(0))` panics.
  19. pub fn gcd(&self, rhs: &UBig) -> UBig {
  20. let (mut a, mut b) = (self.clone(), rhs.clone());
  21. let zeros = match (a.trailing_zeros(), b.trailing_zeros()) {
  22. (None, None) => panic!("gcd(0, 0)"),
  23. (None, Some(_)) => return b,
  24. (Some(_), None) => return a,
  25. (Some(a_zeros), Some(b_zeros)) => {
  26. a >>= a_zeros;
  27. b >>= b_zeros;
  28. a_zeros.min(b_zeros)
  29. }
  30. };
  31. // One round of Euclidean algorithm.
  32. if a < b {
  33. mem::swap(&mut a, &mut b);
  34. }
  35. a %= &b;
  36. // Binary algorithm.
  37. loop {
  38. // b is odd
  39. match a.trailing_zeros() {
  40. None => break,
  41. Some(a_zeros) => a >>= a_zeros,
  42. }
  43. // a is odd
  44. if a < b {
  45. mem::swap(&mut a, &mut b);
  46. }
  47. a -= &b;
  48. }
  49. b << zeros
  50. }
  51. /// Greatest common divisors and the Bézout coefficients.
  52. ///
  53. /// If `a.extended_gcd(&b) == (g, x, y)` then:
  54. /// * `x * a + y * b == g`
  55. /// * `abs(x) <= max(b, 1)`
  56. /// * `abs(y) <= max(a, 1)`
  57. ///
  58. /// # Example
  59. /// ```
  60. /// # use ibig::{ubig, IBig, ops::UnsignedAbs};
  61. /// let a = ubig!(12);
  62. /// let b = ubig!(18);
  63. /// let (g, x, y) = a.extended_gcd(&b);
  64. /// assert_eq!(&a % &g, ubig!(0));
  65. /// assert_eq!(&b % &g, ubig!(0));
  66. /// assert_eq!(&x * IBig::from(&a) + &y * IBig::from(&b), IBig::from(g));
  67. /// assert!(x.unsigned_abs() <= b);
  68. /// assert!(y.unsigned_abs() <= a);
  69. /// ```
  70. ///
  71. /// # Panics
  72. ///
  73. /// `ubig!(0).extended_gcd(&ubig!(0))` panics.
  74. pub fn extended_gcd(&self, rhs: &UBig) -> (UBig, IBig, IBig) {
  75. let zeros = match (self.trailing_zeros(), rhs.trailing_zeros()) {
  76. (None, None) => panic!("extended_gcd(0, 0)"),
  77. (None, Some(_)) => return (rhs.clone(), 0u8.into(), 1u8.into()),
  78. (Some(_), None) => return (self.clone(), 1u8.into(), 0u8.into()),
  79. (Some(a_zeros), Some(b_zeros)) => a_zeros.min(b_zeros),
  80. };
  81. let u = self >> zeros;
  82. let v = rhs >> zeros;
  83. let mut a;
  84. let mut b;
  85. let mut ax;
  86. let mut ay;
  87. let mut bx;
  88. let mut by;
  89. // Invariants:
  90. // gcd(a, b) == gcd(u, v)
  91. // a = ax * u - ay * v
  92. // b = bx * u - by * v
  93. // ax, bx <= v
  94. // ay, by <= u
  95. // One round of Euclidean algorithm.
  96. if u <= v {
  97. let (q, r) = (&v).div_rem(&u);
  98. // u = 1 * u - 0 * v
  99. // r = v - q * u = (v-q) * u - (u-1) * v
  100. a = u.clone();
  101. ax = UBig::from_word(1);
  102. ay = UBig::from_word(0);
  103. b = r;
  104. bx = &v - q;
  105. by = &u - UBig::from_word(1);
  106. } else {
  107. let (q, r) = (&u).div_rem(&v);
  108. // v = 0 * u + 1 * v = v * u - (u-1) * v
  109. // r = 1 * u - q * v
  110. a = v.clone();
  111. ax = v.clone();
  112. ay = &u - UBig::from_word(1);
  113. b = r;
  114. bx = UBig::from_word(1);
  115. by = q;
  116. }
  117. // At least one of a and b is odd (because gcd(u, v) is odd). Make b odd.
  118. if &b & 1u8 == 0u8 {
  119. mem::swap(&mut a, &mut b);
  120. mem::swap(&mut ax, &mut bx);
  121. mem::swap(&mut ay, &mut by);
  122. }
  123. // Binary algorithm.
  124. while a != UBig::from_word(0) {
  125. // b is odd
  126. while &a & 1u8 == 0u8 {
  127. // a is even
  128. if &ax & 1u8 != 0u8 || &ay & 1u8 != 0u8 {
  129. ax += &v;
  130. ay += &u;
  131. }
  132. // Now ax, ay are even.
  133. a >>= 1usize;
  134. ax >>= 1usize;
  135. ay >>= 1usize;
  136. // Again ax <= v, bx <= u.
  137. }
  138. // Both a and b are odd.
  139. if a < b {
  140. mem::swap(&mut a, &mut b);
  141. mem::swap(&mut ax, &mut bx);
  142. mem::swap(&mut ay, &mut by);
  143. }
  144. a -= &b;
  145. if ax < bx {
  146. ax += &v;
  147. ay += &u;
  148. }
  149. ax -= &bx;
  150. ay -= &by;
  151. // ax >= 0 in both cases
  152. // ax <= v in both cases
  153. // ax * u - ay * v = a
  154. // ay * v = ax * u - a <= v * u - 0
  155. // ay <= u
  156. // After one round Euclidean, and at least one subtraction, a < min(u,v).
  157. // ay * v = ax * u - a >= -a > -min(u,v) >= -v
  158. // ay >= 0
  159. }
  160. (b << zeros, IBig::from(bx), -IBig::from(by))
  161. }
  162. }
  163. impl IBig {
  164. /// Greatest common divisor.
  165. ///
  166. /// # Example
  167. ///
  168. /// ```
  169. /// # use ibig::ibig;
  170. /// assert_eq!(ibig!(-12).gcd(&ibig!(18)), ibig!(6));
  171. /// ```
  172. ///
  173. /// # Panics
  174. ///
  175. /// `ibig!(0).gcd(&ibig!(0))` panics.
  176. pub fn gcd(&self, rhs: &IBig) -> IBig {
  177. self.magnitude().gcd(rhs.magnitude()).into()
  178. }
  179. /// Greatest common divisors and the Bézout coefficients.
  180. ///
  181. /// If `a.extended_gcd(&b) == (g, x, y)` then:
  182. /// * `x * a + y * b == g`
  183. /// * `abs(x) <= max(abs(b), 1)`
  184. /// * `abs(y) <= max(abs(a), 1)`
  185. ///
  186. /// # Example
  187. /// ```
  188. /// # use ibig::{ibig, IBig, ops::Abs};
  189. /// let a = ibig!(-12);
  190. /// let b = ibig!(18);
  191. /// let (g, x, y) = a.extended_gcd(&b);
  192. /// assert_eq!(&a % &g, ibig!(0));
  193. /// assert_eq!(&b % &g, ibig!(0));
  194. /// assert_eq!(&x * &a + &y * &b, g);
  195. /// assert!(x.abs() <= b.abs());
  196. /// assert!(y.abs() <= a.abs());
  197. /// ```
  198. ///
  199. /// # Panics
  200. ///
  201. /// `ibig!(0).extended_gcd(&ibig!(0))` panics.
  202. pub fn extended_gcd(&self, rhs: &IBig) -> (IBig, IBig, IBig) {
  203. let (g, x, y) = self.magnitude().extended_gcd(rhs.magnitude());
  204. (IBig::from(g), self.sign() * x, rhs.sign() * y)
  205. }
  206. }