//! Benchmark sqrt and cbrt #![feature(test)] extern crate test; use num_integer::Integer; use num_traits::checked_pow; use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul}; use test::{black_box, Bencher}; trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} fn bench(b: &mut Bencher, v: &[T], f: F, n: u32) where T: BenchInteger, F: Fn(&T) -> T, { // Pre-validate the results... for i in v { let rt = f(i); if *i >= T::zero() { let rt1 = rt + T::one(); assert!(rt.pow(n) <= *i); if let Some(x) = checked_pow(rt1, n as usize) { assert!(*i < x); } } else { let rt1 = rt - T::one(); assert!(rt < T::zero()); assert!(*i <= rt.pow(n)); if let Some(x) = checked_pow(rt1, n as usize) { assert!(x < *i); } }; } // Now just run as fast as we can! b.iter(|| { for i in v { black_box(f(i)); } }); } // Simple PRNG so we don't have to worry about rand compatibility fn lcg(x: T) -> T where u32: AsPrimitive, T: BenchInteger, { // LCG parameters from Numerical Recipes // (but we're applying it to arbitrary sizes) const LCG_A: u32 = 1664525; const LCG_C: u32 = 1013904223; x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_()) } fn bench_rand(b: &mut Bencher, f: F, n: u32) where u32: AsPrimitive, T: BenchInteger, F: Fn(&T) -> T, { let mut x: T = 3u32.as_(); let v: Vec = (0..1000) .map(|_| { x = lcg(x); x }) .collect(); bench(b, &v, f, n); } fn bench_rand_pos(b: &mut Bencher, f: F, n: u32) where u32: AsPrimitive, T: BenchInteger, F: Fn(&T) -> T, { let mut x: T = 3u32.as_(); let v: Vec = (0..1000) .map(|_| { x = lcg(x); while x < T::zero() { x = lcg(x); } x }) .collect(); bench(b, &v, f, n); } fn bench_small(b: &mut Bencher, f: F, n: u32) where u32: AsPrimitive, T: BenchInteger, F: Fn(&T) -> T, { let v: Vec = (0..1000).map(|i| i.as_()).collect(); bench(b, &v, f, n); } fn bench_small_pos(b: &mut Bencher, f: F, n: u32) where u32: AsPrimitive, T: BenchInteger, F: Fn(&T) -> T, { let v: Vec = (0..1000) .map(|i| i.as_().mod_floor(&T::max_value())) .collect(); bench(b, &v, f, n); } macro_rules! bench_roots { ($($T:ident),*) => {$( mod $T { use test::Bencher; use num_integer::Roots; #[bench] fn sqrt_rand(b: &mut Bencher) { crate::bench_rand_pos(b, $T::sqrt, 2); } #[bench] fn sqrt_small(b: &mut Bencher) { crate::bench_small_pos(b, $T::sqrt, 2); } #[bench] fn cbrt_rand(b: &mut Bencher) { crate::bench_rand(b, $T::cbrt, 3); } #[bench] fn cbrt_small(b: &mut Bencher) { crate::bench_small(b, $T::cbrt, 3); } #[bench] fn fourth_root_rand(b: &mut Bencher) { crate::bench_rand_pos(b, |x: &$T| x.nth_root(4), 4); } #[bench] fn fourth_root_small(b: &mut Bencher) { crate::bench_small_pos(b, |x: &$T| x.nth_root(4), 4); } #[bench] fn fifth_root_rand(b: &mut Bencher) { crate::bench_rand(b, |x: &$T| x.nth_root(5), 5); } #[bench] fn fifth_root_small(b: &mut Bencher) { crate::bench_small(b, |x: &$T| x.nth_root(5), 5); } } )*} } bench_roots!(i8, i16, i32, i64, i128); bench_roots!(u8, u16, u32, u64, u128);