DecimalFormat rounding changes in 8 (JEP 177)?

Joe Darcy joe.darcy at oracle.com
Sun May 4 18:41:08 UTC 2014


Hello,

On 5/4/2014 9:56 AM, solo-java-core-libs at goeswhere.com wrote:
> Hey,
>
> Could someone please help me understand what changes have happened in
> rounding in DecimalFormat in Java 8?
>
> new DecimalFormat("0.00").format(1.035) is 1.04 on Java 7, and 1.03 on
> Java 8.  (7u25-2.3.10-1~deb7u1, openjdk build 1.8.0_05-b13 debian and
> Oracle build 1.8.0-b132 win64 tested).
>
> My understanding of the RoundingMode.HALF_EVEN (the default)
> documentation is that 1.04 is the correct answer.  In fact,
> (0.000, 1.0035) is 1.004, and (0.0, 1.35) is 1.4.  I am aware
> that floating point is more complex than this, and I am by no
> means an expert.

There are several inexact processes going on here. The first is the 
decimal to binary conversion of 1.035 to a binary double value. In 
general, decimal fractions are not exactly representable in binary. 
Java's semantics require that on decimal to binary conversion, the 
double value with a numerical value closest to the exact value be used, 
the round to nearest even policy.

The exact numerical value of the double closest to 1.035 is

     1.0349999999999999200639422269887290894985198974609375

a value slightly *less than* 1.035. When this value is rounded to two 
digits after the decimal point using the round to nearest even rounding 
mode, the numerically correct answer is 1.03 *not* 1.04.

A range of numbers of the real line will get converted to a particular 
floating-point value. Some of these ranges straddle half-way points in 
decimal. For example, the range of values that will get converted to the 
floating-point value in question includes

[1.0349999999999999200639422269887290894985198974609375, 1.035]

The full range is

[1.03499999999999980904163976447307504713535308837890625,
  1.03500000000000003108624468950438313186168670654296875]

This range is a one-ulp (unit in the last place, see Math.ulp) wide 
region centered on the exact floating-point value.

When a decimal to binary conversion occurs, the original decimal text 
value is lost. Therefore, after the conversion, the binary double value 
doesn't "know" it came from "1.035" or "1.03499999999999981" or 
something else.

The numerically correct behavior is the new behavior in JDK 8.

HTH,

-Joe

>
>
> It seems that this may be new code, with a known breaking change in it:
>
> http://openjdk.java.net/jeps/177:
>> Compatibility: On JDK 7, (correct) but altered numerical behavior will
>> only be enabled under an aggressive optimization flag to limit
>> behavioral compatibility impact in that release train. In Java SE 8,
>> the correct numerical behavior will always be required by the
>> specification.
> Did this materialise somewhere, and, if so, where's it documented?
>
>
> In summary: My tests fail on Java 8 and I'm not sure they're wrong.
> Any help would be appreciated, thanks.
>




More information about the core-libs-dev mailing list