I'm compiling and running the following program in 32 and 64 bit platforms:
int main()
{
double y = 8.34214e08;
double z = 1.25823e45;
return y * z == 8.34214e08 * 1.25823e45;
}
While in 64bit the result is the expected (the values are the same and the exit code is non-zero) in 32bit seems there is a little difference between the value calculated at compile time, the right hand side of the comparison, and the left side computed at runtime.
Is this a bug in the compiler or there is a logical explanation?
EDIT: this is different from Why comparing double and float leads to unexpected result? because here all the values are double.
Floating point calculations done at compile time often occur at a higher precision than
double
uses at run time. Also C may perform run-time intermediatedouble
calculations at the higherlong double
precision. Either explain your inequality. SeeFLT_EVAL_METHOD
for details.Your results may slightly differ.
IEEE-754 allows intermediate computations to be done in a greater precision (emphasis mine).
In your case for example on a IA-32, the double values could be stored in the x87 FPU registers with greater precision (80-bit instead of 64). So you are actually comparing a multiplication done on double precision with a multiplication done on double-extended precision.
For example, on x64 where the result is
1
(the x87 FPU is not used as SSE is used instead), addinggcc
option-mfpmath=387
to use the x87 makes the result change to0
on my machine.And if you wonder if that is also allowed by C, it is:
In general, never do equality checks with floating point numbers. You need to check whether the result you want differs from the result you get by less than a pre-set precision.
What is happening here is in all likelihood due to the multiplication being run on two different "platforms": once by your code, and once by the compiler, which may have a different precision. This happens with most compilers.
Your program would probably work if you compiled it with the same options that were used to compile the compiler (supposing the compiler was compiled by itself). But that would not mean you would get the correct result; you would be getting the same precision error the compiler is getting.
(Also, I'm assuming that the compiler performs a straight multiplication and the parsing code recognizing floats does not enter into the equation. This might well be wishful thinking on my part).
Testing
Forcing -O0 to avoid the compiler from optimizing out the whole code (thanks @markgz!), we get
$ gcc -m32 -O0 -o float float.c && ./float NOT equal! $ gcc -m32 -frounding-math -O0 -o float float.c && ./float Equal
For the record, since you got there before me :-),