rpn(1): code cleanup

This commit is contained in:
Emma Tebibyte 2024-02-01 10:46:10 -07:00
parent 90ca10990f
commit 34b9519e03
Signed by: emma
GPG Key ID: 06FA419A1698C270

View File

@ -69,9 +69,7 @@ enum CalcType {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct EvaluationError { struct EvaluationError { pub message: String }
pub message: String,
}
impl fmt::Display for EvaluationError { impl fmt::Display for EvaluationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -91,9 +89,7 @@ fn str_to_calc_type(string: &str) -> Option<CalcType> {
Err(_) => None, Err(_) => None,
}; };
if result.is_some() { if result.is_some() { return result; }
return result;
}
match string { match string {
"+" => Some(Add), "+" => Some(Add),
@ -132,22 +128,26 @@ fn eval(
}; };
match x { match x {
Add | Divide | Multiply | Power | Subtract | Modulo => {
ops.push_back(x)
},
Val(x_) => stack.push_back(x_), Val(x_) => stack.push_back(x_),
_ => ops.push_back(x),
} }
} }
for op in &ops { for op in &ops {
match op { 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 { let x = &stack.pop_back().ok_or(EvaluationError {
message: "Stack is empty.".to_string(), message: "Stack is empty.".to_string(),
})?; })?;
let y = &stack.pop_back().ok_or(EvaluationError { let y = &stack.pop_back().ok_or(EvaluationError {
message: "Stack is empty.".to_string(), message: "Stack is empty.".to_string(),
})?; })?;
match op { match op {
@ -160,20 +160,13 @@ fn eval(
_ => &{}, _ => &{},
}; };
}, },
Val(_) => {
return Err(
EvaluationError {
message: "Unexpected value in the operator stack."
.to_string()
}
)
},
}; };
} }
Ok(stack) Ok(stack)
} }
// Round a float to the given precision level
fn round_precise(value: &f64, precision: usize) -> f64 { fn round_precise(value: &f64, precision: usize) -> f64 {
let multiplier = 10_f64.powi(precision as i32); let multiplier = 10_f64.powi(precision as i32);
(value * multiplier).round() / multiplier (value * multiplier).round() / multiplier
@ -183,6 +176,8 @@ fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>(); let argv = args().collect::<Vec<String>>();
let mut stack = VecDeque::new(); let mut stack = VecDeque::new();
let mut buf = String::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; let precision = (-f64::EPSILON.log10() * PRECISION_MOD).ceil() as usize;
if argv.get(1).is_none() { if argv.get(1).is_none() {
@ -196,8 +191,7 @@ fn main() -> ExitCode {
None => break, None => break,
}; };
let precise = round_precise(val, precision); println!("{}", round_precise(val, precision).to_string());
println!("{}", precise.to_string());
buf.clear(); buf.clear();
}, },
Err(err) => { Err(err) => {
@ -215,7 +209,16 @@ fn main() -> ExitCode {
.join(" "); .join(" ");
match eval(&input, stack) { 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) => { Err(err) => {
eprintln!("{}: {}", argv[0], err.message); eprintln!("{}: {}", argv[0], err.message);
return ExitCode::from(EX_DATAERR as u8); return ExitCode::from(EX_DATAERR as u8);