5

フロートをループカウンターとして使用し、以下のようなリスクのないプログラムのように、繰り返しごとに小数点以下をインクリメント/デクリメントすることは安全ですか?もちろん、==演算子はdo.butすることは愚かなことです。しかし、 "通常の"目的のための他の比較演算のための浮動小数点数をオペランドとして使うことは何が問題なのですか? "普通"とは、たとえ浮動小数点数がでない場合でも、数値の数値表現の数値表現ではありませんが、0.000000001のようなバリエーションではなく、ほとんどの場合無視できますか?ループカウンタとしてfloat変数を使用するリスクと、非 "=="条件に対して小数点以下の増減を行うリスクはありますか?

しかし、それは言った(でも明らかではない次のプログラムで例えば)、ここで私のapprehension.Supposeある表現は正確ではありません。そして、我々はデクリメントに行くよう5.0は実際に4.999999。だからであります0.5の各繰り返しで、との最後の比較が偽になり、0.000001の差によってループが終了し、現在の出力の最後の行は表示されません。私はあなたが私のドリフトを得ていることを願っています。私は間違っていますか?

#include<stdio.h> 

int main(void) 
{ 
float f; 

for(f=5.0;f>=0;f-=0.5) 
printf("%f\n",f); 
} 

出力:

5.000000 
4.500000 
4.000000 
3.500000 
3.000000 
2.500000 
2.000000 
1.500000 
1.000000 
0.500000 
0.000000 

答えて

11

いいえ、それはあなたの非常に疑問に与えられた理由のために、安全ではありません。

#include<stdio.h> 

int main(void) { 
    float f = 1.0; 

    for(;f>0;f-=0.1) 
    printf("%f\n",f); 
    return 0; 
} 

この例f1.0によって初期化されるときにquite okを動作するようです:この考えてみましょう。しかし、3.0に変更する - と物事が道more interestingかなりすぐに取得するために開始します。

2.600000 
2.500000 
2.400001 
... 
0.000001 

...悪名高い「オフ・バイ・ワン」の失敗につながります。


あなたは>=の代わり>で安全かもしれないと思いますか? again考える:

float f = 5.0; 
for(;f>=1;f-=0.4) 
    printf("%f\n",f); 

... 
3.400000 
3.000000 
2.599999 
2.199999 
1.799999 
1.399999 

...と( 0.99999が1未満であると)我々は再び行くオフずつ。

8

であれば、開始値、減少量との結果として全て減分は、使用しても安全であり、浮動小数点型によって提供される精度内エラーなしで表すことができます。ここで、「エラーなし」とは絶対誤差が0であることを意味し、非常に小さいエラーはまだエラーとみなされます。あなたのケースでは、開始値5.0およびデクリメント量0.5がエラーなしで表すことができる

、及び4.54.03.5は、...、0.0floatの23ビットの精度内でエラーなしでも表すことができます。あなたの場合は安全です。

のは、開始値が4000000.0で、減少量は0.00390625(2 -8)であるとしましょう場合はデクリメントの結果はfloatの23ビット精度に誤差なく表現することができないので、あなたは、困っています開始値と減少量を正しく表現することができます。

しかし、浮動小数点の使用では、積分型の方が信頼性が高い場合は何も表示されません。上記の条件が当てはまるかどうかを確認する際に脳細胞を無駄にする必要はありません。

+0

+1いい回答です。 –

+0

これらの基準はゼロで終了するループに適用されることは明らかです。たとえば、+ Xから-Yまでループする場合、YがXより大きい場合、エラーが発生する可能性があります。 –

+0

@EricPostpischil:結果値が表現可能でなければならないという条件は、そのケースをカバーしていると思いますか? – nhahtdh

6

浮動小数点表現の問題のために可能な限り浮動小数点以上の整数値を推奨します。

の代わりにあなたのループ制御として、浮動小数点数を使用して、整数を使用するようにロジックを修正する:

.5してカウンタをデクリメントする必要がありますか?あなたの開始値とデクリメントは、1ダブルルーム:

float f = 5.0; 
int i = f * 2; 

for(; i >= 0; i--) 
    printf("%f\n", i/2.0); 

.1デクリメントする必要がありますか?

float f = 5.0; 
int i = f * 10; 

for(; i >= 0; i--) 
    printf("%f\n", i/10.0); 

これは、質問の例の簡単なアプローチです。確かに唯一の方法ではなく、最も正しい方法です。より複雑な例では、少し異なるロジックを再加工する必要があります。どんな状況にも合っている。

私の主張実際の浮動小数点値を使用して、表現によるエラーの導入を減らす可能性がある最後の瞬間まで、作業を延期することが前提です。

+0

+1。 –

関連する問題