From 34b9519e034aceafb7ea7d7e9f6cba2f0367cc07 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 1 Feb 2024 10:46:10 -0700 Subject: [PATCH] rpn(1): code cleanup --- src/rpn.rs | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/rpn.rs b/src/rpn.rs index 893266f..0a0dd40 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -69,9 +69,7 @@ enum CalcType { } #[derive(Debug, Clone)] -struct EvaluationError { - pub message: String, -} +struct EvaluationError { pub message: String } impl fmt::Display for EvaluationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -91,9 +89,7 @@ fn str_to_calc_type(string: &str) -> Option { Err(_) => None, }; - if result.is_some() { - return result; - } + if result.is_some() { return result; } match string { "+" => Some(Add), @@ -132,22 +128,26 @@ fn eval( }; match x { - Add | Divide | Multiply | Power | Subtract | Modulo => { - ops.push_back(x) - }, Val(x_) => stack.push_back(x_), + _ => ops.push_back(x), } } for op in &ops { match op { - Add | Subtract | Multiply | Divide | Power | Modulo => { + Val(_) => { + return Err(EvaluationError { + message: "Unexpected value in the operator stack." + .to_string() + }) + }, + _ => { let x = &stack.pop_back().ok_or(EvaluationError { message: "Stack is empty.".to_string(), })?; let y = &stack.pop_back().ok_or(EvaluationError { - message: "Stack is empty.".to_string(), + message: "Stack is empty.".to_string(), })?; match op { @@ -160,20 +160,13 @@ fn eval( _ => &{}, }; }, - Val(_) => { - return Err( - EvaluationError { - message: "Unexpected value in the operator stack." - .to_string() - } - ) - }, }; } Ok(stack) } +// Round a float to the given precision level fn round_precise(value: &f64, precision: usize) -> f64 { let multiplier = 10_f64.powi(precision as i32); (value * multiplier).round() / multiplier @@ -183,6 +176,8 @@ fn main() -> ExitCode { let argv = args().collect::>(); let mut stack = VecDeque::new(); let mut buf = String::new(); + // Set floating-point precision for correcting rounding errors based on + // machine epsilon let precision = (-f64::EPSILON.log10() * PRECISION_MOD).ceil() as usize; if argv.get(1).is_none() { @@ -196,8 +191,7 @@ fn main() -> ExitCode { None => break, }; - let precise = round_precise(val, precision); - println!("{}", precise.to_string()); + println!("{}", round_precise(val, precision).to_string()); buf.clear(); }, Err(err) => { @@ -215,7 +209,16 @@ fn main() -> ExitCode { .join(" "); match eval(&input, stack) { - Ok(val) => println!("{}", val.iter().last().unwrap().to_string()), + Ok(s) => { + stack = s.clone(); + + let val = match stack.iter().last() { + Some(v) => v, + None => return ExitCode::from(0), + }; + + println!("{}", round_precise(val, precision).to_string()) + }, Err(err) => { eprintln!("{}: {}", argv[0], err.message); return ExitCode::from(EX_DATAERR as u8);