蒙特卡洛方法计算圆周率的三种实现-MPI openmp pthread

蒙特卡洛方法实现计算圆周率的方法比较简单,其思想是假设我们向一个正方形的标靶上随机投掷飞镖,靶心在正中央,标靶的长和宽都是2 英尺。同时假设有一个圆与标靶内切。圆的半径是1英尺,面积是π平方英尺。如果击中点在标靶上是均匀分布的(我们总会击中正方形),那么飞镖击中圆的数量近似满足等式

飞镖落在圆内的次数/飞镖落在标靶内的总次数=π/4

因为环包含的面积与正方形面积的比值是π/4。

因为环所包含的面积与正方形面积的比值是π/4。

我们可以用这个公式和随机数产生器来估计π的值。

伪代码如下:

number_in_circle=0;
for(toss=0;toss<number_of_tosses;toss++){
     x=random double between -1 and 1;
     y=random double between -1 and 1;
     distance_squared=x*x+y*y;
    if(distance_squared<=1) number_in_cycle++;
}
pi_estimate=4*number_in_cycle/((double)number_in_tosses);

这种采用了随机(随机投掷)的方法称为蒙特卡洛(Monte Carlo)方法。

编写了一个采用蒙特卡洛方法的MPI,Pthread,OpenMP程序估计π的值。

使用MPI编写时,进程0读取总的投掷次数,并把它们广播给各个进程。使用MPI_Reduce求出局部变量number_in_cycle的全局总和,并让进程0打印它。

使用Pthread编写时,有主线程读入总的投掷数,然后输出估算值。

使用OpenMP编写时,在开启任何线程前读取总的投掷次数。使用reduction子句计算飞镖集中环内的次数。在合并所有的线程后,打印结果。

这三个程序中,投掷次数可能都非常大,可能总的投掷次数和击中环内的次数都得用long int型来表示。

下面是MPI程序代码

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<math.h>
 4 #include<time.h>
 5 #include<mpi.h>
 6 void read_num(long long int *num_point,int my_rank,MPI_Comm comm);
 7 void compute_pi(long long int num_point,long long int* num_in_cycle,long long int* local_num_point,int comm_sz,long long int *total_num_in_cycle,MPI_Comm comm,int my_rank);
 8 int main(int argc,char** argv){
 9     long long int num_in_cycle,num_point,total_num_in_cycle,local_num_point;
10     int my_rank,comm_sz;
11     MPI_Comm comm;
12     MPI_Init(NULL,NULL);//初始化
13     comm=MPI_COMM_WORLD;
14     MPI_Comm_size(comm,&comm_sz);//得到进程总数
15     MPI_Comm_rank(comm,&my_rank);//得到进程编号
16     read_num(&num_point,my_rank,comm);//读取输入数据
17     compute_pi(num_point,&num_in_cycle,&local_num_point,comm_sz,&total_num_in_cycle,comm,my_rank);
18     MPI_Finalize();
19     return 0;
20 }
21 void read_num(long long int* num_point,int my_rank,MPI_Comm comm){
22     if(my_rank==0){
23         printf("please input num in sqaure \n");
24         scanf("%lld",num_point);
25     }
26     /*
27     广播函数
28     int MPI_Bcast(
29         void*    data_p //in/out
30         int    count  //in
31         MPI_Datatype    datatype //in
32         int    source_proc  //in
33         MPI_Comm    comm  //in
34     )
35     */
36     MPI_Bcast(num_point,1,MPI_LONG_LONG,0,comm);
37
38 }
39 void compute_pi(long long int num_point,long long int* num_in_cycle,long long int* local_num_point,int comm_sz,long long int *total_num_in_cycle,MPI_Comm comm,int my_rank){
40     *num_in_cycle=0;
41     *local_num_point=num_point/comm_sz;
42     double x,y,distance_squared;
43     srand(time(NULL));
44     for(long long int i=0;i< *local_num_point;i++){
45         x=(double)rand()/(double)RAND_MAX;
46         x=x*2-1;
47         y=(double)rand()/(double)RAND_MAX;
48         y=y*2-1;
49         distance_squared=x*x+y*y;
50         if(distance_squared<=1)
51         *num_in_cycle=*num_in_cycle+1;
52     }
53     /*
54     全局函数
55     MPI_Reduce(
56         void*    input_data_p    //in
57         void*    output_data_p    //out
58         int    count        //in
59         MPI_Datatype    datatype     //in
60         MPI_Op    oprtator    //in
61         int    dest_process    //in
62         MPI_Comm    comm    //in
63     )
64     */
65       MPI_Reduce(num_in_cycle,total_num_in_cycle,1,MPI_LONG_LONG,MPI_SUM,0,comm);
66     if(my_rank==0){
67         double pi=(double)*total_num_in_cycle/(double)num_point*4;
68         printf("the estimate value of pi is %lf\n",pi);
69     }
70 }

进行编译 mpicc -std=c99 -o mpi_mete mpi_mete.c

执行 mpiexec -n 4 mpi_mete

输入数据

下面是Pthread程序代码

 1 #include<stdlib.h>
 2 #include<stdio.h>
 3 #include<math.h>
 4 #include<pthread.h>
 5 int thread_count;
 6 long long int num_in_circle,n;
 7 pthread_mutex_t mutex;
 8 void* compute_pi(void* rank);
 9 int main(int argc,char* argv[]){
10     long    thread;
11     pthread_t* thread_handles;
12     thread_count=strtol(argv[1],NULL,10);
13     printf("please input the number of point\n");
14     scanf("%lld",&n);
15     thread_handles=(pthread_t*)malloc(thread_count*sizeof(pthread_t));
16     pthread_mutex_init(&mutex,NULL);
17     for(thread=0;thread<thread_count;thread++){
18         //创建线程
19         /*
20         int pthread_create(
21             pthread_t*    thread_p  //out
22             const    pthread_attr_t*    attr_p
23             void*    (*start_routine)(void*)    //in
24             void*    arg_p    //in
25         )
26         第一个参数是一个指针,指向对应的pthread_t对象。注意,pthread_t对象不是pthread_create函数分配的,必须在调用pthread_create函数前就为pthread_t
27         对象分配内存空间。第二个参数不用,所以只是函数调用时把NULL传递参数。第三个参数表示该线程将要运行的函数;最后一个参数也是一个指针,指向传给函数start_routine的参数
28         */
29         pthread_create(&thread_handles[thread],NULL,compute_pi,(void*)thread);
30     }
31     //停止线程
32     /*
33     int pthread_join(
34         pthread_t    thread    /in
35         void**    ret_val_p    /out
36     )
37     第二个参数可以接收任意由pthread_t对象所关联的那个线程产生的返回值。
38     */
39     for(thread=0;thread<thread_count;thread++){
40         pthread_join(thread_handles[thread],NULL);
41     }
42     pthread_mutex_destroy(&mutex);
43     double pi=4*(double)num_in_circle/(double)n;
44     printf("the esitimate value of pi is %lf\n",pi);
45 }
46 void* compute_pi(void* rank){
47     long long int local_n;
48     local_n=n/thread_count;
49     double x,y,distance_squared;
50     for(long long int i=0;i<local_n;i++){
51         x=(double)rand()/(double)RAND_MAX;
52         y=(double)rand()/(double)RAND_MAX;
53         distance_squared=x*x+y*y;
54         if(distance_squared<=1){
55             pthread_mutex_lock(&mutex);
56             num_in_circle++;
57             pthread_mutex_unlock(&mutex);
58         }
59     }
60     return NULL;
61 }    

进行编译 gcc -std=c99 -o pth_mete pth_mete.c

运行 ./pth_mete 4

输入数据结果如下

下面是OpenMP代码

 1 #include<stdlib.h>
 2 #include<stdio.h>
 3 #include<time.h>
 4 #include<omp.h>
 5 int main(int argc,char** argv){
 6     long long int num_in_cycle=0;
 7     long long int num_point;
 8     int thread_count;
 9     thread_count=strtol(argv[1],NULL,10);
10     printf("please input the number of point\n");
11     scanf("%lld",&num_point);
12     srand(time(NULL));
13     double x,y,distance_point;
14     long long int i;
15     #pragma omp parallel for num_threads(thread_count) default(none) 16         reduction(+:num_in_cycle) shared(num_point) private(i,x,y,distance_point)
17     for( i=0;i<num_point;i++){
18         x=(double)rand()/(double)RAND_MAX;
19         y=(double)rand()/(double)RAND_MAX;
20         distance_point=x*x+y*y;
21         if(distance_point<=1){
22             num_in_cycle++;
23         }
24     }
25     double estimate_pi=(double)num_in_cycle/num_point*4;
26     printf("the estimate value of pi is %lf\n",estimate_pi);
27     return 0;
28 }

编译代码 gcc -std=c99 -fopenmp -o omp_mete omp_mete.c

执行 ./omp_mete 4

结果如下

时间: 2024-08-03 16:33:30

蒙特卡洛方法计算圆周率的三种实现-MPI openmp pthread的相关文章

蒙特卡洛方法求解圆周率

代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>蒙特卡洛方法求解圆周率</title> <style> body { -moz-user-select: none; /*火狐*/ -webkit-user-select: none; /*webkit浏览器*/ -ms-user-sel

Struts2中Action接收参数的方法主要有以下三种:

Struts2中Action接收参数的方法主要有以下三种: 1.使用Action的属性接收参数(最原始的方式):     a.定义:在Action类中定义属性,创建get和set方法:     b.接收:通过属性接收参数,如:userName:     c.发送:使用属性名传递参数,如:user1!add?userName=jim: 2.使用DomainModel接收参数:     a.定义:定义Model类,在Action中定义Model类的对象(不需要new),创建该对象的get和set方法

root的方法大体上有以下三种

root的方法大体上有以下三种一.手机软件安卓版直接root.这种方法不需要电脑的支持,也很安全.安卓版软件有:kingroot,360一键root,一键root大师,Towelroot,支持云root方案匹配的最好.二.电脑软件直接线刷root.在PC上安装root软件,用数据线连接电脑和手机,手机开启USB调试模式,电脑运行软件root.PC版软件有:360一键root,一键root大师,root大师.三.手机卡刷root.在PC上安装刷机程序,用数据线连接电脑和手机,把root补丁包拷贝到

蒙特卡罗方法计算圆周率

蒙特卡罗方法计算圆周率 前几天读到了一篇网志:蒙特卡罗方法入门,http://www.ruanyifeng.com/blog/2015/07/monte-carlo-method.html 其中介绍了用概率计算圆周率的方法,所以就用程序做了以下尝试. 作为常量的PI值的近似在Math.PI中为3.141592653589793. Ⅰ.方形中的所有像素计算 package yumu.probability.montecarlo; public class CalculatePI { private

用蒙特卡洛方法计算派-python和R语言

用蒙特卡洛方法算pi-基于python和R语言 最近follow了MOOC上一门python课,开始学Python.同时,买来了概率论与数理统计,准备自学一下统计.(因为被鄙视过不是统计专业却想搞数据分析) 有趣的是书里面有一块讲蒲丰投针计算Pi,这是一种随机模拟法,也就是蒙特卡洛法.蒲丰投针之于我太难,暂时没想到怎么用计算机模拟这一过程. python课中,老师也提到用随机模拟法,也就是蒙特卡洛法(MonteCarlo),用计算机模拟几千次实验,计算pi的近似值.好巧. 就拿python课中的

C++中实现回调机制的几种方式(一共三种方法,另加三种)

(1)Callback方式Callback的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型. 比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件: typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK);void DownloadFile(const char* pURL, DownloadCallback call

蒙特卡洛方法计算pi

基本思想: 利用圆与其外接正方形面积之比为pi/4的关系,通过产生大量均匀分布的二维点,计算落在单位圆和单位正方形的数量之比再乘以4便得到pi的近似值.样本点越多,计算出的数据将会越接近真识的pi(前提时样本是"真正的"随机分布). 蒙特卡罗(Monte Carlo)算法计算圆周率的主要思想:给定边长为R的正方形,画其内切圆,然后在正方形内随机打点,设点落在圆内的概为P,则根据概率学原理:    P = 圆面积 / 正方形面积 = PI * R * R / 2R * 2R = PI /

mybatis之接口方法多参数的三种实现方式

关键代码举例: DaoMapper.xml 1 <!-- 传入多个参数时,自动转换为map形式 --> 2 <insert id="insertByColumns" useGeneratedKeys="true" keyProperty="id"> 3 insert into user (id, name, age) values (NULL ,#{param1}, #{param2}) 4 </insert>

C#中Math类的计算整数的三种方法

1.Math.Round:四舍六入五取偶 引用内容 Math.Round(0.0) //0 Math.Round(0.1) //0 Math.Round(0.2) //0 Math.Round(0.3) //0 Math.Round(0.4) //0 Math.Round(0.5) //0 Math.Round(0.6) //1 Math.Round(0.7) //1 Math.Round(0.8) //1 Math.Round(0.9) //1 说明:对于1.5,因要返回偶数,所以结果为2.