Skip to content

Commit

Permalink
Added benchmarks for isqrt implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
ChaiTRex committed Jul 24, 2024
1 parent 8859812 commit d180572
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
1 change: 1 addition & 0 deletions library/core/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#![feature(iter_array_chunks)]
#![feature(iter_next_chunk)]
#![feature(iter_advance_by)]
#![feature(isqrt)]

extern crate test;

Expand Down
207 changes: 207 additions & 0 deletions library/core/benches/num/int_sqrt/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
//! This benchmarks the `Integer::isqrt` methods.

macro_rules! benches {
($($T:ident)+) => {
$(
mod $T {
use test::{black_box, Bencher};

// Benchmark the square roots of:
//
// * the first 1,024 perfect squares
// * halfway between each of the first 1,024 perfect squares
// and the next perfect square
// * the next perfect square after the each of the first 1,024
// perfect squares, minus one
// * the last 1,024 perfect squares
// * the last 1,024 perfect squares, minus one
// * halfway between each of the last 1,024 perfect squares
// and the previous perfect square
#[bench]
fn isqrt(bench: &mut Bencher) {
let mut inputs = Vec::with_capacity(6 * 1_024);

// The inputs to benchmark are worked out by using the fact
// that the nth nonzero perfect square is the sum of the
// first n odd numbers:
//
// 1 = 1
// 4 = 1 + 3
// 9 = 1 + 3 + 5
// 16 = 1 + 3 + 5 + 7
//
// Note also that the last odd number added in is two times
// the square root of the previous perfect square, plus
// one:
//
// 1 = 2*0 + 1
// 3 = 2*1 + 1
// 5 = 2*2 + 1
// 7 = 2*3 + 1
//
// That means we can add the square root of this perfect
// square once to get about halfway to the next perfect
// square, then we can add the square root of this perfect
// square again to get to the next perfect square minus
// one, then we can add one to get to the next perfect
// square.
//
// Here we include, for each of the first 1,024 perfect
// squares:
//
// * the current perfect square
// * about halfway to the next perfect square
// * the next perfect square, minus one
let mut n: $T = 0;
for sqrt_n in 0..1_024.min((1_u128 << (($T::BITS - $T::MAX.leading_zeros())/2)) - 1) as $T {
inputs.push(n);
n += sqrt_n;
inputs.push(n);
n += sqrt_n;
inputs.push(n);
n += 1;
}

// Similarly, we include, for each of the last 1,024
// perfect squares:
//
// * the current perfect square
// * the current perfect square, minus one
// * about halfway to the previous perfect square
let maximum_sqrt = $T::MAX.isqrt();
let mut n = maximum_sqrt * maximum_sqrt;

for sqrt_n in (maximum_sqrt - 1_024.min((1_u128 << (($T::BITS - 1)/2)) - 1) as $T..maximum_sqrt).rev() {
inputs.push(n);
n -= 1;
inputs.push(n);
n -= sqrt_n;
inputs.push(n);
n -= sqrt_n;
}

bench.iter(|| {
for x in &inputs {
black_box(black_box(x).isqrt());
}
});
}
}
)*
};
}

macro_rules! push_n {
($T:ident, $inputs:ident, $n:ident) => {
if $n != 0 {
$inputs.push(
core::num::$T::new($n)
.expect("Cannot create a new `NonZero` value from a nonzero value"),
);
}
};
}

macro_rules! nonzero_benches {
($mod:ident $T:ident $RegularT:ident) => {
mod $mod {
use test::{black_box, Bencher};

// Benchmark the square roots of:
//
// * the first 1,024 perfect squares
// * halfway between each of the first 1,024 perfect squares
// and the next perfect square
// * the next perfect square after the each of the first 1,024
// perfect squares, minus one
// * the last 1,024 perfect squares
// * the last 1,024 perfect squares, minus one
// * halfway between each of the last 1,024 perfect squares
// and the previous perfect square
#[bench]
fn isqrt(bench: &mut Bencher) {
let mut inputs: Vec<core::num::$T> = Vec::with_capacity(6 * 1_024);

// The inputs to benchmark are worked out by using the fact
// that the nth nonzero perfect square is the sum of the
// first n odd numbers:
//
// 1 = 1
// 4 = 1 + 3
// 9 = 1 + 3 + 5
// 16 = 1 + 3 + 5 + 7
//
// Note also that the last odd number added in is two times
// the square root of the previous perfect square, plus
// one:
//
// 1 = 2*0 + 1
// 3 = 2*1 + 1
// 5 = 2*2 + 1
// 7 = 2*3 + 1
//
// That means we can add the square root of this perfect
// square once to get about halfway to the next perfect
// square, then we can add the square root of this perfect
// square again to get to the next perfect square minus
// one, then we can add one to get to the next perfect
// square.
//
// Here we include, for each of the first 1,024 perfect
// squares:
//
// * the current perfect square
// * about halfway to the next perfect square
// * the next perfect square, minus one
let mut n: $RegularT = 0;
for sqrt_n in 0..1_024
.min((1_u128 << (($RegularT::BITS - $RegularT::MAX.leading_zeros()) / 2)) - 1)
as $RegularT
{
push_n!($T, inputs, n);
n += sqrt_n;
push_n!($T, inputs, n);
n += sqrt_n;
push_n!($T, inputs, n);
n += 1;
}

// Similarly, we include, for each of the last 1,024
// perfect squares:
//
// * the current perfect square
// * the current perfect square, minus one
// * about halfway to the previous perfect square
let maximum_sqrt = $RegularT::MAX.isqrt();
let mut n = maximum_sqrt * maximum_sqrt;

for sqrt_n in (maximum_sqrt
- 1_024.min((1_u128 << (($RegularT::BITS - 1) / 2)) - 1) as $RegularT
..maximum_sqrt)
.rev()
{
push_n!($T, inputs, n);
n -= 1;
push_n!($T, inputs, n);
n -= sqrt_n;
push_n!($T, inputs, n);
n -= sqrt_n;
}

bench.iter(|| {
for n in &inputs {
black_box(black_box(n).isqrt());
}
});
}
}
};
}

benches!(i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize);
nonzero_benches!(non_zero_u8 NonZeroU8 u8);
nonzero_benches!(non_zero_u16 NonZeroU16 u16);
nonzero_benches!(non_zero_u32 NonZeroU32 u32);
nonzero_benches!(non_zero_u64 NonZeroU64 u64);
nonzero_benches!(non_zero_u128 NonZeroU128 u128);
nonzero_benches!(non_zero_usize NonZeroUsize usize);
1 change: 1 addition & 0 deletions library/core/benches/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod dec2flt;
mod flt2dec;
mod int_log;
mod int_pow;
mod int_sqrt;

use std::str::FromStr;
use test::{black_box, Bencher};
Expand Down

0 comments on commit d180572

Please sign in to comment.