次のコードがあります。
#include <cstdio>
int main()
{
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
gcc (4.4、4.5、および 4.6) を使用して O3 でコンパイルし、ネイティブ (ubuntu 10.10) で実行すると、「等しい」という期待される結果が出力されます。
ただし、同じコードを上記のようにコンパイルして仮想マシン (ubuntu 10.10、virtualbox イメージ) で実行すると、「等しくない」と出力されます。これは、O3 フラグと O2 フラグが設定されているが、O1 以下では設定されていない場合です。clang (O3 および O2) でコンパイルし、仮想マシンで実行すると、正しい結果が得られます。
double を使用して 1.1 を正しく表現できないことを理解しており、 「すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと」を読んだので、そこを指摘しないでください。これは、GCC が行うある種の最適化のようです。どういうわけか、仮想マシンでは機能しないようです。
何か案は?
注: C++ 標準では、この状況での型の昇格は実装に依存すると述べています。GCC は、不等式テストが適用されたときに真を保持する、より正確な内部表現を使用している可能性があります-余分な精度のために?
UPDATE1:上記のコードを次のように変更すると、正しい結果が得られるようになりました。ある時点で、何らかの理由で GCC が浮動小数点制御ワードをオフにしているようです。
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
set_dpfpu();
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
UPDATE2:コードの const 式の性質について尋ねる人のために、次のように変更しましたが、GCC でコンパイルするとまだ失敗します。-しかし、オプティマイザーが次のものもconst式に変換している可能性があると思います。
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
//set_dpfpu(); uncomment to make it work.
double d1 = 1.0;
double d2 = 1.0;
if ((d1 + 0.1) != (d2 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
UPDATE3 解決策: virtualbox をバージョン 4.1.8r75467 にアップグレードすると、問題が解決しました。ただし、1 つの問題が残っています。つまり、clang ビルドが機能した理由です。