PDA

View Full Version : Weird If Statement behaviour using Float and <= sign




roeik
Dec 25, 2008, 03:52 AM
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;
}



Allanist
Dec 25, 2008, 04:28 AM
You're mixing floats and doubles.

float f = 0.04;
double d = 0.04;
if (f==d) {
//This is never true
}


if (ct > 0 && ct < 0.04f) return 0;
if (ct >= 0.04f && ct < .08f) return 1;
...

roeik
Dec 25, 2008, 05:56 AM
thanks

toddburch
Dec 25, 2008, 10:53 AM
Note that your logic is a bit verbose. This is a simplified version that gives you the same functionality, but less 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;
}

savar
Dec 25, 2008, 01:04 PM
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

blueillusion
Dec 25, 2008, 01:14 PM
if you are going to use comparison operators with floats and doubles, consider setting a threshold.

savar
Dec 25, 2008, 01:17 PM
You're mixing floats and doubles.

float f = 0.04;
double d = 0.04;
if (f==d) {
//This is never true
}



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:
/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.

lee1210
Dec 25, 2008, 01:23 PM
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

Allanist
Dec 25, 2008, 04:35 PM
This is true, but misleading. You can compare floats and doubles. It's not the type that matters, its the content of the variable...

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".

lazydog
Dec 25, 2008, 05:20 PM
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:-


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