Метод прямоугольников вычисления определённого интеграла с помощью 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

