1.算法思路
可以用四个基本步骤去设计一个并行程序:
1)将问题的解决方案划分成多个任务。
2)在任务间识别出需要的通信信道。
3)将任务聚合成复合任务。
4)在核上分配复合任务。
在划分阶段,我们通常试着识别出尽可能多的任务。对于梯形积分法,我们可以识别出两种任务:一种是获取单个矩形区域的面积,另一种是计算这些区域的面积和。然后利用通信信道将每个第一种任务与一个第二种任务相连接。
使用的梯形越多,估计值就越精确。也就是说:应该使用尽可能多的梯形。因此,梯形的数目将超过核的数量,需要将梯形区域面积的计算聚合成组。实现这一目标的一个很自然的方法就是将区间[a,b]分成comm_sz个子区间。如果comm_sz可以整除n,即梯形数目,那么我们可以简单地在n/comm_sz个梯形和所有comm_sz个子空间上应用梯形积分法。最后,我们可以利用进程中的某一个,如0号进程,将这些梯形面积的估计值累加起来,完成整个计算过程。
2.程序源码
#include <stdio.h>
#include <mpi.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#define PI 3.1415926535898
double Integral(double a,double b,double (*fun)(double))
{ int i,l; double n=0.001,s=0; l=(b-a)/n;
double top,base;
for(i=0;i<l;i++)
{
top=(*fun)(a+n*i);
base=(*fun)(a+n*(i+1));
s=(top+base)*n/2+s;
}
printf("cos(x)在(%lf,%lf)上的积分为%lf\n",a,b,s);
return s;
}
int main(int argc,char** argv){
MPI_Comm comm = MPI_COMM_WORLD;
int size,rank;
MPI_Init(&argc,&argv);
MPI_Comm_size(comm,&size);
MPI_Comm_rank(comm,&rank);
int i;
double sum=0;
double a=0;
double b=2*PI;
double n=(b-a)/size;
double *sbuf=(double *)malloc(sizeof(double)* size);
double *rbuf=(double *)malloc(sizeof(double)* size);
double *start=(double *)malloc(sizeof(double)*1);
double *part=(double *)malloc(sizeof(double)*1);
if(rank==0){ for(i=0;i<size;i++) sbuf[i]=a+n*i;
}
MPI_Scatter(sbuf,1,MPI_DOUBLE,start,1,MPI_DOUBLE,0,comm);
(*part)=Integral((*start),(*start)+n,cos);
MPI_Gather(part,1,MPI_DOUBLE,rbuf,1,MPI_DOUBLE,0,comm);
if(rank==0){
for(i=0;i<(size+1);i++)
{
sum+=rbuf[i];
}
printf("cos(x)在(%lf,%lf)的定积分为%lf\n",a,b,sum);
}
MPI_Finalize();
return 0;
}
3.运行结果
并行:
串行
:
4.性能分析
在同样的环境中,计算相同的积分,通过比较串行程序和并行程序的运行时间可知,并行程序的运行时间较长