Floating point comparison
Solution 1
int main()
{
float a = 0.7, b = 0.5; // These are FLOATS
if(a < .7) // This is a DOUBLE
{
if(b < .5) // This is a DOUBLE
printf("2 are right");
else
printf("1 is right");
}
else
printf("0 are right");
}
Floats get promoted to doubles during comparison, and since floats are less precise than doubles, 0.7 as float is not the same as 0.7 as double. In this case, 0.7 as float becomes inferior to 0.7 as double when it gets promoted. And as Christian said, 0.5 being a power of 2 is always represented exactly, so the test works as expected: 0.5 < 0.5
is false.
So either:
- Change
float
todouble
, or: - Change
.7
and.5
to.7f
and.5f
,
and you will get the expected behavior.
Solution 2
It's due to rounding issues while converting from float to double
Solution 3
Generally comparing equality with floats is a dangerous business (which is effectively what you're doing as you're comparing right on the boundary of > ), remember that in decimal certain fractions (like 1/3) cannot be expressed exactly, the same can be said of binary,
0.5= 0.1
, will be the same in float or double.
0.7=0.10110011001100
etc forever, 0.7 cannot be exactly represented in binary, you get rounding errors and may be (very very slightly) different between float and double
Note that going between floats and doubles you cut off a different number of decimal places, hence your inconsistant results.
Comments
-
sasidhar almost 2 years
int main() { float a = 0.7; float b = 0.5; if (a < 0.7) { if (b < 0.5) printf("2 are right"); else printf("1 is right"); } else printf("0 are right"); }
I would have expected the output of this code to be
0 are right
. But to my dismay the output is1 is right
why? -
sasidhar over 12 yearsThe first if and second if should get evaluated the same way right?? so the answer should either be
2 are right
or0 are right
but why1 is right
?? -
user703016 over 12 yearsI edited my answer to explain why.
-
Emil Vikström over 12 yearssasidhar, they are different numbers so they may lose precision in different ways.
-
Christian Rau over 12 years@sasidhar 0.5 is always representable exactly (assuming IEEE), so there is no difference between the float and double versions.
-
sasidhar over 12 yearsIs there a way to understand when these floats will exactly be promoted which way? I mean 0.7 is inferior but 0.5 is superior. Is this behavior unpredictable? Given such a question what should be my answer? Unpredictable?
-
Christian Rau over 12 years+1 For the only answer that didn't call out "never compare floats" when seeing the question and actually thought about what is really going on here.
-
R.. GitHub STOP HELPING ICE over 12 yearsThe behavior is 100% predictable assuming IEEE 754 floating point.
0.7
becomes the nearestdouble
(0.6999999999999999555910790149937383830547332763671875) and converting that tofloat
rounds to the nearestfloat
value (0.699999988079071044921875). -
Admin over 12 years@R: Thought about writing an answer? :)
-
Martin York over 12 years@sasidhar: It is easy to predicate when types get promoted. ALL operations (on normal types) are done on operands of the same type. Thus <,<=,>=,>,+,-,*,/ etc both sides of the operator are converted to the same type before the operation happens. Thus
0.5 < 1
As types is<double> < <int>
Thus the compiler will convert the RHS to double to make sure both sides are the same type.0.5 < 1.0
-
sasidhar over 12 years@Martin Its quite predictable when they get promoted. I agree. But is it predictable when these get evaluated which way? At one point
<float> < <double>
evaluated to true, while at other, it evaluate to false. Is this behavior predictable? -
Martin York over 12 years@sasidhar: Yes it is predictable. But you have to know the binary representation of the numbers. Floating Point format. Here 0.5 is stored precisely so its representation in float is converted to double with no loss of information. Unfortunately 0.7 is not represented precisely as float. So when you assign it to the variable 'a' information is lost. When this value is promoted to a double you can not re-create this lost information.
-
Martin York over 12 years@sasidhar: 0.7 represented as float is stored as
0.699999988079071044921875
and stored as a double is0.699999999999999955591079014994
So there is a difference of0.000000011920928910669204014994
which is lost during the assignment toa
That information can not be re-created whena
is converted to a double. -
Martin York over 12 years@sasidhar: You should assume that all floating point numbers will not be stored precisely and their will be some loss of information. (thus comparison of floating point values should not be done precisely but to a margin of error). Note if the variables get optimized out and all the values remain in registers for the duration of the program then you may get a different result. Try compiling in release mode with the optimizer turned to its highest level and see if the results change.
-
Bruce Dawson almost 10 yearsThis answer is good. While .7 and .2 are exact in base-10 floating-point, they are approximate in base-2 floating-point, and the error is different for different values and different for float and double. I blogged about this precise issue, to distinguish between this and the general problem of floating-point comparisons. Here: randomascii.wordpress.com/2012/06/26/…