1 //! Benchmark comparing the current GCD implemtation against an older one.
5 extern crate num_integer
;
6 extern crate num_traits
;
9 use num_integer
::Integer
;
10 use num_traits
::{AsPrimitive, Bounded, Signed}
;
11 use test
::{black_box, Bencher}
;
13 trait GcdOld
: Integer
{
14 fn gcd_old(&self, other
: &Self) -> Self;
17 macro_rules
! impl_gcd_old_for_isize
{
20 /// Calculates the Greatest Common Divisor (GCD) of the number and
21 /// `other`. The result is always positive.
23 fn gcd_old(&self, other
: &Self) -> Self {
24 // Use Stein's algorithm
31 // find common factors of 2
32 let shift
= (m
| n
).trailing_zeros();
34 // The algorithm needs positive numbers, but the minimum value
35 // can't be represented as a positive one.
36 // It's also a power of two, so the gcd can be
37 // calculated by bitshifting in that case
39 // Assuming two's complement, the number created by the shift
40 // is positive for all numbers except gcd = abs(min value)
41 // The call to .abs() causes a panic in debug mode
42 if m
== Self::min_value() || n
== Self::min_value() {
43 return (1 << shift
).abs();
46 // guaranteed to be positive now, rest like unsigned algorithm
50 // divide n and m by 2 until odd
52 n
>>= n
.trailing_zeros();
55 m
>>= m
.trailing_zeros();
57 std
::mem
::swap(&mut n
, &mut m
)
68 impl_gcd_old_for_isize
!(i8);
69 impl_gcd_old_for_isize
!(i16);
70 impl_gcd_old_for_isize
!(i32);
71 impl_gcd_old_for_isize
!(i64);
72 impl_gcd_old_for_isize
!(isize);
73 impl_gcd_old_for_isize
!(i128
);
75 macro_rules
! impl_gcd_old_for_usize
{
78 /// Calculates the Greatest Common Divisor (GCD) of the number and
79 /// `other`. The result is always positive.
81 fn gcd_old(&self, other
: &Self) -> Self {
82 // Use Stein's algorithm
89 // find common factors of 2
90 let shift
= (m
| n
).trailing_zeros();
92 // divide n and m by 2 until odd
94 n
>>= n
.trailing_zeros();
97 m
>>= m
.trailing_zeros();
99 std
::mem
::swap(&mut n
, &mut m
)
110 impl_gcd_old_for_usize
!(u8);
111 impl_gcd_old_for_usize
!(u16);
112 impl_gcd_old_for_usize
!(u32);
113 impl_gcd_old_for_usize
!(u64);
114 impl_gcd_old_for_usize
!(usize);
115 impl_gcd_old_for_usize
!(u128
);
117 /// Return an iterator that yields all Fibonacci numbers fitting into a u128.
118 fn fibonacci() -> impl Iterator
<Item
= u128
> {
119 (0..185).scan((0, 1), |&mut (ref mut a
, ref mut b
), _
| {
127 fn run_bench
<T
: Integer
+ Bounded
+ Copy
+ '
static>(b
: &mut Bencher
, gcd
: fn(&T
, &T
) -> T
)
129 T
: AsPrimitive
<u128
>,
130 u128
: AsPrimitive
<T
>,
132 let max_value
: u128
= T
::max_value().as_();
133 let pairs
: Vec
<(T
, T
)> = fibonacci()
136 .filter(|&pair
| pair
[0] <= max_value
&& pair
[1] <= max_value
)
137 .map(|pair
| (pair
[0].as_(), pair
[1].as_()))
140 for &(ref m
, ref n
) in &pairs
{
141 black_box(gcd(m
, n
));
146 macro_rules
! bench_gcd
{
149 use crate::{run_bench, GcdOld}
;
150 use num_integer
::Integer
;
154 fn bench_gcd(b
: &mut Bencher
) {
155 run_bench(b
, $T
::gcd
);
159 fn bench_gcd_old(b
: &mut Bencher
) {
160 run_bench(b
, $T
::gcd_old
);