mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
factor: Make the implementation of GCD more readable (#1576)
* factor::numeric::gcd: Switch variable names to be more consistent * factor::numeric::gcd: Improve comments * factor::numeric::gcd: Extend loop invariant to v
This commit is contained in:
parent
37f717f5e3
commit
d9be24e354
1 changed files with 24 additions and 20 deletions
|
@ -9,39 +9,43 @@
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::mem::swap;
|
use std::mem::swap;
|
||||||
|
|
||||||
pub fn gcd(mut n: u64, mut m: u64) -> u64 {
|
pub fn gcd(mut u: u64, mut v: u64) -> u64 {
|
||||||
// Stein's binary GCD algorithm
|
// Stein's binary GCD algorithm
|
||||||
// Base cases: gcd(n, 0) = gcd(0, n) = n
|
// Base cases: gcd(n, 0) = gcd(0, n) = n
|
||||||
if n == 0 {
|
if u == 0 {
|
||||||
return m;
|
return v;
|
||||||
} else if m == 0 {
|
} else if v == 0 {
|
||||||
return n;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract common factor-2: gcd(2ⁱ n, 2ⁱ m) = 2ⁱ gcd(n, m)
|
// gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
|
||||||
// and reducing until odd gcd(2ⁱ n, m) = gcd(n, m) if m is odd
|
// 2ᵏ is the greatest power of two that divides both u and v
|
||||||
let k = {
|
let k = {
|
||||||
let k_n = n.trailing_zeros();
|
let i = u.trailing_zeros();
|
||||||
let k_m = m.trailing_zeros();
|
let j = v.trailing_zeros();
|
||||||
n >>= k_n;
|
u >>= i;
|
||||||
m >>= k_m;
|
v >>= j;
|
||||||
min(k_n, k_m)
|
min(i, j)
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Invariant: n odd
|
// Loop invariant: u and v are odd
|
||||||
debug_assert!(n % 2 == 1, "n = {} is even", n);
|
debug_assert!(u % 2 == 1, "u = {} is even", u);
|
||||||
|
debug_assert!(v % 2 == 1, "v = {} is even", v);
|
||||||
|
|
||||||
if n > m {
|
// gcd(u, v) = gcd(|u - v|, min(u, v))
|
||||||
swap(&mut n, &mut m);
|
if u > v {
|
||||||
|
swap(&mut u, &mut v);
|
||||||
}
|
}
|
||||||
m -= n;
|
v -= u;
|
||||||
|
|
||||||
if m == 0 {
|
if v == 0 {
|
||||||
return n << k;
|
// Reached the base case; gcd is 2ᵏ u
|
||||||
|
return u << k;
|
||||||
}
|
}
|
||||||
|
|
||||||
m >>= m.trailing_zeros();
|
// gcd(u, 2ʲ v) = gcd(u, v) as u is odd
|
||||||
|
v >>= v.trailing_zeros();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue