具有不同进程数的不同浮点答案

时间:2012-03-21 15:38:43

标签: c++ floating-point mpi floating-accuracy

我是学习MPI的新手,我编写了以下简单程序来执行集成 在Ubuntu 10.10上使用Open MPI的梯形规则。这是代码:

#include <iostream>
#include <mpi.h>
#include <cstdlib>

//function to integrate
double f (double x )
{
  return 4.0/(1+x*x);
}


//function which integrates the function defined above on the interval local_a and local_b for a given refinement parameters
double Trap(double local_a , double local_b, int local_n , double h)
{

  double integral ;
  double x;

  integral = ( f(local_a) + f(local_b) )/2.0;

  x = local_a ;

  for (int i = 1; i < local_n - 1; ++i)
    {
      x        += h; 
      integral += f(x);
    }

  integral *= h;
  return integral;
}

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

  int my_rank;
  int p;
  double a = 0.0;
  double b = 1.0;
  int n = atoi(argv[1]);//number of subdivisions of the interval
  double h;
  double local_a;
  double local_b;
  int local_n;

  double integral;
  double total;
  int source;
  int dest = 0;
  int tag = 0;
  MPI_Status status;

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD,&p);//get number pf processes
  MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);//get rank

  double start , finish;
  MPI_Barrier(MPI_COMM_WORLD);
  start = MPI_Wtime();  

////////////////////////////////////////////////////////////////////////////////////////////////////
  h = (b-a)/n;
  local_n = n/p;

  local_a = a + my_rank*local_n*h;
  local_b = local_a + local_n*h;

  integral = Trap(local_a , local_b , local_n , h);

  if (my_rank==0)
    {
      total = integral;

     for (source = 1; source < p; ++source)
       {
     MPI_Recv(&integral, 1, MPI_DOUBLE , source , tag , MPI_COMM_WORLD, &status );
         total+= integral;

       }
     }

  else
    {
      MPI_Send(&integral, 1, MPI_DOUBLE, dest, tag , MPI_COMM_WORLD);
    }

  if (my_rank == 0)
    {
      printf("With n=%d trapezoids our estimate \n", n );
      printf("Of the integral from %f to %f = %f \n" , a ,b , total);

    }

   ////////////////////////////////////////////////////////////////////////////////////////////////////
  MPI_Barrier(MPI_COMM_WORLD);
  finish = MPI_Wtime();

  if(my_rank == 0)  std::cout << "Time taken is " << finish - start << std::endl ; 

  MPI_Finalize();
  return 0;
}

正在整合的功能是f(x) = 4.0 / 1+x^2,当它集成在[0,1]时会pi = 3.14159...

现在,当我使用不同数量的流程运行程序时,我会得到不同的答案。如下所示,差异非常显着。

Desktop: mpirun -np 1 ./a.out 50000
With n=50000 trapezoids our estimate 
Of the integral from 0.000000 to 1.000000 = 3.141553 
Time taken is 0.000718832
Desktop: 
Desktop: 
Desktop: mpirun -np 2 ./a.out 50000
With n=50000 trapezoids our estimate 
Of the integral from 0.000000 to 1.000000 = 3.141489 
Time taken is 0.000422001
Desktop: 
Desktop: 
Desktop: 
Desktop: mpirun -np 3 ./a.out 50000
With n=50000 trapezoids our estimate 
Of the integral from 0.000000 to 1.000000 = 3.141345 
Time taken is 0.000365019
Desktop: 
Desktop: 
Desktop: 
Desktop: mpirun -np 4 ./a.out 50000
With n=50000 trapezoids our estimate 
Of the integral from 0.000000 to 1.000000 = 3.141362 
Time taken is 0.0395319

2 个答案:

答案 0 :(得分:4)

您的代码中有两个不同的问题:

1。集成边界取决于MPI流程的数量,并且在p未划分n时错误。即,最后一个过程的上限是

a + p * int(n/p) * (b-a)/n

b不同。我希望这是你代码中最重要的错误(除非我还没有看到另一个错误)

2。浮点运算既不是关联的也不是可交换的。因此,并行算法的结果将从部分和中汇总,因此将取决于部分和的数量。

答案 1 :(得分:2)

进行浮点运算时,运算顺序很重要。在实数算术中(我的意思是实数的算术)a+b+c+d==a+c+d+b(以及添加的任何其他顺序)。对于浮点运算,这不一定适用。由于MPI不保证每次浮点行为不确定时都以相同的顺序从M个处理器减少到1个处理器,至少就我们大多数人需要关注而言。

将这一点放在一边,不同数量的处理器上的结果之间的差异确实看起来比我预期的要大。看看你的代码我认为你在这一行使用整数运算:

local_n = n/p;

导致总区域的一小部分未分配给任何计算过程。通过我的计算线

local_b = local_a + local_n*h;

没有为最后一个进程将local_b设置为1.0。