是的,我已经阅读了有关比较NSNumber的stackoverflow上的其他帖子,但他们似乎都没有完全解决这种特殊情况。
这个解决方案特别糟糕...... NSNumber compare: returning different results
因为建议的解决方案根本不起作用。
使用abs(value1 - value2)<公差从一开始就是有缺陷的,因为小数值被剥离,使公差无关紧要。
从Apple文档中...... NSNumber明确地不保证返回的类型与用于创建它的方法相匹配。换句话说,如果您获得了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将返回false,假设NSNumber的创建是一个黑盒子,可能会在出路时给你一些其他类型,我不确定该方法有多好。
因此,如果您要对脏进行测试,因为现有值已更改为新值...最简单的方法是处理所有NSNumber比较。不只是浮动和加倍,而是所有NSNumbers?
似乎转换为字符串值,然后进行比较将是最有用的,或者可能是使用NSNumberFormatter的大量额外代码。
你有什么想法?
答案 0 :(得分:4)
无法可靠地比较两个IEEE浮点数或双精度数。这与NSNumber
无关。这是浮点的本质。这在Strange problem comparing floats in objective-C处的简单C类型的上下文中讨论。 唯一正确的比较浮点数的方法是通过测试公差。我不知道你的意思是“小数值被剥离了”。在浮点表示中,某些数字总是丢失。
您提供的特定测试值非常好地展示了这些问题。 1.00001不能用有限数量的二进制数字精确表示。 Wolfram Alpha是探索此问题的好方法,但作为双倍,1.00001回合到1.0000100000000001。作为一个浮点数,它舍入到1.00001001。显然,这些数字并不相同。如果您以不同的方式往返它们,isEqualToNumber:
失败并不会让您感到惊讶。这应该明确为什么你的两个floatValue
电话确实是平等的。圆形到浮动的精度,它们“足够接近。”
如果要比较浮点数,则必须与epsilon进行比较。鉴于编译器优化的最新进展,如果使用-Ofast
,即使两个相同的浮点C代码也会在其最低有效数字中生成稍微不同的值(我们通过允许获得了很大的性能优势)这一点)。
如果您需要一些特定数量的重要小数位数,那么通常最好使用定点符号。只需按照您需要的位数来缩放所有数字,然后使用整数。如果你需要浮点数,但只想让base-10运行良好(而不是base-2),那么使用NSDecimalNumber
或NSDecimal
。这将把你的问题转移到基础10中严重的问题。但是如果你在浮点工作,你必须处理舍入错误。
有关更广泛的讨论,请参阅"What Every Programmer Should Know About Floating-Point Arithmetic."