use std::time::Instant; use rand::prelude::*; use std::f64::consts; use console::Term; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; fn main() { //Handler to terminate on CTRL+C let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); ctrlc::set_handler(move || { r.store(false, Ordering::SeqCst); println!(); }).expect("Error setting Ctrl-C handler"); let term = Term::stdout(); //Parses env 'SHOW_PROGRESS', value must be an int and sets how frequent to log progress //If has a value, should log progress. let log_interval: Option = match std::env::var("SHOW_PROGRESS").ok() { Some(value) => Some(value.parse::().expect("not a valid integer")), None => None }; //Gets the maximum loops to run or none for infinity let max_loops: Option = match std::env::var("LOOPS") { Ok(val) => Some(val.parse::().expect("not a valid integer")), _ => None }; match max_loops { Some(max_loops) => { println!("Running {} iterations. Press CTRL+C to exit at any time.", max_loops); run_limited(term, running, log_interval, max_loops); }, None => { println!("No maximum loops specified, running forever. Press CTRL+C to exit at any time."); run_unlimited(term, running, log_interval); } } } //Runs upto X times fn run_limited(term: Term, running: Arc, log_interval: Option, max_loops: u64) { let now = Instant::now(); let mut total_count: u64 = 0; let mut count: u64; let mut sum: f64; //Print header only if showing progress if log_interval.is_some() { println!("Iteration\tValue \t% Err\tCurrent %\tTime Elapsed"); } for i in 0..max_loops { count = 0; sum = 0.0; //Run until sum hits 1.0 while sum <= 1.0 { count += 1; sum += rand::thread_rng().gen::(); } total_count += count; //Prints progress: if log_interval.is_some() && i % log_interval.unwrap() == 0 { let average = total_count as f64 / i as f64; let pererror = (average - consts::E).abs() / consts::E * 100.0; let cur_percent = i as f64 / max_loops as f64 * 100.0; term.write_line(&format!(" {:9.10}\t{:.10}\t{:5.2}%\t{:9.2}%\t{:?}", i, average, pererror, cur_percent, now.elapsed())).ok(); term.move_cursor_up(1).ok(); } //Checks if CTRL+C was called, end loop here if !running.load(Ordering::SeqCst) { break; } } let average = total_count as f64 / max_loops as f64; let pererror = (average - consts::E).abs() / consts::E * 100.0; println!("---------------------------"); println!("Iterations: {}", max_loops); println!("Final Average: {}", average); println!("Final % Error: {:.4}%", pererror); println!("Took: {:?}", now.elapsed()); } fn run_unlimited(term: Term, running: Arc, log_interval: Option) { let now = Instant::now(); let mut total_count: u64 = 0; let mut count: u64; let mut sum: f64; let mut i: u64 = 0; if log_interval.is_some() { println!("Iteration\tValue \t% Err\tTime Elapsed"); } loop { count = 0; sum = 0.0; //Run until sum hits 1.0 while sum <= 1.0 { count += 1; sum += rand::thread_rng().gen::(); } total_count += count; //Prints progress: if log_interval.is_some() && i % log_interval.unwrap() == 0 { let average = total_count as f64 / i as f64; let pererror = (average - consts::E).abs() / consts::E * 100.0; term.write_line(&format!(" {:9.10}\t{:.10}\t{:5.2}%\t{:?}", i, average, pererror, now.elapsed())).ok(); term.move_cursor_up(1).ok(); } //Checks if CTRL+C was called, end loop here if !running.load(Ordering::SeqCst) { break; } i += 1; } let average = total_count as f64 / i as f64; let pererror = (average - consts::E).abs() / consts::E * 100.0; println!("---------------------------"); println!("Iterations: {}", i); println!("Final Average: {}", average); println!("Final % Error: {:.4}%", pererror); println!("Took: {:?}", now.elapsed()); }