浮動小数点加算と浮動小数点加算の相対速度はどれくらいですか?浮動小数点乗算

StackOverflow https://stackoverflow.com/questions/1146455

質問

10 年か 2 年前は、乗算と除算の使用を避け、代わりに加算と減算を使用する数値コードを作成する価値がありました。良い例は次のとおりです 前方差異 多項式を直接計算する代わりに多項式曲線を評価します。

これは今でも当てはまるのでしょうか、それとも、*、/ が +、- の何倍も遅くないところまで現代のコンピューター アーキテクチャが進歩したのでしょうか?

具体的に言うと、ソフトウェアで FP を実行しようとする小さなマイクロではなく、大規模なオンボード浮動小数点ハードウェアを備えた現代の一般的な x86 チップ上で実行されるコンパイル済みの C/C++ コードに興味があります。パイプライン処理やその他のアーキテクチャの強化により、特定のサイクル数が除外されることは理解していますが、それでも有益な直感を得ることができればと考えています。

役に立ちましたか?

解決

また、命令ミックスに依存します。あなたのプロセッサは、任意の時点で待機複数の演算ユニットを持つことになりますし、それらのすべては、すべての時間を満たされている場合は、最大スループットを得るでしょう。だから、MULのループを実行すると同じように高速ループを実行するようであるか追加されます - しかし、式が複雑になる場合も同じことが保持していない

たとえば、このループを取ります:

for(int j=0;j<NUMITER;j++) {
  for(int i=1;i<NUMEL;i++) {
    bla += 2.1 + arr1[i] + arr2[i] + arr3[i] + arr4[i] ;
  }
}

NUMITER = 10 ^ 7のために、= 10 ^ 2 numelの、小さな正数に初期化両方の配列は、(NaNには、はるかに遅い)、これは64ビットのPROCにダブルスを使用して6.0秒を要します。私はループを交換する場合は、

bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;

これは、わずか1.7秒かかります...私たちは追加を「overdid」以来、MULSは基本的に自由でした。そして、追加の減少が助けました。それを得るのさらに混乱ます:

bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;

- 同じMUL /は、ディストリビューションを追加したが、今は定数に追加されたのではなくで乗算され、 - 3.7秒かかります。お使いのプロセッサは、おそらくより効率的に、典型的な数値計算を実行するために最適化されています。そうMULSの合計とスケールの合計のようなドット積は、それを取得と同じくらい良いです。定数を追加することが遅くなりますので...

、ほぼ同じ一般的ではありません
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; /*someval == 2.1*/

再び1.7秒かかります。

bla += someval + arr1[i] + arr2[i] + arr3[i] + arr4[i] ; /*someval == 2.1*/

(最初のループと同様、高価定数添加なし:2.1秒)

bla += someval * arr1[i] * arr2[i] * arr3[i] * arr4[i] ; /*someval == 2.1*/

(主にMULS、しかし、1つの追加:1.9秒)

だから、基本的には、それが速くなると言うのは難しいですが、あなたはボトルネックを回避したい場合は、より重要なのは、まともなミックスを持っているNaNまたはINFを避けるため、定数を加算しないようにすることです。多くの場合、小さな変化だけで違いを作ることができるので、何をするにしても、あなたがテストし、様々なコンパイラ設定をテストすることを確認します。

いくつかのより多くのケースます:

bla *= someval; // someval very near 1.0; takes 2.1 seconds
bla *= arr1[i] ;// arr1[i] all very near 1.0; takes 66(!) seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; // 1.6 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, 2.2 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, floats 2.2 seconds
bla += someval * arr1[i]* arr2[i];// 0.9 in x64, 1.6 in x86
bla += someval * arr1[i];// 0.55 in x64, 0.8 in x86
bla += arr1[i] * arr2[i];// 0.8 in x64, 0.8 in x86, 0.95 in CLR+x64, 0.8 in CLR+x86

他のヒント

理論的には、情報は次のとおりです。

インテル® 64 および IA-32 アーキテクチャー最適化リファレンス・マニュアル、付録 C 命令レイテンシーとスループット

リストされているすべてのプロセッサについて、FMUL のレイテンシは FADD または FDIV のレイテンシに非常に近いです。一部の古いプロセッサでは、FDIV は 2 ~ 3 倍遅くなりますが、新しいプロセッサでは FMUL と同じになります。

注意事項:

  1. 実際、私がリンクした文書には、プロセッサーは、それが正しければ処理を高速化するために必要なことを実行するため、現実にはこれらの数値に頼ることはできないと述べています。

  2. コンパイラが、浮動小数点乗算/除算が利用できる多くの新しい命令セットの 1 つを使用することを決定する可能性が高くなります。

  3. これはコンパイラ作成者だけが読むことを意図した複雑なドキュメントなので、私が間違っている可能性があります。一部の CPU で FDIV レイテンシの数値が完全に欠落している理由がわかりません。

この質問に答える最善の方法は、実行する必要がある処理のベンチマーク/プロファイルを実際に作成することです。可能な限り、理論よりも経験を使用する必要があります。特にそれが簡単に達成できる場合。

実行する必要がある Math のさまざまな実装をすでに知っている場合は、その Math を変換するいくつかの異なるコードを作成して、パフォーマンスがどこでピークに達するかを確認できます。これにより、プロセッサ/コンパイラはさまざまな実行ストリームを生成してプロセッサ パイプラインを満たし、答えに対する具体的な答えを得ることができます。

特に DIV/MUL/ADD/SUB タイプの命令のパフォーマンスに興味がある場合は、インライン アセンブリを組み込んで、これらの命令のどのバリアントが実行されるかを具体的に制御することもできます。ただし、システムが実現できるパフォーマンスを十分に把握するには、複数の実行ユニットをビジー状態に保つ必要があります。

また、このようなことを行うと、同じプログラムを実行するだけで、複数のプロセッサーのバリエーションでパフォーマンスを比較できるようになり、マザーボードの違いを考慮に入れることもできます。

編集:

+- の基本的なアーキテクチャは同じです。したがって、論理的には計算にかかる時間は同じになります。* 一方、単一の演算を完了するには、通常は「全加算器」で構成される複数の層が必要です。これにより、* はサイクルごとにパイプラインに発行できますが、加算/減算回路よりも待ち時間が長くなることがわかります。fp / 演算は通常、時間の経過とともに正解に向かって反復的に収束する近似法を使用して実装されます。これらのタイプの近似は通常、乗算によって実装されます。したがって、浮動小数点の場合、乗算 (それ自体がすでに大きな回路である) を多数の乗算回路のパイプラインに「展開」するのは非現実的であるため、一般に除算には時間がかかると想定できます。それでも、特定のシステムのパフォーマンスはテストによって測定するのが最も効果的です。

私は決定的な参照を見つけることができませんが、部門は(「何度も」遅くなり、どちらかではない)ではありませんしながら、大規模な実験は、そのフロート乗算は、今日だけ加算と減算と同じ速度程度であると言われます。あなたがあなた自身の実験を実行することによってのみ希望直感を得ることができます - として、あなたがタイミングを開始する前にそれらを読んで、事前に乱数(それらの何百万)を生成し、他のプロセスの実行中に(CPUのパフォーマンスカウンタを使用することを忘れないでくださいあなたは正確な測定のため)からそれらを停止することができますようくらい!

+対* /の速度差 - あなたのプロセッサアーキテクチャに依存します。一般とx86で、特に速度差が少ない現代のプロセッサとなってきています。 *、+に近いものでなければならないとき、疑問がある:ちょうど実験。あなたはFP操作のたくさんの本当に難しい問題がある場合も、ベクトルプロセッサとして動作し、あなたのGPU(GeForceは、...)を使用することを検討します。

乗算と加算の間の時間にはほとんど違いはおそらくあります。一方、部門は、その再帰的性質の乗算その後、まだかなり遅いです。 上の近代的なx86アーキテクチャのSSE命令がfpu.Thoughに良いCを使用してというし、浮動小数点演算を行うとき/ C ++コンパイラはあなたの代わりに、FPUのSSEを使用するオプションを与えるべきであると考えるべきである。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top