问题描述
我是 mpi
的新手,我正在尝试编写一个迷你 C
程序来计算用户输入数字的 ratio 百分比。
百分比率由该表达式计算
`δi = ((xi – xmin ) / (xmax – xmin )) * 100`.
用户输入的数字存储在一个固定大小的数组 data[100]
中,并分散到所有进程中(这个程序应该只适用于四个进程)。
我面临的问题是尽管所有进程都有数据,但该部门不起作用。例如,如果用户输入数字 {1,2,3,4}
,根据数学表达式的预期百分比是 {0,33.3,66.6,100}
,但我得到的是 {0,100,100}
。这就是我所拥有的。
#include <stdio.h>
#include "mpi.h"
int main(int argc,char** argv){
int my_rank;
int total_processes;
int root = 0;
int data[100];
int loc_data[100];
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);
MPI_Comm_size(MPI_COMM_WORLD,&total_processes);
int input_size = 0;
if (my_rank == 0){
printf("Input how many numbers: ");
scanf("%d",&input_size);
printf("Input the elements of the array: ");
for(int i=0; i<input_size; i++){
scanf("%d",&data[i]);
}
}
MPI_Bcast(&input_size,1,MPI_INT,root,MPI_COMM_WORLD);
int loc_num = input_size/total_processes;
MPI_Scatter(&data,loc_num,loc_data,MPI_COMM_WORLD);
int global_max = 0;
int global_min = 0;
MPI_Reduce(&loc_data,&global_max,MPI_MAX,MPI_COMM_WORLD);
MPI_Reduce(&loc_data,&global_min,MPI_MIN,MPI_COMM_WORLD);
float loc_delta[100];
int x = 0;
int y = 0;
float p = 0;
for(int j = 0; j< loc_num; j++){
x = loc_data[j] - global_min;
y = global_max - global_min;
}
MPI_Bcast(&y,MPI_COMM_WORLD);
for(int j = 0; j< loc_num ; j++){
p = (x / y) * 100;
printf("p= %f \n",p);
loc_delta[j] = p;
}
float final_delta[100];
MPI_Gather(&loc_delta,MPI_FLOAT,final_delta,MPI_COMM_WORLD);
if(my_rank == 0){
printf("max number: %d\n",global_max);
printf("min number: %d\n",global_min);
for(int i = 0; i<input_size; i++)
printf("delta[%d]: %.2f | ",i+1,final_delta[i]);
}
printf("\n");
MPI_Finalize();
return 0;
}
解决方法
您的代码有几个问题。
首先:
int global_max = 0;
int global_min = 0;
MPI_Reduce(&loc_data,&global_max,1,MPI_INT,MPI_MAX,root,MPI_COMM_WORLD);
MPI_Reduce(&loc_data,&global_min,MPI_MIN,MPI_COMM_WORLD);
不幸的是,
MPI 没有得到数组中所有元素的最小值,你必须 手动执行此操作。 (source)
因此,需要先计算每个进程数组中的min
和max
,然后才能将这些min
和max
的结果相减过程。因为,所有进程都应该具有该数组的 min
和 max
,而不是 MPI_Reduce,您应该使用 MPI_Allreduce。您的代码如下所示:
int local_max = loc_data[0];
int local_min = loc_data[0];
for(int i = 1; i < loc_num; i++){
local_max = (local_max > loc_data[i]) ? local_max : loc_data[i];
local_min = (local_min < loc_data[i]) ? local_min : loc_data[i];
}
int global_max = local_max;
int global_min = local_min;
MPI_Allreduce(&local_max,MPI_COMM_WORLD);
MPI_Allreduce(&local_min,MPI_COMM_WORLD);
除非您假设 loc_num=1
(您不应该这样做),否则此代码
for(int j = 0; j< loc_num; j++){
x = loc_data[j] - global_min;
y = global_max - global_min;
}
覆盖相同的 x
和 y
。此外,您不应该调用 MPI_Bcast(&y,MPI_COMM_WORLD);
,您希望所有进程首先根据公式并行计算它们的工作:
δi = ((xi – xmin ) / (xmax – xmin )) * 100.
然后才将他们的工作发送回 master 进程。因此,每个进程都应该将该公式应用于它们的输入索引,将结果存储在一个数组中并将其发送回 master 进程。像这样:
float loc_delta[100];
float y = global_max - global_min;
for(int j = 0; j< loc_num; j++){
loc_delta[j] = (((float) (loc_data[j] - global_min) / y) * 100.0);
}
float final_delta[100];
MPI_Gather(&loc_delta,loc_num,MPI_FLOAT,final_delta,MPI_COMM_WORLD);
请注意,我将 (((float) (loc_data[j] - global_min) / y) * 100.0);
转换为 float。否则,C
将返回结果的 int
表示。