9

だから私はこのようなものになります機能があります:いくつかの時点で何らかの方法で変数を変更できますか?

float function(){ 
    float x = SomeValue; 
    return x/SomeOtherValue; 
} 

を、この機能は非常に大きな負の値をオーバーフローして返します。

float function(){ 
    float x = SomeValue; 
    cout << x; 
    return x/SomeOtherValue; 
} 

、それが働いた:関数はこのように見えたように試してみて、これが起こっていた場所を正確に追跡するために、私はcoutの文を追加しました!もちろん、私はダブルを使って問題を完全に解決しました。しかし、なぜ私はそれを叫んだときに機能が正常に働いたのか不思議です。これは典型的なことですか、それとも私が行方不明の別の場所にバグがありますか?

(それは任意のヘルプだ場合は、フロートに格納されている値がちょうど整数値ではなく、特に大きなものである。私はちょうど鋳造を回避するために、フロートに入れる。)

答えて

18

浮動小数点の素晴らしい世界へようこそ。あなたが得る答えは、コードをコンパイルした浮動小数点モデルにおそらく依存します。

これは、IEEE仕様とコードが実行されているハードウェアの違いのために発生します。 CPUには、32ビットの浮動小数点値を保持するために使用される80ビットの浮動小数点レジスタがあります。これは、メモリアドレス(レジスタの「原点復帰」とも呼ばれます)に強制されている場合よりも、値がレジスタにとどまっている間に精度がはるかに高いことを意味します。

この値をcoutに渡すと、コンパイラは浮動小数点をメモリに書き込む必要があり、結果として精度が低下し、WRTのオーバーフローが発生する可能性があります。

VC++ floating point switchesに関するMSDNのドキュメントを参照してください。/fp:strictでコンパイルして何が起こっているのか見ることができます。

+0

GCCノートもhttp://gcc.gnu.org/wiki/x87note この素晴らしい動作のために、浮動小数点計算を比較することは、あらかじめ計算された値を使用しない限り、本質的に壊れています。 – hazzen

3

coutに値を印刷パラメタの値を変更するべきではありません。

しかし、私はデバッグステートメントを追加すると、値が変更されるという同様の動作が見られました。これらのケースでは、おそらくこれも私の推測では、追加の文がコンパイラのオプティマイザの動作が異なるため、関数用に異なるコードを生成することになりました。

cout文を追加すると、xの値が直接使用されます。オプティマイザを使用しないと、変数が削除され、計算の順序が変更され、結果が返されます。

0

私はcoutが変数に何らかの影響を与えているとは考えていませんが、問題はどこかにあるはずです。

2

さておき、それはconstを使用して不変の変数を宣言することは常に良い考えだと:他のもののうち、

float function(){ 
    const float x = SomeValue; 
    cout << x; 
    return x/SomeOtherValue; 
} 

、これは意図せずに非constの参照を経由して、それらを変更することができる機能にあなたの変数を渡すことを防止することができます。

1

coutは、変数への参照を引き起こします。これは、コンパイラが強制的にスタックに流出させる原因となることがよくあります。

これは浮動小数点型なので、通常のようにdoubleまたはlong double表現から値が切り捨てられる可能性があります。

ポインタや参照を必要とする関数(インラインでないもの)を呼び出すと、同じ動作が発生するはずですが、後でコンパイラがよりスマートになり、インライン展開することを覚えていれば、同じように悩まされるでしょう:)

関連する問題