ISibboI/evalexpr

Evaluation result of redundant expression

Closed this issue · 2 comments

Hi there,

I tried evalexpr and found an un-expected result for the expression

"x*0.2*5/4+x*2*4*1*1*1*1*1*1*1+7*math::sin(y)-z/math::sin(3/2/(1-x*4*1*1*1*1))"

I used evalexpr = "6.4.0" as dependency in my Cargo.toml. Running

use evalexpr::{build_operator_tree, ContextWithMutableVariables, HashMapContext, Value};

fn main() {
    let expr_str = "x*0.2*5/4+x*2*4*1*1*1*1*1*1*1+7*math::sin(y)-z/math::sin(3/2/(1-x*4*1*1*1*1))";
    let parsed_exprs = build_operator_tree(expr_str).unwrap();

    let compute_result = |x: f64, y: f64, z: f64| {
        let mut context = HashMapContext::new();

        context.set_value("x".into(), x.into()).unwrap();
        context.set_value("y".into(), y.into()).unwrap();
        context.set_value("z".into(), z.into()).unwrap();

        match parsed_exprs.eval_with_context(&context).unwrap() {
            Value::Float(val) => val,
            _ => panic!("What?"),
        }
    };

    let compute_reference = |x: f64, y: f64, z: f64| {
        x * 0.2 * 5.0 / 4.0 + x * 2.0 * 4.0 + 7.0 * y.sin()
            - z / (3.0 / 2.0 / (1.0 - x * 4.0f64)).sin()
    };

    let res = compute_result(0.0, 3.0, 4.0);
    let reference = compute_reference(0.0, 3.0, 4.0);
    println!("res {}, ref {}", res, reference);
    assert!((res - reference).abs() < 1e-12);
}

resulted in the output

res -3.7657403666934144, ref -3.022205160567829
thread 'main' panicked at 'assertion failed: (res - reference).abs() < 1e-12', src\main.rs:28:5
stack backtrace:
...

I double checked the expression in a Python repl

In [1]: from math import sin

In [2]: x=0

In [3]: y=3

In [4]: z=4

In [5]: x*0.2*5/4+x*2*4*1*1*1*1*1*1*1+7*sin(y)-z/sin(3/2/(1-x*4*1*1*1*1))
Out[5]: -3.022205160567829

Hi, thank you for the report.

I checked your expression, and the issue seems to be caused by a different handling of integer divisions between python and evalexpr. The expression 3 / 2 is evaluated as integer division by evalexpr, while python divides using floats. In the corresponding rust code, you have manually converted the integers to floats, resulting in a floating point division as well.

I added a test for this expression anyways, since I think it is a nice test case. And I also added some examples to the documentation.

Ah. Interesting. Thanks.