Weird If Statement behaviour using Float and <= sign

Discussion in 'Mac Programming' started by roeik, Dec 25, 2008.

  1. macrumors member

    Joined:
    Dec 25, 2008
    #1
    Hi,

    I wrote the following function using if statements.
    Everything works fine except for two bugs. If ct is equal to .04, .08, 0.7, or 0.9 the function returns the value in the previous return statement. So for example, when ct is .04 it returns 0 and not 1. The same weird behavior occurs with the numbers I specified above, but works well with all the other numbers. Any suggestions?
    Thanks.

    - (int) sizeIndex:(float) ct
    {
    NSLog(@"%f", ct);
    if (ct > 0 && ct < 0.04) return 0;
    if (ct >= 0.04 && ct < .08) return 1;
    if (ct >= 0.08 && ct < .15) return 2;
    if (ct >= 0.15 && ct < .18) return 3;
    if (ct >= 0.18 && ct < .23) return 4;
    if (ct >= 0.23 && ct < .3) return 5;
    if (ct >= 0.3 && ct < .4) return 6;
    if (ct >= 0.4 && ct < .5) return 7;
    if (ct >= 0.5 && ct < .7) return 8;
    if (ct >= 0.7 && ct < .9) return 9;
    if (ct >= 0.9 && ct < 1) return 10;
    if (ct >= 1 && ct < 1.5) return 11;
    if (ct >= 1.5 && ct < 2) return 12;
    if (ct >= 2 && ct < 3) return 13;
    if (ct >= 3 && ct < 4) return 14;
    if (ct >= 4 && ct < 5) return 15;
    if (ct >= 5 && ct < 10) return 16;
    if (ct >= 10) return 17;
    else return -1;
    }
     
  2. macrumors newbie

    Joined:
    Mar 18, 2007
    #2
    You're mixing floats and doubles.
    Code:
    float f = 0.04;
    double d = 0.04;
    if (f==d) {
      //This is never true
    }
    
    Code:
    if (ct > 0 && ct < 0.04[B]f[/B]) return 0;
    if (ct >= 0.04f && ct < .08f) return 1;
    ...
    
     
  3. thread starter macrumors member

    Joined:
    Dec 25, 2008
    #3
    thanks
     
  4. macrumors 6502a

    Joined:
    Dec 4, 2006
    Location:
    Katy, Texas
    #4
    Note that your logic is a bit verbose. This is a simplified version that gives you the same functionality, but less code.

    Code:
    - (int) sizeIndex: (float) ct {
    	NSLog(@"%f", ct);
    	if (ct > 0 && ct < 0.04) return 0;
    	if (ct < .08)  return 1;
    	if (ct < .15)  return 2;
    	if (ct < .18)  return 3;
    	if (ct < .23)  return 4;
    	if (ct < .3)   return 5;
    	if (ct < .4)   return 6;
    	if (ct < .5)   return 7;
    	if (ct < .7)   return 8;
    	if (ct < .9)   return 9;
    	if (ct < 1.0)  return 10;
    	if (ct < 1.5)  return 11;
    	if (ct < 2.0)  return 12;
    	if (ct < 3.0)  return 13;
    	if (ct < 4.0)  return 14;
    	if (ct < 5.0)  return 15;
    	if (ct < 10.0) return 16;
    	if (ct >= 10)  return 17;
    	return -1;
    }
     
  5. macrumors 68000

    savar

    Joined:
    Jun 6, 2003
    Location:
    District of Columbia
    #5
    You can't use the equality comparision (==, <=, or >=) with floating point numbers. (In most languages, float and double are both floating point types, just with differing degrees of precision.)

    The fact that most languages will compile code like this only adds to the confusion; you'll get the correct result for some cases, but it won't work in others.

    http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
     
  6. macrumors member

    Joined:
    Aug 18, 2008
    #6
    if you are going to use comparison operators with floats and doubles, consider setting a threshold.
     
  7. macrumors 68000

    savar

    Joined:
    Jun 6, 2003
    Location:
    District of Columbia
    #7
    This is true, but misleading. You can compare floats and doubles. It's not the type that matters, its the content of the variable. Consider the following:
    Code:
    /Users/mehaase $ cat test.c
    #import <stdio.h>
    
    int main(int argc, char *argv) {
      float f=.25;
      double d=.25;
      if (f==d)
        printf("equal\n");
      else
        printf("not equal\n");
    }
    
    /Users/mehaase $ gcc test.c -o test
    /Users/mehaase $ ./test
    equal
    
    Your example doesn't work because the number you picked (.4) is a repeating number when converted to binary representation. Because it repeats infinitely, the differing precision of float and double result in slightly different floating point numbers. (As an example, is 1/3 == .333 or is 1/3 == .333333?)

    In my example, .25 is a very simple fraction when represented in binary (1/2, 1/4, 1/8 are all simple fractions in binary because the denominator is a power of two). Therefore, the differences in precision between float and double don't make a difference.

    To the OP: if you're a CS student or a professional developer, you really need to learn this stuff. If you're just a hobbyist, then just keep in mind that floating point numbers are trickier than they seem and avoid them when possible.
     
  8. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
    Posting from my phone, so no links, but google "machine delta", and use it. This is essentially what savar and blueillusion were indicating. Since machines use a different number system than we are used to using to express things, methods of approximation had to be developed. IEEE-734 is the method that is most commonly used. Essentially, every mathmatical operation you perform on a float accumulates errors, which can eventually cause significant errors. This is obviously worse with 32-bit floating point numbers than 64-bit, simply because of lower possible precision.

    You're dealing with very few significant digits. You may be able to just deal with integers that are 100x larger than the real values you are dealing with.

    Good luck!

    -Lee
     
  9. macrumors newbie

    Joined:
    Mar 18, 2007
    #9
    I never said they can't be compared, I was just showing a case where OP's logic fails, without diving too deep into theory. But I agree my example was misleading.
    And I think your "1/3 example" is a good way of explaining the reason behind this "anomaly".
     
  10. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #10
    This is a subtle point but worth pointing out I think. In expressions containing mixed precision, the compiler always promotes the lower precision values to the higher precision type. So, when evaluating the if statement expression:-

    Code:
    if (ct > 0 && ct < 0.04)
    
    ct is first promoted to a double value and then compared to the (double) value 0.04. If the compiler took the alternative approach to resolving such cases, ie de-promote 0.04 to a float, then all would have been fine in the original code.

    b e n
     

Share This Page