Come calcolare il rapporto percentuale?

Jan 06 2021

Sono nuovo mpie sto cercando di scrivere un mini Cprogramma che calcoli il rapporto percentuale dei numeri che l'utente inserisce.

Il rapporto percentuale viene calcolato da tale espressione

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

I numeri immessi dall'utente sono memorizzati in un array di dimensioni fisse data[100]e sono sparsi per tutti i processi (si suppone che questo programma funzioni solo con quattro processi). Il problema che sto affrontando è che la divisione non funziona sebbene tutti i processi abbiano i dati. Ad esempio, se l'utente inserisce i numeri, {1, 2, 3, 4}il rapporto percentuale previsto in base all'espressione matematica è {0, 33.3, 66.6, 100}ma invece ottengo {0,0,100,100}. Questo è quello che ho.

#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;
}

Risposte

2 dreamcrash Jan 06 2021 at 22:23

Ci sono diversi problemi con il tuo codice.

Primo:

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

purtroppo,

MPI non ottiene il minimo di tutti gli elementi nell'array, devi farlo manualmente. ( fonte )

Pertanto, è necessario prima calcolare l' array mine maxall'interno di ciascun processo, quindi è possibile ridurre quelli mine i maxrisultati tra gli altri processi. Poiché tutti i processi dovrebbero avere il mine maxdi quell'array, invece di MPI_Reduce , dovresti usare MPI_Allreduce . E il tuo codice sarebbe simile al seguente:

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

A meno che tu non stia assumendo che loc_num=1, cosa che non dovresti, questo codice

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

sovrascrive lo stesso xe y. Inoltre, non dovresti chiamare MPI_Bcast(&y, 1, MPI_INT, root, MPI_COMM_WORLD);, vuoi che tutti i processi calcolino prima in parallelo il loro lavoro in base alla formula:

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

e solo allora rimandano il lavoro al processo master . Quindi ogni processo dovrebbe applicare quella formula ai propri indici di input, memorizzare i risultati in un array e inviarlo di nuovo al processo master . Così:

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

Notate che sto lanciando (((float) (loc_data[j] - global_min) / y) * 100.0);per galleggiare . In caso contrario, Crestituirebbe una intrappresentazione del risultato.