NSNumber 比较:返回不同的结果

发布于 2025-01-04 08:01:13 字数 683 浏览 0 评论 0原文

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

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

日志输出:

没有
是的

是的

这让我非常沮丧。我知道这可能是因为浮点数与双精度数之间的位数不同。在我看来,它将双精度截断为浮点数来进行比较。但如果我不知道数字是如何创建的,我如何获得正确的结果呢?有没有不同的方法来比较 NSNumber 的?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

春庭雪 2025-01-11 08:01:13

我尝试使用 isEqualToNumber: 但它返回 NO。它们不相同的原因是 1.004 无法用二进制精确表示。 double 近似值比 float 近似值的小数点后位数更多,因此两个数字不同。通常,在比较浮点数时,您会测试它们是否等于容差值 fabs(a - b) fabs(a - b) <公差

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

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
柳絮泡泡 2025-01-11 08:01:13

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

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

此 stackoverflow 问题也给出了详细的解答

please try the isEqualToNumber: method to check your condition

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

this stackoverflow question also gives a detailed answer

旧时模样 2025-01-11 08:01:13

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 中数据的类型。

The compare: method follows the standard C rules for type conversion. For example, if you compare an NSNumber object that has an integer value with an NSNumber object that has a floating point value, the integer value is converted to a floating-point value for comparison.

Also, initializing an NSNumber with a float, then converting it to a double loses some precision.

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

If you know you may have a mix of float and doubles, one solution is to compare the NSNumber floatValues like you did in the last line of your code snippet in your question.

Also, you can get the type of the data in the NSNumber with the objCType method.

很糊涂小朋友 2025-01-11 08:01:13

对我有用的另一个解决方案是将它们转换为 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];
}

这解决了我比较带有 2 个尾随零的双精度型和没有尾随零的浮点数的问题。

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

Another solution that worked for me was to convert them to NSStrings and do a string comparison. This was because I am working with 4 digit decimal prices and this worked well for me.

-(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];
}

This got rid of the issue where I was comparing a double with 2 trailing zeros and a float with none.

I'd normally warn against string comparisons like this but as my rules were always fixed it was OK for me in this case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文