2

私はコードを書き、本当に奇妙な問題に遭遇しました。2 つの float 間NOの比較は、実際の比較が true の場合でも返されます。と比較して、安全な浮動小数点比較も使用しました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 にスケールアップすることです。float 値を使用する必要がある場合は、int を 100 で割ります。

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

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