パーセンテージ比の計算方法は?

Jan 06 2021

私は初めてで、ユーザーが入力した数値のパーセンテージを計算mpiするミニCプログラムを作成しようとしています。

パーセンテージ比は、その式によって計算されます

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

ユーザーが入力した数値は固定サイズの配列に格納され、data[100]すべてのプロセスに分散されます(このプログラムは4つのプロセスでのみ機能することになっています)。私が直面している問題は、すべてのプロセスにデータがあるにもかかわらず、除算が機能しないことです。たとえば、ユーザーが数値を入力した場合、{1, 2, 3, 4}数式に従って期待されるパーセンテージ比はです{0, 33.3, 66.6, 100}が、代わりに{0,0,100,100}。を取得します。これは私が持っているものです。

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

回答

2 dreamcrash Jan 06 2021 at 22:23

コードにはいくつかの問題があります。

最初:

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

残念ながら、

MPIは、配列内のすべての要素の最小値を取得するわけではありません。手動で取得する必要があります。(ソース)

したがって、最初に各プロセスの配列内のminとを計算する必要があります。次に、他のプロセス間でmaxそれらminmax結果を減らすことができます。すべてのプロセスが持っている必要があり、以来minmaxその配列の、代わりのMPI_Reduce、あなたが使用する必要がありますMPI_Allreduceを。そして、あなたのコードは次のようになります:

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

あなたがそれを仮定していない限り、あなたはloc_num=1すべきではありません、このコード

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

同じxとをオーバーライドしますy。さらに、を呼び出すべきではありません。MPI_Bcast(&y, 1, MPI_INT, root, MPI_COMM_WORLD);すべてのプロセスが最初に次の式に基づいて作業を並行して計算する必要があります。

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

その後、作業をマスタープロセスに送り返します。したがって、各プロセスはその式を入力インデックスに適用し、結果を配列に格納して、マスタープロセスに送り返す必要があります。そのようです:

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

フロートにキャスト(((float) (loc_data[j] - global_min) / y) * 100.0);していることに注意してください。それ以外の場合は、結果の表現を返します。Cint