问题描述
区间分割法求解代数方程:给定一个函数,然后给定一个区间(保证函数在该区间内单调且有且仅有一个解),使用并行程序设计方法求出该解。(对于非单调、有多解的情况可能不适用,最多能找到一个解)
方法描述
- 进程0接收区间输入,并且限定仅接收一次。
- 进程0将区间划分为size(进程数目)个小区间。
- 然后进程0将(size-1)个区间广播给其它进程,进程0自己判断一个区间。
- 各进程判断要寻找的解是否在自己负责的区间;若在进程0负责的区间,更新区间信息,到步骤5;若在其他进程负责的区间,则将该区间发送给进程0。
- 进程0接收到新的区间后,判断该区间是否达到精度要求,达到则输区间中值作为近似解,同时进程0将结束信息发送给各进程;若未达到精度要求,则执行步骤2。
代码
#include <mpi.h>
#include <iostream>
#include <math.h>
using namespace std;
double func(double x) {
return pow((x - 0.11),2)-3; //定义函数
}
int main(int argc, char* argv[]) {
double a=0, b=0; //初始求解区间
int fin = 1;
double jd = 1.0 / 1000;// 精度
double N=0;
int flag = 1;
double x, y;
int gg = 1;
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Status status;
while (flag==1) {
if (rank == 0 and fin == 1) {
cout << "输入初始求解区间:";
cin >> a >> b;
fin = 0;
cout << a << b << size << endl;
}
if (rank == 0) {
N = ((b - a) * 1.0) / size; // 分成size个区间的区间大小
cout << "N= " << N << endl;
// 进程0广播
for (int i = 1; i <= size - 1; i++) {
x = a + i * N;
y = a + (i + 1) * N;
MPI_Send(&x, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
MPI_Send(&y, 1, MPI_DOUBLE, i, 1, MPI_COMM_WORLD);
cout << "进程0广播到进程"<< i << endl;
}
// 对进程0自身判断
if (func(a) * func(a + N) <= 0) {
b = a + N;
gg = 0;
}
//进程0等待接收
if (gg == 1) {
MPI_Recv(&a, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status);
MPI_Recv(&b, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 1, MPI_COMM_WORLD, &status);
}
gg = 1;
cout << "新的区间(" << a << " , " << b << ")" << endl;
if (b - a < jd) { //区间达到精度要求
flag = 0;
cout << "一个近似的解:" << (a + b) * 1.0 / 2 << endl;
for (int i = 1; i <= size - 1; i++) {
MPI_Send(&flag, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
MPI_Send(&flag, 1, MPI_DOUBLE, i, 1, MPI_COMM_WORLD);
cout << "进程0广播结束标志到进程" << i << endl;
}
}}
else {
MPI_Recv(&x, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
MPI_Recv(&y, 1, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD, &status);
if(x == y){
flag = 0;
cout << "进程" << rank << "接收来自进程0的结束进程广播" << endl;
continue;}
cout << "进程" << rank << "接收来自进程0的广播" << endl;
if (func(x) * func(y) <= 0) { // 异号 或 有一个值是解
MPI_Send(&x, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
MPI_Send(&y, 1, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);
cout << "*****进程" << rank << "将消息发送给进程0 " << endl;
}
}}
cout << "进程 "<<rank<<" 结束!" << endl;
MPI_Finalize();
return 0;
}
结果展示
我的size=8,因此[0,2]划分为8个区间,每个区间长度为0.25。第一次找到近似解在区间[1.75,2],不满足精度,然后进行第二次的区间划分,长度为0.03125。然后找到新的解区间[1.8125,1.84375],仍然不满足区间精度,继续划分,长度为0.00390625。然后找到新的解区间[1.83984,1.84375],仍不满足精度,继续划分,长度为0.000488281。然后找到新的解区间[1.8418,1.84204],满足精度,输出区间中值作为近似解。结束所有进程。