¿Cómo calcular la relación porcentual?

Jan 06 2021

Soy nuevo mpiy estoy tratando de escribir un mini Cprograma que calcule la proporción porcentual de números que ingresa el usuario.

La relación porcentual se calcula mediante esa expresión

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

Los números que ingresa el usuario se almacenan en una matriz de tamaño fijo data[100]y están dispersos en todos los procesos (se supone que este programa solo funciona con cuatro procesos). El problema al que me enfrento es que la división no funciona aunque todos los procesos tienen los datos. Por ejemplo, si el usuario ingresa los números, {1, 2, 3, 4}la proporción porcentual esperada de acuerdo con la expresión matemática es, {0, 33.3, 66.6, 100}pero en cambio estoy obteniendo {0,0,100,100}. Esto es lo que tengo.

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

Respuestas

2 dreamcrash Jan 06 2021 at 22:23

Hay varios problemas con su código.

Primero:

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

Desafortunadamente,

MPI no obtiene el mínimo de todos los elementos de la matriz, debe hacerlo manualmente. ( fuente )

Por lo tanto, primero se necesita calcular el miny maxdentro de la matriz de cada proceso, y luego se pueden reducir esos miny los maxresultados entre los otros procesos. Dado que, todos los procesos deben tener el miny maxde esa matriz, en lugar de MPI_Reduce , debe usar MPI_Allreduce . Y su código se vería así:

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 menos que esté asumiendo que loc_num=1, lo cual no debería, este código

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

anula lo mismo xy y. Además, no debe llamar MPI_Bcast(&y, 1, MPI_INT, root, MPI_COMM_WORLD);, desea que todos los procesos calculen primero en paralelo su trabajo en función de la fórmula:

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

y solo entonces enviar su trabajo de vuelta al proceso maestro . Entonces, cada proceso debe aplicar esa fórmula a sus índices de entrada, almacenar los resultados en una matriz y enviarlos de vuelta al proceso maestro . Al igual que:

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

Observe que estoy lanzando (((float) (loc_data[j] - global_min) / y) * 100.0);para flotar . De Clo contrario, devolvería una intrepresentación del resultado.