2017-10-10 6 views
1

私は時間配列が必要な小さなODEソルバをプログラミングしていたとき、次のような本当に奇妙な動作に終わった。次のコードでは、問題を明確に再現する必要があります。<=と==演算子がループを終了するために正しく動作しない

#include <iostream> 
using namespace std; 

int main() { 
    double t = 0.0; 
    for (t = 0.0; t <= 1.00; t += 0.01) { 
     cout << t << " "; 
    } 
    cout << endl; 

    cout << "t = "<< t << " and t <= 1.00? " << (t <= 1.00) << endl; 
    double c = 1.00; 
    cout << "c = "<< c << " and c <= 1.00? " << (c <= 1.00) << endl; 
    cout << "t == 1.00? " << (t == 1.00) << " and c == 1.00? " << (c == 1.00) << endl; 
    return 0; 
} 

これは次のように出力できます:

0 0.01 0.02 0.03 0.04 ... 0.97 0.98 0.99 
t = 1 and t <= 1.00? 0 
c = 1 and c <= 1.00? 1 
t == 1.00? 0 and c == 1.00? 1 

私の質問は:tははっきり1と同じである必要がありながら、なぜ(トン< = 1.00)とさ(t == 1.00)がfalseを返すんをし、 tはdouble型ですか?

私は本当に私のT-ステップは、ハードなどをコード化されていない、私の実際のコードでは、この問題の原因を避けることができない...

は事前にありがとうございます。

編集:回答ありがとうございます。実際、0.01などのバイナリ表現の問題は正確ではなく、ある程度の丸め誤差を伴います。 tスケールは、プログラムの他の物理量によって実際に強制されました。その間に私が他に持っていた別の答え/ヒントは、浮動小数点メンバーを使って作業する必要がある場合、常に許容値で作業することでした。この場合、アプリケーションで必要とされるように可変精度hで作業する場合、「t < = 1.00」は「t < 1.00 + 0.01/2」またはより一般的な「t < 1.00 + h/2」になる可能性があります。

+0

tobi303 @:偽得になっています。それが真であれば、ループは止まらないでしょう。 ( 'c <= 1.00'が真であるのは、' c!= t'のためです。) – user2357112

+0

@ user2357112ええ、私はちょうど私の愚かさを認識しました。浮動小数点数がうまくいけないことを考慮すると、期待通りです。 – user463035818

+0

'main'の最初に' cout.precision(17); 'を追加してみてください。問題は明らかになります。 )。累積誤差を四捨五入する小数点以下の桁数を表示しています。 –

答えて

2

浮動小数点演算は期待通りに機能しません。

t <= 1.00 

tdoubleで、0.00から0.01が1.00に正確に等しいが、それにほぼ等しいではありません100回を追加し、結果として:

犯人は、forループであなたの状態です。

あなたはこの方法を解決することができます:

int t; 
for (t = 0; t <= 100; t++) { 
    std::cout << static_cast<double>(t)/100 << " "; 
} 

そして:

std::cout << "t = "<< static_cast<double>(t)/100 << " and t <= 1.00? " << (static_cast<double>(t)/100 <= 1) << std::endl; 
関連する問題