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