Расчеты MPI неверны на многоядерных, чем на одном - PullRequest
2 голосов
/ 29 сентября 2019

Я новичок в MPI и изучаю его как университетский курс. Задача состояла в том, чтобы численно найти значение const e , используя MPI_Send() и MPI_Recv(). Единственный подходящий способ, который я нашел, был

enter image description here

Я запускаю его на 2, 3 и 4 ядрах, но получаю неправильное число, в то время как на 1 ядре все в порядке,Вот мой код:

#include <iostream>
#include <fstream>
#include <cmath>
#include "mpi.h"

using namespace std;

const int n = 1e04;
double start_time, _time;
int w_size, w_rank, name_len;
char cpu_name[MPI_MAX_PROCESSOR_NAME];
ofstream fout("exp_result", std::ios_base::app | std::ios_base::out);

long double factorial(int num){
    if (num < 1)
        return 1;
    else
        return num * factorial(num - 1);
}

void e_finder(){
    long double sum = 0.0, e = 0.0;
    if(w_rank == 0)
        start_time = MPI_Wtime();

    for(int i = 0; i < n; i+=w_size)
        sum += 1.0 / factorial(i);
    MPI_Send(&sum, 1, MPI_LONG_DOUBLE, 0, 0, MPI_COMM_WORLD);

    if(w_rank == 0){
        // e += sum;
        for (int i = 0; i < w_size; i++){
            MPI_Recv(&sum, 1, MPI_LONG_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            e += sum;
        }
        _time = MPI_Wtime() - start_time;
        cout.precision(29);
        cout << "e = "<< e << endl << fixed << "error is " << abs(e - M_E) << endl;
        cout.precision(9);
        cout << "\nwall clock time = " <<_time << " sec\n";
        fout << w_size << "\t" << _time << endl;
    }
}

int main(int argc, char const *argv[]) {
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &w_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &w_rank);
    MPI_Get_processor_name(cpu_name, &name_len);

    cout<<"calculations started on cpu:" << w_rank << "!\n";
    MPI_Barrier(MPI_COMM_WORLD);

    e_finder();

    MPI_Finalize();
    fout.close();
    return 0;
}

Может ли кто-нибудь помочь мне узнать и понять ошибку? Вот результаты:

$ mpirun -np 1 ./exp1
calculations started on cpu:0!
e = 2.718281828459045235428168108
error is 0.00000000000000014463256980957

wall clock time = 4.370553009 sec



$ mpirun -np 2 ./exp1
calculations started on cpu:0!
calculations started on cpu:1!
e = 3.0861612696304875570925407846
error is 0.36787944117144246629694248618

wall clock time = 2.449338411 sec



$ mpirun -np 3 ./exp1
calculations started on cpu:0!
calculations started on cpu:1!
calculations started on cpu:2!
e = 3.5041749401277555767651727958
error is 0.78589311166871048596957449739

wall clock time = 2.011082204 sec



$ mpirun -np 4 ./exp1
calculations started on cpu:0!
calculations started on cpu:3!
calculations started on cpu:1!
calculations started on cpu:2!
e = 4.1667658813667669917037150729
error is 1.44848405290772190090811677443

wall clock time = 1.617427335 sec

1 Ответ

3 голосов
/ 29 сентября 2019

Вопрос в том, как вы распределяете работу. Похоже, вы хотите, чтобы каждая программа рассчитывала часть фракций. Однако все они начинаются с первой дроби и затем вычисляют каждую w_size -ю дробь. Это приводит к тому, что некоторые дроби рассчитываются несколько раз, а некоторые вообще не рассчитываются. Это должно быть исправлено путем изменения строки

for(int i = 0; i < n; i+=w_size)

на

for(int i = w_rank; i < n; i+=w_size)

. Это заставляет каждую программу запускаться с разной дробью, и так как они вычисляют каждые w_size -ые дроби,не должно быть больше столкновений между вычисленными дробями.

...