Skip to content

Commit a44177c

Browse files
authored
feat: add greatest_common_divisor_stein to greatest_common_divisor (#429)
1 parent e8e1d22 commit a44177c

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

src/math/greatest_common_divisor.rs

+32
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
///
55
/// Wikipedia reference: https://en.wikipedia.org/wiki/Greatest_common_divisor
66
/// gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a, -b) by definition of divisibility
7+
use std::cmp::{max, min};
78

89
pub fn greatest_common_divisor_recursive(a: i64, b: i64) -> i64 {
910
if a == 0 {
@@ -22,6 +23,28 @@ pub fn greatest_common_divisor_iterative(mut a: i64, mut b: i64) -> i64 {
2223
b.abs()
2324
}
2425

26+
pub fn greatest_common_divisor_stein(a: u64, b: u64) -> u64 {
27+
match ((a, b), (a & 1, b & 1)) {
28+
// gcd(x, x) = x
29+
((x, y), _) if x == y => y,
30+
// gcd(x, 0) = gcd(0, x) = x
31+
((0, x), _) | ((x, 0), _) => x,
32+
// gcd(x, y) = gcd(x / 2, y) if x is even and y is odd
33+
// gcd(x, y) = gcd(x, y / 2) if y is even and x is odd
34+
((x, y), (0, 1)) | ((y, x), (1, 0)) => greatest_common_divisor_stein(x >> 1, y),
35+
// gcd(x, y) = 2 * gcd(x / 2, y / 2) if x and y are both even
36+
((x, y), (0, 0)) => greatest_common_divisor_stein(x >> 1, y >> 1) << 1,
37+
// if x and y are both odd
38+
((x, y), (1, 1)) => {
39+
// then gcd(x, y) = gcd((x - y) / 2, y) if x >= y
40+
// gcd(x, y) = gcd((y - x) / 2, x) otherwise
41+
let (x, y) = (min(x, y), max(x, y));
42+
greatest_common_divisor_stein((y - x) >> 1, x)
43+
}
44+
_ => unreachable!(),
45+
}
46+
}
47+
2548
#[cfg(test)]
2649
mod tests {
2750
use super::*;
@@ -44,6 +67,15 @@ mod tests {
4467
assert_eq!(greatest_common_divisor_iterative(27, 12), 3);
4568
}
4669

70+
#[test]
71+
fn positive_number_stein() {
72+
assert_eq!(greatest_common_divisor_stein(4, 16), 4);
73+
assert_eq!(greatest_common_divisor_stein(16, 4), 4);
74+
assert_eq!(greatest_common_divisor_stein(3, 5), 1);
75+
assert_eq!(greatest_common_divisor_stein(40, 40), 40);
76+
assert_eq!(greatest_common_divisor_stein(27, 12), 3);
77+
}
78+
4779
#[test]
4880
fn negative_number_recursive() {
4981
assert_eq!(greatest_common_divisor_recursive(-32, -8), 8);

src/math/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub use self::gaussian_elimination::gaussian_elimination;
5858
pub use self::gcd_of_n_numbers::gcd;
5959
pub use self::greatest_common_divisor::{
6060
greatest_common_divisor_iterative, greatest_common_divisor_recursive,
61+
greatest_common_divisor_stein,
6162
};
6263
pub use self::interest::{compound_interest, simple_interest};
6364
pub use self::karatsuba_multiplication::multiply;

0 commit comments

Comments
 (0)