Small Rust library for calculating greatest common divisor crates.io/crates/gcd
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Change Swap Mechanism and Improve Legibility (#7)

authored by

Avery R and committed by
GitHub
78f84acc 285c438b

+61 -26
+32
.github/workflows/rust.yml
··· 1 + name: Rust 2 + 3 + on: 4 + push: 5 + branches: [ master ] 6 + pull_request: 7 + branches: [ master ] 8 + 9 + env: 10 + CARGO_TERM_COLOR: always 11 + 12 + jobs: 13 + check: 14 + runs-on: ubuntu-latest 15 + steps: 16 + - uses: actions/checkout@v2 17 + - name: Check 18 + run: cargo check --verbose 19 + 20 + test: 21 + runs-on: ubuntu-latest 22 + steps: 23 + - uses: actions/checkout@v2 24 + - name: Run tests 25 + run: cargo test --verbose 26 + 27 + bench: 28 + runs-on: ubuntu-latest 29 + steps: 30 + - uses: actions/checkout@v2 31 + - name: Run Benches 32 + run: cargo bench
+1 -1
Cargo.toml
··· 1 1 [package] 2 2 name = "gcd" 3 - version = "2.0.1" 3 + version = "2.0.2" 4 4 authors = ["Corey Farwell <coreyf@rwell.org>"] 5 5 description = "Small Rust library (with no dependencies) for calculating greatest common divisor" 6 6 license = "MIT/Apache-2.0"
+1 -1
benches/gcd_benchmark.rs
··· 23 23 }) 24 24 }); 25 25 }; 26 - }; 26 + } 27 27 28 28 bench_function!("gcd euclid u8", u8, gcd_euclid); 29 29 bench_function!("gcd euclid u16", u16, gcd_euclid);
+27 -24
src/lib.rs
··· 1 1 #![no_std] 2 2 3 + use core::mem; 4 + 3 5 pub trait Gcd { 4 6 /// Determine [greatest common divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) 5 7 /// using [`gcd_binary`]. ··· 18 20 /// assert_eq!(44, 2024u32.gcd(748)); 19 21 /// ``` 20 22 fn gcd(self, other: Self) -> Self; 23 + 21 24 /// Determine [greatest common divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) 22 25 /// using the [Binary GCD algorithm](https://en.wikipedia.org/wiki/Binary_GCD_algorithm). 23 26 fn gcd_binary(self, other: Self) -> Self; 27 + 24 28 /// Determine [greatest common divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) 25 29 /// using the [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm). 26 30 fn gcd_euclid(self, other: Self) -> Self; 27 31 } 28 32 29 33 macro_rules! gcd_impl { 30 - ($($t:ty),*) => ($( 31 - impl Gcd for $t { 32 - fn gcd(self,other: Self) -> Self { 34 + ($($T:ty),*) => {$( 35 + impl Gcd for $T { 36 + fn gcd(self, other: $T) -> $T { 33 37 self.gcd_binary(other) 34 38 } 35 - fn gcd_binary(self, mut v: Self) -> Self { 39 + 40 + fn gcd_binary(self, mut v: $T) -> $T { 36 41 let mut u = self; 37 - if u == 0 { 38 - return v; 39 - } 40 - if v == 0 { 41 - return u; 42 - } 42 + 43 + if u == 0 { return v; } 44 + if v == 0 { return u; } 45 + 43 46 let shift = (u | v).trailing_zeros(); 44 47 u >>= shift; 45 48 v >>= shift; 46 49 u >>= u.trailing_zeros(); 50 + 47 51 loop { 48 52 v >>= v.trailing_zeros(); 53 + 49 54 if u > v { 50 - //XOR swap algorithm 51 - v ^= u; 52 - u ^= v; 53 - v ^= u; 55 + mem::swap(&mut u, &mut v); 54 56 } 55 - v -= u; // Here v >= u. 56 - if v == 0 { 57 - break; 58 - } 57 + 58 + v -= u; // here v >= u 59 + 60 + if v == 0 { break; } 59 61 } 62 + 60 63 u << shift 61 64 } 62 - fn gcd_euclid(self, other: Self) -> Self { 63 - // variable names based off Euclidean divison equation: a = b · q + r 65 + 66 + fn gcd_euclid(self, other: $T) -> $T { 67 + // variable names based off euclidean divison equation: a = b · q + r 64 68 let (mut a, mut b) = if self > other { 65 69 (self, other) 66 70 } else { ··· 68 72 }; 69 73 70 74 while b != 0 { 71 - let r = a % b; 72 - a = b; 73 - b = r; 75 + mem::swap(&mut a, &mut b); 76 + b %= a; 74 77 } 75 78 76 79 a 77 80 } 78 81 } 79 - )*) 82 + )*}; 80 83 } 81 84 82 85 gcd_impl! { u8, u16, u32, u64, u128, usize }