JDK-8000978 : [Fmt-De] DecimalFormat produces wrong format() results when close to a tie
  • Type: Backport
  • Backport of: JDK-7131459
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2012-10-16
  • Updated: 2017-05-17
  • Resolved: 2013-04-15
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.
JDK 7 JDK 8
7u40 b13Fixed 8Fixed
Description
When using a DecimalFormat instance in the default recommended way:

double myDouble = ....;
NumberFormat nf = NumberFormat.getInstance(); // or NumberFormat.getCurrencyInstance() 
String myStr = nf.format(myDouble);

the returned string from format(...) will be sometimes wrong when
the passed double value is close to a tie (like 1.3905d for example).
Such values are writen in decimal radix as : 
"iiiiii.ff5" in the currency case (getCurrencyInstance()), i.e. 2 fractional digits.
or
"iiiiiiii.fff5" in the decimal case (getInstance()), i.e. 3 fractional digits.

where 'i' represents an integral digit and 'f' represents a fractional digit.

Example of such value are:
0.8055d, 1.1015d, 1.1835d, 7.9005d. There are a lot of them.

These kind of values cannot be represented exactly with the double floating-point encoding format.

So only an approximation of them is recorded in memory:
0.8055d => exact value = 0.80549999999999999378275106209912337362766265869140625
1.1015d => exact value = 1.1014999999999999236166559057892300188541412353515625
1.1835d => exact value = 1.183499999999999996447286321199499070644378662109375
7.9005d => exact value = 7.90050000000000007815970093361102044582366943359375

nf.format(0.8055d); will return "0.806" where it should return "0.805" (see exact value above)
nf.format(1.1015d); will return "1.102" where it should return "1.101" (see exact value above)
nf.format(1.1835d); will return "1.184" where it should return "1.183" (see exact value above)
nf.format(7.9005d); will return "7.9" where it should return "7.901"   (see exact value above)

This will also happen if DecimalFormat instance has not been created using the default usage pattern.
For example, if the associated pattern requires 5 digits after decimal point when the value is close
to a tie from the rounding standpoint (fractional part like "fffff5").

This may be impacting (at from the end-user standpoint) with series of '9' digits:
like format(9.9995d) returning "10" where it may have to return "9.999".

Try the small following program that shows the wrong behavior:

    public static void main(String[] args) {
	java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
	double aDouble;
	String myStr;

	aDouble = 0.8055d;
	myStr = nf.format(aDouble);
        System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"0.805\".");
        aDouble = 1.1015d;
	myStr = nf.format(aDouble);
        System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"1.101\".");
        aDouble = 1.1835d;
	myStr = nf.format(aDouble);
        System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"1.183\".");
        aDouble = 7.9005d;
	myStr = nf.format(aDouble);
        System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"7.901\".");
    }

Comments
Verified jdk 7u14b13 Linux x64
17-04-2013