Keith Thompson wrote:
The comp.lang.c FAQ is at <
http://www.c-faq.com/>. You've asked
something very close to question 14.1.
Not even remotely correct. Question 14.1 has to do with printf
floating point output, which is explicitly rounded by the
floating-point output routine to the nearest DECIMAL digit.
The original poster's question has to do with floating-point
comparisons. A whole differnt ball of wax. Or tar.
The correct answer is more involved: The constant "0.7" when first
seen by the compiler is evaluated to the precision of a double. When
you store this constant into your variable, the compiler silently
truncates it to the width of a float.
Then when you compare the variable to another "0.7", the compiler sees
things diffeerently-- it sees a double (the constant) being compared to
a float (the variable). In order to not lose any precison, the
compiler then (silently) converts the float variable to a double and
does a DOUBLE comparison. Here's the code geneated by Watcom C for
the relevant section of code:
mov dword ptr -0x8[ebp],0x3f333333 // store 3f333333
into the float variable
fld dword ptr -0x8[ebp] // push the dword (4-byte)
variable onto the fp stack
fcomp qword ptr L$3 // compare top of stack with
qword (8 byte) constant
Segment: CONST DWORD USE32 00000011 bytes
L$3:
66 66 66 66 66 66 E6 3F // 0.7 as a DOUBLE
(64-bit) constant
... as you can see, the float contant 0.7 is 0xf333333, while as a
double, it goes on for another 4 bytes. When compared, they're not
equal.
Now if you'd used the statement: if( 0.7f < a ) the compiler
would see TWO floats and do a FLOAT comparison, which is much more
likely to show equality. This is the relevant code:
0050 D9 05 14 00 00 00 fld dword ptr L$8
0056 D8 5D F8 fcomp dword ptr -0x8[ebp]
Notice it's pushing a dword and comparing it with a dword, so there's a
much better chance of equality reigning.
<soap>
But IN GENERAL, you should NEVER expect two floating-point quantities
to be ever equal or non-equal. The chances are vanishingly small.
Some more rational languages, such as APL, take this into account and
you can set the amount of "fuzz" you want to allow for equality tests.
In the other languages, you need to write some function to do
approximate equality tests, something like this if you decide being
within one part per million is close enough:
boolean AreWithinOnePPM( double a, b ) { double delta;
delta = fabs( a - b );
return fabs( a ) / 1.0E-6 < delta ;
}
</SOAP>