Comment calculer le pourcentage?

Jan 06 2021

Je suis nouveau mpiet je suis en train d'écrire un mini - Cprogramme qui calcule le pourcentage rapport du nombre que les entrées de l' utilisateur.

Le rapport en pourcentage est calculé par cette expression

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

Les nombres que l'utilisateur saisit sont stockés dans un tableau de taille fixe data[100]et sont dispersés dans tous les processus (ce programme est censé ne fonctionner qu'avec quatre processus). Le problème auquel je suis confronté est que la division ne fonctionne pas bien que tous les processus aient les données. Par exemple, si l'utilisateur entre les nombres, {1, 2, 3, 4}le rapport de pourcentage attendu selon l'expression mathématique est {0, 33.3, 66.6, 100}mais j'obtiens à la place {0,0,100,100}. C'est ce que j'ai.

#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 \n", 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\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;
}

Réponses

2 dreamcrash Jan 06 2021 at 22:23

Il y a plusieurs problèmes avec votre code.

D'abord:

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);

Malheureusement,

MPI n'obtient pas le minimum de tous les éléments du tableau, vous devez le faire manuellement. ( source )

Par conséquent, il faut d'abord calculer le minet le maxtableau de chaque processus, puis on peut réduire ceux-ci minet les maxrésultats parmi les autres processus. Étant donné que tous les processus doivent avoir le minet maxde ce tableau, au lieu de MPI_Reduce , vous devez utiliser MPI_Allreduce . Et votre code ressemblerait à ceci:

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);

À moins que vous ne supposiez que loc_num=1, ce que vous ne devriez pas, ce code

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

remplace le même xet y. De plus, vous ne devez pas appeler MPI_Bcast(&y, 1, MPI_INT, root, MPI_COMM_WORLD);, vous voulez que tous les processus calculent d'abord en parallèle leur travail en fonction de la formule:

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

et seulement ensuite renvoyer leur travail au processus maître . Ainsi, chaque processus doit appliquer cette formule à ses index d'entrée, stocker les résultats dans un tableau et les renvoyer au processus maître . Ainsi:

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);

Remarquez que je lance (((float) (loc_data[j] - global_min) / y) * 100.0);pour flotter . Sinon, Cretournerait une intreprésentation du résultat.