use core::hint::black_box;
use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main};
use lazy_static::lazy_static;
use std::time::Duration;
const SAMPLES: usize = 50;
const N: usize = 20;
const DEFAULT_DURATION_SECS: u64 = 10;
lazy_static! {
static ref DURATION: Duration = Duration::from_secs(DEFAULT_DURATION_SECS);
}
fn bench_fib_func(c: &mut Criterion) {
c.bench_function("fibonacci", |b| b.iter(|| fib::fibonacci(black_box(N))));
}
fn bench_fib_recursive(c: &mut Criterion) {
c.bench_function("recursive_fibonacci", |b| {
b.iter(|| fib::recursive_fibonacci(black_box(N)))
});
}
fn bench_fib_iter(c: &mut Criterion) {
let measure_for = Duration::from_secs(DEFAULT_DURATION_SECS);
let mut group = c.benchmark_group("Fibonacci Iter");
group.measurement_time(measure_for);
group.sample_size(SAMPLES);
for &n in &[10, 50, 100, 500, 1000] {
group.bench_with_input(BenchmarkId::new("Fibonacci::compute", n), &n, |b, &x| {
b.iter_batched(
fib::Fibonacci::new,
|mut fib| {
black_box(fib.compute(x));
},
BatchSize::SmallInput,
);
});
}
group.finish();
}
criterion_group! {
benches,
bench_fib_func,
bench_fib_iter,
bench_fib_recursive,
}
criterion_main!(benches);
pub mod fib {
#[inline]
pub fn fibonacci(n: usize) -> u128 {
let mut a = 0;
let mut b = 1;
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
b
}
pub const fn recursive_fibonacci(n: usize) -> u128 {
const fn _inner(n: usize, previous: u128, current: u128) -> u128 {
if n == 0 {
current
} else {
_inner(n - 1, current, current + previous)
}
}
_inner(n, 0, 1)
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Fibonacci {
curr: u32,
next: u32,
}
impl Fibonacci {
pub const fn new() -> Fibonacci {
Fibonacci { curr: 0, next: 1 }
}
pub const fn curr(&self) -> u32 {
self.curr
}
pub const fn curr_mut(&mut self) -> &mut u32 {
&mut self.curr
}
pub const fn next(&self) -> u32 {
self.next
}
pub const fn next_mut(&mut self) -> &mut u32 {
&mut self.next
}
#[inline]
pub fn compute(&mut self, n: usize) -> u32 {
if let Some(res) = self.nth(n + 1) {
return res;
}
panic!("Unable to compute the nth value of the fibonacci sequence...")
}
pub const fn reset(&mut self) -> &mut Self {
self.set_curr(0).set_next(1)
}
#[inline]
const fn compute_next(&self) -> u32 {
self.curr() + self.next()
}
const fn replace_curr(&mut self, curr: u32) -> u32 {
core::mem::replace(self.curr_mut(), curr)
}
const fn replace_next(&mut self, next: u32) -> u32 {
core::mem::replace(self.next_mut(), next)
}
const fn set_curr(&mut self, curr: u32) -> &mut Self {
self.curr = curr;
self
}
const fn set_next(&mut self, next: u32) -> &mut Self {
self.next = next;
self
}
const fn update(&mut self, next: u32) -> u32 {
let new = self.replace_next(next);
self.replace_curr(new)
}
}
impl Default for Fibonacci {
fn default() -> Self {
Self::new()
}
}
impl Iterator for Fibonacci {
type Item = u32;
fn next(&mut self) -> Option<u32> {
let new_next = self.compute_next();
let prev = self.update(new_next);
Some(prev)
}
}
}