double は近似値にすぎないことを理解しています。でも驚いたのは
double f(int x, int y)
{
return double(x)/y;
}
と
double f(int x, int y)
{
double z = double(x)/y;
return z;
}
異なる値を返すことができます。誰かが理由を知っていますか?
double は近似値にすぎないことを理解しています。でも驚いたのは
double f(int x, int y)
{
return double(x)/y;
}
と
double f(int x, int y)
{
double z = double(x)/y;
return z;
}
異なる値を返すことができます。誰かが理由を知っていますか?
「理由」の主な理由は、標準で許可されているためです (ただし、許可されているとは 100% 確信していません)。実際的な理由は、一部のプロセッサ (Intel 32 ビット プロセッサを含む) では、浮動小数点レジスタの精度がdouble
. 中間計算は、適合する場合はレジスターで行われます (そして、標準では明らかに中間結果の精度を高くすることが許可されています)。そのため、指定された式の結果は、コンパイラーがレジスターを管理する方法と、いつメモリにスピルするかによって異なります。そして、そのようなプロセッサ用の多くの (ほとんどの?) コンパイラは、余分な精度を保持するレジスタに浮動小数点値を返します。(これが合法かどうかはわかりません。double を代入するとき、および double を copy 構築するときは、値を適合させる必要があると思います。値を返すことは copy 構築なので、double を適合させる必要があると思います.とにかく...ほとんどのコンパイラはそうではないので、標準がそれについて何を言う必要があるかどうかに関係なく、それに対処する必要があります.)
最終結果を明示的にキャストすることで、これを防ぐことができると思います。
return double( double(x)/y );
、しかし、私にはわかりません(標準がそれについて何を言っているかについても、コンパイラが実際に何をするかについても)。
結果が異なるかどうかは、それらをどう処理するかに多少依存することに注意してください。それらをすぐに に代入するdouble
か、 を必要とする別の関数に渡すdouble
と、丸めが少し遅れて発生するだけです (ただし、同じ値に対して)。ただし、式で値を使用すると、すべての賭けが無効になります。あなたの場合、丸めた後でも、2.0 * f( a, b )
の実装に応じて異なる値になる可能性があります。f
そして最も顕著なのは、f( a, b ) == f( a, b )
false を返す可能性があることです。(これが原因std::sort
でクラッシュするケースを見たことがあります。使用された比較関数は、 の行に沿って何かを
return lhs.f() < rhs.f();
行いtrue
、lhs
とrhs
同じオブジェクトへの参照でした。コンパイラは、呼び出した最初の関数の結果をメモリに書き込んでから、2 番目の関数が返したレジスタ内の値と比較しました。)