I am using Visual Studio 6 with some old time code written in c. I found an issue where the code looks like this..
int x = 3;
float y = 3.0;
if(x == y){
No one else has cited it yet, and I haven't linked to it in a while, so here is the classic paper on the scary edges of floating point representation and arithmetic: What Every Computer Scientist Should Know About Floating Point.
The paper is a challenging read for a non-mathematician, but the key points are well stated in between the heavy swaths of math backing them up.
For this discussion, the points made by the other answers here are all valid. Floating point arithmetic is inexact, and hence comparisons for exact equality are generally a bad idea. Hence, epsilon is your friend.
One exception to the exact comparison rule is a test for exactly zero. It is perfectly legal and often sensible to test for exactly zero before a division or logarithm since the answer is well defined for any non-zero value. Of course, in the presence of IEEE rules and NaN, you can let that slide and test for NaN or Inf later on.
If the code looks literally like what you posted (with no intervening computations), then it comes to a question of whether 3.0
and (float)3
(since the integer is automatically converted to a float) are the same. I think they are guaranteed to be the same in this case, because 3 is exactly representable as a float
.
Aside: And even if the integer is not exactly representable as a float (i.e. if it is really big), I would imagine that in most implementations, x.0
and (float)x
would be the same because, how would the compiler generate x.0
in the first place, if not to do something just like (float)x
? However, I guess this is not guaranteed by the standard.
I am going to buck the trend here a bit. As to the first question about whether the comparison is valid, the answer is yes. It is perfectly valid. If you want to know if a floating point value is exactly equal to 3, then the comparison to an integer is fine. The integer is implicitly converted to a floating point value for the comparison. In fact, the following code (at least with the compiler I used) produced identical assembly instructions.
if ( 3 == f )
printf( "equal\n" );
and
if ( 3.0 == f )
printf( "equal\n" );
So it depends on the logic and what the intended goal is. There is nothing inherently wrong with the syntax.
The crux of the problem is that floating point numbers which have a finite representation in base 10, decimal don't always have a finite representation in base 2, binary.
For your specific example, "do some crazy stuff" will execute. 3.0 will not be 3.0000001 at run-time.
The other answers are more for general cases, but even a hardcoded epsilon is not the greatest idea in the world. A dynamic epsilon based on the actual numbers involved is much better since the more positive and more negative the numbers are, the less likely the hardcoded epsilon will be relevant.