Вычисление числа Пи. Мирошник Глеб. 6 курс — различия между версиями
(Новая страница: «==Цель== Оценить число π при помощи знакочередующегося ряда Лейбница двумя способами: сум…») |
(→Листинг программ) |
||
Строка 20: | Строка 20: | ||
==Листинг программ== | ==Листинг программ== | ||
+ | ===Для суммирования ряда=== | ||
<code> | <code> | ||
− | #include "stdafx.h" | + | #include "stdafx.h" |
− | #include <iostream> | + | #include <iostream> |
− | #include "mpi.h" | + | #include "mpi.h" |
− | #include <math.h> | + | #include <math.h> |
− | #include <time.h> | + | #include <time.h> |
using namespace std; | using namespace std; | ||
− | #define Iterations 10000000 //количество итераций | + | #define Iterations 10000000 //количество итераций |
+ | |||
+ | |||
+ | int main() { | ||
+ | |||
+ | int ProcNum, ProcRank, i; | ||
+ | |||
+ | double x, MyPi = 0; | ||
+ | |||
+ | double Sum = 0; | ||
+ | |||
+ | double TotalTime; | ||
+ | |||
+ | clock_t StartClock, EndClock; // объявляем стартовую и конечную переменную таймера и инициализируем стартовую переменную | ||
+ | |||
+ | StartClock = clock(); | ||
+ | |||
+ | MPI_Init(NULL, NULL); // инициализируем MPI | ||
+ | |||
+ | MPI_Comm_size(MPI_COMM_WORLD, &ProcNum); // записываем количество процессов с переменную ProcNum | ||
+ | |||
+ | MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank); // записываем номер процесса в переменную ProcRank | ||
+ | |||
+ | for (i = ProcRank; i < Iterations; i += ProcNum) | ||
+ | |||
+ | { | ||
+ | |||
+ | x = pow(-1,ProcRank)*4/(2*i + 1); | ||
+ | |||
+ | Sum += x; | ||
+ | |||
+ | } | ||
+ | |||
+ | MPI_Reduce(&Sum, &MyPi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // пердварительные суммы Sum в переменную MyPi | ||
+ | |||
+ | MPI_Finalize(); // завершаем работу MPI | ||
+ | |||
+ | if (ProcRank == 0) | ||
+ | |||
+ | { | ||
+ | |||
+ | |||
+ | EndClock = clock(); // останавливаем таймер и переходим к выводу результатов на экран | ||
+ | |||
+ | printf("Number of iterations = %i\n", Iterations); | ||
+ | |||
+ | printf("Obtained value of Pi = %3.20f\n", MyPi); | ||
+ | |||
+ | double pi = 3.1415926535897932384626433832795; | ||
+ | |||
+ | printf("Refrence value of Pi = %3.20f\n", pi); | ||
+ | |||
+ | printf("Error = %3.20f\n", abs(MyPi - pi)); | ||
+ | |||
+ | TotalTime = (double)(EndClock - StartClock) / CLOCKS_PER_SEC; | ||
+ | |||
+ | printf("Computing time = %f sec\n", TotalTime); | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | ===Для вычисления интеграла=== | ||
+ | <code> | ||
+ | #include "stdafx.h" | ||
+ | #include <iostream> | ||
+ | #include "mpi.h" | ||
+ | #include <math.h> | ||
+ | #include <time.h> | ||
+ | using namespace std; | ||
+ | #define Iterations 10000000 //количество итераций | ||
Версия 13:49, 19 января 2017
Содержание
Цель
Оценить число π при помощи знакочередующегося ряда Лейбница двумя способами: суммированием и интегрированием. Разработать программу для параллельных вычислений. Оценить скорость вычислений в зависимости от количества задействованных процессоров.
Постановка задачи
Лейбниц доказал, что ряд
равен
- .
Также данный ряд можно получить разложением арктангенса 1 в ряд Тейлора, что даёт нам возможность оценить число π вычислением определённого интеграла
Предлагаемое решение
Суммированием элементов ряда
После объявления переменных и инициализации MPI запускается счётчик времени. Предлагается при фиксированном количестве элементов ряда n считать элементы последовательно каждым процессором, "перепрыгивая" через количество процессов, занятых в расчёте. Начальный рассчитываемый номер ряда определяется порядковым номером процесса. Рассчитанный элемент добавляется к сумме внутри процесса. После окончания расчёта предварительные суммы "скидываются" в нулевой процесс и суммируются между собой. Таймер останавливается. Происходит вычисление ошибки по эталонному значению числа π и вывод информации о расчёте.
Численным вычислением определённого интеграла
Численное вычисление интеграла предлагается проводить методом прямоугольников. Сам же процесс будет аналогичен решению суммированием элементов ряда.
Листинг программ
Для суммирования ряда
#include "stdafx.h"
#include <iostream>
#include "mpi.h"
#include <math.h>
#include <time.h>
using namespace std;
#define Iterations 10000000 //количество итераций
int main() {
int ProcNum, ProcRank, i;
double x, MyPi = 0;
double Sum = 0;
double TotalTime;
clock_t StartClock, EndClock; // объявляем стартовую и конечную переменную таймера и инициализируем стартовую переменную
StartClock = clock();
MPI_Init(NULL, NULL); // инициализируем MPI
MPI_Comm_size(MPI_COMM_WORLD, &ProcNum); // записываем количество процессов с переменную ProcNum
MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank); // записываем номер процесса в переменную ProcRank
for (i = ProcRank; i < Iterations; i += ProcNum)
{
x = pow(-1,ProcRank)*4/(2*i + 1);
Sum += x;
}
MPI_Reduce(&Sum, &MyPi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // пердварительные суммы Sum в переменную MyPi
MPI_Finalize(); // завершаем работу MPI
if (ProcRank == 0)
{
EndClock = clock(); // останавливаем таймер и переходим к выводу результатов на экран
printf("Number of iterations = %i\n", Iterations);
printf("Obtained value of Pi = %3.20f\n", MyPi);
double pi = 3.1415926535897932384626433832795;
printf("Refrence value of Pi = %3.20f\n", pi);
printf("Error = %3.20f\n", abs(MyPi - pi));
TotalTime = (double)(EndClock - StartClock) / CLOCKS_PER_SEC;
printf("Computing time = %f sec\n", TotalTime);
} }
Для вычисления интеграла
#include "stdafx.h"
#include <iostream>
#include "mpi.h"
#include <math.h>
#include <time.h>
using namespace std;
#define Iterations 10000000 //количество итераций
int main() {
int ProcNum, ProcRank, i;
double x, MyPi = 0;
double Sum = 0;
double TotalTime;
clock_t StartClock, EndClock; // объявляем стартовую и конечную переменную таймера и инициализируем стартовую переменную
StartClock = clock();
MPI_Init(NULL, NULL); // инициализируем MPI
MPI_Comm_size(MPI_COMM_WORLD, &ProcNum); // записываем количество процессов с переменную ProcNum
MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank); // записываем номер процесса в переменную ProcRank
double h = 1.0 / Iterations;
for (i = ProcRank; i < Iterations; i += ProcNum) // вычисляем численно интеграл по методу прямоугольников
{
x = (i + 0.5) * h;
Sum += 4.0 / (1 + x*x); // (после общего суммирования надо будет разделить на количество итераций)
}
MPI_Reduce(&Sum, &MyPi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // пердварительные суммы Sum в переменную MyPi
MPI_Finalize(); // завершаем работу MPI
if (ProcRank == 0)
{
MyPi *= h; //делим сумму на количество итераций
EndClock = clock(); // останавливаем таймер и переходим к выводу результатов на экран
printf("Number of iterations = %i\n", Iterations);
printf("Obtained value of Pi = %3.20f\n", MyPi);
double pi = 3.1415926535897932384626433832795;
printf("Refrence value of Pi = %3.20f\n", pi);
printf("Error = %3.20f\n", abs(MyPi - pi));
TotalTime = (double)(EndClock - StartClock) / CLOCKS_PER_SEC;
printf("Computing time = %f sec\n", TotalTime);
} }
Компьютерная реализация
Результаты
Количество процессов | Время рассчета (сек) |
---|---|
1 | 184.2 |
2 | 91.6 |
5 | 39.4 |
10 | 19.2 |
20 | 9.9 |
30 | 8.1 |
40 | 7.5 |
Выводы
- Для малого числа узлов в сетке использовать многопроцессорные вычисления не выгодно: время работы программы увеличивается.
- При увеличении числа процессоров относительный выигрыш во времени уменьшается.