代码之家  ›  专栏  ›  技术社区  ›  Tolga

OpenMP蒙特卡罗模拟实现目标接近PI

  •  0
  • Tolga  · 技术社区  · 7 年前

    我正在尝试编写一个并行程序,它接受一个错误率(即0.01),并返回一个比蒙特卡罗模拟的错误更接近PI的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;
    }
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Brice    7 年前

    使命感 omp_get_num_threads() 在平行段外,将始终返回 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
    }
    
    推荐文章