I have an application that receives a list of JEXL expressions and evaluates them in the loop with data retrieved from the database. It does work, but calculations are not accurate. For example, this simple formula:
a*b+c
where a is integer, b - float and c - double. with values a = 600, b = 6.287 and c = 102.245 result is suppose to be 3874.445 but JEXL gives me 3874.223. I checked it on couple hundreds of samples and error varies from 0.001% to 0.3% but I never got exact answer. My JEXL engine looks like this:
JexlEngine jexl = new JexlBuilder().cache(2048).silent(false).strict(false).create();
I did put strict to false, because some data might be null and I don't want JEXL to barf on such data. Any ideas why it is happening?
The short answer is look at IEEE 754 double-precision binary floating-point format. This implies that, even in pure Java code, you get a result like:
double r = 600 * 6.287f + 102.245d; // r == 3874.4451953125
A longer answer is that you can derive JexlArithmetic so that every operator converts its arguments to BigDecimal to obtain a precise answer. As an example, the following evaluates 'correctly' (note the 600b which makes the first number a 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);
}