木村です. 下記のようなトラブルに遭遇しました.調べた限りではこの問題は 報告されていないので,この ML で情報を募りたくメール致しました.
1. 状況 FreeBSD 5.3 + gcc(3.4.2) で作成した,拡張倍精度 (long double) を使ったプログラムを FreeBSD 6.2 + gcc(3.4.6) にて使用すると, 結果が違いました.検討した末,以下のことが分かりました. gcc に -m96bit-long-double (default) と -m128bit-long-double の option を付けた場合を各々 96bit, 128bit と書くことにしますと, (1) FreeBSD 5.3 (96, 128bit), FreeBSD 6.2 (128bit) の三者の 結果は同じになる. (2) FreeBSD 6.2 (96bit) の場合,(1) よりも概して精度が悪い. 2. 原因 この問題の生じ方を探りますと,「FreeBSD 6.2 において拡張倍 精度として 96bit を使うと,式の中の定数の精度が double に 落とされてしまう」ことに起因していることが分かりました. (この段階では「原因」とは言えないでしょうが.) 例えば,こんな使い方をした場合です. x = 3.14159265358979323846L; x = sqrtl(1.5L); 参考までに,この問題の簡単な確認法を示します. main(void) { double c; long double lc; c = 3.14159265358979323846; lc = 3.14159265358979323846L; } これを s.c とし,二通りにコンパイルしてアセンブラを出力します. % gcc -m96bit-long-double -S s.c -o s1.a % gcc -m128bit-long-double -S s.c -o s2.a 両者のアセンブラの,この数値に関連した部分は次のようになります. (ちなみに,FreeBSD 5.3 の二つと,FreeBSD 6.2 にて -m128bit-long-double を規定した場合の三者は同じです.) 変数 c .long 1413754136 ← 仮数部 (2) .long 1074340347 ← 符合,指数部,仮数部 (1) が混在 変数 lc movl $560513024, %eax ← 仮数部 (2). 128bit では $560513589 movl $-921707870, %edx ← 仮数部 (1) movl $16384, %ecx ← 符合と指数部 この数値から double の変数 c の仮数部 (mant) を求めると次のようになります. double : 1074340347 1413754136 mant = 09 21 fb 54 44 2d 18 これを long double の変数 lc の仮数部と比較するために, 左に 3bit シフトして,かつ最上位の 1bit を立てます. それと lc の 96, 128bit の場合の仮数部を並記すると次のようになります. double : mant = c9 0f da a2 21 68 c0 96bit : -921707870 560513024 mant = c9 0f da a2 21 68 c0 00 128bit : -921707870 560513589 mant = c9 0f da a2 21 68 c2 35 すなわち,96bit の拡張倍精度の場合,定数の精度が倍精度に落とされ てしまっています. 3. お願い 以下の二点を確認して,必要ならば send-pr しようと思います. (1) これは bug なのか,隠れ compile option などがあるのか? (2) bug であったとして,FreeBSD 6.3 や 7.0 でもこの問題は起き 続けているのか? (これらはうちにないので確認できません.) 先ず,(1) について御存じの方,情報をお願い致します. Satoshi Kimura ([メールアドレス保護])