这两天完成了jacobi迭代的算法,在此记录一下心得
算法原理部分是参考的链接
主要有以下注意点:
1.这个算法是需要再来申请一个数组的,如果不申请数组的话求出来的数就是乱的,也就是代码中的B,这个B可以用N/size那么大,但是我还没改。
2.进程:每一个进程负责一部分,然后呢就要说到最后printf这个数组的时候,不能用某一个rank来printf,每个进程只改变了一块的数据,如果想输出的话,需要在每个进程中挨个输出,我之前就是最后想用0进程全部输出出来,但是发现只有0进程的数据进行了更新,其他的并没有更新,后来才改正确。
3.输出的时候最好是设置一个信号量,也就是代码中的x,让进程输出是按照顺序输出的,这样比较好检查。
这个代码中代码重复量比较大,接下来会将大量冗余代码封装成函数,然后传数据的时候采用指针来传送,还有就是,这个代码还没有测性能,这些都等着接下来再高吧!
代码如下,有大量的注释,数组用的是8*8的测试
#include<stdio.h>
#include<stdlib.h>
#include<mpi.h>
#include<time.h>
//int N = 8; // 这个代表的意思是本身的矩阵是400行的矩阵,然后在各个分块的上下各加一行,用来进程传递信息
#define N 8
float B[N][N];
int main(int arg, char* argv[]){
MPI_Init(&arg, &argv);
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Status status;
//首先创建一下二维数组
int i, j, k, x, y;
float A[N + 8][N];
int size2 = (N+8)/4;
// float (*p)[N + 8] = A; 等完事了用指针试一下 ,直接传一个指针
srand(time(0));
for(i = 0; i < N + 8; i++){
if(i != 0 && i != size2 - 1 && i != size2 && i != 2*size2 - 1 && i != 2*size2 && i != 3*size2 - 1 && i != 3*size2 && i != 4*size2 - 1)
for(j = 0; j < N; j++){
A[i][j] = rand() % 10;
}
else{
for(k = 0; k < N; k++){
A[i][k] = 0.0;
}
}
}
if(rank == 0){
for(i = 0; i < N + 8;i++){
if(i != 0 && i != size2 - 1 && i != size2 && i != 2*size2 - 1 && i != 2*size2 && i != 3*size2 - 1 && i != 3*size2 && i != 4*size2 - 1){
printf("\n");
for(j = 0;j < N;j++){
printf("%f ", A[i][j]);
}
}
}
}
printf("\n");
int m = 0;
//int pr = N / 4; //因为本机是4核的, 所以就用4个进程
if(rank == 0){ // 0号进程处理的是矩阵中第0行到第N/4 - 1行
for(k = 0; k < N; k++){
MPI_Send(&A[size2 - 2][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD);
}
for(k = 0; k < N; k++){// 接收1号进程发来的消息
MPI_Recv(&A[size2 - 1][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD, &status);
}
// 赋值+计算
for(i = 1; i < size2 - 1;i++){
if(i == 1){
for(j = 0;j < N;j++){
B[i-1][j] = A[i][j];
}
}
else{
for(j = 0;j < N;j++){
if(j == 0 || j == N-1){
B[m][j] = A[i][j];
}
else{
// B[i-1][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
B[m][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
}
}
}
m += 1;
}
// 给1发消息阻塞一下
MPI_Send(&y, 1, MPI_INT, 1, 200, MPI_COMM_WORLD);
for(i = 0;i < N/size;i++){
printf("\n");
for(j = 0; j < N;j++){
printf("%f ", B[i][j]);
}
}
}
else if(rank == 1){
for(k = 0; k < N; k++){//不整一些花里胡哨,直接把 N/4 - 1行全传过去
// if(k == 0){
// printf("\n %d \n", A[size2][k]);
// }
// 给2号进程发消息
MPI_Send(&A[2 * size2 - 2][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD);
// 给0号进程发消息
MPI_Send(&A[size2 + 1][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD);
// 收0号进程给发过来的消息
MPI_Recv(&A[size2][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD, &status);
}
// printf("\n=================================================\n");
// for(i = 0; i < N;i++){
// printf("%f ",A[size2][i] );
// }
// 接收2号进程发来的消息
for(k = 0; k < N; k++){
MPI_Recv(&A[2*size2 - 1][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD, &status);
}
// printf("\n=================================================\n");
//
// for(i = 0; i < N;i++){
// printf("%f ",A[2*size2 - 1][i] );
// }
// 赋值+计算
for(i = size2 + 1; i < 2*size2 - 1;i++){
for(j = 0;j < N;j++){
if(j == 0 || j == N-1){
B[m][j] = A[i][j];
}
else{
// B[i-2 * rank - 1][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
B[m][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
}
}
m += 1;
}
MPI_Recv(&x, 1, MPI_INT, 0, 200, MPI_COMM_WORLD, &status);
// for(i = N/size;i < 2 * N/size - 1;i++){
// printf("\n");
// for(j = 0; j < N;j++){
// printf("%f ", B[i][j]);
// }
// }
for(i = 0;i < N/size;i++){
printf("\n");
for(j = 0; j < N;j++){
printf("%f ", B[i][j]);
}
}
MPI_Send(&x, 1, MPI_INT, 2, 200, MPI_COMM_WORLD);
}
else if(rank == 2){
// 给3号进程和2号进程发消息
for(k = 0; k < N; k++){//不整一些花里胡哨,直接把 N/4 - 1行全传过去
// 接收1号进程发来的消息
MPI_Send(&A[3 * size2 - 2][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD);
MPI_Send(&A[2*size2 + 1][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD);
MPI_Recv(&A[2*size2][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD, &status);
}
// printf("\n=================================================\n");
// for(i = 0; i < N;i++){
// printf("%f ",A[2*size2][i] );
// }
// 接收3号进程发来的消息
for(k = 0; k < N; k++){
MPI_Recv(&A[3*size2 - 1][k], 1, MPI_FLOAT, rank + 1, k, MPI_COMM_WORLD, &status);
}
// printf("\n=================================================\n");
//
// for(i = 0; i < N;i++){
// printf("%f ",A[3*size2 - 1][i] );
// }
// 赋值+计算
for(i = 2*size2 + 1; i < 3*size2 - 1;i++){
for(j = 0;j < N;j++){
if(j == 0 || j == N-1){
B[m][j] = A[i][j];
}
else{
// B[i-3 * rank - 1][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
B[m][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
}
}
m += 1;
}
MPI_Recv(&x, 1, MPI_INT, 1, 200, MPI_COMM_WORLD, &status);
// for(i = 2*N/size + 1;i < 3*N/size - 1; i++){
// printf("\n");
// for(j = 0; j < N;j++){
// printf("%f ", B[i][j]);
// }
// }
for(i = 0;i < N/size;i++){
printf("\n");
for(j = 0; j < N;j++){
printf("%f ", B[i][j]);
}
}
MPI_Send(&x, 1, MPI_INT, 3, 200, MPI_COMM_WORLD);
}
else{
// 给2号进程发消息
for(k = 0; k < N; k++){
MPI_Send(&A[3*size2 + 1][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD);
}
// 接收2号进程发来的消息
for(k = 0; k < N; k++){
MPI_Recv(&A[3*size2][k], 1, MPI_FLOAT, rank - 1, k, MPI_COMM_WORLD, &status);
}
// 赋值+计算
for(i = 3*size2 + 1; i < 4*size2 - 1;i++){
if( i == 4*size2 - 2){
for(j = 0;j < N;j++){
B[i-4 * rank - 1][j] = A[i][j];
}
}
else{
for(j = 0;j < N;j++){
if(j == 0 || j == N-1){
B[m][j] = A[i][j];
}
else{
// B[i-4 * rank - 1][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
B[m][j] = 0.25 * (A[i-1][j] + A[i][j-1] + A[i+1][j] + A[i][j+1]);
}
}
}
m += 1;
}
MPI_Recv(&x, 1, MPI_INT, 2, 200, MPI_COMM_WORLD, &status);
// for(i = 3* N/size + 1;i < 4*N/size - 1; i++){
// printf("\n");
// for(j = 0; j < N;j++){
// printf("%f ", B[i][j]);
// }
// }
for(i = 0;i < N/size;i++){
printf("\n");
for(j = 0; j < N;j++){
printf("%f ", B[i][j]);
}
}
}
printf("\n");
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}