Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
323 views
in Technique[技术] by (71.8m points)

c - How to calculate percentage ratio?

I am new to mpi and I am trying to write a mini C program that calculates the percentage ratio of numbers that the user inputs.

The percentage ratio is calculated by that expression

`δi = ((xi – xmin ) / (xmax – xmin )) * 100`. 

The numbers that the user inputs are stored in an array of fixed size data[100] and are scattered to all processes (this program is supposed to work only with four processes). The problem I am facing is that the division doesn't work although all the processes have the data. For example if the user inputs the numbers {1, 2, 3, 4} the expected percentage ratio according to the mathematical expression is {0, 33.3, 66.6, 100} but instead I am getting {0,0,100,100}. This is what I have.

#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, MPI_INT, loc_data, loc_num, MPI_INT, root, MPI_COMM_WORLD);

    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, 1, MPI_INT, MPI_MIN, root, 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, 1, MPI_INT, root, MPI_COMM_WORLD); 
    
    for(int j = 0; j< loc_num ; j++){
        p = (x / y) * 100;
        printf("p= %f 
", p);
        loc_delta[j] = p; 
    }

    float final_delta[100];
    MPI_Gather(&loc_delta, 1, MPI_FLOAT, final_delta, 1, MPI_FLOAT, root, MPI_COMM_WORLD);


    if(my_rank == 0){
        printf("max number: %d
", global_max);
        printf("min number: %d
", global_min);
        
        for(int i = 0; i<input_size; i++)
            printf("delta[%d]: %.2f | ", i+1, final_delta[i]);
    }

    printf("
");

        MPI_Finalize();

    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are several issues with your code.

First:

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, 1, MPI_INT, MPI_MIN, root, MPI_COMM_WORLD);

unfortunately,

MPI does not get the minimum of all elements in the array, you have to do that manually. (source)

Therefore, one needs to first calculate the min and the max within each process' array, and then one can reduce those min and max results among the other processes. Since, all processes should have the min and max of that array, instead of MPI_Reduce, you should use MPI_Allreduce. And your code would look like the following:

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, &global_max, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
MPI_Allreduce(&local_min, &global_min, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);

Unless you are assuming that loc_num=1, which you should not, this code

  for(int j = 0; j< loc_num; j++){
        x = loc_data[j] - global_min;
        y = global_max - global_min;
    }

overrides the same x and y. Moreover, you should not call MPI_Bcast(&y, 1, MPI_INT, root, MPI_COMM_WORLD);, you want for all the processes to first calculate in parallel their work based on the formula:

δi = ((xi – xmin ) / (xmax – xmin )) * 100.

and only then send their work back to the master process. So each process should apply that formula to their input indices, stored the results in an array and send it back to the master process. Like so:

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, loc_num, MPI_FLOAT, root, MPI_COMM_WORLD);

Notice that I am casting (((float) (loc_data[j] - global_min) / y) * 100.0); to float. Otherwise, C would return an int representation of the result.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...