JDK-8059861 : Modifications to NumberFormat format() caused new rounding errors
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 8u20
  • Priority: P4
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: os_x
  • CPU: x86
  • Submitted: 2014-10-02
  • Updated: 2014-10-08
  • Resolved: 2014-10-08
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Darwin opf.local 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
Changes to the fix the rounding behaviour of NumberFormat format() (see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7131459) appear to have cause new failures in other edge cases.

ADDITIONAL REGRESSION INFORMATION: 
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Attempt to use HALF_EVEN rounding when printing 12.345 with two decimal places of accuracy. It will give 12.35 instead of 12.34.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
JVM Version: 1.8.0-ea
Should print (3 sig.fig.) 0.805 got 0.805 - correct? = true
Should print (2 sig.fig.) 12.34 got 12.35 - correct? = true

ACTUAL -
Under Java 7, I get this:

JVM Version: 1.7.0_51
Should print (3 sig.fig.) 0.805 got 0.806 - correct? = false
Should print (2 sig.fig.) 12.34 got 12.34 - correct? = true

But under Java 8:

JVM Version: 1.8.0-ea
Should print (3 sig.fig.) 0.805 got 0.805 - correct? = true
Should print (2 sig.fig.) 12.34 got 12.35 - correct? = false


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.text.NumberFormat;

public class TestNumberFormatRounding {

    public static void main(String[] args) {
        System.out
                .println("JVM Version: " + System.getProperty("java.version"));

        NumberFormat nf = java.text.NumberFormat.getInstance();
        nf.setMaximumFractionDigits(3);
        nf.setMinimumFractionDigits(0);
        String expected = "0.805";
        String result = nf.format(0.8055d);
        System.out.println("Should print (3 sig.fig.) " + expected + " got "
                + result
                + " - correct? = " + (expected.equals(result)));

        nf.setMaximumFractionDigits(2);
        double test = 12.345;
        expected = "12.34";
        result = nf.format(test);
        System.out.println("Should print (2 sig.fig.) " + expected + " got "
                + result
                + " - correct? = " + (expected.equals(result)));
    }

}
---------- END SOURCE ----------


Comments
Hi Naoto, You are right this "yet again" a false positive ! And in addition this test is wrong: EXPECTED RESULT of "0.805" for value 0.8055 is wrong. Below is a detailed explanation. Under HALF_EVEN rounding mode (which is what you get using NumberFormat.getInstance()), if 0.8055 was represented exactly in the machine, rounding 0.8055 at the 3rd fractional digit would gives "0.806", not "0.805". Thus the String "expected" ("0.805") in the first part of the test is wrong. The HALF_EVEN rounding rule is misunderstood here. Now both 0.8055 and 12.345 cannot be represented exactly in any binary format: - closest binary approximation to 0.8055 is 0.80549999999999999378275106209912337362766265869140625 - closest binary approximation to 12.345 is 12.3450000000000006394884621840901672840118408203125 So the binary representation of 0.8055 in the machine is just below the tie regarding the targeted rounding (49999.................40625). Since below the tie, the rounding result at 3rd fractional digit must be "0.805", not "0.806". However since test is wrong regarding the expected value, the test finds that JDK8 rounds correctly to 0.805 because it equals the wrong "0.805" expected string. JDK_1.7.0_51 is wrong and does not take into account the binary representation in the machine (this is exactly what 7131459 fixes). Thus it returns "0.806" (HALF_EVEN rounding with odd 3rd digit as 5), which is considered as failing since "expected" string is not the same. Now for 12.345, when rounding at 2nd digit, the test "expected" string of "12.34", if 12.345 could be represented exactly in the machine, is correct. However binary representation of 12.345 is just above the tie (5000..........203125), and thus the returned result must be "12.35" under HALF_EVEN rounding, which is returned correctly by JDK8, while JDK_1.7.0_51 returns a wrong "12.34" string because it does not take into account the binary representation in the machine (again this is what 7131459 fixes). To summarize: 1- test is wrong, 2- JDK8 provides correct results (due to 7131459 fix) and JDK7 provides wrong results. The correct results for this test are: - 0.8055, rounding half_even at 3rd frac digit --> "0.805" - 12.345, rounding half_even at 2nd frac digit --> "12.35" Closing it as "not-a-bug"
08-10-2014