将 NSNumber 实例与 isEqualToNumber 进行比较

Comparing NSNumber instances with isEqualToNumber

是的,我已经阅读了 Whosebug 上关于比较 NSNumber 的其他帖子,其中 none 似乎完全解决了这种特殊情况。
这个解决方案特别糟糕...... NSNumber compare: returning different results
因为建议的解决方案根本不起作用。 使用 abs(value1 - value2) < tolerance 从一开始就是有缺陷的,因为小数值被剥离,使得 tolerance 无关紧要。

并且来自 Apple 文档...NSNumber 明确不保证 returned 类型将匹配用于创建它的方法。换句话说,如果给你一个 NSNumber,你无法确定它是否包含 float、double、int、bool 或其他任何东西。

此外,据我所知,NSNumber isEqualToNumber 是比较两个 NSNumber 的不可信方法。

鉴于这些定义...

NSNumber *float1 = [NSNumber numberWithFloat:1.00001];
NSNumber *double1 = [NSNumber numberWithDouble:1.00001];

如果您 运行 调试器然后使用 == 对这些相同的数字进行 2 次比较,一次失败,另一次则没有。

p [double1 floatValue] == [float1 floatValue]   **// returns true**
p [double1 doubleValue] == [float1 doubleValue]   **// returns false**

如果您使用 isEqualToNumber

比较它们
p [float1 isEqualToNumber:double1]             **// returns false**

因此,如果 isEqualToNumber 会 return false,鉴于 NSNumber 的创建是一个黑盒子,可能会在输出时为您提供其他类型,我不确定该方法有什么好处是。

因此,如果您要对脏进行测试,因为现有值已更改为新值...最简单的方法是什么来处理所有 NSNumber 比较...而不仅仅是浮点数和双倍,但所有 NSNumbers?

似乎转换为字符串值,然后进行比较是最有用的,或者使用 NSNumberFormatter 可能需要大量额外代码。

你有什么想法?

无法可靠地比较两个 IEEE 浮点数或双精度数。这与NSNumber无关。这就是浮点数的本质。这在 Strange problem comparing floats in objective-C 的简单 C 类型的上下文中进行了讨论。 比较浮点数的正确方法是通过测试公差。我不知道你所说的 "fractional values are stripped off." 是什么意思 有些数字 总是 在浮点表示中丢失。

您提供的特定测试值很好地说明了问题。 1.00001 不能用有限的二进制数字精确表示。 Wolfram Alpha 是探索这个的好方法,但作为双精度数,1.00001 舍入为 1.0000100000000001。作为浮点数,它四舍五入为 1.00001001。显然,这些数字并不相等。如果您以不同的方式往返它们,那么 isEqualToNumber: 失败就不足为奇了。这应该清楚为什么你的两个 floatValue 调用结果是相等的。四舍五入到浮点数的精度,它们是 "close enough."

如果要比较浮点数,则必须与 epsilon 进行比较。考虑到编译器优化的最新进展,如果您使用 -Ofast,即使是两个 相同的 浮点 C 代码片段也可以在它们的最低有效数字中生成略微不同的值(我们获得了很大的性能允许这样做的好处)。

如果您需要一些特定数量的有效小数位,那么通常最好使用定点表示法。只需按您需要的位数缩放所有内容并以整数形式工作。如果您需要浮点数,但只想以 10 为基数(而不是以 2 为基数)运行良好,则使用 NSDecimalNumberNSDecimal。这会将您的问题转移到以 10 为基数的不好的地方。但是,如果您使用的是浮点数,则必须处理舍入错误。

有关更广泛的讨论,请参阅 "What Every Programmer Should Know About Floating-Point Arithmetic."