如何将MPI_Reduce转换为MPI_Send和MPI_Recv?

如何将MPI_Reduce转换为MPI_Send和MPI_Recv?,c,parallel-processing,mpi,C,Parallel Processing,Mpi,我正在开发一个使用MPI_Send()和MPI_Recv()而不是使用MPI_Reduce()的并行处理程序。我知道MPI_Send()需要从每个处理器向根处理器(也称为0)发送一个值,MPI_Recv()需要从每个处理器接收所有值 我不断得到一个错误,其中Send中的值不会发送到接收方,因此最终值为0。MPI_Reduce()函数仍在代码中,但已注释掉,以查看需要替换的内容。有人能帮忙吗 #include "mpi.h" #include <stdio.h> #

我正在开发一个使用MPI_Send()和MPI_Recv()而不是使用MPI_Reduce()的并行处理程序。我知道MPI_Send()需要从每个处理器向根处理器(也称为0)发送一个值,MPI_Recv()需要从每个处理器接收所有值

我不断得到一个错误,其中Send中的值不会发送到接收方,因此最终值为0。MPI_Reduce()函数仍在代码中,但已注释掉,以查看需要替换的内容。有人能帮忙吗

#include "mpi.h"
#include <stdio.h>
#include <math.h>
 
int main( int argc, char *argv[])
{
    int n, i;
    double PI25DT = 3.141592653589793238462643;
    double pi, h, sum, x;
 
    int numprocs, myid;
    double startTime, endTime;
 
    /* Initialize MPI and get number of processes and my number or rank*/
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);
 
    /* Processor zero sets the number of intervals and starts its clock*/
    if (myid==0) {
       n=600000000;
       startTime=MPI_Wtime();
       for (int i = 0; i < numprocs; i++) {
           if (i != myid) {
               MPI_Send(&n, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
           }
       }
    } 
    else {
        MPI_Recv(&n, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }
 
    /* Calculate the width of intervals */
    h   = 1.0 / (double) n;
 
    /* Initialize sum */
    sum = 0.0;
    /* Step over each inteval I own */
    for (i = myid+1; i <= n; i += numprocs) {
        /* Calculate midpoint of interval */
        x = h * ((double)i - 0.5);
        /* Add rectangle's area = height*width = f(x)*h */
        sum += (4.0/(1.0+x*x))*h;
    }
    /* Get sum total on processor zero */
    //MPI_Reduce(&sum,&pi,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);
    double value = 0;
    if (myid != 0) {
            MPI_Send(&sum, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
    }
    else {
        for (int i = 1; i < numprocs; i++) {
            MPI_Recv(&value, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            pi += value;
            }
    }
    
    /* Print approximate value of pi and runtime*/
    if (myid==0) {
       printf("pi is approximately %.16f, Error is %e\n",
                       pi, fabs(pi - PI25DT));
       endTime=MPI_Wtime();
       printf("runtime is=%.16f",endTime-startTime);
    }
    MPI_Finalize();
    return 0;
}
#包括“mpi.h”
#包括
#包括
int main(int argc,char*argv[])
{
int n,i;
双PI25DT=3.141592653589793238462643;
双π,h,和,x;
int numprocs,myid;
双开始时间,结束时间;
/*初始化MPI并获取进程数和我的编号或排名*/
MPI_Init(&argc,&argv);
MPI通信大小(MPI通信世界和numprocs);
MPI通信等级(MPI通信世界和myid);
/*处理器zero设置间隔数并启动其时钟*/
如果(myid==0){
n=600000000;
startTime=MPI_Wtime();
for(int i=0;i对于(i=myid+1;i您正在使用
MPI\u INT
发送类型为
double
的值:

if(myid!=0){
MPI_发送(&sum,1,MPI_INT,0,0,MPI_COMM_WORLD);
//                ^^^^^^^
}
int
的长度为4字节;
double
的长度为8字节。虽然接收操作成功,但如果消息中只有4个字节,它无法构造类型为
MPI\u double
的值,因此它不会将任何内容写入
value
中,并且仍然保持
0.0
。如果替换:

MPI\u Recv(&value,1,MPI\u DOUBLE,i,0,MPI\u COMM\u WORLD,MPI\u STATUS\u IGNORE);

MPI\u状态;
整数计数;
MPI_Recv(&value,1,MPI_DOUBLE,i,0,MPI_COMM_WORLD,&status);
MPI\u获取计数(&status,MPI\u DOUBLE,&count);
如果(计数==未定义的MPI_){
printf(“收到短消息”);
MPI_中止(MPI_通信世界,0);
}
您的程序将中止,这表明由于
MPI\u Get\u count()
count
中返回
MPI\u UNDEFINED
,执行了条件语句体,这表明接收到的消息长度不是
MPI\u DOUBLE
大小的整数倍

此外,在接收循环之前,
pi
必须显式初始化为
sum
,否则由于以下任一错误,您将获得错误的
pi
值:

  • pi
    未初始化且具有任意初始值,以及
  • 等级0的贡献不会添加到最终结果中