2

我写了一段代码,遇到了一个非常奇怪的问题。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 模拟器上对此进行了测试。

4

2 回答 2

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...   

Xcode 5.1 上的 lldb

(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
于 2014-08-29T07:31:04.613 回答
1

您必须使用浮点数来解决问题吗?另一种方法是扩大到 int。如果需要使用浮点值,请将 int 除以 100。

- (void)increment:(NSUInteger)f {
    f += 2;

    if (f > 200) {
        NSLog(@"STOP");
    }
    else {
        [self increment:f];
    }
}
于 2014-08-29T07:40:54.507 回答