rusty-fib-facts/src/factorial.rs

85 lines
1.9 KiB
Rust

use std::f64::consts::{E, PI};
/// Calculate the value of a factorial iteratively
///
/// Can calculate up to 34! using native unsigned 128 bit integers.
///
/// Example:
/// ```rust
/// use rusty_fib_facts::factorial;
///
/// let valid = factorial(3); // Some(6)
/// # assert_eq!(6, valid.unwrap());
///
/// let invalid = factorial(35); // None
/// # assert!(invalid.is_none());
/// ```
#[inline]
pub fn it_factorial(n: usize) -> Option<u128> {
let mut total: u128 = 1;
if matches!(n, 0 | 1) {
Some(1u128)
} else {
for x in 1..=n {
total = total.checked_mul(x as u128)?;
}
Some(total)
}
}
/// Calculate the value of a factorial recursively
///
/// Can calculate up to 34! using native unsigned 128 bit integers.
///
/// Example:
/// ```rust
/// use rusty_fib_facts::factorial;
///
/// let valid = factorial(3); // Some(6)
/// # assert_eq!(6, valid.unwrap());
///
/// let invalid = factorial(35); // None
/// # assert!(invalid.is_none());
/// ```
#[inline]
pub fn factorial(n: usize) -> Option<u128> {
if matches!(n, 0 | 1) {
Some(1u128)
} else {
let prev = factorial(n - 1)?;
(n as u128).checked_mul(prev)
}
}
/// Approximates a factorial using Stirling's approximation
///
/// Based on https://en.wikipedia.org/wiki/Stirling's_approximation
///
/// Can approximate up to ~ 170.624!
///
/// Example:
/// ```rust
/// use rusty_fib_facts::approx_factorial;
///
/// let valid = approx_factorial(170.6); // Some(..)
/// # assert!(valid.is_some());
///
/// let invalid = approx_factorial(171.0); // None
/// # assert!(invalid.is_none());
/// ```
#[inline]
pub fn approx_factorial(n: f64) -> Option<f64> {
let power = (n / E).powf(n);
let root = (PI * 2.0 * n).sqrt();
let res = power * root;
if res >= std::f64::MIN && res <= std::f64::MAX {
Some(res)
} else {
None
}
}