Because you can't store the same values in base-2 "fraction-point" notation (which is how IEEE 754, the floating point standard used by Java and other languages) that you can using the same kind of notation in base-10.

For example, it is impossible to store the base-10 value 0.1 (one-tenth) exactly in base-2 no matter how many bits we use, for exactly the same reason that we can't store 1/3 exactly in base-10.

Thanks Jeff. Perhaps I made the title of the post misleading. My questions is really about how the floating point result is converted back to a String. It's kind of surprising that the result of this program:

is:
19.999999000000003
19.999999

However, the underlying results before converting to Strings are:
4033FFFFEF390860 19.9999990000000030000
4033FFFFEF39085F 19.9999989999999990000

Why doesn't the second result also print 15 decimal places?

Presumably the default format is set to cut of trailing zeros, and everything out to that position would be zeros for that expression.

And no, it's not surprising that 10 + 9.999999 yields different results from 0 + 19.999999. This is part of why we don't use == to compare FP values, but rather, check whether they're within some epsilon that we define

Michael L. Miller
Greenhorn

Joined: May 07, 2013
Posts: 3

posted

0

Thanks again, Jeff. Seems like the String representations would have been:

19.999999000000003
19.999998999999999

if the algorithm set out to cut off trailing zeros.

And yes, I think it is surprising that the String representation of these two results in the JVM is not more consistent.

The Mike Miller wrote:Thanks again, Jeff. Seems like the String representations would have been:

19.999999000000003
19.999998999999999

if the algorithm set out to cut off trailing zeros.

Most likely that second one had another 9 on the end, and so got rounded up to 19.999999000000000.

And yes, I think it is surprising that the String representation of these two results in the JVM is not more consistent.

The String representations are different because the double values are different.

Floating point arithmetic is very non-intuitive, and the order of operations matters in cases where it wouldn't if we were doing it by hand. A + B + C does not always equal C + B + A.

For example, if we start off with zero, and add something really small, like 0.0000000000001 (plus or minus a few zeros), and keep adding that value enough bazillions of times to get the value 10, and then add that 10 to the value 10000000000000000 (plus or minus a few zeros), we'll get the expected 10000000000000010, or maybe that with a .00000125 on th end. BUT if we instead start with the really big value, and then at the tiny value a few bazillion times, we end up with ... exactly the big value we started with.

This non-intuitive behavior is one of the tradeoffs that have to be made in order to have fast arithmetic over a large range with a small number of bits. In the end, though, we have about 16 decimal digits of precision, which is more than is needed for a lot of use cases. As long as we're smart about how we do our operations, and pay attention to the difference between the double value and the String representation, we'll get the results we expect.