summaryrefslogtreecommitdiffstats
path: root/third_party/rust/num-integer/benches/average.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/num-integer/benches/average.rs')
-rw-r--r--third_party/rust/num-integer/benches/average.rs414
1 files changed, 414 insertions, 0 deletions
diff --git a/third_party/rust/num-integer/benches/average.rs b/third_party/rust/num-integer/benches/average.rs
new file mode 100644
index 0000000000..649078c39d
--- /dev/null
+++ b/third_party/rust/num-integer/benches/average.rs
@@ -0,0 +1,414 @@
+//! Benchmark sqrt and cbrt
+
+#![feature(test)]
+
+extern crate num_integer;
+extern crate num_traits;
+extern crate test;
+
+use num_integer::Integer;
+use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul};
+use std::cmp::{max, min};
+use std::fmt::Debug;
+use test::{black_box, Bencher};
+
+// --- Utilities for RNG ----------------------------------------------------
+
+trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
+
+impl<T> BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
+
+// Simple PRNG so we don't have to worry about rand compatibility
+fn lcg<T>(x: T) -> T
+where
+ u32: AsPrimitive<T>,
+ 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_())
+}
+
+// --- Alt. Implementations -------------------------------------------------
+
+trait NaiveAverage {
+ fn naive_average_ceil(&self, other: &Self) -> Self;
+ fn naive_average_floor(&self, other: &Self) -> Self;
+}
+
+trait UncheckedAverage {
+ fn unchecked_average_ceil(&self, other: &Self) -> Self;
+ fn unchecked_average_floor(&self, other: &Self) -> Self;
+}
+
+trait ModuloAverage {
+ fn modulo_average_ceil(&self, other: &Self) -> Self;
+ fn modulo_average_floor(&self, other: &Self) -> Self;
+}
+
+macro_rules! naive_average {
+ ($T:ident) => {
+ impl super::NaiveAverage for $T {
+ fn naive_average_floor(&self, other: &$T) -> $T {
+ match self.checked_add(*other) {
+ Some(z) => Integer::div_floor(&z, &2),
+ None => {
+ if self > other {
+ let diff = self - other;
+ other + Integer::div_floor(&diff, &2)
+ } else {
+ let diff = other - self;
+ self + Integer::div_floor(&diff, &2)
+ }
+ }
+ }
+ }
+ fn naive_average_ceil(&self, other: &$T) -> $T {
+ match self.checked_add(*other) {
+ Some(z) => Integer::div_ceil(&z, &2),
+ None => {
+ if self > other {
+ let diff = self - other;
+ self - Integer::div_floor(&diff, &2)
+ } else {
+ let diff = other - self;
+ other - Integer::div_floor(&diff, &2)
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+macro_rules! unchecked_average {
+ ($T:ident) => {
+ impl super::UncheckedAverage for $T {
+ fn unchecked_average_floor(&self, other: &$T) -> $T {
+ self.wrapping_add(*other) / 2
+ }
+ fn unchecked_average_ceil(&self, other: &$T) -> $T {
+ (self.wrapping_add(*other) / 2).wrapping_add(1)
+ }
+ }
+ };
+}
+
+macro_rules! modulo_average {
+ ($T:ident) => {
+ impl super::ModuloAverage for $T {
+ fn modulo_average_ceil(&self, other: &$T) -> $T {
+ let (q1, r1) = self.div_mod_floor(&2);
+ let (q2, r2) = other.div_mod_floor(&2);
+ q1 + q2 + (r1 | r2)
+ }
+ fn modulo_average_floor(&self, other: &$T) -> $T {
+ let (q1, r1) = self.div_mod_floor(&2);
+ let (q2, r2) = other.div_mod_floor(&2);
+ q1 + q2 + (r1 * r2)
+ }
+ }
+ };
+}
+
+// --- Bench functions ------------------------------------------------------
+
+fn bench_unchecked<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
+where
+ T: Integer + Debug + Copy,
+ F: Fn(&T, &T) -> T,
+{
+ b.iter(|| {
+ for (x, y) in v {
+ black_box(f(x, y));
+ }
+ });
+}
+
+fn bench_ceil<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
+where
+ T: Integer + Debug + Copy,
+ F: Fn(&T, &T) -> T,
+{
+ for &(i, j) in v {
+ let rt = f(&i, &j);
+ let (a, b) = (min(i, j), max(i, j));
+ // if both number are the same sign, check rt is in the middle
+ if (a < T::zero()) == (b < T::zero()) {
+ if (b - a).is_even() {
+ assert_eq!(rt - a, b - rt);
+ } else {
+ assert_eq!(rt - a, b - rt + T::one());
+ }
+ // if both number have a different sign,
+ } else {
+ if (a + b).is_even() {
+ assert_eq!(rt, (a + b) / (T::one() + T::one()))
+ } else {
+ assert_eq!(rt, (a + b + T::one()) / (T::one() + T::one()))
+ }
+ }
+ }
+ bench_unchecked(b, v, f);
+}
+
+fn bench_floor<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
+where
+ T: Integer + Debug + Copy,
+ F: Fn(&T, &T) -> T,
+{
+ for &(i, j) in v {
+ let rt = f(&i, &j);
+ let (a, b) = (min(i, j), max(i, j));
+ // if both number are the same sign, check rt is in the middle
+ if (a < T::zero()) == (b < T::zero()) {
+ if (b - a).is_even() {
+ assert_eq!(rt - a, b - rt);
+ } else {
+ assert_eq!(rt - a + T::one(), b - rt);
+ }
+ // if both number have a different sign,
+ } else {
+ if (a + b).is_even() {
+ assert_eq!(rt, (a + b) / (T::one() + T::one()))
+ } else {
+ assert_eq!(rt, (a + b - T::one()) / (T::one() + T::one()))
+ }
+ }
+ }
+ bench_unchecked(b, v, f);
+}
+
+// --- Bench implementation -------------------------------------------------
+
+macro_rules! bench_average {
+ ($($T:ident),*) => {$(
+ mod $T {
+ use test::Bencher;
+ use num_integer::{Average, Integer};
+ use super::{UncheckedAverage, NaiveAverage, ModuloAverage};
+ use super::{bench_ceil, bench_floor, bench_unchecked};
+
+ naive_average!($T);
+ unchecked_average!($T);
+ modulo_average!($T);
+
+ const SIZE: $T = 30;
+
+ fn overflowing() -> Vec<($T, $T)> {
+ (($T::max_value()-SIZE)..$T::max_value())
+ .flat_map(|x| -> Vec<_> {
+ (($T::max_value()-100)..($T::max_value()-100+SIZE))
+ .map(|y| (x, y))
+ .collect()
+ })
+ .collect()
+ }
+
+ fn small() -> Vec<($T, $T)> {
+ (0..SIZE)
+ .flat_map(|x| -> Vec<_> {(0..SIZE).map(|y| (x, y)).collect()})
+ .collect()
+ }
+
+ fn rand() -> Vec<($T, $T)> {
+ small()
+ .into_iter()
+ .map(|(x, y)| (super::lcg(x), super::lcg(y)))
+ .collect()
+ }
+
+ mod ceil {
+
+ use super::*;
+
+ mod small {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = small();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = small();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = small();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = small();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
+ }
+ }
+
+ mod overflowing {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = overflowing();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = overflowing();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = overflowing();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = overflowing();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
+ }
+ }
+
+ mod rand {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = rand();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = rand();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = rand();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = rand();
+ bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
+ }
+ }
+
+ }
+
+ mod floor {
+
+ use super::*;
+
+ mod small {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = small();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = small();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = small();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = small();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
+ }
+ }
+
+ mod overflowing {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = overflowing();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = overflowing();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = overflowing();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = overflowing();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
+ }
+ }
+
+ mod rand {
+
+ use super::*;
+
+ #[bench]
+ fn optimized(b: &mut Bencher) {
+ let v = rand();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
+ }
+
+ #[bench]
+ fn naive(b: &mut Bencher) {
+ let v = rand();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
+ }
+
+ #[bench]
+ fn unchecked(b: &mut Bencher) {
+ let v = rand();
+ bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
+ }
+
+ #[bench]
+ fn modulo(b: &mut Bencher) {
+ let v = rand();
+ bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
+ }
+ }
+
+ }
+
+ }
+ )*}
+}
+
+bench_average!(i8, i16, i32, i64, i128, isize);
+bench_average!(u8, u16, u32, u64, u128, usize);