Search code examples
iphoneobjective-cnsnumber

NSNumber compare: returning different results


I'm trying to do some number comparisons and I'm getting some weird results.

NSNumber* number1 = [NSNumber numberWithFloat:1.004];
NSNumber* number2 = [NSNumber numberWithDouble:1.004];

([number1 compare:number2] == NSOrderedSame) ? NSLog(@"YES") : NSLog(@"NO");
([number1 compare:number2] == NSOrderedAscending) ? NSLog(@"YES") : NSLog(@"NO");
([number1 doubleValue] == [number2 doubleValue]) ? NSLog(@"YES") : NSLog(@"NO");
([number1 floatValue] == [number2 floatValue]) ? NSLog(@"YES") : NSLog(@"NO");

Log output:

NO
YES
NO
YES

This is extremely frustrating to me. I know this is probably because the difference between the number of bits in a float compared to a double. It seems to me it's truncating the double down to a float to do the compare. But if I don't know how the number is created, how do I get the correct results? Is there a different way to compare NSNumber's?


Solution

  • I tried using isEqualToNumber: and it returned NO. The reason they aren't the same is because 1.004 can't be represented exactly in binary. The double approximation has more digits after the decimal point than the float approximation so the two numbers are different. Normally, when comparing floating point numbers, you test to see if they are equal to within a tolerance value fabs(a - b) < tolerance:

    NSNumber* number1 = [NSNumber numberWithFloat:1.004];
    NSNumber* number2 = [NSNumber numberWithDouble:1.004];
    
    NSLog(@"number 1: %.12f", [number1 doubleValue]);
    NSLog(@"number 2: %.12f", [number2 doubleValue]);
    
    ([number1 isEqualToNumber:number2]) ? NSLog(@"YES") : NSLog(@"NO");
    fabs([number1 floatValue] - [number2 doubleValue]) < 1.0e-7 ? NSLog(@"YES") : NSLog(@"NO");
    

    results:

    2012-02-09 15:08:34.272 so9219935[3313:903] number 1: 1.003999948502
    2012-02-09 15:08:34.274 so9219935[3313:903] number 2: 1.004000000000
    2012-02-09 15:08:34.275 so9219935[3313:903] NO
    2012-02-09 15:08:34.275 so9219935[3313:903] YES