为什么执行此C MPI应用程序以进行Pi近似时的结果始终相同?

时间:2017-10-27 08:54:09

标签: c parallel-processing mpi pi srand

这个用于Pi近似的C MPI应用程序总是在每个问题大小上打印出相同的结果,即随机生成的点数(npts)。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"

int main(int argc, char *argv[]) {

  int myid,nprocs;

  double PI25DT = 3.141592653589793238462643;

  long long npts = 1e10;

  long i,mynpts;

  long double f,sum,mysum;
  long double xmin,xmax,x;

  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD,&myid);

  if (myid == 0) {
    mynpts = npts - (nprocs-1)*(npts/nprocs);
  } else {
    mynpts = npts/nprocs;
  }

  mysum = 0.0;
  xmin = 0.0;
  xmax = 1.0;

  srand(myid);  

  for (i=0; i<mynpts; i++) {
    x = (long double) rand()/RAND_MAX*(xmax-xmin) + xmin;
    mysum += 4.0/(1.0 + x*x);
  }

  MPI_Reduce(&mysum,&sum,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

  if (myid == 0) {
    f = sum/npts;
    printf("PI calculated with %lld points = %.16f \n",npts,f);
    printf("Error is: %.16f \n",fabs(f-PI25DT));
  }

  MPI_Finalize();
}  

这是输出。我认为每次运行应用程序的结果应该有所不同。我在具有128个节点的集群上执行它。

$ mpicc pi.c -o /mnt/cluster_128/pi
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi  /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 

3 个答案:

答案 0 :(得分:3)

你在这里播种PRNG:

srand(myid);

myid是您拨打MPI_Comm_rank()时设置的值,您只对myid == 0的结果感兴趣,因此这始终是相同的值。播种相同的值会产生相同的“随机”数字序列。

使用常见的播种习语:

#include <time.h>
#include <stdlib.h>

[...]

srand(time(0));

答案 1 :(得分:1)

您的代码仅在if (myid == 0)显示您的RNG种子无用时打印任何结果。

我建议

srand((unsigned)time(NULL));

答案 2 :(得分:1)

现有的答案已经指出了正确的方向,但我认为他们的解释并不完全正确。

如前所述,问题在于RNG种子。您使用myid作为srand的种子,它始终是0N-1之间的数字(排名为N,即数字你传递给mpiexec -np N executable命令。这是确定性的:它不会因不同的执行而改变。

因此,所有N个进程都将创建相同的种子集,并且生成的随机数对于相同数量的进程将是相同的:

  • 对于单个进程(N = 1):种子值始终为0
  • 对于五个过程(N = 5):每个过程中的种子值始终为0,1,2,3和4。等等。

MPI_Reduce集合收集每个进程的所有部分结果(由于随机数相同而产生相同的值),并在根进程(myid=0)中打印总和。带有myid的进程打印结果的事实并不重要,因为还有其他N-1进程具有不同的myid值,这些进程会影响正在打印的最终结果。

2个进程的小例子,myid

  • 等级0 srand(0),计算部分和(mysum),累积其他流程&#39; sum变量中的部分和(指定0作为MPI_Reduce第7个参数中的根进程。打印结果(myid==0true)。

  • 等级1 srand(1),计算部分和(mysum)将其发送到MPI_Reduce根进程(0)。不打印结果(myid==0false)。

使用MPI需要了解的最重要的事情是,您通常使用多个进程执行单个程序,并且每个进程都会获得不同的环境(输出参数MPI_Comm_rank )。