(インテルとAMDのCPUの)三角関数は不要


インテルとAMDのCPUには,三角関数を数値的に計算するための命令が備えられていますが,その結果は正しくありません。たとえば,CPUの命令FCOSの結果とstd::cosでソフトウェア的に計算した結果を比べると,後者の方が真の値に近くなります。

再現のためのコード(FCOSを使う部分だけインラインアセンブラを使っています。)

Core i5 6600とg++ 4.8.4で試した結果はこんな感じです。

x = 0.98233490762409514385
c1 = fcos(x)     = 0.55508189550073283591
c2 = std::cos(x) = 0.55508189550073294694
c  = mp::cos(x)  = 0.555081895500732891425063460345544265145531916268
abs(c - c1) = 5.5512e-17
abs(c - c2) = 5.551e-17

c1 is better: 0
c2 is better: 25
total: 100000

(その正しさをどうやって確かめるのかという問題はありますが)Boost.Multiprecisionで計算した結果と比較すると,命令`FCOS`より`std::cos`の方が正確なようです(Visual Studioの場合はまた違った結果になるようです)。

Pentiumが割り算を間違うといって大騒ぎになったことがありましたが(Pentium FDIV バグ),数値計算はどうせ近似値だからでしょうか,この問題は,ドキュメントに注意書きが追記されただけで,根本的な解決はされないままのようです。

参考:サイン、コサインをインテルの CPU で計算すると少しバグっているらしい

(インテルとAMDのCPUの)三角関数は不要” への3件のコメント

    • 佐久田先生,そういう他人を信用しない方のおかげで,他人を信用できる社会ができていくんですね。

  1. Core i7 5500U + Cygwin64 + GCC 5.4.0 で試してみましたが

    x = 0.64194851165728106235
    c1 = fcos(x) = 0.80093059368438657142
    c2 = std::cos(x) = 0.8009305936843864604
    c = mp::cos(x) = 0.80093059368438651844553907563966573888952735157970728964
    abs(c – c1) = 5.2973e-17
    abs(c – c2) = 5.805e-17

    c1 is better: 4249
    c2 is better: 11
    total: 100000

    全然違う結果となりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です