extern crate separator; use separator::Separatable; use std::io; use std::u128; ///! 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. /// If the result overflows, an error message will be displayed. 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 } } } fn main() { // The lookup table for previously calculated values let mut table: Vec = vec![1, 1, 2]; println!("Factorial calculator."); println!("Any non-number will exit."); loop { println!("\nWhich factorial to calculate?"); let mut index = String::new(); io::stdin().read_line(&mut index) .expect("Failed to read line"); let index = match index.trim().parse() { Ok(num) => num, Err(_) => break, // Exit on non-number }; println!("Calculating factorial of: {}", index); match factorial(index, &mut table) { Some(calculated) => { println!("{}! is {}", index, calculated.separated_string()) }, None => { println!("Calculation overflow. The factorial base was too large."); } } } }