Bug 50500 - EL evaluation of floating-point String value vs BigInteger loses precision
EL evaluation of floating-point String value vs BigInteger loses precision
Status: RESOLVED FIXED
Product: Tomcat 6
Classification: Unclassified
Component: Jasper
6.0.29
All All
: P2 minor (vote)
: default
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2010-12-19 19:00 UTC by Konstantin Kolinko
Modified: 2011-01-07 13:43 UTC (History)
0 users



Attachments
Patch to check for a BigInteger parameter before coercing to a double (2.35 KB, patch)
2010-12-20 21:12 UTC, brian.weisleder
Details | Diff
ELArithmetic test case (1.31 KB, patch)
2010-12-20 21:13 UTC, brian.weisleder
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Konstantin Kolinko 2010-12-19 19:00:53 UTC
According to the EL spec ch.1.7.1,
the A+B,A-B,A*B expressions when A is a "String containing ., e, or E" and B is a BigInteger have to be evaluated as follows:

"coerce both A and B to BigDecimal and apply operator"

The actual implementation though, instead of coercing A as String -> BigDecimal, does two coercions:  String -> Double -> BigDecimal, which produces a different result.

To reproduce, run the following JSP page:
<%
  pageContext.setAttribute("a", "1.1");
  pageContext.setAttribute("b", new java.math.BigInteger("1000000000000000000000"));
  // "c" is used to explicitly coerce arguments to BigDecimal
  pageContext.setAttribute("c", new java.math.BigDecimal("0"));
%>${a + b}<br>
${(a+c) + (b+c)}<br>
${a - b}<br>
${(a+c) - (b+c)}<br>
${a * b}<br>
${(a+c) * (b+c)}

Actual result:
1000000000000000000001.100000000000000088817841970012523233890533447265625
1000000000000000000001.1
-999999999999999999998.899999999999999911182158029987476766109466552734375
-999999999999999999998.9
1100000000000000088817.841970012523233890533447265625000000000000000000000
1100000000000000000000.0 

Expected result:
1000000000000000000001.1
1000000000000000000001.1
-999999999999999999998.9
-999999999999999999998.9
1100000000000000000000.0 
1100000000000000000000.0 

I think it is a minor issue, though.
This is reproducible in the current tc6.0.x as well.

Maybe o.a.el.lang.ELArithmetic#add(Object, Object) should delegate to BIGDECIMAL instead of DOUBLE with these types of arguments.
Comment 1 brian.weisleder 2010-12-20 21:12:37 UTC
Created attachment 26429 [details]
Patch to check for a BigInteger parameter before coercing to a double

This patch will correctly handle cases where a string, double, or float is added, subtracted, or multiplied by a BigInteger. It does this by checking to see if one of the parameters of a method call is a BigInteger if it knows the other is a float, double, or string containing '.', 'e' or 'E'
Comment 2 brian.weisleder 2010-12-20 21:13:55 UTC
Created attachment 26430 [details]
ELArithmetic test case
Comment 3 Mark Thomas 2011-01-04 09:25:23 UTC
Thanks for the patches. I applied them (with some minor alterations after reviewing the spec) to 7.0.x and they will be included in 7.0.6 onwards. I also proposed back-porting the changes to 6.0.x.

Since this is now fixed in 7.0.x, I'm moving this issue to 6.0.x
Comment 4 Mark Thomas 2011-01-07 13:43:55 UTC
Fixed in 6.0.x and will be included in 6.0.30 onwards.