More factorial/fibonacci optimizing
Some checks failed
timw4mail/rusty-numbers/pipeline/head There was a failure building this commit
Some checks failed
timw4mail/rusty-numbers/pipeline/head There was a failure building this commit
This commit is contained in:
parent
f49d1798e2
commit
d4458bae08
@ -1,16 +1,16 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
use rusty_numbers::{factorial, fibonacci, mem_fibonacci, mem_factorial};
|
use rusty_numbers::{factorial, fibonacci, it_factorial, mem_fibonacci, rec_fibonacci};
|
||||||
|
|
||||||
fn bench_factorial(c: &mut Criterion) {
|
fn bench_factorial(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("Factorials");
|
let mut group = c.benchmark_group("Factorials");
|
||||||
|
|
||||||
for i in [0usize, 5, 10, 15, 20, 25, 30, 34].iter() {
|
for i in [0usize, 5, 10, 15, 20, 25, 30, 34].iter() {
|
||||||
group.bench_with_input(BenchmarkId::new("Recursive memoized", i), i, |b, i| {
|
|
||||||
b.iter(|| mem_factorial(*i))
|
|
||||||
});
|
|
||||||
group.bench_with_input(BenchmarkId::new("Recursive naive", i), i, |b, i| {
|
group.bench_with_input(BenchmarkId::new("Recursive naive", i), i, |b, i| {
|
||||||
b.iter(|| factorial(*i))
|
b.iter(|| factorial(*i))
|
||||||
});
|
});
|
||||||
|
group.bench_with_input(BenchmarkId::new("Iterative", i), i, |b, i| {
|
||||||
|
b.iter(|| it_factorial(*i))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
group.finish();
|
group.finish();
|
||||||
}
|
}
|
||||||
@ -27,6 +27,16 @@ fn bench_fibonacci(c: &mut Criterion) {
|
|||||||
b.iter(|| fibonacci(*i))
|
b.iter(|| fibonacci(*i))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group.finish();
|
||||||
|
|
||||||
|
let mut group = c.benchmark_group("Recursive Fibonacci");
|
||||||
|
for i in [0usize, 5, 10, 15, 20, 25, 26, 27, 28, 29, 30].iter() {
|
||||||
|
group.bench_with_input(BenchmarkId::new("Naive Recursive", i), i, |b, i| {
|
||||||
|
b.iter(|| rec_fibonacci(*i))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
group.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, bench_factorial, bench_fibonacci);
|
criterion_group!(benches, bench_factorial, bench_fibonacci);
|
||||||
|
117
src/lib.rs
117
src/lib.rs
@ -37,6 +37,11 @@ pub fn mem_fibonacci(n: usize) -> Option<u128> {
|
|||||||
/// Actual calculating function for `fibonacci`
|
/// Actual calculating function for `fibonacci`
|
||||||
#[inline]
|
#[inline]
|
||||||
fn _mem_fibonacci(n: usize, table: &mut [u128]) -> Option<u128> {
|
fn _mem_fibonacci(n: usize, table: &mut [u128]) -> Option<u128> {
|
||||||
|
if n < 2 {
|
||||||
|
// The first values are predefined.
|
||||||
|
return Some(table[n]);
|
||||||
|
}
|
||||||
|
|
||||||
if n > 186 {
|
if n > 186 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -51,8 +56,8 @@ fn _mem_fibonacci(n: usize, table: &mut [u128]) -> Option<u128> {
|
|||||||
table[n] = a + b;
|
table[n] = a + b;
|
||||||
|
|
||||||
Some(table[n])
|
Some(table[n])
|
||||||
},
|
}
|
||||||
x => Some(x)
|
x => Some(x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +106,7 @@ pub fn fibonacci(n: usize) -> Option<u128> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the value of a factorial,
|
/// Calculate the value of a factorial iteratively
|
||||||
/// using a lookup table for better worst-case performance.
|
|
||||||
///
|
///
|
||||||
/// Can calculate up to 34! using native unsigned 128 bit integers.
|
/// Can calculate up to 34! using native unsigned 128 bit integers.
|
||||||
///
|
///
|
||||||
@ -117,40 +121,22 @@ pub fn fibonacci(n: usize) -> Option<u128> {
|
|||||||
/// # assert!(invalid.is_none());
|
/// # assert!(invalid.is_none());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mem_factorial(n: usize) -> Option<u128> {
|
pub fn it_factorial(n: usize) -> Option<u128> {
|
||||||
let mut table = [0u128; 35];
|
let mut total: u128 = 1;
|
||||||
table[0] = 1;
|
|
||||||
table[1] = 1;
|
|
||||||
table[2] = 2;
|
|
||||||
|
|
||||||
|
match n {
|
||||||
_mem_factorial(n, &mut table)
|
0 | 1 => Some(1u128),
|
||||||
|
_ => {
|
||||||
|
for x in 1..=n {
|
||||||
|
total = total.checked_mul(x as u128)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Actual Calculation function for factoral
|
Some(total)
|
||||||
#[inline]
|
|
||||||
fn _mem_factorial(n: usize, table: &mut [u128]) -> Option<u128> {
|
|
||||||
if n > 34 {
|
|
||||||
return None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match table[n] {
|
|
||||||
// Empty spaces in the lookup array are zero-filled
|
|
||||||
0 => {
|
|
||||||
// The ? suffix passes along the Option value
|
|
||||||
// to be handled later
|
|
||||||
// See: https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator
|
|
||||||
let prev = _mem_factorial(n - 1, table)?;
|
|
||||||
|
|
||||||
table[n] = (n as u128) * prev;
|
|
||||||
|
|
||||||
Some(table[n])
|
|
||||||
},
|
|
||||||
x => Some(x),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the value of a factorial,
|
/// Calculate the value of a factorial recrursively
|
||||||
///
|
///
|
||||||
/// Can calculate up to 34! using native unsigned 128 bit integers.
|
/// Can calculate up to 34! using native unsigned 128 bit integers.
|
||||||
///
|
///
|
||||||
@ -184,36 +170,71 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_factorial() {
|
fn test_factorial() {
|
||||||
assert_eq!(1, factorial(0).unwrap());
|
for pair in [[1usize, 0], [1, 1], [2, 2], [6, 3]].iter() {
|
||||||
assert_eq!(1, factorial(1).unwrap());
|
assert_eq!(
|
||||||
assert_eq!(6, factorial(3).unwrap());
|
Some(pair[0] as u128),
|
||||||
|
factorial(pair[1]),
|
||||||
|
"{}! should be {}",
|
||||||
|
pair[1],
|
||||||
|
pair[0]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Some(pair[0] as u128),
|
||||||
|
it_factorial(pair[1]),
|
||||||
|
"{}! should be {}",
|
||||||
|
pair[1],
|
||||||
|
pair[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify each implementation returns the same results
|
||||||
let res = factorial(34);
|
let res = factorial(34);
|
||||||
let res2 = mem_factorial(34);
|
let res2 = it_factorial(34);
|
||||||
assert!(res.is_some());
|
assert!(res.is_some());
|
||||||
assert_eq!(res.unwrap(), res2.unwrap());
|
assert!(res2.is_some());
|
||||||
|
assert_eq!(res, res2);
|
||||||
|
|
||||||
let res = factorial(35);
|
// Bounds checks
|
||||||
assert!(res.is_none());
|
assert!(factorial(35).is_none());
|
||||||
|
assert!(it_factorial(35).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fibonacci() {
|
fn test_fibonacci() {
|
||||||
assert_eq!(0, fibonacci(0).unwrap());
|
// Sanity checking
|
||||||
assert_eq!(1, fibonacci(1).unwrap());
|
for pair in [[0usize, 0], [1, 1], [1, 2], [2, 3]].iter() {
|
||||||
assert_eq!(1, fibonacci(2).unwrap());
|
assert_eq!(
|
||||||
|
Some(pair[0] as u128),
|
||||||
let res = fibonacci(20);
|
fibonacci(pair[1]),
|
||||||
let res2 = rec_fibonacci(20);
|
"fibonacci({}) should be {}",
|
||||||
assert_eq!(res, res2);
|
pair[1],
|
||||||
|
pair[0]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Some(pair[0] as u128),
|
||||||
|
mem_fibonacci(pair[1]),
|
||||||
|
"fibonacci({}) should be {}",
|
||||||
|
pair[1],
|
||||||
|
pair[0]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Some(pair[0] as u128),
|
||||||
|
rec_fibonacci(pair[1]),
|
||||||
|
"fibonacci({}) should be {}",
|
||||||
|
pair[1],
|
||||||
|
pair[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify each implementation returns the same results
|
||||||
let res = fibonacci(186);
|
let res = fibonacci(186);
|
||||||
let res2 = mem_fibonacci(186);
|
let res2 = mem_fibonacci(186);
|
||||||
assert!(res.is_some());
|
assert!(res.is_some());
|
||||||
assert!(res2.is_some());
|
assert!(res2.is_some());
|
||||||
assert_eq!(res.unwrap(), res2.unwrap());
|
assert_eq!(res, res2);
|
||||||
|
|
||||||
let res = fibonacci(187);
|
// Bounds checks
|
||||||
assert!(res.is_none());
|
assert!(fibonacci(187).is_none());
|
||||||
|
assert!(mem_fibonacci(187).is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user