2014-03-28

なんでGCCはa*a*a*a*a*a を (a*a*a)*(a*a*a) に最適化できないの?っと

c - Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)? - Stack Overflow

俺は科学技術計算の数値計算の最適化をしてたんだけどさ。GCCはpow(a, 2)a*aにしてくれるんだな。うん。で、pow(a, 6)は最適化されずに、ライブラリ関数であるpowを呼んじゃうんだ。パフォーマンス的に最悪。(Intel C++ Compilerはpow(a,6)のライブラリ関数呼び出しを消し去ってくれるんだけどな)

どうもよくわからんのが、pow(a, 6)a*a*a*a*a*aで置き換えて、GCC 4.5.1をオプション"-O3 -lm -funroll-loops -msse4"で使ったら、mulsd命令を5個使う。

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13

だが、(a*a*a)*(a*a*a)と書いたら、出力は、

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13

これは、乗算命令が3個になっている。iccもGCCとほぼ同じだ。

なんでコンパイラーはこれを最適化できないんだ?

答え:浮動小数点数演算では、結果が変わってしまうおそれがあるから。

それは、浮動小数点数は結合法則を満たさないからだ。浮動小数点乗算のオペランドの囲み方により、結果の数値精度に影響を及ぼすからだ。

その結果、ほとんどのコンパイラーは、浮動小数点数演算のリオーダリングに対して極めて保守的なのだ。答えが変わらないと確信できるときや、数値精度を気にしない場合にしか最適化できない。たとえば、GCCの-ffast-mathだ。

c - Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)? - Stack Overflow

GCCに-ffast-mathオプションを指定すると、浮動小数点数演算の誤差を気にしないとコンパイラーに伝えたことになる。このオプションを指定すると、GCCは浮動小数点数の演算に対して、大胆な最適化ができるようになる。もちろん、演算精度に注意しなければならない。

What Every Computer Scientist Should Know About Floating-Point Arithmetic(すべてのコンピューター科学者が浮動小数点数演算について知っておくべきこと)

ドワンゴ広告

この記事はC++とは直接関係がないが、ドワンゴ勤務中に書かれた。

ドワンゴはIEEE 754フォーマットを忘れたくても忘れられない本物のプログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

3 comments:

  1. いやー、ほんとに浮動小数点は色々面倒くさいですね…。
    再現性を考えると、固定小数点で作りたくなりますわほんと。

    ReplyDelete
  2. ↑速度考えたらどう考えても浮動小数点が圧倒しますけどね。
    計算順序なんて目じゃない。

    ReplyDelete
  3. この問題は丸め誤差が原因なので
    固定小数点でも最適化できない問題が起きると
    思います

    例えば、小数点第3位で四捨五入して丸めると
    いうルールで1.5x1.5x1.5x1.5の計算を考えます。
    この時、1.5x1.5x1.5x1.5は5.07で、
    (1.5x1.5)x(1.5x1.5)は5.06になります。
    この結果は固定小数点でも結合法則は
    満たさないことが起きることを示しています。

    なにか勘違いしていたら、訂正願います。

    ReplyDelete

You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.