JDK-8039915 : Wrong NumberFormat.format() HALF_UP rounding when last digit exactly at rounding position greater than 5
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-04-09
  • Updated: 2019-05-15
  • Resolved: 2014-10-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
8u40Fixed 9 b36Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) Server VM (build 25.0-b70, mixed mode)

Linux paris 2.6.32-220.4.1.el6.i686 #1 SMP Mon Feb 6 16:10:45 CET 2012 i686 i686 i386 GNU/Linux

Formating 0.950000550000 to a six fraction digits works properly, I get "0.950001".
Formating 0.950000600000 to a six fraction digits works wrong, I get "0.95" instead of "0.950001".

REGRESSION.  Last worked in version 7u51

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public void test_roundingOfDoubleValues() {
  NumberFormat format = DecimalFormat.getInstance( Locale.US );
  format.setGroupingUsed( false );
  format.setMaximumFractionDigits( 6 );
  format.setRoundingMode( RoundingMode.HALF_UP );
  String val95000055 = format.format( 0.950000550000 );
  assertEquals( "0.950001", val95000055 );  // this is okay
  String val95000060 = format.format( 0.950000600000 );
  assertEquals( "0.950001", val95000060 );  // this provides an error

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

Review thread: http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-September/028583.html

Digging further the problem, I discovered this is in fact coming from the DigitList.ShouldRoundUp() method modified for dealing with 7131459 JDK long-standing bug we discovered with fastpath implementation, even if this does not use fastpath code. This is a rare rounding corner case that was nether tested by any of the existing test suites (jdk unit tests, sqe testbase, jck test suite). Thus I am reassigning it to myself.

This is an rounding case where FloatingDecimal.dtoa() rounding behavior must be ignored. HALF_UP case should separate "exact tie" case and "above the tie" case, while currently merging it into "above or equal to tie" case. Additional unit tests to be writen.

The rounding threshold is a 5 digit at "rounding position"+1 Note: For any binary representation of a floating-point value, the last digit of it, which in most case will the closest representable approximation, will be a '5' ! i.e. 1.26 cannot be represented exactly, closest approx is 1.2600000000000000088817841970012523233890533447265625. in addition IEEE-754 format imposes constraint on the possible precision, thus Double.toString (called in DigitList.set()) will return here 1.26. For every value, we have only 3 possibilities for pre- rounding/truncation by sun.misc.FloatingDecimal.dtoa() (called by Double.toString()). A- binary representation exact, we have all digits (no round-up/truncation, last digit is a 5) B- binary representation inexact and digit sequence was truncated C- binary representation inexact and digit sequence was rounded up We must check against the digit at the rounding position. The 6 different cases are thus : 1- digit > 5 ==> must round-up 2- digit < 5 ==> dont round-up 3- digit == 5 ==> 3-a '5' digit is not the last one (there are following further digits that are ignored) ==> round-up 3-b '5' digit is the last one : 3-b-1 exact representation ==> must round-up 3-b-2 digit sequence rounded-up by dtoa() ==> dont round-up a second time !!! 3-b-3 digit sequence truncated by dtoa() ==> must round-up (take into account remaining digits) Problem with current code is that it mixes case 1 and 3 above. So the code is ok when rounding at the last available digit, with a '5' digit, but wrong when this digit is greater than '5', like here with 0.9500006 at the sixth fractional digit. Solution: separate case 1 and 3 in the code.

Unassigning myself since not being related to fastpath

I believe this is yet another false claim for the rounding fix in 8.