JDK-8029896 : Regression in NumberFormat rounding from 1.7 to 1.8. Rounding no longer works.
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: linux
  • Submitted: 2013-12-09
  • Updated: 2014-10-28
  • Resolved: 2013-12-11
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b118)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b60, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux Studio-XPS-9100 3.2.0-31-generic #50-Ubuntu SMP Fri Sep 7 16:16:45 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
A NumberFormat object with the RoundingMode set to HALF_EVEN rounds correctly in jdk 1.7, but no longer rounds in jdk 1.8.
Code for a test case is given in the Steps to Reproduce


REGRESSION.  Last worked in version 7u40

ADDITIONAL REGRESSION INFORMATION:
Broken version:
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b118)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b60, mixed mode)


Previous, working version:
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following test will print "55.6%" in jdk 1.7 (which is correct) but will print "55.5%" in jdk 1.8 (incorrect).

import java.text.NumberFormat;
import java.math.RoundingMode;
public class NumberFormatTest {
    public static void main(String[] args) {
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMinimumFractionDigits(1);
        percent.setMaximumFractionDigits(1);
        percent.setRoundingMode(RoundingMode.HALF_EVEN);
        System.out.println(0.5555);
        System.out.println(percent.format(0.5555));
    }
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
print "55.6%"
ACTUAL -
prints "55.5%"

REPRODUCIBILITY :
This bug can be reproduced always.
Comments
You are right Naoto, JDK7 is buggy behavior (please see JDK-7131459), and.JDK8 is the correct behavior. The problem is that "0.5555", which we all understand as the decimal value 0.5555 cannot be represented in any binary representation (including IEEE-754). The most precise binary representation of this number that can be obtained is 0.55549999999999999378275106209912337362766265869140625 . One can get this best possible approximation using BigDecimal which provides infinite precision: System.out.println("BigDecimal output for 0.5555: " + new BigDecimal(0.5555).toString()); The above will return: "BigDecimal output for 0.5555 : 0.55549999999999999378275106209912337362766265869140625" Thus we can see that the closest binary representation for 0.5555 is a bit less than 0.5555 (0.555499.....). So even if programmer intents to use decimal 0.5555, the computer works with the best approximation from IEEE-754, which is something like 0.5554999999999999... Again this is less than 0.5555 decimal value. Under HALF-EVEN rounding rule, when rounding at the 3rd fractional digit after decimal point, which is the case in the above program, no rounding up of this fractional digit should happen, and the correct result here is "55.5%" JDK7 is wrong here, JDK8 is correct. JDK-7131459 is long standing bug that has been discovered while working on optimization of NumberFormat/DecimalFormat stack (see JDK-7050528).
11-12-2013

I believe JDK8 result is the correct behavior, as the result of fixing JDK-7131459. Assigning this to Olivier for the confirmation.
10-12-2013

Reproduced with java8-b116
10-12-2013