OpenMP Monte_Carlo 模拟实现目标接近 PI

OpenMP Monte_Carlo simulation achieve target closeness to PI

我正在尝试编写一个并行程序,它采用错误率(即 0.01)和 returns 一个 PI 值,它比 montecarlo 模拟的错误更接近 PI。 我写了一个简单的函数,但它不会终止,因为错误率总是在 11 左右。 感谢您的评论。

#include "stdio.h"
#include "omp.h"
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

double drand48(void);

double monte_carlo(double epsilon){
    double x,y, pi_estimate = 0.0;
    double drand48(void);
    double error = 10000.0;
    int n = 0; // total number of points
    int i = 0; // total numbers of points inside circle
    int p = omp_get_num_threads();
    while(error>=epsilon){
        #pragma omp parallel private(x, y) reduction(+:i)//OMP parallel directive
        {
            x = drand48();
            y = drand48();
            if((x*x+y*y)<=1.0){i+=1;}
        }
        n+=p;
        printf("%lf\n", error);
        pi_estimate=4.0*(double)i/(double)n;
        error = fabs(M_PI-pi_estimate)/M_PI;
    }
    return pi_estimate;
}

int main(int argc, char* argv[]) {
    double epsilon = 0.01;
    printf("PI estimate: %lf",monte_carlo(epsilon));
    return 0;
}

在并行部分之外调用 omp_get_num_threads() 将始终 return 1,因为调用该函数时只有一个活动线程。以下代码应该会给出正确的结果,但由于执行一个非常简单的操作需要大量的并行化和同步开销,因此会比串行版本慢得多。

#pragma omp parallel private(x, y) reduction(+:i)//OMP parallel directive
{
    x = drand48();
    y = drand48();
    if((x*x+y*y)<=1.0){i+=1;}
    #pragma omp master
    n+=omp_get_num_threads();
}

以下避免重复生成线程并且可能更高效,但仍然可能更慢。

#pragma omp parallel private(x, y)
while(error>=epsilon){
        x = drand48();
        y = drand48();
        if((x*x+y*y)<=1.0){
            #pragma omp atomic
            i++;
        }
    #pragma omp barrier
    #pragma omp single
    {
        n+=omp_get_num_threads();
        pi_estimate=4.0*(double)i/(double)n;
        error = fabs(M_PI-pi_estimate)/M_PI;
        printf("%lf\n", error);
    } // implicit barrier here
}

为了真正走得更快,应该给出最小迭代次数,例如:

#define ITER 1000
#pragma omp parallel private(x, y)
while(error>=epsilon){
    #pragma omp for reduction(+:i)
    for (int j=1;j<ITER;j++){
        x = drand48();
        y = drand48();
        if((x*x+y*y)<=1.0) i+=1;
    }
    /* implicit barrier + implicit atomic addition
     * of thread-private accumulator to shared variable i
     */

    #pragma omp single
    {
        n+=ITER;
        pi_estimate=4.0*(double)i/(double)n;
        error = fabs(M_PI-pi_estimate)/M_PI;
        printf("%lf\n", error);
    } // implicit barrier
}