You have some small problems with your code, namely unused variables, and variables not initialized. You should compile your code with some warning flags such as -Wall and -pedantic, among others. Those, flags warning the user about the aforementioned problems.
Furthermore, you can change this:
for(i=0; i< loc_num; i++){
loc_sum += data_loc[i];
loc_avg = loc_sum / loc_num;
}
to
for(i=0; i< loc_num; i++){
loc_sum += data_loc[i];
}
loc_avg = loc_sum / loc_num;
You need to initialize the variable loc_sum with zero, since the first time the code interacts with that variable is to perform loc_sum += data_loc[i];, otherwise is undefined behavior.
And since the average can be a floating number, the data type of the variables loc_avg , avg, and fin should be a float as a type (or double) instead of int.
You are calling the MPI_Gather only by the master:
if(my_rank==0){
MPI_Gather(&loc_avg, loc_num, MPI_INT, final_res, loc_num, MPI_INT, root, MPI_COMM_WORLD);
for(i=0; i<n; i++){
fin += final_res[i];
}
avg=fin/n;
printf("Final average: %d \n", avg);
}
MPI_Gather is a collect communication directive, it should be called by all the processes within the group. Moreover, you are calling MPI_Gather with the wrong parameters, instead of :
MPI_Gather(&loc_avg, loc_num, MPI_INT, final_res, loc_num, MPI_INT, root, MPI_COMM_WORLD);
called with
MPI_Gather(&loc_avg, 1, MPI_FLOAT, final_res, 1, MPI_FLOAT, root, MPI_COMM_WORLD);
This loc_num = n/p; only works fine when the input can be evenly divided among processes, but (for instance) if you have an input of 10 and 4 processes loc_num = n/p; would be equal to 2, so each process will compute 2 of 10. Hence, all processes will compute 8 instead of 10. This one I will leave it you to solve. Alternatively, you can just assume that n/p produces always a natural number.
Lastly, instead of:
for(i=0; i<n; i++){
fin += final_res[i];
}
avg=fin/n;
you should have
for(i=0; i<p; i++){
fin += final_res[i];
}
avg=fin/p;
You want to sum the local average of all processes, hence use the total of number of processes "p", and not the size of the input array "n".
Some advices:
- if you can, declare the variable as close as possible to the code where they are being used;
- give better name to your variables, for instance, instead of "n" and "p", called input_size and "total_processes", respectively.
IMO this improves the code readability. With all these change your code will look like:
#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 data_loc[100];
float final_res[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, MPI_INT, data_loc, loc_num, MPI_INT, root, MPI_COMM_WORLD);
int loc_sum = 0;
for(int i=0; i< loc_num; i++)
loc_sum += data_loc[i];
float loc_avg = (float) loc_sum / (float) loc_num;
MPI_Gather(&loc_avg, 1, MPI_FLOAT, final_res, 1, MPI_FLOAT, root, MPI_COMM_WORLD);
if(my_rank==0){
float fin = 0;
for(int i=0; i<total_processes; i++)
fin += final_res[i];
float avg = fin / (float) total_processes;
printf("Final average: %f \n", avg);
}
MPI_Finalize();
return 0;
}
Test input : 10 elements, with the elements being {1,2,3,4,5,6,7,8}
Result :
PROCESS=0 loc_avg=1.5 {1, 2}
PROCESS=1 loc_avg=3.5 {3, 4}
PROCESS=2 loc_avg=5.5 {5, 6}
PROCESS=3 loc_avg=7.5 {7, 8}
Final average: 4.500000