doubleの精度が-O0だと80ビットで-O3だと64ビットになるケース
誰か同じ罠に嵌る and/or 気づくかと思い「秘密のエントリ」「あとで公開する」としていましたが、だれもハマってくれないようなので公開します。
例のPHPのround問題の関係でgccの-ffloat-storeを試していたのですが、
static double f(double x) { return x * 100.0; } int main() { return f(1.075) >= 107.5; }
というプログラムをコンパイルして動かすと下のようになります。
> uname -mrs Linux 2.6.9-42.0.10.ELsmp i686 > gcc --version gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-8) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > gcc -O0 hoge.c -o hoge && ./hoge ; echo $status 0 > gcc -O3 hoge.c -o hoge && ./hoge ; echo $status 1 > gcc -O0 -ffloat-store hoge.c -o hoge && ./hoge ; echo $status 0 > gcc -O3 -ffloat-store hoge.c -o hoge && ./hoge ; echo $status 1
アセンブリコードを見るとわかるのですが、どうやら-O0のほうではfの返り値がメモリにストアされず、FPUのレジスタ(というかx86なのでスタックマシンですが)に乗ったままで比べられるようです。一方で-O3のほうはfがインライン展開されるので、-ffloat-storeをつければ乗算の結果はメモリにストアされます。また、-O3をつけて-ffloat-storeをつけないと、コンパイル時の定数畳み込みにより、やはり64ビットで結果が計算されます。
要するに「-ffloat-storeか-O0をつければdoubleの精度がすべて64ビットになる」とは限らず、それどころか「-O3を-O0にしたら精度が向上する」こともあるようです。これはgccのバグなのか仕様なのか…? もっと新しいバージョンのgccでどうなるかはまだ試していませんgcc version 4.7.2 (Debian 4.7.2-5)の-m32でも-ffloat-storeをつけないほうは同様の結果になることを確認しました(-O0 -ffloat-storeのほうは1になります)。