ifステートメントをに変更します(s >= 1.0 || s == 0.0)
。さらに良いbreak
ことに、次の例に示すように、複素数のペア(u、v)を返すSIMDガウス乱数を生成するためにを使用します。これは、メルセンヌツイスター乱数ジェネレーター dsfmt()
を使用します。単一の実数の乱数のみが必要な場合は、戻り値のみを返し、次のパスu
のためにを保存します。v
inline static void randn(double *u, double *v)
{
double s, x, y; // SIMD Marsaglia polar version for complex u and v
while (1){
x = dsfmt_genrand_close_open(&dsfmt) - 1.;
y = dsfmt_genrand_close_open(&dsfmt) - 1.;
s = x*x + y*y;
if (s < 1) break;
}
s = sqrt(-2.0*log(s)/s);
*u = x*s; *v = y*s;
return;
}
このアルゴリズムは驚くほど高速です。4つの異なるガウス乱数ジェネレーターの2つの乱数(u、v)を計算するための実行時間は次のとおりです。
Times for delivering two Gaussian numbers (u + iv)
i7-2600K @ 4GHz, gcc -Wall -Ofast -msse2 ..
gsl_ziggurat = 20.3 (ns)
Box-Muller = 78.8 (ns)
Box-Muller with fast_sin fast_cos = 28.1 (ns)
SIMD Marsaglia polar = 35.0 (ns)
Charles K. Garrettのfast_sinおよびfast_cos多項式ルーチンは、cos()およびsin()のネストされた多項式実装を使用して、ボックスミュラー計算を2.9倍高速化します。SIMDボックスミュラー法と極座標アルゴリズムは確かに競争力があります。また、それらは簡単に並列化できます。gcc -Ofast -Sを使用すると、アセンブリコードダンプは平方根がSIMD SSE2であることを示します:sqrt-> sqrtsd%xmm0、%xmm0
コメント:gcc5で正確なタイミングを取得するのは本当に難しくてイライラしますが、これらは問題ないと思います:2016年2月3日現在:DLW
[1]関連リンク:cmalloc配列ポインターがcythonで返される
[2]アルゴリズムの比較。ただし、SIMDバージョンである必要はありません:http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf
[3] Charles K. Garrett: http: //krisgarrett.net/papers/l2approx.pdf