I was recently reading about storing floating point values in the memory. And I’ve written a small program to test what I’ve read. And I noticed that there is a difference in the way Java processes the floating point values.
public class Test
{
public static void main(String args[])
{
double a = 0.90;
System.out.println(a);
System.out.println(2.00-1.10);
}
}
The above program is printing
0.9
0.8999999999999999
Why both these statements are not printing the same value? I know some floating values can’t be represented exactly. In that case, both should give same value.
When “0.90” is converted to double, the result is .9 plus some small error, e0. Thus
aequals .9+e0.When “1.10” is converted to double, the result is 1.1 plus some small error, e1, so the result is 1.1+e1.
These two errors, e0 and e1, are generally unrelated to each other. Simply put, different decimal numbers are different distances away from binary floating-point numbers. When you evaluate
2.00-1.10, the result is 2–(1.1+e1) = .9–e1. So one of your numbers is .9+e0, and the other is .9-e1, and there is no reason to expect them to be the same.(As it happens in this case, e0 is .00000000000000002220446049250313080847263336181640625, and e1 is .000000000000000088817841970012523233890533447265625. Also, subtracting 1.1 from 2 introduces no new error, after the conversion of “1.1” to double, by Sterbenz’ Lemma.)
Additional details:
In binary, .9 is .11100110011001100110011001100110011001100110011001100 11001100… The bits in bold fit into a double. The trailing bits do not fit, so the number is rounded at that point. That causes a difference between the exact value of .9 and the value of “.9” represented as a double. In binary, 1.1 is 1.00011001100110011001100110011001100110011001 10011001… Again, the number is rounded. But observe the amount rounding is different. For .9, 1100 1100… was rounded up to 1 0000 0000…, which adds 00110011… at that position. For 1.1, 1001 1001 is rounded up to 1 0000 0000…, which adds 01100110… at that position (and causes a carry in the bold bits). And the two positions are different; 1.1 starts to the left of the radix point, so it looks like this: 1.[52 bits here][place where rounding occurs]. .9 starts to the right of the radix point, so it looks like this: .[53 bits here][place where rounding occurs]. So the rounding for 1.1, besides being 01100110… instead of 00110011…, is also doubled because it occurs one bit to the left of the .9 rounding. So you have two effects making e0 different from e1: The trailing bits that were rounded are different, and the place where rounding occurs is different.