4
4
///
5
5
/// Wikipedia reference: https://en.wikipedia.org/wiki/Greatest_common_divisor
6
6
/// gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a, -b) by definition of divisibility
7
+ use std:: cmp:: { max, min} ;
7
8
8
9
pub fn greatest_common_divisor_recursive ( a : i64 , b : i64 ) -> i64 {
9
10
if a == 0 {
@@ -22,6 +23,28 @@ pub fn greatest_common_divisor_iterative(mut a: i64, mut b: i64) -> i64 {
22
23
b. abs ( )
23
24
}
24
25
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
+
25
48
#[ cfg( test) ]
26
49
mod tests {
27
50
use super :: * ;
@@ -44,6 +67,15 @@ mod tests {
44
67
assert_eq ! ( greatest_common_divisor_iterative( 27 , 12 ) , 3 ) ;
45
68
}
46
69
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
+
47
79
#[ test]
48
80
fn negative_number_recursive ( ) {
49
81
assert_eq ! ( greatest_common_divisor_recursive( -32 , -8 ) , 8 ) ;
0 commit comments