49.95 + 0.45 = 50.400000000000006
Tuesday, September 25. 2007
Have a look at the following simple piece of code:
Oh my god! Another calculation bug in an Intel processor? A bug in the Java VM? Or is it the Linux Kernel that is misbehaving? Wrong! In fact the result is perfectly OK. In fact it's even a defined behaviour for floating point numbers (see IEEE 754) and this will also happen in a similar C program.
To understand this result you have to think in binary. Floating point numbers are approximated by binary numbers. There is no exact representation possible, just an approximation to the next closest representation of a floating point number in binary. As a simple float is represented in single precision by a 32 bit number there are cases, when 49.95 is in fact something like 49.950000000000004, which got rounded to 49.95. When you add another float the imprecision introduced by the approximation sums up and in some cases the result will be different than expected.
On the web you can find various examples covering the same issue. A detailed discussion can be found on Suns Java forum.
public class WeirdDouble {
public static void main(String args[]) {
Double result = 49.95 + 0.44;
System.out.println(result);
result = 49.95 + 0.45;
System.out.println(result);
result = 49.95 + 0.46;
System.out.println(result);
result = 49.95 + 0.47;
System.out.println(result);
}
}
Theres nothing complicated going on here. Just a few simple addition of Of course you would expect the following output:50.39Wrong! The output will look like this.
50.40
50.41
50.42
50.39
50.400000000000006
50.410000000000004
50.42
Oh my god! Another calculation bug in an Intel processor? A bug in the Java VM? Or is it the Linux Kernel that is misbehaving? Wrong! In fact the result is perfectly OK. In fact it's even a defined behaviour for floating point numbers (see IEEE 754) and this will also happen in a similar C program.
To understand this result you have to think in binary. Floating point numbers are approximated by binary numbers. There is no exact representation possible, just an approximation to the next closest representation of a floating point number in binary. As a simple float is represented in single precision by a 32 bit number there are cases, when 49.95 is in fact something like 49.950000000000004, which got rounded to 49.95. When you add another float the imprecision introduced by the approximation sums up and in some cases the result will be different than expected.
On the web you can find various examples covering the same issue. A detailed discussion can be found on Suns Java forum.
Update (2007-27-09):
Joel Spolsky has a very nice explanation of this effect in the context of the Excel 2007 calculation bug.
Trackbacks
Trackback specific URI for this entry
No Trackbacks



Comments
For the C (without the fancy ++ or #) people, try to compile and run the following:
#include<stdlib.h>
#include<stdio.h>
int main (void)
{
float a = 0.;
int b = 0;
while ( a < 1. ) {
printf ( "%d %g %g\n", b, b*0.00001, a );
b++;
a+= 0.00001;
}
return 0;
}
The final line of this is *shudder*:
99901 0.99901 0.999999
If you are interested in more details, please read:
http://docs.sun.com/source/806-3568/ncg_goldberg.html
If you think: "Nah, I'm using Excel all the time, this can never happen to me!" then read this:
http://it.slashdot.org/it/07/09/24/2339203.shtml
Have fun!