posted 5 years ago

I realize that floating point primitives in Java use IEEE 754, but why are the results from the println() displayed so inconsistently by default?

posted 5 years ago

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.

For more details, google for what every developer should know about floating point numbers.

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.

For more details, google for what every developer should know about floating point numbers.

Michael L. Miller

Greenhorn

Posts: 3

posted 5 years ago

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:

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

is:

19.999999000000003

19.999999

However, the underlying results before converting to Strings are:

`4033FFFFEF390860 19.9999990000000030000`

4033FFFFEF39085F 19.99999899999999900004033FFFFEF39085F 19.9999989999999990000

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

posted 5 years ago

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

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

Posts: 3

posted 5 years ago

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

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.
posted 5 years ago

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

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.

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

Stringrepresentation 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.

Don't get me started about those stupid light bulbs. |