web-dev-qa-db-ja.com

乗算は浮動小数点除算よりも高速ですか?

C/C++では、次のコードを設定できます。

double a, b, c;
...
c = (a + b) / 2;

これはまったく同じことを行います:

c = (a + b) * 0.5;

どちらを使用するのが良いのだろうかと思っています。 1つの操作は他の操作よりも基本的に高速ですか?

69
wodesuck

乗算は除算よりも高速です。大学では、除算は乗算の6倍かかると教えられました。実際のタイミングはアーキテクチャに依存しますが、一般的に乗算は除算ほど遅くなることはありません。丸め誤差が許す場合は、乗算を使用するようにコードを常に最適化します。

したがって、例では、これは一般的に遅くなります...

for (int i=0; i<arraySize; i++) {
    a[i] = b[i] / x;
}

... これより ...

y=1/x;
for (int i=0; i<arraySize; i++) {
    a[i] = b[i] * y;
}

もちろん、丸め誤差では、2番目の方法では(少し)精度が低下しますが、x=1/x;それは多くの問題を引き起こす可能性は低いです。

編集:

参照用です。 Googleで検索して、動作タイミングのサードパーティ比較を掘り下げました。

http://gmplib.org/~tege/x86-timing.pdf

MULとDIVの数字を見てください。これは、プロセッサによって5〜10倍の差があることを示しています。

36
Philip Couling

浮動小数点の乗算は、通常、浮動小数点の除算よりも少ないサイクルで済みます。しかし、リテラルオペランドを使用すると、オプティマイザーはこの種のマイクロ最適化を十分に認識します。

25
ouah

この場合、コンパイラーが除算を乗算に変換する可能性が非常に高くなります。浮動小数点での2による除算は、他のフロート除算よりも速い場合があります。コンパイラがそれを変換しない場合、乗算を使用する方が速くなる場合がありますが、確実ではありません-プロセッサ自体に依存します。

コンパイラが「安全」であると判断できない場合、除算の代わりに乗算を手動で使用することによるゲインは非常に大きくなる可能性があります(たとえば、0.1は浮動小数点数で0.1として正確に格納できず、0.10000000149011612になります) )。 AMDプロセッサの数値については、以下を参照してください。これは、クラスの代表とみなすことができます。

コンパイラがこれをうまく行うかどうかを判断するために、実験のために少しコードを書いてみませんか。コンパイラが定数値を計算するだけでなく、ループ内のすべての計算を破棄するように記述してください。

編集:

ファミリー15hプロセッサー向けのAMDの最適化ガイドでは、fdivおよびfmul-42および6の数値をそれぞれ提供しています。 SSEバージョンは少し近いです。DIVPS、DIVPD、DIVSS、DIVSD(除算)の場合は24(シングル)または27(ダブル)サイクル、すべての形式の乗算では6サイクルです。

記憶から、Intelの数字はそれほど遠くない。

24
Mats Petersson