94 lines
2.5 KiB
Rust
94 lines
2.5 KiB
Rust
|
///! Sequences and other 'stock' math functions
|
||
|
|
||
|
///! Calculate a number in the fibonacci sequence,
|
||
|
///! using a lookup table for better worst-case performance.
|
||
|
///
|
||
|
/// Can calculate up to 186 using native unsigned 128 bit integers.
|
||
|
pub fn fibonacci(n: usize) -> Option<u128> {
|
||
|
let mut table: Vec<u128> = vec![];
|
||
|
|
||
|
_fibonacci(n, &mut table)
|
||
|
}
|
||
|
|
||
|
/// Actual calculating function for `fibonacci`
|
||
|
#[inline]
|
||
|
fn _fibonacci(n: usize, table: &mut Vec<u128>) -> Option<u128> {
|
||
|
match table.get(n) {
|
||
|
Some(x) => Some(*x),
|
||
|
None => {
|
||
|
let a = _fibonacci(n - 1, table)?;
|
||
|
let b = _fibonacci(n - 2, table)?;
|
||
|
|
||
|
// Check for overflow when adding
|
||
|
let attempt = a.checked_add(b);
|
||
|
|
||
|
if let Some(current) = attempt {
|
||
|
table.insert(n, current);
|
||
|
}
|
||
|
|
||
|
attempt
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
///! Calculate the value of a factorial,
|
||
|
///! using a lookup table for better worst-case performance.
|
||
|
///
|
||
|
/// Can calculate up to 34! using native unsigned 128 bit integers.
|
||
|
/// If the result overflows, an error message will be displayed.
|
||
|
pub fn factorial(n: usize) -> Option<u128> {
|
||
|
let mut table: Vec<u128> = vec![0, 1, 1, 2, 3, 5];
|
||
|
|
||
|
_factorial(n, &mut table)
|
||
|
}
|
||
|
|
||
|
/// Actual Calculation function for factoral
|
||
|
#[inline]
|
||
|
fn _factorial (n: usize, table: &mut Vec<u128>) -> Option<u128> {
|
||
|
match table.get(n) {
|
||
|
// Vec<T>.get returns a Option with a reference to the value,
|
||
|
// so deref and wrap in Some() for proper return type
|
||
|
Some(x) => Some(*x),
|
||
|
None => {
|
||
|
// 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 = _factorial(n - 1, table)?;
|
||
|
|
||
|
// Do an overflow-checked multiply
|
||
|
let attempt = (n as u128).checked_mul(prev);
|
||
|
|
||
|
// If there isn't an overflow, add the result
|
||
|
// to the calculation table
|
||
|
if let Some(current) = attempt {
|
||
|
table.insert(n, current);
|
||
|
}
|
||
|
|
||
|
attempt // Some(x) if no overflow
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn test_factorial() {
|
||
|
let res = factorial(34);
|
||
|
assert!(res.is_some());
|
||
|
|
||
|
let res = factorial(35);
|
||
|
assert!(res.is_none());
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_fibonacci() {
|
||
|
let res = fibonacci(186);
|
||
|
assert!(res.is_some());
|
||
|
|
||
|
let res = fibonacci(187);
|
||
|
assert!(res.is_none());
|
||
|
}
|
||
|
}
|