Hello,

On 04/05/2014 20:41, Joe Darcy wrote:
Hello,

On 5/4/2014 9:56 AM, solo-java-core-l...@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
Just to insist on Joe's words (Thanks Joe for the detailed reply):
with floating-point "What You See *Is Not* What You Get" in most cases,
and this is true with DecimalFormat when formatting double or float values.

Don't expect exactness with floating-point. This is even true with constant
values inside you source code like 1.035 here (which cannot be represented
exactly in binary format).

JDK8 fixes a bug that was discovered during JDK7 dev.

Hope that helps,
Olivier.





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.



Reply via email to