//! # 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 fibonacci(n: usize) -> Option { let mut table: Vec = vec![0, 1, 1, 2, 3, 5]; _fibonacci(n, &mut table) } /// Actual calculating function for `fibonacci` #[inline] fn _fibonacci(n: usize, table: &mut Vec) -> Option { 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 a number in the fibonacci sequence, /// using naive recursion /// /// 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) }, } } #[inline] pub fn it_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 factorial(n: usize) -> Option { let mut table: Vec = vec![1, 1, 2]; _factorial(n, &mut table) } /// Actual Calculation function for factoral #[inline] fn _factorial(n: usize, table: &mut Vec) -> Option { match table.get(n) { // Vec.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 } } } /// Calculate the value of a factorial using recursion /// /// Can calculate up to 34! using native unsigned 128 bit integers. #[inline] pub fn rec_factorial(n: usize) -> Option { match n { 0 => Some(1u128), 1 => Some(1u128), _ => { let prev = rec_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 = rec_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(186); let res2 = it_fibonacci(186); assert!(res.is_some()); assert!(res2.is_some()); assert_eq!(res.unwrap(), res2.unwrap()); let res = fibonacci(187); assert!(res.is_none()); } }