[解決済み] 0.1fを0にすると、なぜ10倍もパフォーマンスが落ちるのですか?
質問
なぜ、このようなコードがあるのか。
const float x[16] = { 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8,
1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
1.923, 2.034, 2.145, 2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
y[i] = x[i];
}
for (int j = 0; j < 9000000; j++)
{
for (int i = 0; i < 16; i++)
{
y[i] *= x[i];
y[i] /= z[i];
y[i] = y[i] + 0.1f; // <--
y[i] = y[i] - 0.1f; // <--
}
}
は、次のビット(特記事項以外は同一)よりも10倍以上高速に実行できますか?
const float x[16] = { 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8,
1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
1.923, 2.034, 2.145, 2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
y[i] = x[i];
}
for (int j = 0; j < 9000000; j++)
{
for (int i = 0; i < 16; i++)
{
y[i] *= x[i];
y[i] /= z[i];
y[i] = y[i] + 0; // <--
y[i] = y[i] - 0; // <--
}
}
Visual Studio 2010 SP1 でコンパイルした場合。
最適化レベルは
-02
と
sse2
を有効にします。
他のコンパイラではテストしていません。
解決方法は?
の世界へようこそ。 非正規化浮動小数点 ! パフォーマンスに大打撃を与える可能性があります!!!
非正規数(または準正規数)は、浮動小数点表現からゼロに非常に近い余分な値を得るためのハックのようなものです。非正規化された浮動小数点に対する演算は、以下のようになります。 数十倍から数百倍遅くなる は、正規化された浮動小数点の場合よりも優れています。これは、多くのプロセッサがこれらを直接処理できず、マイクロコードを使ってトラップして解決しなければならないからです。
10,000回繰り返した後の数値をプリントアウトしてみると、以下のようにそれぞれ異なる値に収束していることがわかります。
0
または
0.1
が使用されます。
以下は、x64でコンパイルしたテストコードです。
int main() {
double start = omp_get_wtime();
const float x[16]={1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4,2.5,2.6};
const float z[16]={1.123,1.234,1.345,156.467,1.578,1.689,1.790,1.812,1.923,2.034,2.145,2.256,2.367,2.478,2.589,2.690};
float y[16];
for(int i=0;i<16;i++)
{
y[i]=x[i];
}
for(int j=0;j<9000000;j++)
{
for(int i=0;i<16;i++)
{
y[i]*=x[i];
y[i]/=z[i];
#ifdef FLOATING
y[i]=y[i]+0.1f;
y[i]=y[i]-0.1f;
#else
y[i]=y[i]+0;
y[i]=y[i]-0;
#endif
if (j > 10000)
cout << y[i] << " ";
}
if (j > 10000)
cout << endl;
}
double end = omp_get_wtime();
cout << end - start << endl;
system("pause");
return 0;
}
出力します。
#define FLOATING
1.78814e-007 1.3411e-007 1.04308e-007 0 7.45058e-008 6.70552e-008 6.70552e-008 5.58794e-007 3.05474e-007 2.16067e-007 1.71363e-007 1.49012e-007 1.2666e-007 1.11759e-007 1.04308e-007 1.04308e-007
1.78814e-007 1.3411e-007 1.04308e-007 0 7.45058e-008 6.70552e-008 6.70552e-008 5.58794e-007 3.05474e-007 2.16067e-007 1.71363e-007 1.49012e-007 1.2666e-007 1.11759e-007 1.04308e-007 1.04308e-007
//#define FLOATING
6.30584e-044 3.92364e-044 3.08286e-044 0 1.82169e-044 1.54143e-044 2.10195e-044 2.46842e-029 7.56701e-044 4.06377e-044 3.92364e-044 3.22299e-044 3.08286e-044 2.66247e-044 2.66247e-044 2.24208e-044
6.30584e-044 3.92364e-044 3.08286e-044 0 1.82169e-044 1.54143e-044 2.10195e-044 2.45208e-029 7.56701e-044 4.06377e-044 3.92364e-044 3.22299e-044 3.08286e-044 2.66247e-044 2.66247e-044 2.24208e-044
2回目の実行では、数値がゼロに非常に近くなっていることに注目してください。
非正規化された数値は一般にまれであるため、ほとんどのプロセッサは効率的に処理しようとしない。
これが非正規化された数と関係があることを示すために、次のようにすると デノーマルをゼロにする を、コードの先頭に追加してください。
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
というバージョンでは
0
は、もはや10倍も遅くはなく、むしろ速くなるのです。(これには、SSEを有効にしてコンパイルする必要があります)。
つまり、低精度のほぼゼロという奇妙な値を使うのではなく、代わりにゼロに丸めるだけなのです。
タイミング Core i7 920 @ 3.5 GHz。
// Don't flush denormals to zero.
0.1f: 0.564067
0 : 26.7669
// Flush denormals to zero.
0.1f: 0.587117
0 : 0.341406
結局、これは整数か浮動小数点かは関係ないんです。そのため
0
または
0.1f
は、両方のループの外側でレジスタに変換/格納されます。そのため、パフォーマンスには影響がありません。
関連
-
[解決済み】C++エラー。アーキテクチャ x86_64 に対して未定義のシンボル
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み] 数値定数の前にunqualified-idを付けて、数値を定義することを期待する。
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
-
[解決済み] なぜPythonのコードは関数の中でより速く実行されるのですか?
-
[解決済み] 8192個の要素にループをかけると、プログラムが遅くなるのはなぜですか?
-
[解決済み] Math.round(0.4999999999994) はなぜ1を返すのですか?
-
[解決済み】sumの順番を変えると違う結果になるのはなぜですか?
-
[解決済み】C++のコンパイルにはなぜそんなに時間がかかるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】'std::cout'への未定義の参照