As mentioned in other answers to this question, JDK 8 made intentional changes to DecimalFormat
rounding in issue JDK-7131459: DecimalFormat produces wrong format() results when close to a tie.
However, those changes introduced a real bug filed as JDK-8039915: Wrong NumberFormat.format() HALF_UP rounding when last digit exactly at rounding position greater than 5. For example:
99.9989 -> 100.00
99.9990 -> 99.99
To put it simply, this demonstrates a case where a higher number rounds down, and a lower number rounds up: (x <= y) != (round(x) <= round(y))
. It appears to only affect the HALF_UP
rounding mode, which is the kind of rounding taught in grade school arithmetic classes: 0.5 rounds away from zero, always.
This issue exists in both Oracle and OpenJDK releases of Java 8 and updates 8u5, 8u11, 8u20, 8u25, and 8u31.
Oracle fixed this bug in Java 8 update 40
An unofficial runtime patch is available for earlier versions
Thanks to research by Holger in this answer to a related question, I was able to develop a runtime patch and my employer has released it free under the terms of the GPLv2 license with Classpath Exception1 (the same as the OpenJDK source code).
The patch project and source code is hosted on GitHub with more details about this bug as well as links to downloadable binaries. The patch works at runtime so no modifications are made to the Java files on disk, and it should be safe for use on all versions of Oracle Java >= 6 and at least through version 8 (including u40 and later).
1 I am not a lawyer, but my understanding is that GPLv2 w/ CPE allows commercial use in binary form without GPL applying to the combined work.