我写了一段代码,遇到了一个非常奇怪的问题。即使实际比较为真,两个浮点数之间的比较也会返回NO
。我甚至通过与FLT_EPSILON
进行比较来使用安全浮点比较。这是代码:
//To start the process run this:
[self increment:0.0f];
- (void)increment:(float)f {
f += 0.02f;
if ((fabs(f - 1.0f) < FLT_EPSILON)) {
NSLog(@"STOP");
}
else {
NSLog(@"F %f", f);
[self increment:f];
}
}
比较将始终失败,代码将进入无限循环。我已经在iOS 7上的32位设备和iOS 8上的iPhone 5S模拟器上进行了测试。
答案 0 :(得分:3)
问题是您正在积累不精确的值。 FLT_EPSILON
应定义为最小值1.0f + FLT_EPSILON != 1.0f
。
在每一步中,您将有限精度值添加到另一个有限精度值,并累积一个小错误。由于您正在检查一个足够接近1.0f
的值,以便与1.0f
无法区分,因此检查总是失败。
如果你需要在1.0停止,你应该直接检查if (f > 1.0f)
,或使用更宽松的约束。请注意,如果值在所需值之前稍微增加,则使用f > 1.0f
可能会产生额外的迭代,因此如果迭代量必须精确,则可能不合适。像f > 1.0 - 0.02f/2
这样的东西应该更精确。
0.98 1.0-0.02/2 1.0
| | ACCEPTABLE | ACCEPTABLE...
lldb on Xcode 5.1
(lldb) p f
(float) $0 = 0.999999582
(lldb) p -(f - 1.0f)
(float) $1 = 0.000000417232513
(lldb) p __FLT_EPSILON__
(float) $2 = 0.00000011920929
(lldb) p (-(f - 1.0)) < __FLT_EPSILON__
(bool) $3 = false
答案 1 :(得分:1)
你必须使用花车来解决问题吗?另一种方法是扩展到int。如果需要使用浮点值,则将int除以100。
- (void)increment:(NSUInteger)f {
f += 2;
if (f > 200) {
NSLog(@"STOP");
}
else {
[self increment:f];
}
}