NCalc Expression.Evaluate() 给出错误的输出
NCalc Expression.Evaluate() gives wrong output
我们有类似
的代码
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();
原表达式:- [OD1000]=[OD1100]+[OD1200]+[OD1350]+[OD1450]
评估后调用解析表达式:- {([OD1000])= (((([OD1100])+ ([OD1200])+ ([OD1350])+ ([OD1450])}
添加参数值测试如下
1) 9.33 = 2.25 + 3.25 + 1.5 + 2.33
2) 15617031.48 = 15226149.36 + 166208.00 + 0.00 + 224674.12
评估后 1) return 为真,2) return 为假,尽管两个表达式都是正确的。
求推荐。
使用 'equlas' 运算符比较浮点值是个坏主意,因为计算结果必须适合浮点表示。为了正确执行比较,您需要指定公差,即结果与预期值的偏差有多大。我稍微重写了您的公式以添加一些 '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;
我从其他论坛得到了确切的答案:- 这是浮点数存储方式的限制。
当您使用 float (System.Single) 或 double (System.Double) 时,数字使用二进制格式存储,无法精确表示每个十进制值。您经常会发现,看起来相同的数字由于其最低有效数字的不同而被视为不相等。这记录在 MSDN[^].
如果您采用表达式 #2 并在常规 C# 代码中对其求值,您会发现它仍然 returns 为假。如果您使用指定的 R 格式打印结果,您会明白为什么:
Console.WriteLine(15617031.48 == 15226149.36 + 166208.00 + 0.00 + 224674.12); // 假
Console.WriteLine("{0:R}", 15617031.48); // 15617031.48
Console.WriteLine("{0:R}", 15226149.36 + 166208.00 + 0.00 + 224674.12); // 15617031.479999999
如果您需要精确的小数计算,您可能应该改用小数类型[^]。
我们有类似
的代码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();
原表达式:- [OD1000]=[OD1100]+[OD1200]+[OD1350]+[OD1450]
评估后调用解析表达式:- {([OD1000])= (((([OD1100])+ ([OD1200])+ ([OD1350])+ ([OD1450])}
添加参数值测试如下
1) 9.33 = 2.25 + 3.25 + 1.5 + 2.33
2) 15617031.48 = 15226149.36 + 166208.00 + 0.00 + 224674.12
评估后 1) return 为真,2) return 为假,尽管两个表达式都是正确的。
求推荐。
使用 'equlas' 运算符比较浮点值是个坏主意,因为计算结果必须适合浮点表示。为了正确执行比较,您需要指定公差,即结果与预期值的偏差有多大。我稍微重写了您的公式以添加一些 '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;
我从其他论坛得到了确切的答案:- 这是浮点数存储方式的限制。
当您使用 float (System.Single) 或 double (System.Double) 时,数字使用二进制格式存储,无法精确表示每个十进制值。您经常会发现,看起来相同的数字由于其最低有效数字的不同而被视为不相等。这记录在 MSDN[^].
如果您采用表达式 #2 并在常规 C# 代码中对其求值,您会发现它仍然 returns 为假。如果您使用指定的 R 格式打印结果,您会明白为什么:
Console.WriteLine(15617031.48 == 15226149.36 + 166208.00 + 0.00 + 224674.12); // 假
Console.WriteLine("{0:R}", 15617031.48); // 15617031.48
Console.WriteLine("{0:R}", 15226149.36 + 166208.00 + 0.00 + 224674.12); // 15617031.479999999
如果您需要精确的小数计算,您可能应该改用小数类型[^]。