OpenMP,核心数和随机数计算的准确性

时间:2016-11-17 12:57:46

标签: multithreading random parallel-processing openmp

我遇到了有趣的问题。我尝试使用Monte-Carlo方法评估Pi的值,最多12个CPU内核。我发现的是,与使用4个核心相比,使用12个核心时,Pi的准确度会降低。

以下是结果(稳定,即每次新运行都重复)

4核:

3.14159

12核:

3.1416

我已经使用函数

实现了OpenMP代码
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 个答案:

答案 0 :(得分:1)

由于每个线程中的伪随机序列是固定的,并且您在整数值上求和,即没有出现舍入误差源,因此当线程数改变时唯一可能影响结果的是伪随机序列中的相关性。

rand_r是一个线性同余生成器(LCG),周期相对较短(给定N的较大值时相对较短)。 LCG是并行处理的最差选择,因为伪随机序列的未来完全由发生器的最后输出确定(没有隐藏状态向量)。因此,一旦一个发生器产生与其他发生器之一的种子匹配的值,则两个序列变得相关,并且第一序列对蒙特卡罗过程的精度的贡献减小。另一种看待它的方法是LCG的输出是一些固定的循环数字序列的连续子序列。不同的种子只是使子序列从固定的不同点开始。

您应该使用更好的伪随机生成器,并确保初始播种不会导致相关的伪随机序列。 random_r是一个很好的候选者,因为它实现了非线性附加反馈生成器。它的周期应足够长,以便进行2次 30 次迭代。如有疑问,请使用Mersenne Twister发电机。它在标准C ++库中提供(自C ++ 11开始)。