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.

Merge pull request #5 from raidwas/patch-1

add binary gcd algorithm

authored by

Corey Farwell and committed by
GitHub
b8c67e77 a064ce72

+75 -38
+2
Cargo.toml
··· 11 11 12 12 [dev-dependencies] 13 13 criterion = "0.3" 14 + rand = "0.7" 15 + rand_chacha = "0.2" 14 16 15 17 [[bench]] 16 18 name = "gcd_benchmark"
+29 -32
benches/gcd_benchmark.rs
··· 1 1 extern crate criterion; 2 2 extern crate gcd; 3 + extern crate rand; 4 + extern crate rand_chacha; 3 5 4 6 use criterion::{black_box, criterion_group, criterion_main, Criterion}; 5 7 use gcd::Gcd; 8 + use rand::{Rng, SeedableRng}; 9 + 10 + const SEED: u64 = 314; 6 11 7 12 fn criterion_benchmark(c: &mut Criterion) { 8 - c.bench_function("gcd u8", |b| b.iter(|| { 9 - black_box(0u8.gcd(0)); 10 - black_box(0u8.gcd(237)); 11 - black_box(237u8.gcd(0)); 12 - black_box(237u8.gcd(178)); 13 - })); 13 + macro_rules! bench_function { 14 + ($name:expr, $type:ty, $func:ident) => { 15 + c.bench_function($name, |b| { 16 + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(SEED); 17 + let values: Vec<$type> = (0..1000).map(|_| rng.gen()).collect(); 18 + b.iter(|| { 19 + for i in 0..values.len() - 1 { 20 + let (a, b) = (values[i], values[i + 1]); 21 + black_box(a.$func(b)); 22 + } 23 + }) 24 + }); 25 + }; 26 + }; 14 27 15 - c.bench_function("gcd u16", |b| b.iter(|| { 16 - black_box(0u16.gcd(0)); 17 - black_box(0u16.gcd(10)); 18 - black_box(237u16.gcd(0)); 19 - black_box(237u16.gcd(178)); 20 - })); 28 + bench_function!("gcd euclid u8", u8, gcd_euclid); 29 + bench_function!("gcd euclid u16", u16, gcd_euclid); 30 + bench_function!("gcd euclid u32", u32, gcd_euclid); 31 + bench_function!("gcd euclid u64", u64, gcd_euclid); 32 + bench_function!("gcd euclid u128", u128, gcd_euclid); 21 33 22 - c.bench_function("gcd u32", |b| b.iter(|| { 23 - black_box(0u32.gcd(0)); 24 - black_box(0u32.gcd(10)); 25 - black_box(237u32.gcd(0)); 26 - black_box(237u32.gcd(178)); 27 - })); 28 - 29 - c.bench_function("gcd u64", |b| b.iter(|| { 30 - black_box(0u64.gcd(0)); 31 - black_box(0u64.gcd(10)); 32 - black_box(237u64.gcd(0)); 33 - black_box(237u64.gcd(178)); 34 - })); 35 - 36 - c.bench_function("gcd u128", |b| b.iter(|| { 37 - black_box(0u128.gcd(0)); 38 - black_box(0u128.gcd(10)); 39 - black_box(237u128.gcd(0)); 40 - black_box(237u128.gcd(178)); 41 - })); 34 + bench_function!("gcd binary u8", u8, gcd_binary); 35 + bench_function!("gcd binary u16", u16, gcd_binary); 36 + bench_function!("gcd binary u32", u32, gcd_binary); 37 + bench_function!("gcd binary u64", u64, gcd_binary); 38 + bench_function!("gcd binary u128", u128, gcd_binary); 42 39 } 43 40 44 41 criterion_group!(benches, criterion_benchmark);
+44 -6
src/lib.rs
··· 16 16 /// assert_eq!(44, 2024u32.gcd(748)); 17 17 /// ``` 18 18 fn gcd(self, other: Self) -> Self; 19 + fn gcd_binary(self, other: Self) -> Self; 20 + fn gcd_euclid(self, other: Self) -> Self; 19 21 } 20 22 21 23 macro_rules! gcd_impl { 22 24 ($($t:ty),*) => ($( 23 25 impl Gcd for $t { 24 - fn gcd(self, other: Self) -> Self { 26 + fn gcd(self,other: Self) -> Self { 27 + self.gcd_binary(other) 28 + } 29 + fn gcd_binary(self, mut v: Self) -> Self { 30 + let mut u = self; 31 + if u == 0 { 32 + return v; 33 + } 34 + if v == 0 { 35 + return u; 36 + } 37 + let shift = (u | v).trailing_zeros(); 38 + u >>= shift; 39 + v >>= shift; 40 + u >>= u.trailing_zeros(); 41 + loop { 42 + v = v >> (v.trailing_zeros()); 43 + if u > v { 44 + //XOR swap algorithm 45 + v ^= u; 46 + u ^= v; 47 + v ^= u; 48 + } 49 + v -= u; // Here v >= u. 50 + if v == 0 { 51 + break; 52 + } 53 + } 54 + u << shift 55 + } 56 + fn gcd_euclid(self, other: Self) -> Self { 25 57 // variable names based off Euclidean divison equation: a = b · q + r 26 58 let (mut a, mut b) = if self > other { 27 59 (self, other) ··· 49 81 50 82 #[test] 51 83 fn test_gcd() { 52 - assert_eq!(0, 0u8.gcd(0)); 53 - assert_eq!(10, 10u8.gcd(0)); 54 - assert_eq!(10, 0u8.gcd(10)); 55 - assert_eq!(10, 10u8.gcd(20)); 56 - assert_eq!(44, 2024u32.gcd(748)); 84 + assert_eq!(0, 0u8.gcd_euclid(0)); 85 + assert_eq!(10, 10u8.gcd_euclid(0)); 86 + assert_eq!(10, 0u8.gcd_euclid(10)); 87 + assert_eq!(10, 10u8.gcd_euclid(20)); 88 + assert_eq!(44, 2024u32.gcd_euclid(748)); 89 + 90 + assert_eq!(0, 0u8.gcd_binary(0)); 91 + assert_eq!(10, 10u8.gcd_binary(0)); 92 + assert_eq!(10, 0u8.gcd_binary(10)); 93 + assert_eq!(10, 10u8.gcd_binary(20)); 94 + assert_eq!(44, 2024u32.gcd_binary(748)); 57 95 } 58 96 }