我有一个应用程序,它接收 JEXL 表达式列表,并使用从数据库检索的数据在循环中对它们进行计算。它确实有效,但计算不准确。例如,这个简单的公式:
a*b+c
其中 a 是整数,b - 浮点数,c - 双精度数。 值a = 600,b = 6.287和c = 102.245结果应该是3874.445,但JEXL给我3874.223。我检查了数百个样本,误差从 0.001% 到 0.3% 不等,但我从未得到确切的答案。 我的 JEXL 引擎看起来像这样:
JexlEngine jexl = new JexlBuilder().cache(2048).silent(false).strict(false).create();
我确实将 strict 设置为 false,因为某些数据可能为空,并且我不希望 JEXL 对此类数据感到厌烦。 有什么想法为什么会发生吗?
简短的答案是查看 IEEE 754 双精度二进制浮点格式。这意味着,即使在纯 Java 代码中,您也会得到如下结果:
double r = 600 * 6.287f + 102.245d; // r == 3874.4451953125
更长的答案是,您可以派生 JexlArithmetic,以便每个运算符将其参数转换为 BigDecimal 以获得精确的答案。作为示例,以下计算“正确”(注意 600b 使第一个数字成为 BigDecimal)。
@Test
public void testSO20230225() throws Exception {
String src = "let a = 600b; let b = 6.287f; let c = 102.245d; a * b + c";
final JexlBuilder builder = new JexlBuilder();
final JexlEngine jexl = builder.create();
JexlScript script = jexl.createScript(src);
Object result = script.execute(null);
double r = 3874.445d;
Assert.assertEquals(r, ((Number) result).doubleValue(), 0.0000001d);
}