double
演算子を使用して C++ で値を比較する場合、<,>,=,!=
常に結果の正確性を確認できるとは限りません。そのため、他の手法を使用して を比較doubles
します。たとえば、2 つの double の a と b を比較して、それらの差が本当にゼロに近いかどうかをテストできます。私の質問は、C++ 標準ライブラリがこれらの手法を実装std::less<double>
しstd::greater<double>
て使用しているのか、それとも安全でない比較演算子を使用しているだけなのかということです。
4 に答える
operator<
operator>
少なくとも可能な限り、正しい結果が得られます。ただし、浮動小数点演算の使用にはいくつかの基本的な問題があり、特にdouble
. これらは、現在のCPUで使用されている浮動小数点表現に固有のものであるため、言及した比較関数を使用しても削減されません。
関数std::less
/std::greater
については、標準演算子のパッケージ バージョンに過ぎず、STL アルゴリズムで二項述語が必要な場合に使用することを目的としています。
値は 64 ビットで表現されdouble
ますが、Intel CPU の元の「double」演算は 80 ビットで行われます。最初は「無料で」精度を上げるのは良いことのように思えますが、コンパイラが FPU レジスタ (80 ビット) から直接中間結果を使用できるようにするか、メモリに書き戻された値から中間結果を使用できるようにするかによって、結果が異なることも意味します。 (64 ビットに丸められます)。この種の最適化は完全にコンパイラ次第であり、どの標準でも定義されていません。
物事をより複雑にするために、最新のコンパイラは新しいベクトル命令 (MMX / SSE) を利用することもできますが、これも 64 ビットのみです。上記の問題は、このコンテキストでは発生しません。ただし、これらの命令を浮動小数点演算に使用するかどうかは、コンパイラによって異なります。
差が仮数の最後のビットのみにある場合、ほぼ等しい値の小さい/大きいの比較は常に問題になります。それらは常に切り捨てエラーの影響を受けるため、プログラムが次の結果に批判的に依存していないことを確認する必要があります。非常に近い値の比較。たとえば、差がしきい値よりも小さい場合、それらを等しいと見なすことができますif (fabs(a - b)/a < factor*DBL_EPSILON) { /* EQUAL */ }
。DBL_EPSILON
は で定義されておりfloat.h
、factor
切り捨て/丸めの可能性のある数学的操作が以前に行われた回数に依存し、徹底的にテストする必要があります。前後の値で安全ですfactor=16..32
が、走行距離は異なる場合があります。