Floating point comparison

15,367

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 to double, 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.

Share:
15,367
sasidhar
Author by

sasidhar

I am a computer science engineering student.

Updated on June 28, 2022

Comments

  • sasidhar
    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 is 1 is right why?

  • sasidhar
    sasidhar over 12 years
    The first if and second if should get evaluated the same way right?? so the answer should either be 2 are right or 0 are right but why 1 is right??
  • user703016
    user703016 over 12 years
    I edited my answer to explain why.
  • Emil Vikström
    Emil Vikström over 12 years
    sasidhar, they are different numbers so they may lose precision in different ways.
  • Christian Rau
    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
    sasidhar over 12 years
    Is 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
    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
    R.. GitHub STOP HELPING ICE over 12 years
    The behavior is 100% predictable assuming IEEE 754 floating point. 0.7 becomes the nearest double (0.6999999999999999555910790149937383830547332763671875) and converting that to float rounds to the nearest float value (0.699999988079071044921875).
  • Admin
    Admin over 12 years
    @R: Thought about writing an answer? :)
  • Martin York
    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
    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
    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
    Martin York over 12 years
    @sasidhar: 0.7 represented as float is stored as 0.699999988079071044921875 and stored as a double is 0.699999999999999955591079014994 So there is a difference of 0.000000011920928910669204014994 which is lost during the assignment to a That information can not be re-created when a is converted to a double.
  • Martin York
    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
    Bruce Dawson almost 10 years
    This 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/…