JDK-8062756 : Rounding HALF_UP produce wrong text representations
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 8u25
  • Priority: P3
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2014-10-28
  • Updated: 2014-11-07
  • Resolved: 2014-11-07
Related Reports
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
windows:
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

linux:
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 :
Windows 7 64bit, Java8u25
Xubuntu 64bit, Kernel 3.13.0-37-generic, Java8u20

A DESCRIPTION OF THE PROBLEM :
Using DecimalFormat with RoundingMode.HALF_UP doesn't round correct. On tie-breaking or above the digit isn't rounded up.

For example: When one digit in the fraction is needed I assume following values:
1.17 ~~ 1.2
1.19 ~~ 1.2
1.49 ~~ 1.5

These values could be produced by Java7 but not in Java8. This is really bad because RoundingMode HALF_UP is used for commercial rounding of almost all.

REGRESSION.  Last worked in version 7u71

ADDITIONAL REGRESSION INFORMATION: 
not ready to hand for windows

linux:
java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Instantiate NumberFormatter
2. Set the rounding mode to HALF-UP
3. add fraction digits to round - don't round to whole digits
3. try to format values without zero as integer and without zero left of the rounding position

fe: 
0.55 ~~ 0.6 << this works
1.55 ~~ 1.6 << this doesn't work, Java8 calculates 1.5


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1.17d should be rounded to 1.2
1.55d should be rounded to 1.6
ACTUAL -
1.17 have been rounded to 1.1
1.55 have been rounded to 1.5

ERROR MESSAGES/STACK TRACES THAT OCCUR :
no error

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import org.junit.Test;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

import static org.junit.Assert.assertEquals;

public class Java8roundings {
    
    private final DecimalFormat OUT = buildFormatter();

    @Test
    public void testSpecificValue() {
        assertEquals("1,2", OUT.format(1.17d));
    }

    @Test
    public void shouldRoundGivenValuesFromJavadocDividedByTen() {
        assertEquals("0,6", OUT.format(0.55d));
        assertEquals("0,3", OUT.format(0.25d));
        assertEquals("0,2", OUT.format(0.16d));
        assertEquals("0,1", OUT.format(0.11d));
        assertEquals("-0,1", OUT.format(-0.11d));
        assertEquals("-0,3", OUT.format(-0.25d));
        assertEquals("-0,6", OUT.format(-0.55d));
    }

    @Test
    public void shouldRoundGivenValuesFromJavadocDividedByTenAddOne() {
        assertEquals("1,6", OUT.format(1.55d));
        assertEquals("1,3", OUT.format(1.25d));
        assertEquals("1,2", OUT.format(1.16d));
        assertEquals("1,1", OUT.format(1.11d));
        assertEquals("-1,1", OUT.format(-1.11d));
        assertEquals("-1,3", OUT.format(-1.25d));
        assertEquals("-1,6", OUT.format(-1.55d));
    }

    @Test
    public void checkValuesAroundTheSpecificValue() {
        assertEquals("1,1", OUT.format(1.14d));
        assertEquals("1,2", OUT.format(1.15d));
        assertEquals("1,2", OUT.format(1.16d));
        assertEquals("1,2", OUT.format(1.18d));
        assertEquals("1,2", OUT.format(1.19d));
        assertEquals("1,2", OUT.format(1.20d));
    }

    @Test
    public void useHigherValues() {
        assertEquals("1,5", OUT.format(1.49d));
        assertEquals("1,6", OUT.format(1.55d));
    }
    
    private DecimalFormat buildFormatter() {
        final DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.GERMANY);
        formatter.setRoundingMode(RoundingMode.HALF_UP); // that's what we want to test
        formatter.applyPattern("0.0");
        return formatter;
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Downgrade to Java7u71


Comments
This is yet another false alarm. JDK-7131459 fixes a long-standing bug that was fixed in 8, which JDK7 does not provide. For example the assertEquals("1,2", OUT.format(1.15d)) is wrong, because 1.15d is recorded in the machine as 1.149999999999999911182158029987476766109466552734375. Thus result must be 1.1, not 1.2, which JDK8 provides correctly ! However a few of the values in the test are falling in the case of JDK-8039915. These are : 1.16, 1.17, 1.18. All of these 8039915 cases are now fixed since 8u40-b12. Please refer to 8u backport of 8039915 (JDK-8061380). So apart from these 3 above cases all JDK8 results are correct, but some results provided by JDK7 are wrong I am attaching a java test program showing correctness of values, and results for this test: - one commented running JDK8 without 8039915 fix, - a second JDK8 run with 8039915 fix showing most recent result, all fully correct. Going to close it as "Not an Issue" since 8039915 is already fixed in both JDK8 and 9
07-11-2014

test partly falls in JDK-7131459, unavailable in JDK7, which thus provides wrong results, and in JDK-8039915 case which is now fixed in JDK8.
07-11-2014