また、命令の組み合わせによっても異なります。あなたのプロセッサにはいつでも複数の計算ユニットが待機しており、すべてが常に満たされていれば最大のスループットを得ることができます。したがって、mulのループを実行するのは、ループや追加を実行するのと同じくらい速いですが、式が複雑になる場合も同じです。
たとえば、このループを取る:NUMITERため
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] ;
}
}
= 10^7、関数numelは=^2 10、小さな正の数(NaNには、はるかに遅い)に初期化両方のアレイが、これは使用して6.0秒かかり64ビットのprocで2倍になります。私は
bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;
とループを交換した場合にのみ、我々は追加の「overdid」以来、MULSは基本的に自由だったので... 1.7秒かかります。追加の削減が助けになりました。同じMULは/ディストリビューションを追加したが、今は定数に追加されたのではなくで乗算され、 - -
bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;
3.7秒をとります。それはのはもっと混乱するかもしれません。お使いのプロセッサは一般的な数値計算をより効率的に実行するように最適化されている可能性がありますだから、麦と秤の合計のようなドット積は、それが得られるほど良くなります。定数の追加はそれほど一般的ではないので、遅いです...
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
命令のミックスは良い点です。私は200の浮動小数点DSPが600個の固定小数点DSPを実行しようとしていると主張している人がいます。ループ処理は絶対に必要なく、I/Oの処理に費やす時間は計算よりも長くなります。より速い固定小数点プロセッサーは全体的な命令ミックスに基づいて勝つだろうが、人々はちょうどFPユニットがデータ構造のハードウェア実装ではなく魔法であると考えている。 – NoMoreZealots
ああ、魔法のappproach ;-) - それは残念です。 –
直感的な例で素敵な説明! –