85 lines
1.9 KiB
Rust
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
|
||
|
}
|
||
|
}
|