What's bugging me is the second line in the output. It's not possible to store the value 0.9 precisely in the double variable, hence the first line of the output. That's fine. I get that. But, that being the case, I don't really understand why the second line doesn't print "d2 = 0.8999999999999999". How is the value 0.9 being held precisely between lines 2 and 4. I'm just curious about what is happening under-the-hood and I can't seem to find the relevant part of the JLS to explain it.
I'm just curious about what is happening under-the-hood and I can't seem to find the relevant part of the JLS to explain it.
The floating point formats (and behavior) is not defined in the JLS. Java uses the IEEE standard for floating points -- 32 bit and 64 bit standard.
OK, I see that in the JLS. But, as I understand it*, it specifies how floating point numbers are encoded into binary. Using this encoding it's not possible to precisely specify the number 0.9 (for example). This causes the rounding error in the assignment to variable d in the example I posted. This same rounding error does not occur in the assignment to variable d2. This leads to to believe that the JVM is not using IEEE 754 to encode the literal 0.9 in the assignment to d2.
If this behaviour is explained somewhere in IEEE 754, I've missed it. I also cannot see anything in the JLS that suggests the JVM ever uses anything other than IEEE 754 to encode floating point numbers. Obviously I've missed something in one of the two specifications. So, if you happen to know a part of IEEE 754 spec that would explains this, I would be very grateful if you could point it out as it's esaping me for the moment.
Thanks for the reply,
* I admit my understanding may not be perfect, hence the post.
I have never actually read IEEE754(1985) which I think is now called something different [but I do know what the structure of floating-point numbers is]. But it was unnecessary to explain imprecision; programmers in those days had used slide rules (I still have an old slide rule I bought about 1968) and were familiar with imprecision. Look in our FAQ (no 20) where it gives some useful links.
It also might be worth noting that with the simple example given above, the compiler can do some optimizations because it knows the value of d is calculated from two constants when assigned. Which means the results is a constant. Which means the math can be done at compile time rather than run time. On the other hand, the value of d and d2 are never changed, so they can be replaced by constants as well. Given this code:
You can get this byte code (un-important stuff cleaned out)
So when d is encountered it is treated like the constant 0.89999...d, while when d2 is encountered it is treated as the constant 0.9d. Not sure if it helps, or is exactly pertinent to your question, but it is something to keep in mind when making these sorts of comparisons.