Метод прямоугольников вычисления определённого интеграла с помощью MPI на C++

Пытаюсь вычислить определённый интеграл методом прямоугольников. В зависимости от количества процессов исходный интервал разбивается на подинтервалы, их количество соответствует общему количеству процессов - 1. Интервалы вычисляются корректно, передача из нулевого процесса в остальные также верная, в момент суммирования результатов вычислений с помощью метода reduce число получается некорректное. Результат вычислений подписан как Total Integral value. Подскажите как исправить чтобы суммировалось всё корректно

введите сюда описание изображения

int main(int argc, char** argv)
{
int n;

int procid;
int countprocs;

float a = 2, b = 6, S, divid, e = 0.1;

float* res = new float;

MPI_Status status;
double startwtime = 0.0, endwtime;


MPI_Init(&argc, &argv);


MPI_Comm_size(MPI_COMM_WORLD, &countprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &procid);


if (procid == 0)
{
    float* borders = new float[2];


    printf(">>> Num threads: %d\n", countprocs);

    divid = (b - a) / (countprocs-1);
    for (int to_proc = 1; to_proc < countprocs; to_proc++)
    {
        if (to_proc == 1)
        {
            borders[0] = a;
            borders[1] = a + divid;
        }

        else if (to_proc == countprocs)
        {
            borders[0] = b - divid;
            borders[1] = b;
        }

        else
        {
            borders[0] = borders[1];
            borders[1] = borders[0] + divid;
        }
        cout << "l: " << borders[0] << "    r: " << borders[1] << endl;
        MPI_Ssend(borders, 2, MPI_FLOAT, to_proc, 0, MPI_COMM_WORLD);

        startwtime = MPI_Wtime();
    }
}

else
{
    float* border = new float[2];
    MPI_Recv(border, 2, MPI_FLOAT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    rectangles(border[0], border[1], e, S);
    cout << "Integral value: " << S << endl;
}
MPI_Allreduce(&S, res, 1, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD);

    if (procid == 0)
    {
    endwtime = MPI_Wtime();


    cout << "Total Integral value: " << *res << endl;
    cout << "Time: " << (endwtime - startwtime) * 1000;

}

MPI_Finalize();

return 0;
}

Ответы (1 шт):

Автор решения: NunOfIt
#include "mpi.h"
#include <cmath>
#include <stdio.h>

#define RETURN return 0
#define FIRST_THREAD_ID 0

double f(double);

int main(int argc, char** argv) {
    MPI_Status status;
    
    int thread_id, thread_count;
    double start_time, end_time;
    double area, x, h = 0, res = 0;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &thread_id);
    MPI_Comm_size(MPI_COMM_WORLD, &thread_count);

    if (thread_id == FIRST_THREAD_ID) {
        printf(">>> Num threads: %d\n", thread_count);

        // Вводим a и b
        double a, b;
        printf("Input a and b: ");
        scanf("%lf %lf", &a, &b);

        // Вычисляем h (diff)
        h = (b - a) / (thread_count + 0.);

        x = a + h; // x 1-го процесса
        for (int i = FIRST_THREAD_ID + 1; i < thread_count; ++i) {
            // Отсылаем в каждый ненулевой поток значения h и x
            MPI_Ssend(&h, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
            MPI_Ssend(&x, 1, MPI_DOUBLE, i, 1, MPI_COMM_WORLD);
            x += h;
        }

        x = a; // x 0-го процесса
        start_time = MPI_Wtime();
    }
    else {
        // Получаем значения h и x
        MPI_Recv(&h, 1, MPI_DOUBLE, FIRST_THREAD_ID, 0, MPI_COMM_WORLD, &status);
        MPI_Recv(&x, 1, MPI_DOUBLE, FIRST_THREAD_ID, 1, MPI_COMM_WORLD, &status);
    }

    // Вычисляем площадь i-го прямоугольника
    area = h * f(x);
    printf("id: %d; l: %lf; r: %lf; area: %lf\n", thread_id, x, x + h, area);

    // Прибавляем площадь i-го прямоугольника к res
    MPI_Allreduce(&area, &res, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

    if (thread_id == FIRST_THREAD_ID) {
        end_time = MPI_Wtime();

        printf("Integral Value: %lf\n", res);
        printf("Time: %lf\n", 1000 * (end_time - start_time));
    }

    MPI_Finalize();
    RETURN;
}

double f(double x) {
    return sin(x) * cos(x);
}

Результат:

введите сюда описание изображения

Проверка:

-0.252267 + -0.271110 + 0.124717 + 0.329786 + 0.030439 + -0.315465 = -0,3539

→ Ссылка