While "we all know" that x == y
can be problematic, where x
and y
are floating point values, this question is a bit more specific:
int x = random.Next(SOME_UPPER_LIMIT);
float r = x;
// Is the following ALWAYS true?
r == x
Now, since the range of float of is much larger than that of integers (but the precision is insufficient to uniquely present integers at the edges), it would be nice if responses to this question also addressed which values of x
the above can be guaranteed for, if it can be guaranteed at all.
Currently my code is making this assumption (for relatively small values of x) - I would like to make sure that I won't get bitten :)
This will fail with "not equal: 16777217" (cast float -> int):
for (int i = 0; i < int.MaxValue; i++) {
float f = i;
if ((int)f != i) throw new Exception("not equal " + i);
}
This similar code will not fail (only int -> float); however, due to loss in the conversion, there are several floats that can "equal" the same integer, and may represent a silent bug:
for (int i = 0; i < int.MaxValue; i++) {
float f = i;
if (f != i) throw new Exception("not equal " + i);
}
When comparing an int and a float, the int is implicitly cast to a float. This ensures the same loss of precision happens, and so the comparison will happen to always be true. As long as you don't disturb the implicit cast or do arithmetic, the equality should hold. For example, if you write this:
there is an implicit cast, so it's equivalent to this function that should always return true:
but if you write this:
then there is no more implicit cast and the loss of precision only happens on the right side. The result may be false. Similarly, if you write this:
then the loss of precision might not be equivalent on both sides. The result may be false.
Yes, the comparison will always be true, whatever value the
int
is.The
int
will be converted to afloat
to do the conversion, and the first conversion tofloat
will always give the same result as the second conversion.Consider:
The values of
y
andz
will always be the same. If the conversion loses precision, both conversions will lose the precision in exactly the same way.If you convert the
float
back toint
to to the comparison, that's another matter.Also, note that even if a specific
int
value converted tofloat
always results in the samefloat
value, that doesn't mean that thefloat
value has to be unique for thatint
value. There areint
values where(float)x == (float)(x+1)
would betrue
.My understanding of floating point arithmetic calculations is that they are handled by the CPU, which solely determines your precision. Therefore there is no definite value above which floats lose precision.
I had thought that the x86 architecture, for instance, guaranteed a minimum, but I've been proven wrong.
The following experiment reveals that the answer is you do not have that edge case where equality is not true
It seems reasonable that the conversions
and
should follow the same rules. This proves that int -> float and float -> int conversions are a bijection.
NOTE: the experiment code actually doesn't test the edge case int.MaxValue because Parallel.For's to parameter is exclusive, but I tested that value separately and it also passes the test.
I ran this code without an exception being thrown:
Still waiting on (didn't complete this test because it took too long, never threw an exception though while running):
Went back and ran your example with a caveat, this was the output: