Hello Lennart,

Sorry for the little belated reply.

The behaviour you see is due to a fix for JDK-7131459 and is the expected one.

While working on the DecimalFormat optimization which you noticed in the code, we discovered a long-standing bug in the DigitList.java class
(see bug 7131459 <http://bugs.sun.com/view_bug.do?bug_id=7131459>).
We have fixed this bug and the fix is now part of the JDK8 builds (starting in b82 IIRC). so b108 and b111 are fixed.

The fact is that most decimal values cannot be represented exactly in a binary representation. For example the closest binary representation to -0.15 is -0.1499999999999999944488848768742172978818416595458984375 .

As you can see the absolute value of this representation is "below" the tie value "0.15". So the closest binary representation of -0.15 that can be recorded in a computer is a bit greater than the "tie" value provided in the program text ("-0.15"), and for this reason, as stated by the HALF-EVEN rounding rules, we should not round the result, in order to provide an exact
and fair HALF-EVEN rounding of *what is recorded* in the computer.

Thus the correct result to return here is -0.1 because maximumFractionDigits is set to 1, and correct rounding leaves the '1' digit in 1st
fractional position unchanged.

Approximated closest binary representation is the case of all values you provided in your example, except for 0.25 which can be represented *exactly*. So there is no change in the output only for that value when comparing older and recent builds.

The correct formatting is the one provided by recent JDK8 builds like b108 and b111.

To help understanding, I have changed a bit your example to show what is the approximated binary representation that is recorded in the computer memory by using the call "new BigDecimal(d).toString()" which provides the exact decimal representation of what is
recorded in the computer :

you will find below the changed code and the corresponding results for JDK8 builds that include (or don't include) the fix for
JDK-7131459

Hope that helps.

Best Regards,
Olivier.

changed code :
--------------------------------------
import java.text.DecimalFormat;
import java.math.BigDecimal;

public class Jdk8Formatting {

    public static void main(String[] args) {

double dd[] = {-0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65};
        DecimalFormat fmt = new DecimalFormat("0.#");

        for (double d : dd) {
// Prints-out first the "approximated" double floating-point value
            System.out.println("FloatingDecimal output : " + d);

// Then the exact binary representation using as much memory as needed System.out.println("BigDecimal output : " + new BigDecimal(d).toString());

            // And finally the string returned by DecimalFormat.format()
            System.out.println(d + " " + fmt.format(d));
        }
    }
}
--------------------------------------

Output of the above program for JDK8 builds that include the fix:
FloatingDecimal output : -0.15
BigDecimal output : -0.1499999999999999944488848768742172978818416595458984375
-0.15 -0.1
FloatingDecimal output : -0.05
BigDecimal output : -0.05000000000000000277555756156289135105907917022705078125
-0.05 -0.1
FloatingDecimal output : 0.05
BigDecimal output : 0.05000000000000000277555756156289135105907917022705078125
0.05 0.1
FloatingDecimal output : 0.15
BigDecimal output : 0.1499999999999999944488848768742172978818416595458984375
0.15 0.1
FloatingDecimal output : 0.25
BigDecimal      output : 0.25
0.25 0.2
FloatingDecimal output : 0.35
BigDecimal output : 0.34999999999999997779553950749686919152736663818359375
0.35 0.3
FloatingDecimal output : 0.45
BigDecimal output : 0.450000000000000011102230246251565404236316680908203125
0.45 0.5
FloatingDecimal output : 0.55
BigDecimal output : 0.5500000000000000444089209850062616169452667236328125
0.55 0.6
FloatingDecimal output : 0.65
BigDecimal output : 0.65000000000000002220446049250313080847263336181640625
0.65 0.7

---------------------------------------------------------------------------------

Output of the above program for JDK8 builds that *do not* include the fix:
FloatingDecimal output : -0.15
BigDecimal output : -0.1499999999999999944488848768742172978818416595458984375
-0.15 -0.2
FloatingDecimal output : -0.05
BigDecimal output : -0.05000000000000000277555756156289135105907917022705078125
-0.05 -0
FloatingDecimal output : 0.05
BigDecimal output : 0.05000000000000000277555756156289135105907917022705078125
0.05 0
FloatingDecimal output : 0.15
BigDecimal output : 0.1499999999999999944488848768742172978818416595458984375
0.15 0.2
FloatingDecimal output : 0.25
BigDecimal      output : 0.25
0.25 0.2
FloatingDecimal output : 0.35
BigDecimal output : 0.34999999999999997779553950749686919152736663818359375
0.35 0.4
FloatingDecimal output : 0.45
BigDecimal output : 0.450000000000000011102230246251565404236316680908203125
0.45 0.4
FloatingDecimal output : 0.55
BigDecimal output : 0.5500000000000000444089209850062616169452667236328125
0.55 0.6
FloatingDecimal output : 0.65
BigDecimal output : 0.65000000000000002220446049250313080847263336181640625
0.65 0.6
---------------------------------------------------------------------------



Lennart Börjeson said  on date 10/21/2013 11:26 AM:
I've found what I believe is a DecimalFormat regression bug in Java 8, i.e. 
Java 8 seems to format some numbers differently than previous releases do.

I've tried submitting a proper bug report using the form at bugreport.sun.com, but it 
just throws back a "submission error" at me, so I resort to mailing you.

Just try the code below.
--------------
import java.text.DecimalFormat;
public class Jdk8FormattingBug {

    public static void main(String[] args) {
        double dd[] = {-0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65};
     DecimalFormat fmt = new DecimalFormat("0.#");

     for (double d : dd) {
     System.out.println(d+" "+fmt.format(d));
     }
     }
}
----------------

I've tested JDK 1.8 b108 and b111, on Linux and on Mac, and they all print:

-0.15 –0.1
-0.05 –0.1
0.05 0.1
0.15 0.1
0.25 0.2
0.35 0.3
0.45 0.5
0.55 0.6
0.65 0.7


Yet the printout using all other Java versions I've tried is:

-0.15 –0.2
-0.05 -0
0.05 0
0.15 0.2
0.25 0.2
0.35 0.4
0.45 0.4
0.55 0.6
0.65 0.6

which is the documented behaviour, respecting RoundingMode.HALF_EVEN.

I'd expect formatting to behave the same in Java 8, or have I missed some 
change here? I've noticed there has been some optimisation work done on 
DecimalFormat, but shouldn't the output stay the same?

Best regards,

Lennart Börjeson

Reply via email to