Win a copy of Mesos in Action this week in the Cloud/Virtualizaton forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Arithmetic using primitive double

 
Michael L. Miller
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I realize that floating point primitives in Java use IEEE 754, but why are the results from the println() displayed so inconsistently by default?

 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Michael L. Miller
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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?
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.

 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic