最近学习了蒙特卡洛求π的算法,自己实现了串行与并行算法。
(1)串行算法
算法思想:产生2n个随机数据,范围[0,1],对每个数据点计算其坐标是否满足,统计满足此关系的点的数量count,则 π=count/4n。
代码:
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#define n 1000000000
void main()
{
int i,count=0;
double x,y,pi;
srand((int)time(NULL));
for(i=0;i<n;i++)
{
x=(double)(1.0*rand()/RAND_MAX); //产生0-1的随机数
y=(double)(1.0*rand()/RAND_MAX);
if(pow(x,2)+pow(y,2)<=1)
{
count+=1;
}
}
pi=4.0*count/n;
printf("%f",pi);
}
(2)并行算法
算法思想:
1. 确定需要产生的点的个数n,参与运行的处理器数m;
2. 对每一个处理器,生成两个随机数x,y,范围[0,1];
3. 判断两个随机数x,y是否满足;
4. 若满足,则变量COUNTi++;
5. 重复步骤2-4,直至每个处理器均生成n/m个随机点;
6. 收集COUNTi的值,并累加至变量COUNT中,此即为随机点落在圆弧内的数量;
7. 计算π的值。
代码:
//#include"stdafx.h"
#include<windows.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
#define POINT_NUM 10000000000//点的数目,尽量不适用N、M这些会出现命名冲突
#define THREAD_NUM 10 //线程数
DWORD Thread(int *pData)
{
double x,y;
srand(time(NULL));
for(int i=0;i<POINT_NUM/THREAD_NUM;i++)
{
x=(double)(1.0*rand()/RAND_MAX); //产生0-1的随机数
y=(double)(1.0*rand()/RAND_MAX);
if(pow(x,2)+pow(y,2)<=1.0) //满足范围
(*pData)+=1;
}
printf("点数:%d\n",*pData);
return 0;
}
int main(int argc,char* argv[])
{
double pi;
int count[THREAD_NUM];
int total=0;
HANDLE h[THREAD_NUM];
printf("每个:%d\n",POINT_NUM/THREAD_NUM);
for(int i=0;i<THREAD_NUM;i++)
{
count[i]=0;
h[i]=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) Thread,
&count[i],
0,
NULL);
if(h[i]==NULL)
printf("CreateThread Thread%d Error!\n",i);
Sleep(1000); //若不sleep,则会出现各线程产生的点数一样的情况
}
WaitForMultipleObjects(THREAD_NUM,h,TRUE,INFINITE);
for(i=0;i<THREAD_NUM;i++)
total+=(count[i]);
printf("总数:%d\n",total);
pi=4.0*total/POINT_NUM;
printf("pi:%f\n",pi); //注意输出格式
return 0;
}
将生成点的数目写的非常大,并在两个程序中分别加上时间函数,输出算法运行时间(如下的两张图,分别为串行和并行算法的运行结果截图),从中可以看出在生成的总点数相同的前提下,两算法的精度相差不大,但并行算法的效率更高。