NSNumber比较:返回不同的结果

时间:2012-02-09 22:33:56

标签: iphone objective-c nsnumber

我正在尝试进行一些数字比较,而且我得到了一些奇怪的结果。

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");

日志输出:

  

NO
  YES
  NO
  是的

这对我来说非常令人沮丧。我知道这可能是因为浮点数与双精度数之间的差异。在我看来,它正在将双倍缩减到浮点数来进行比较。但如果我不知道如何创建数字,我该如何得到正确的结果呢?是否有不同的方法来比较NSNumber?

4 个答案:

答案 0 :(得分:7)

我尝试使用isEqualToNumber:并返回NO。它们不相同的原因是因为1.004不能完全用二进制表示。 double近似值在小数点后面的位数多于float近似值,因此两个数字不同。通常,在比较浮点数时,您要测试它们是否等于公差值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");

结果:

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

答案 1 :(得分:2)

compare:方法遵循标准C规则进行类型转换。例如,如果将具有整数值的NSNumber对象与具有浮点值的NSNumber对象进行比较,则将整数值转换为浮点值以进行比较。

此外,使用float初始化NSNumber,然后将其转换为double会失去一些精度。

NSNumber* number1 = [NSNumber numberWithFloat:1.004];
NSNumber* number2 = [NSNumber numberWithDouble:1.004];
NSLog(@"number1 double: %1.16f", [number1 doubleValue]);
NSLog(@"number2 double: %1.16f", [number2 doubleValue]);
NSLog(@"number1 objCType %s", [number1 objCType]);
NSLog(@"number2 objCType %s", [number2 objCType]);

2012-02-09 15:59:49.487 testNSNumber[89283:f803] number1 double: 1.0039999485015869
2012-02-09 15:59:49.488 testNSNumber[89283:f803] number2 double: 1.0040000000000000
2012-02-09 16:21:01.655 testNSNumber[4351:f803] number1 objCType f
2012-02-09 16:21:01.656 testNSNumber[4351:f803] number2 objCType d

如果你知道你可能有浮动和双打的混合,一种解决方案就是比较你问题代码片段最后一行中的NSNumber floatValues。

此外,您可以使用objCType方法获取NSNumber中的数据类型。

答案 2 :(得分:2)

请尝试使用isEqualToNumber:方法检查您的病情

([number1 isEqualToNumber:number2]) ? NSLog(@"YES") : NSLog(@"NO");

this stackoverflow question也提供了详细的答案

答案 3 :(得分:0)

另一个对我有用的解决方案是将它们转换为NSString并进行字符串比较。这是因为我正在使用4位数的十进制价格,这对我来说效果很好。

-(BOOL) hasPriceChanged{
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    formatter.numberStyle = NSNumberFormatterDecimalStyle;
    formatter.maximumFractionDigits = 4;
    NSString *p = [formatter stringFromNumber:self.price];
    NSString *op = [formatter stringFromNumber:self.originalPrice];
    return ![p isEqualToString:op];
}

这摆脱了我在比较带有两个尾随零的double和没有浮点的浮点的问题。

我通常会警告不要进行这样的字符串比较,但是由于我的规则总是固定的,因此在这种情况下对我来说是可以的。