pub fn fibonacci(n: u64) -> Option<u64> {
fibonacci_pair(n).map(|(f, _)| f)
}
pub fn fibonacci_pair(n: u64) -> Option<(u64, u64)> {
if n == 0 {
return Some((0, 1));
}
let (f, f1) = fibonacci_pair(n / 2)?;
let two_f1 = f1.checked_mul(2)?;
let two_f1_minus_f = two_f1.checked_sub(f)?;
let c = f.checked_mul(two_f1_minus_f)?;
let d = f.checked_mul(f)?.checked_add(f1.checked_mul(f1)?)?;
if n % 2 == 0 {
Some((c, d))
} else {
Some((d, c.checked_add(d)?))
}
}
pub fn fibonacci_u128(n: u64) -> Option<u128> {
fibonacci_pair_u128(n).map(|(f, _)| f)
}
pub fn fibonacci_pair_u128(n: u64) -> Option<(u128, u128)> {
if n == 0 {
return Some((0, 1));
}
let (f, f1) = fibonacci_pair_u128(n / 2)?;
let two_f1 = f1.checked_mul(2)?;
let two_f1_minus_f = two_f1.checked_sub(f)?;
let c = f.checked_mul(two_f1_minus_f)?;
let d = f.checked_mul(f)?.checked_add(f1.checked_mul(f1)?)?;
if n % 2 == 0 {
Some((c, d))
} else {
Some((d, c.checked_add(d)?))
}
}
pub fn lucas_number(n: u64) -> Option<u64> {
let (f, f1) = fibonacci_pair(n)?;
let two_f1 = f1.checked_mul(2)?;
two_f1.checked_sub(f)
}
pub fn catalan_number(n: u64) -> Option<u64> {
if n == 0 {
return Some(1);
}
let mut c: u128 = 1;
for k in 1..=n {
let num = 2 * (2 * k as u128 - 1);
let den = k as u128 + 1;
c = c.checked_mul(num)? / den;
}
u64::try_from(c).ok()
}
pub fn bell_number(n: usize) -> Option<u64> {
if n == 0 {
return Some(1);
}
let mut row: Vec<u128> = vec![1]; for _row_idx in 0..n {
let mut next_row = Vec::with_capacity(row.len() + 1);
let first = *row.last().expect("row is non-empty");
next_row.push(first);
for prev in &row {
let last = *next_row.last().expect("next_row is non-empty");
next_row.push(last.checked_add(*prev)?);
}
row = next_row;
}
let bell = *row.first().expect("row is non-empty");
u64::try_from(bell).ok()
}
pub fn stirling_first(n: usize, k: usize) -> Option<i64> {
if k > n {
return Some(0);
}
let mut row = vec![0i64; n + 1];
row[0] = 1; for i in 1..=n {
let mut new_row = vec![0i64; n + 1];
for j in 1..=i {
let term1 = row[j - 1];
let term2 = (i as i64 - 1).checked_mul(row[j])?;
new_row[j] = term1.checked_sub(term2)?;
}
row = new_row;
}
Some(row[k])
}
pub fn stirling_first_unsigned(n: usize, k: usize) -> Option<u64> {
stirling_first(n, k).map(|v| v.unsigned_abs())
}
pub fn stirling_second(n: usize, k: usize) -> Option<u64> {
if k > n {
return Some(0);
}
if k == 0 {
return if n == 0 { Some(1) } else { Some(0) };
}
let mut row = vec![0u128; n + 1];
row[0] = 1; for i in 1..=n {
let mut new_row = vec![0u128; n + 1];
for j in 1..=i {
let term1 = (j as u128).checked_mul(row[j])?;
let term2 = row[j - 1];
new_row[j] = term1.checked_add(term2)?;
}
row = new_row;
}
u64::try_from(row[k]).ok()
}
pub fn derangement_count(n: usize) -> Option<u64> {
match n {
0 => Some(1),
1 => Some(0),
_ => {
let mut d_prev2: u128 = 1; let mut d_prev1: u128 = 0; for i in 2..=n {
let d = ((i as u128) - 1).checked_mul(d_prev2.checked_add(d_prev1)?)?;
d_prev2 = d_prev1;
d_prev1 = d;
}
u64::try_from(d_prev1).ok()
}
}
}
pub fn euler_number(n: usize) -> Option<i64> {
if n % 2 != 0 {
return Some(0);
}
let half = n / 2;
let mut e: Vec<i128> = vec![0; half + 1];
e[0] = 1; for m in 1..=half {
let two_m = 2 * m;
let mut s: i128 = 0;
let mut binom: i128 = 1;
for k in 0..m {
s = s.checked_add(binom.checked_mul(e[k])?)?;
let num = (two_m as i128 - 2 * k as i128)
.checked_mul(two_m as i128 - 2 * k as i128 - 1)?;
let den = (2 * k as i128 + 1).checked_mul(2 * k as i128 + 2)?;
binom = binom.checked_mul(num)? / den;
}
e[m] = s.checked_neg()?;
}
i64::try_from(e[half]).ok()
}
pub fn bernoulli_fraction(n: usize) -> Option<(i64, u64)> {
fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
a %= b;
std::mem::swap(&mut a, &mut b);
}
a
}
fn reduce(num: i64, den: u64) -> (i64, u64) {
if num == 0 {
return (0, 1);
}
let g = gcd(num.unsigned_abs(), den);
(num / g as i64, den / g)
}
let mut b_num = vec![0i128; n + 1];
let mut b_den = vec![1u128; n + 1];
b_num[0] = 1;
b_den[0] = 1;
for m in 1..=n {
let mut s_num: i128 = 0;
let mut s_den: u128 = 1;
let mut binom: u128 = 1; for k in 0..m {
let term_num = binom as i128 * b_num[k];
let term_den = b_den[k];
s_num = s_num * term_den as i128 + term_num * s_den as i128;
s_den = s_den.checked_mul(term_den)?;
let g = {
let a = s_num.unsigned_abs() as u128;
let b = s_den;
let mut aa = a;
let mut bb = b;
while bb != 0 {
aa %= bb;
std::mem::swap(&mut aa, &mut bb);
}
aa
};
if g > 1 {
s_num /= g as i128;
s_den /= g;
}
binom = binom.checked_mul((m as u128 + 1 - k as u128))? / (k as u128 + 1);
}
b_num[m] = -s_num;
b_den[m] = s_den.checked_mul(m as u128 + 1)?;
let g = {
let a = b_num[m].unsigned_abs() as u128;
let b = b_den[m];
let mut aa = a;
let mut bb = b;
while bb != 0 {
aa %= bb;
std::mem::swap(&mut aa, &mut bb);
}
aa
};
if g > 1 {
b_num[m] /= g as i128;
b_den[m] /= g;
}
}
let num = i64::try_from(b_num[n]).ok()?;
let den = u64::try_from(b_den[n]).ok()?;
Some(reduce(num, den))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fibonacci_small() {
let expected = [0u64, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
for (i, &exp) in expected.iter().enumerate() {
assert_eq!(
fibonacci(i as u64),
Some(exp),
"F({i}) should be {exp}"
);
}
}
#[test]
fn test_fibonacci_93() {
assert_eq!(fibonacci(93), Some(12200160415121876738u64));
}
#[test]
fn test_fibonacci_overflow() {
assert!(fibonacci(94).is_none());
}
#[test]
fn test_lucas() {
let expected = [2u64, 1, 3, 4, 7, 11, 18, 29, 47];
for (i, &exp) in expected.iter().enumerate() {
assert_eq!(lucas_number(i as u64), Some(exp), "L({i}) should be {exp}");
}
}
#[test]
fn test_catalan() {
let expected = [1u64, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];
for (i, &exp) in expected.iter().enumerate() {
assert_eq!(
catalan_number(i as u64),
Some(exp),
"C({i}) should be {exp}"
);
}
}
#[test]
fn test_bell() {
let expected = [1u64, 1, 2, 5, 15, 52, 203, 877, 4140, 21147];
for (i, &exp) in expected.iter().enumerate() {
assert_eq!(bell_number(i), Some(exp), "B({i}) should be {exp}");
}
}
#[test]
fn test_stirling_first() {
assert_eq!(stirling_first(0, 0), Some(1));
assert_eq!(stirling_first(1, 1), Some(1));
assert_eq!(stirling_first(2, 1), Some(-1));
assert_eq!(stirling_first(3, 2), Some(3));
assert_eq!(stirling_first(4, 2), Some(-11));
assert_eq!(stirling_first(4, 3), Some(6));
assert_eq!(stirling_first(4, 4), Some(1));
assert_eq!(stirling_first(2, 5), Some(0));
}
#[test]
fn test_stirling_second() {
assert_eq!(stirling_second(0, 0), Some(1));
assert_eq!(stirling_second(1, 1), Some(1));
assert_eq!(stirling_second(3, 2), Some(3));
assert_eq!(stirling_second(4, 2), Some(7));
assert_eq!(stirling_second(4, 4), Some(1));
assert_eq!(stirling_second(5, 3), Some(25));
assert_eq!(stirling_second(2, 5), Some(0));
}
#[test]
fn test_derangements() {
let expected = [1u64, 0, 1, 2, 9, 44, 265, 1854, 14833];
for (i, &exp) in expected.iter().enumerate() {
assert_eq!(
derangement_count(i),
Some(exp),
"D({i}) should be {exp}"
);
}
}
#[test]
fn test_euler_numbers() {
assert_eq!(euler_number(0), Some(1));
assert_eq!(euler_number(2), Some(-1));
assert_eq!(euler_number(4), Some(5));
assert_eq!(euler_number(6), Some(-61));
assert_eq!(euler_number(3), Some(0));
}
#[test]
fn test_bernoulli() {
assert_eq!(bernoulli_fraction(0), Some((1, 1)));
assert_eq!(bernoulli_fraction(1), Some((-1, 2)));
assert_eq!(bernoulli_fraction(2), Some((1, 6)));
assert_eq!(bernoulli_fraction(3), Some((0, 1)));
assert_eq!(bernoulli_fraction(4), Some((-1, 30)));
}
}