⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jacobi.c

📁 利用MPI实现并行化的jacobi算法
💻 C
字号:
/****************************************************************************
程序名:jacobi.c
程序功能:
1、利用MPI实现利用jacobi算法实现n*n线性方程组求解的并行计算
2、在主节点进行串行jacobi算法,对同一方程组求解
3、对比执行时间
****************************************************************************/
//需引用头文件:
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>

//常量定义区
#define MAX_Node 100 //允许的最大未知数个数
#define MAX_BufSize (MAX_Node * MAX_Node) //允许最大的系数的个数

#define MAX_loops 10000 //最大迭代次数
#define TOLERANCE 0.0001 //误差

//变量定义区
int pID, pSize; //pID:当前进程ID,pSize:总的进程数
int size,n, iteration = 0; //n:未知数的个数,iternation:迭代的次数
float x[MAX_Node], new_x[MAX_Node], result_x[MAX_Node]; //x:表示上一次迭代的结果,new_x:表示这一次迭代的结果,result_x:表示归约之后得到的总的结果
float a[MAX_Node][MAX_Node]; //系数
float b[MAX_Node]; 
FILE *finput;//输入数据

//函数定义区
float norm_inf(float x[],int n)
{
 float norm;
 int i;
 norm=fabs(x[0]);
 for(i=1;i<n;i++)
 {
  if(fabs(x[i])>norm)
   norm=fabs(x[i]);
 }
 return norm;
} 
//串行算法实现函数:
void serial_jacobi(float a[MAX_Node][MAX_Node],float g[MAX_Node],int n)
{
 float b[MAX_Node][MAX_Node]={0},x0[MAX_Node],x1[MAX_Node],x1_x0[MAX_Node],norm,temp;
 int i,j,k;
 //初始化结果集:
 for(i=0;i<n;i++)
 {
  g[i]=g[i]/a[i][i];
  for(j=0;j<n;j++)
  {
   if(i==j)
    continue;
   b[i][j]=-a[i][j]/a[i][i];
  }
 }
 
 for(i=0;i<n;i++)
 {
  x0[i]=0;
  x1[i]=1;
  x1_x0[i]=x1[i]-x0[i];
 }
 k=0;
 norm=norm_inf(x1_x0,n);
 
 //叠代计算新的结果集
 while((norm>=TOLERANCE)&&(k<MAX_loops))
 {
  for(i=0;i<n;i++)
   x0[i]=x1[i];
  for(i=0;i<n;i++)
  {
   temp=0;
   for(j=0;j<n;j++)
    temp=temp+b[i][j]*x0[j];
   x1[i]=temp+g[i];
   x1_x0[i]=x1[i]-x0[i];
  }
  norm=norm_inf(x1_x0,n);
  k++;
 }
 //结果输出
 for(i=0;i<n;i++)
  printf("x[%d]=%lf\n",i,x1[i]);
 printf("Serial Total Iteration : %d\n", k);

}
//读取输入文件
void input(){
	
    
    int i, j;
    printf("The n is %d\n", n);
    fflush(stdout);
        
		fscanf(finput,"%d", &size);
    // 判断是否是合法输入,如果不是,程序退出
    if(size != n)
    {
        puts("The input is error!");
        MPI_Finalize();
        exit(0);
    }
    //读入A的系数和b,并保存到aij和bj中
    for(i = 0; i < size; i ++)
    {
        for(j = 0; j < size; j ++) fscanf(finput, "%f", &a[i][j]);
        fscanf(finput, "%f", &b[i]);
    }
    
    //输出待测内容:
    for(i = 0; i < size; i ++)
    {
    		for(j = 0; j < size; j ++) 
    		{
    			if (j==size-1) printf("%f*X[%d]\t",a[i][j],j);
    				else printf("%f*X[%d] + ",a[i][j],j);
    		}
     		printf(" = %f\n",b[i]); 			
  	}
    fclose(finput);
}
//输出结果
void p_output(){
    
    int i;
    printf("parallel jacobi:\n");
        if(iteration > MAX_loops) printf(", that is out of the limit of iteration!\n");
    for(i = 0; i < n; i++)
        printf("x[%d] is %f\n", i, result_x[i]);
    printf("Parallel Total Iteration : %d\n", iteration);
}
//判断精度是否满足要求,满足要求则返回1,否则,返回0
char tolerance(){
    
    int i;
    
    //有一个不满足误差的,则返回0
    for(i = 0; i < n; i++)
        if(result_x[i] - x[i] > TOLERANCE || x[i] - result_x[i] > TOLERANCE)
            return 0;
    
    //全部满足误差,返回1
    return 1;
}

//入口,主函数
int main(int argc, char* argv[]) {
    
    MPI_Status status; 
    int i, j;
    float sum;
    double starttime, endtime; 
    char	CfgFileName[100];
    
    //输入文件:默认为input,如加参数可指定读入文件名,但必须和可执行文件处于同一目录下
    if (argc == 1)
			finput=fopen("input","r");
		else if (argc == 2)
			sprintf(CfgFileName, "./%s", argv[1]);
    finput=fopen(CfgFileName,"r");
     
    //初始化
    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &pID); 
    MPI_Comm_size(MPI_COMM_WORLD, &pSize); 
   
   	    
    //每个进程对应一个未知数
    n = pSize; 

    //根进程负责输入
    if(!pID) input();
    
    //开始计时
    starttime = MPI_Wtime(); 
        
    //广播系数
    MPI_Bcast(a, MAX_BufSize, MPI_FLOAT, 0, MPI_COMM_WORLD);
    //广播b
    MPI_Bcast(b, MAX_Node, MPI_FLOAT, 0, MPI_COMM_WORLD);
    
    //初始化x的值
    for(i = 0; i < n; i++) {
        x[i] = b[i];
        new_x[i] = b[i];
    }
    
       //当前进程处理的元素为该进程的ID
    i = pID;
    
    //迭代求x[i]的值
    do{
        //迭代次数加1
        iteration++;
        
        //将上一轮迭代的结果作为本轮迭代的起始值,并设置新的迭代结果为0
        for(j = 0; j < n; j++)
        {
            x[j] = result_x[j];
            new_x[j] = 0;
            result_x[j] = 0;
        }            
        
        //同步等待
        MPI_Barrier(MPI_COMM_WORLD);
          
        //求和
        sum = - a[i][i] * x[i];
        for(j = 0; j < n; j++) sum += a[i][j] * x[j];
        
        //求新的x[i]
        new_x[i] = (b[i] - sum) / a[i][i];
          
        //使用归约的方法,同步所有计算结果
        MPI_Allreduce(new_x, result_x, n, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD);
        
        //如果迭代次数超过了最大迭代次数则退出
        if(iteration > MAX_loops) {
            break;
        }
    } while(!tolerance()); //精度不满足要求继续迭代
    
    //根进程负责输出结果
    if(!pID) {
    p_output();
        endtime   = MPI_Wtime(); 
   	printf("parallel took %f seconds\n",endtime-starttime); 
  	}
    //并行结束
   
   	//主进程运算串行算法
    if(!pID) {
    printf("serial jacobi:\n");

    starttime = MPI_Wtime();
    serial_jacobi(a,b,n);
    endtime   = MPI_Wtime(); 

   	printf("serial took %f seconds\n",endtime-starttime); 
  	}
    
    MPI_Finalize(); 
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -