NCalc Expression.Evaluate() gives wrong output

1.4k Views Asked by At

We have code like

ncalcFormula = "[OD1000]=[OD1100]+[OD1200]+[OD1350]+[OD1450]"    
var expression = new Expression(ncalcFormula);  

foreach (FormulaParameter fp in parsedParameters)
{
    expression.Parameters[fp.QuestionKey] = fp.Value;
}    
object res = expression.Evaluate();

Original expression :- [OD1000]=[OD1100]+[OD1200]+[OD1350]+[OD1450]

After Evaluate called Parsed expression :- {([OD1000])= (((([OD1100])+ ([OD1200])+ ([OD1350])+ ([OD1450])}

Tested with adding parameter values as follows

1) 9.33 = 2.25 + 3.25 + 1.5 + 2.33

2) 15617031.48 = 15226149.36 + 166208.00 + 0.00 + 224674.12

After evaluate 1) will return true and 2) will return false though both expression are correct.

Please suggest.

2

There are 2 best solutions below

0
On BEST ANSWER

Using 'equlas' operator to compare float values is a bad idea since result of calculations has to be fitted into float representation. IN order to perform comparison correctly you need to specify tolerance, i.e. how much the result can diverge from the intended value. I rewrote your formula a bit to add some 'tolerance'.

        var ncalcFormula = "Abs([OD1000]-([OD1100]+[OD1200]+[OD1350]+[OD1450])) < 0.00001";    
        var expression = new Expression(ncalcFormula);  
        expression.Parameters["OD1000"] = 15617031.48;
        expression.Parameters["OD1100"] = 15226149.36;
        expression.Parameters["OD1200"] = 166208.00;
        expression.Parameters["OD1350"] =  0.00;
        expression.Parameters["OD1450"] = 224674.12;
0
On

I got the exact answer from other forum :- This is a limitation of how floating-point numbers are stored.

When you use float (System.Single) or double (System.Double), the numbers are stored using a binary format, which cannot precisely represent every decimal value. You will often find that numbers which appear identical are not considered equal due to differences in their least significant digits. This is documented on MSDN[^].

If you take expression #2 and evaluate it in regular C# code, you'll see that it still returns false. If you print the result using the R format specified, you'll see why:

Console.WriteLine(15617031.48 == 15226149.36 + 166208.00 + 0.00 + 224674.12); // false

Console.WriteLine("{0:R}", 15617031.48); // 15617031.48

Console.WriteLine("{0:R}", 15226149.36 + 166208.00 + 0.00 + 224674.12); // 15617031.479999999

If you need exact decimal calculations, you should probably use the decimal type[^] instead.