Improve rounding imprecision

This commit is contained in:
Kasper 2025-05-30 01:16:16 +02:00
parent 8cfac98bc7
commit a95fc61874
No known key found for this signature in database
GPG Key ID: 3E47D7CD99820B85

View File

@ -47,10 +47,10 @@ pub fn cbrt(input: d128) -> d128 {
}
fn pi() -> d128 {
d128!(3.141592653589793238462643383279503)
d128!(3.14159265358979323846264338327950288)
}
fn pi2() -> d128 {
d128!(6.283185307179586476925286766559006)
d128!(6.283185307179586476925286766559005768)
}
fn pi_half() -> d128 {
d128!(1.570796326794896619231321691639751)
@ -59,8 +59,8 @@ fn eulers_number() -> d128 {
d128!(2.718281828459045235360287471352662)
}
fn rounding_base() -> d128 {
// DO NOT add a trailing zero here, it must be one less than the others
d128!(0.00000000000000000000000000000001)
// DO NOT add trailing zeroes
d128!(0.0000000000000000000000000000001)
}
/// Returns the sine of a [`struct@d128`]
@ -88,7 +88,7 @@ pub fn sin(mut input: d128) -> d128 {
let unrounded_result = negative_correction * result;
// This uses bankers rounding, but I *think* it's fine
// This uses bankers rounding
unrounded_result.quantize(rounding_base())
}
@ -148,7 +148,8 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
}
Ln => {
if child_answer.unit.category() == UnitType::NoType {
let result = child_answer.value.ln();
let unrounded_result = child_answer.value.ln();
let result = unrounded_result.quantize(unrounded_result * d128!(10));
Ok(Number::new(result, child_answer.unit))
} else {
Err("ln() only accepts UnitType::NoType".to_string())
@ -311,3 +312,62 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
_ => Err(format!("Unexpected token {:?}", token)),
}
}
#[cfg(test)]
mod tests {
use crate::eval;
use super::*;
fn eval_default<'a>(input: &'a str) -> Number {
let result = eval(input, true, false).unwrap();
result
}
fn eval_num<'a>(input: &'a str) -> String {
let result = eval(input, true, false).unwrap();
assert_eq!(result.unit, Unit::NoUnit);
result.get_simplified_value().to_string()
}
#[test]
fn test_evaluations() {
assert_eq!(eval_num("-2(-3)"), "6");
assert_eq!(eval_num("-2(3)"), "-6");
assert_eq!(eval_num("(3)-2"), "1");
assert_eq!(eval_default("-1km to m"), Number::new(d128!(-1000), Unit::Meter));
assert_eq!(eval_num("2*-3*0.5"), "-3");
assert_eq!(eval_num("-3^2"), "-9");
assert_eq!(eval_num("-1+2"), "1");
}
#[test]
fn test_functions() {
assert_eq!(eval_num("cbrt(125)"), "5");
assert_eq!(eval_num("sqrt(25)"), "5");
assert_eq!(eval_num("log(100)"), "2");
assert_eq!(eval_num("log(2)"), "0.301029995663981195213738894724493");
assert_eq!(eval_num("ln(1)"), "0");
assert_eq!(eval_num("ln(2)"), "0.693147180559945309417232121458177");
assert_eq!(eval_num("ln(e)"), "1");
assert_eq!(eval_num("ln(e^2)"), "2");
assert_eq!(eval_num("round(1.4)"), "1");
assert_eq!(eval_num("round(1.6)"), "2");
assert_eq!(eval_num("round(1.5)"), "2");
assert_eq!(eval_num("round(2.5)"), "3");
assert_eq!(eval_num("ceil(1.5)"), "2");
assert_eq!(eval_num("ceil(-1.5)"), "-1");
assert_eq!(eval_num("floor(1.5)"), "1");
assert_eq!(eval_num("floor(-1.5)"), "-2");
assert_eq!(eval_num("abs(-3)"), "3");
assert_eq!(eval_num("sin(2)"), "0.9092974268256816953960198659117");
assert_eq!(eval_num("sin(-2)"), "-0.9092974268256816953960198659117");
}
}