2016-11-17 24 views
0

興味深い問題が出てきました。私は、最大12個のCPUコアを持つモンテカルロ法を使ってPiの価値を評価しようとしました。そして私が知ったのは、4コアに比べ12コアを使用した場合、Piの精度が低下したことです。OpenMP、コア数、乱数計算の精度

3.14159 

12コア:

3.1416 

私は、OpenMPを実装している。ここ

は(彼らはそれぞれの新しい実行と繰り返している。すなわち、安定している)の結果

4コアがあります機能付きコード

rand_r() 
乱数生成用の

(これはあまり良くありませんが、スレッドセーフであることが保証されています)。シードはスレッドごとに異なる値を持っていました。

完全なコードが

#include <iostream> 
#include <random> 
#include <ctime> 
#include "omp.h" 
#include <stdlib.h> 

using namespace std; 

unsigned seed; 

int main() 
{ 
double start = time(0); 

int n, N; 
double x, y; 

N = 1<<30; 
n = 0; 

double pi; 

#pragma omp parallel private(x, y, seed) 
{ 
seed = 25234 + 17 * omp_get_thread_num(); 

#pragma omp for reduction(+:n) 
for (int i = 0; i < N; i++) { 

    x = (double) rand_r(&seed)/(double) RAND_MAX; 
    y = (double) rand_r(&seed)/(double) RAND_MAX; 

    if (x*x + y*y <= 1) 
     n++; 
} 
} 
pi = 4. * n/(double) (N); 

cout << pi << endl; 

double stop = time(0); 

cout << (stop - start) << endl; 

return 0; 
} 

であるが、それはコア数を増やしながら、より悪い精度を持って合理的ですか?
乱数生成と何とか結びついていますか(特に、関数rand_rを使って)?
それはfor-loopの配布についてですか?

答えて

1

各スレッドの擬似ランダムシーケンスは固定されており、整数値を合計した値、つまり丸め誤差の原因がないため、スレッド数が変化したときに結果に影響する可能性があるのは疑似ランダムシーケンス内の相関。

rand_rは比較的短期間(比較的短い場合はNの大きな値を指定)の線形合同発生器(LCG)です。擬似ランダムシーケンスの将来は、ジェネレータの最後の出力(隠れ状態ベクトルがない)によって完全に決定されるので、LCGは並列処理にとって最悪の選択である。したがって、発電機の1つが他の発電機の1つのシードと一致する値を生成すると、2つのシーケンスは相関し、モンテカルロプロセスの精度に対する第1のシーケンスの寄与が減少する。それを見る別の方法は、LCGの出力が固定された巡回数列の連続したサブシーケンスであることです。異なるシードは、単純にサブシーケンスを固定されたものの異なる点から開始させる。

より優れた擬似ランダムジェネレータを使用して、最初のシードが相関擬似ランダムシーケンスにならないようにする必要があります。 random_rは、非線形加算器フィードバック生成器を実装しているため、良い候補です。その期間は、2 の反復で十分です。不確かな場合は、Mersenne Twisterジェネレータを使用してください。標準のC++ライブラリ(C++ 11以降)で使用できます。

+0

ありがとうございます。これはまさに私が思ったものです。 – newt