一个mpi程序,将数字从1添加到16000000,结果不同

一个mpi程序,将数字从1添加到16000000,结果不同,mpi,Mpi,*主任务首先初始化一个数组,然后将该数组的相等部分分配给其他任务。在其他任务接收到它们的数组部分后,它们对每个数组元素执行加法操作。它们还为它们的数组部分维护一个和。主任务对其数组部分也执行类似操作。作为每一个非主人 任务完成后,它们将更新的阵列部分发送给主机。 MPI集体通信调用用于收集每个任务维护的总和。最后,主任务显示最终数组的选定部分和所有数组元素的全局和* #include "mpi.h" #include <stdio.h> #include <stdlib.h&g

*主任务首先初始化一个数组,然后将该数组的相等部分分配给其他任务。在其他任务接收到它们的数组部分后,它们对每个数组元素执行加法操作。它们还为它们的数组部分维护一个和。主任务对其数组部分也执行类似操作。作为每一个非主人 任务完成后,它们将更新的阵列部分发送给主机。 MPI集体通信调用用于收集每个任务维护的总和。最后,主任务显示最终数组的选定部分和所有数组元素的全局和*

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#define ARRAYSIZE 16000000
#define MASTER

float data[ARRAYSIZE];

int main (int argc, char *argv[])
{
int numtasks, taskid, rc, dest, source, offset, i, j, tag1,
    tag2, chunksize;
float mysum, sum;
float update(int myoffset, int chunk, int myid);
MPI_Status status;

/******Initializations******/
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
if (numtasks % 4 != 0) {
    printf("Quitting. Number of MPI tasks must be divisible by 4. \n");
    MPI_Abort(MPI_COMM_WORLD, rc);
    exit(0);
    }
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
chunksize = ARRAYSIZE / numtasks;
tag2 = 1;
tag1 = 2;

/******Master task only ******/
if (taskid == MASTER){
   /* Initialize the array */
    sum = 0;
    for (i = 0; i < ARRAYSIZE; i++){
         data[i] = i * 1.0;
         sum = sum + data[i];
      }
printf("Initialized array sum = %e\n", sum);

/* Send each task its portion of the array - mater keeps 1st part */
offset = chunksize;
for (dest = 1; dest < numtasks; dest++){
     MPI_Send(&offset, 1, MPI_INT, dest, tag1, MPI_COMM_WORLD);
     MPI_Send(&data[offset], chunksize, MPI_FLOAT, dest, tag2, MPI_COMM_WRLD);
     printf("Sent %d elements to task %d offset = %d\n, chunksize, dest, offset);
     offset = offset + chunksize;
  }

/* Master does its part of the work */
offset = 0;
mysum = update(offset, chunksize, taskid);

/* Get final sum */
MPI_Reduce(&mysum, &sum, 1, MPI_FLOAT, MPI_SUM, MASTER, MPI_COMM_WORLD);
printf("***Final sum = %e ***\n", sum);
} /* end of master section */

/******Non-master tasks only ******/
if (taskid > MASTER){

   /* Receive my portion of array from the master task */
   source = MASTER;
   MPI_Recv(&offset, 1, MPI_INT, source, tag1, MPI_COMM_WORLD, &status);
   MPI_Recv(&data[offset], chunksize, MPI_FLOAT, source, tag2, MPI_COMM_WORLD, &status);
   mysum = update(offset, chunksize, taskid);
   MPI_Reduce(&mysum, &sum, 1, MPI_FLOAT, MPI_SUM, MASTER, MPI_COMM_WORLD);
   }  /* end of non-master */

MPI_Finalize();
} /* end of main */

float update(int myoffset, int chunk, int myid){
int i;
float mysum;
/* Perform addition to each of my array elements and keep my sum */
mysum = 0;
for (i = myoffset; i < myoffset + chunk; i++){
     mysum = mysum + data[i];
  }
printf("Task %d mysum = %e\n", myid, mysum);
return mysum;
}


/******The result of this program is: ******/
MPI task 0 has started...
MPI task 1 has started...
MPI task 2 has started...
MPI task 3 has started...
Initialized array sum = 1.335708e+14
Sent 4000000 elements to task 1 offset= 4000000
Sent 4000000 elements to task 2 offset= 8000000
Task 1 mysum = 2.442024e+13
Sent 4000000 elements to task 3 offset= 12000000
Task 2 mysum = 3.991501e+13
Task 3 mysum = 5.809336e+13
Task 0 mysum = 7.994294e+12
Sample results: 
   0.000000e+00  1.000000e+00  2.000000e+00  3.000000e+00  4.000000e+00
   4.000000e+06  4.000001e+06  4.000002e+06  4.000003e+06  4.000004e+06
   8.000000e+06  8.000001e+06  8.000002e+06  8.000003e+06  8.000004e+06
   1.200000e+07  1.200000e+07  1.200000e+07  1.200000e+07  1.200000e+07
*** Final sum= 1.304229e+14 ***
#包括“mpi.h”
#包括
#包括
#定义阵列化16000000
#定义主机
浮动数据[排列];
int main(int argc,char*argv[])
{
int numtask、taskid、rc、dest、source、offset、i、j、tag1、,
tag2,块大小;
浮糠,总和;
浮点更新(int-myoffset、int-chunk、int-myid);
MPI_状态;
/******初始化******/
MPI_Init(&argc,&argv);
MPI通信大小(MPI通信世界和numtasks);
如果(numtask%4!=0){
printf(“退出。MPI任务的数量必须可以被4整除。\n”);
MPI_中止(MPI_通信世界,rc);
出口(0);
}
MPI通信等级(MPI通信世界和任务ID);
chunksize=ARRAYSIZE/numtask;
tag2=1;
tag1=2;
/******仅主任务******/
if(taskid==MASTER){
/*初始化数组*/
总和=0;
对于(i=0;i主任务){
/*从主任务接收我的阵列部分*/
源=主;
MPI_Recv(偏移量、1、MPI_INT、源、标记1、MPI_通信世界和状态);
MPI_Recv(和数据[offset]、chunksize、MPI_FLOAT、source、tag2、MPI_COMM_WORLD和status);
mysum=更新(偏移量、块大小、任务ID);
MPI_Reduce(&mysum,&sum,1,MPI_FLOAT,MPI_sum,MASTER,MPI_COMM_WORLD);
}/*非主程序的结束*/
MPI_Finalize();
}/*主管道末端*/
浮点更新(int-myoffset、int-chunk、int-myid){
int i;
浮糠;
/*对我的每个数组元素执行加法,并保持和*/
mysum=0;
对于(i=myoffset;i

*所以我的问题是,为什么这两个和不具有相同的值**

您将结果存储在32位浮点数(即浮点数)中这根本不足以维持你所需要的所有精确度。你所看到的是一个典型的例子,说明舍入误差是如何根据你把数字加在一起的顺序不同而累积的

如果您只是将所有浮点数替换为双倍浮点数,则可以:

mpiexec -n 4 ./arraysum
Initialized array sum = 1.280000e+14
Sent 4000000 elements to task 1 offset = 4000000
Task 1 mysum = 2.400000e+13
Sent 4000000 elements to task 2 offset = 8000000
Task 2 mysum = 4.000000e+13
Sent 4000000 elements to task 3 offset = 12000000
Task 0 mysum = 7.999998e+12
Task 3 mysum = 5.600000e+13
***Final sum = 1.280000e+14 ***

您将结果存储在32位浮点数(即浮点)中,这根本不足以保持所需的所有精度。您看到的是一个典型的示例,说明舍入误差如何根据数字相加的顺序累积不同

如果您只是将所有浮点数替换为双倍浮点数,则可以:

mpiexec -n 4 ./arraysum
Initialized array sum = 1.280000e+14
Sent 4000000 elements to task 1 offset = 4000000
Task 1 mysum = 2.400000e+13
Sent 4000000 elements to task 2 offset = 8000000
Task 2 mysum = 4.000000e+13
Sent 4000000 elements to task 3 offset = 12000000
Task 0 mysum = 7.999998e+12
Task 3 mysum = 5.600000e+13
***Final sum = 1.280000e+14 ***