//! # Rusty Numbers //! //! Playin' with Numerics in Rust #![forbid(unsafe_code)] #[cfg_attr(tarpaulin, skip)] pub mod bigint; pub mod num; pub mod rational; /// 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. /// /// Example: /// ```rust /// use rusty_numbers::fibonacci; /// /// let valid = fibonacci(45); // Some(1134903170) /// # assert_eq!(1134903170, fibonacci(45).unwrap()); /// # assert!(valid.is_some()); /// /// let invalid = fibonacci(187); // None /// # assert!(invalid.is_none()); /// ``` #[inline] pub fn mem_fibonacci(n: usize) -> Option { let mut table = [0u128; 187]; table[0] = 0; table[1] = 1; table[2] = 1; _mem_fibonacci(n, &mut table) } /// Actual calculating function for `fibonacci` #[inline] fn _mem_fibonacci(n: usize, table: &mut [u128]) -> Option { if n > 186 { return None; } match table[n] { // The lookup array starts out zeroed, so a zero // is a not yet calculated value 0 => { let a = _mem_fibonacci(n - 1, table)?; let b = _mem_fibonacci(n - 2, table)?; table[n] = a + b; Some(table[n]) }, x => Some(x) } } /// Calculate a number in the fibonacci sequence, /// using naive recursion /// /// REALLY SLOW /// /// Can calculate up to 186 using native unsigned 128 bit integers. #[inline] pub fn rec_fibonacci(n: usize) -> Option { match n { 0 => Some(0), 1 => Some(1), n => { let a = rec_fibonacci(n - 1)?; let b = rec_fibonacci(n - 2)?; a.checked_add(b) } } } /// Calculate a number in the fibonacci sequence, /// using iteration /// /// Can calculate up to 186 #[inline] pub fn fibonacci(n: usize) -> Option { let mut a: u128 = 0; let mut b: u128 = 1; match n { 0 => Some(a), 1 => Some(b), _ => { for _ in 0..n - 1 { let c: u128 = a.checked_add(b)?; a = b; b = c; } Some(b) } } } /// 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. /// /// Example: /// ```rust /// use rusty_numbers::factorial; /// /// let valid = factorial(3); // Some(6) /// # assert_eq!(6, valid.unwrap()); /// /// let invalid = factorial(35); // None /// # assert!(invalid.is_none()); /// ``` #[inline] pub fn mem_factorial(n: usize) -> Option { let mut table = [0u128; 35]; table[0] = 1; table[1] = 1; table[2] = 2; _mem_factorial(n, &mut table) } /// Actual Calculation function for factoral #[inline] fn _mem_factorial(n: usize, table: &mut [u128]) -> Option { 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, /// /// Can calculate up to 34! using native unsigned 128 bit integers. /// /// Example: /// ```rust /// use rusty_numbers::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 { match n { 0 => Some(1u128), 1 => Some(1u128), _ => { let prev = factorial(n - 1)?; (n as u128).checked_mul(prev) } } } #[cfg(test)] #[cfg_attr(tarpaulin, skip)] mod tests { use super::*; #[test] fn test_factorial() { assert_eq!(1, factorial(0).unwrap()); assert_eq!(1, factorial(1).unwrap()); assert_eq!(6, factorial(3).unwrap()); let res = factorial(34); let res2 = mem_factorial(34); assert!(res.is_some()); assert_eq!(res.unwrap(), res2.unwrap()); let res = factorial(35); assert!(res.is_none()); } #[test] fn test_fibonacci() { assert_eq!(0, fibonacci(0).unwrap()); assert_eq!(1, fibonacci(1).unwrap()); assert_eq!(1, fibonacci(2).unwrap()); let res = fibonacci(20); let res2 = rec_fibonacci(20); assert_eq!(res, res2); let res = fibonacci(186); let res2 = mem_fibonacci(186); assert!(res.is_some()); assert!(res2.is_some()); assert_eq!(res.unwrap(), res2.unwrap()); let res = fibonacci(187); assert!(res.is_none()); } }