解线性方程组(二)——Jacobi迭代法求解(C++)

迭代法

相比于直接法求解,迭代法使用多次迭代来逐渐逼近解,其精度比不上直接法,但是其速度会比直接法快很多,计算精度可控,特别适用于求解系数矩阵为大型稀疏矩阵的方程组。

Jacobi迭代法

假设有方程组如下:
{ a 11 x 1 + a 12 x 2 + ⋯ + a 1 n x n = b 1 a 21 x 1 + a 22 x 2 + ⋯ + a 2 n x n = b 2 ⋯ ⋯ ⋯ a n 1 x 1 + a n 2 x 2 + ⋯ + a n n x n = b n \begin{cases} a_{11}x_1+a_{12}x_2+\cdots+a_{1n}x_n=b_1\\ a_{21}x_1+a_{22}x_2+\cdots+a_{2n}x_n=b_2\\ \cdots \qquad \qquad\cdots \qquad \qquad \cdots \\ a_{n1}x_1+a_{n2}x_2+\cdots+a_{nn}x_n=b_n\\ \end{cases} a11x1+a12x2++a1nxn=b1a21x1+a22x2++a2nxn=b2an1x1+an2x2++annxn=bn
将其转换为矩阵形式
A x ⃗ = b ⃗ A\vec{x}=\vec{b} Ax =b
[ a 11 a 12 ⋯ a 1 n a 21 a 22 ⋯ a 2 n ⋮ ⋮ ⋱ ⋮ a m 1 a m 2 ⋯ a m n ] [ x 1 x 2 ⋮ x n ] = [ b 1 b 2 ⋮ b n ] \begin{bmatrix} {a_{11}}&{a_{12}}&{\cdots}&{a_{1n}}\\ {a_{21}}&{a_{22}}&{\cdots}&{a_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{m1}}&{a_{m2}}&{\cdots}&{a_{mn}}\\ \end{bmatrix} \begin{bmatrix} {x_{1}}\\ {x_{2}}\\ {\vdots}\\ {x_{n}}\\ \end{bmatrix}= \begin{bmatrix} {b_{1}}\\ {b_{2}}\\ {\vdots}\\ {b_n} \end{bmatrix} a11a21am1a12a22am2a1na2namn x1x2xn = b1b2bn
对于是否可以使用Jacobi迭代法,需要满足以下条件之一:

  1. A为行对角优阵,即 ∣ a i i ∣ > ∑ j ≠ i ∣ a i j ∣ ( i = 1 , 2 , ⋯ , n ) |a_{ii}|>\sum_{j \neq i}|a_{ij}|(i=1,2,\cdots,n) aii>j=iaij(i=1,2,,n)
  2. A为行列角优阵,即 ∣ a j j ∣ > ∑ j ≠ i ∣ a i j ∣ ( j = 1 , 2 , ⋯ , n ) |a_{jj}|>\sum_{j \neq i}|a_{ij}|(j=1,2,\cdots,n) ajj>j=iaij(j=1,2,,n)
  3. A的元素满足 ∑ i ≠ j ∣ a i j ∣ ∣ a i i ∣ < 1 ( j , 1 , 2 , ⋯ , n ) \sum_{i \neq j}\frac{|a_{ij}|}{|aii|}<1(j,1,2,\cdots,n) i=jaiiaij<1(j,1,2,,n)
    若矩阵A满足上述条件之一,则可以使用Jacobi迭代法求解方程组。
    首先将上述的方程组转为如下形式:
    { x 1 = 1 a 11 ( − a 12 x 2 − ⋯ − a 1 n x n + b 1 ) x 2 = 1 a 22 ( − a 21 x 1 − ⋯ − a 2 n x n + b 2 ) ⋯ ⋯ ⋯ x n = 1 a n n ( − a n 1 x 1 − ⋯ − a n n − 1 x n − 1 + b n ) \begin{cases} x_1=\frac{1}{a_{11}}(-a_{12}x_2-\cdots -a_{1n}x_n+b_1)\\ x_2=\frac{1}{a_{22}}(-a_{21}x_1-\cdots -a_{2n}x_n+b_2)\\ \cdots \qquad \qquad\cdots \qquad \qquad \cdots \\ x_n=\frac{1}{a_{nn}}(-a_{n1}x_1-\cdots -a_{nn-1}x_{n-1}+b_n)\\ \end{cases} x1=a111(a12x2a1nxn+b1)x2=a221(a21x1a2nxn+b2)xn=ann1(an1x1ann1xn1+bn)
    写成矩阵形式可以得到Jacobi迭代式:
    ( D + L + u ) x ⃗ = b ⃗ D x ⃗ = − ( L + U ) x ⃗ + b ⃗ x ⃗ ( k + 1 ) = − D − 1 ( L + U ) x ⃗ ( k ) + D − 1 b ⃗ (D+L+u)\vec{x}=\vec{b}\\ D\vec{x}=-(L+U)\vec{x}+\vec{b}\\ \vec{x}^{(k+1)}=-D^{-1}(L+U)\vec{x}^{(k)}+D^{-1}\vec{b} (D+L+u)x =b Dx =(L+U)x +b x (k+1)=D1(L+U)x (k)+D1b
    其中 D D D为对角矩阵, L L L为下三角矩阵- D D D U U U为上三角矩阵- U U U D + L + U D+L+U D+L+U为矩阵A。
    在这里插入图片描述

代码实现

由于这个过程涉及大量的矩阵操作,整个算法分为两个源文件:Matrix.cpp实现矩阵操作,main.cpp实现Jacobi迭代法。
首先是Matrix.cpp的代码,其中矩阵求逆的原理参考:

#include <Matrix.h>
#include <iostream>
#include <cmath>
//矩阵与向量相乘,输入矩阵A,向量b,运算结果result和维数n
void matrix_multiply_vector(double **A,double *b,double * result,int n)
{for(int i=0;i<n;i++){result[i]=0.0;for(int j=0;j<n;j++){result[i]+=A[i][j]*b[j];}}
}
//矩阵乘法
void matrix_multiply_matrix(double **A,double **B,double **result,int n)
{for(int i=0;i<n;i++){for(int j=0;j<n;j++){result[i][j]=0.0;for(int k=0;k<n;k++){result[i][j]+=A[i][k]*B[k][j];}}}
}
//矩阵加减法
void matrix_add_matrix(double **A,double **B,double **result,int n,bool isAdd)
{for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(isAdd){result[i][j]=A[i][j]+B[i][j];}else{result[i][j]=A[i][j]-B[i][j];}}}
}
//向量的加减法
void vactor_add_vector(double *A,double *B,double *result,int n,bool isAdd)
{for(int i=0;i<n;i++){if(isAdd){result[i]=A[i]+B[i];}else{result[i]=A[i]-B[i];}}
}
//判断向量误差范围,只要符合精度即可
bool vector_equal(double *A,double *B,int n,double error)
{for(int i=0;i<n;i++){if(fabs(A[i]-B[i])>error){return false;}}return true;
}
//向量赋值
void vector_copy(double *A,double *B,int n)
{for(int i=0;i<n;i++){B[i]=A[i];}
}
//矩阵初始化
void matrix_init(double **A,int n)
{for(int i=0;i<n;i++){A[i]=new double [n];for(int j=0;j<n;j++){A[i][j]=0.0;}}
}
//判断矩阵A是否有收敛性
bool astringency(double **A,int n)
{double abs_row_sum=0.0;double abs_col_sum=0.0;double the_third_condition=0.0;bool RowOptimalMatrix=true;bool ColOptimalMatrix=true;for(int i=0;i<n;i++)//判断是不是行对角优阵{abs_row_sum=0.0;for(int j=0;j<n;j++){if(i!=j){abs_row_sum+=fabs(A[i][j]);}}if(abs_row_sum>A[i][i])//证明不是行对角优阵{RowOptimalMatrix=false;break;}}for(int j=0;j<n;j++)//判断是不是列对角优阵{abs_col_sum=0.0;for(int i=0;i<n;i++){if(i!=j){abs_col_sum+=fabs(A[i][j]);}}if(abs_col_sum>A[j][j]){ColOptimalMatrix=false;break;}}return ColOptimalMatrix or RowOptimalMatrix;
}
//矩阵交换某两行
void matrix_swap_row(double **A,int i,int j,int n)
{double temp;for(int k=0;k<n;k++){temp=A[i][k];A[i][k]=A[j][k];A[j][k]=temp;}
}
//矩阵第i行=矩阵第i行-矩阵第j行*a
void matrix_minus_inner(double **A,double a,int i,int j,int n)
{for(int k=0;k<n;k++){A[i][k]-=a*A[j][k];}
}
//矩阵求逆
void matrix_inverse(double **A,double **A_inverse,int n)
{double **A_E=new double*[2*n];//构建增广矩阵for(int i=0;i<n;i++){A_E[i]=new double [n*2];for(int j=0;j<n*2;j++){if(j<n){A_E[i][j]=A[i][j];}else if((j-n)==i){A_E[i][j]=1;}else{A_E[i][j]=0;}}}//首先将矩阵化为上三角矩阵for(int i=0;i<n;i++){if(A_E[i][i]==0){for(int k=i+1;k<n;k++){if(A_E[k][i]!=0){matrix_swap_row(A_E,i,k,n*2);break;}}}for(int j=i+1;j<n;j++){matrix_minus_inner(A_E,A_E[j][i]/A_E[i][i],j,i,2*n);}}//判断矩阵是否可逆for(int i=0;i<n;i++){if(A_E[i][i]==0){std::cout<<"矩阵不可逆"<<std::endl;exit(0);}}//将上三角转换为对角矩阵for(int j=1;j<n;j++){for(int i=0;i<j;i++){matrix_minus_inner(A_E,A_E[i][j]/A_E[j][j],i,j,2*n);}}for(int i=0;i<n;i++){for(int j=n;j<2*n;j++){A_inverse[i][j-n]=A_E[i][j]/A_E[i][i];}}
}

main.cpp文件内容如下:

//Jacobi迭代法求解线性方程组
/*
5x1+2x2-2x3=1
x1+4x2+x3=2
x1-2x2+4x3=-1
*/
#include<iostream>
#include<cmath>
#include<Matrix.h>//自定义头文件
using namespace std;
int main()
{int n;cout<<"Enter the matrix dimension A: ";cin>>n;//输入数组维度double **A=new double *[n];cout<<"Enter the coefficient matrix:"<<endl;for(int i=0;i<n;i++){A[i]=new double[n];for(int j=0;j<n;j++){cin>>A[i][j];//每次输入一个数字都用空格隔开,输入样例//1 2 3\enter//4 5 6\enter//7 8 9\enter}}double *b=new double[n];cout<<"Input vectors b: ";for(int i=0;i<n;i++){cin>>b[i];//输入方程组右边的向量,1 2 3\enter}bool isAstringency=astringency(A,n);//判断系数矩阵A是否具有收敛性if(isAstringency){cout<<"矩阵A符合收敛性"<<endl;}else{exit(0);cout<<"矩阵A不符合收敛性"<<endl;}double *x=new double[n];//解向量Xdouble *x_last=new double[n];//上一次的xfor(int i=0;i<n;i++){x[i]=0.0;//初始化x}double **A_L_U=new double*[n];//L+Udouble **A_D_inverse=new double*[n];//D的逆for(int i=0;i<n;i++){A_D_inverse[i]=new double [n];A_L_U[i]=new double [n];for(int j=0;j<n;j++){if(i==j){A_L_U[i][j]=0.0;A_D_inverse[i][j]=1.0/A[i][j];//对角矩阵的逆为其倒数}else{A_L_U[i][j]=A[i][j];A_D_inverse[i][j]=0.0;}}}double **B=new double *[n];//公式前半段的矩阵matrix_init(B,n);matrix_multiply_matrix(A_D_inverse,A_L_U,B,n);//求D^(-1)(L+U)double *f=new double[n];matrix_multiply_vector(A_D_inverse,b,f,n);//求取D^-1 * bdouble *temp1=new double[n];do{vector_copy(x,x_last,n);matrix_multiply_vector(B,x_last,temp1,n);//计算公式前半段vactor_add_vector(f,temp1,x,n,false);}while(vector_equal(x,x_last,n,1e-6)==false);//判断向量在误差范围内相等cout<<"运行结果为:"<<endl;for(int i=0;i<n;i++){cout<<x[i]<<" ";}system("pause");return 0;
}

结果分析

代码运行结果如下:
在这里插入图片描述

当下一次的迭代结果与上一次的迭代结果的最大相差值小于1e-6时,认为迭代已经收敛,输出结果即可(当然也可以换成其它结束迭代方法,如:判断两个向量之差的二范数)。
与直接使用克拉默法则计算准确的解以及matlab计算结果比较,不难发现其 x 1 x_1 x1 x 3 x_3 x3均不为0,只是是一个在我们设定的误差范围内接近0的数,符合迭代法的解的性质,只能在设定的误差范围内得到一个近似的解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/472630.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JDBC查询操作

目录 加载驱动获取连接创建会话发送SQL处理结果关闭资源测试 加载驱动 // 加载驱动Class.forName("com.mysql.cj.jdbc.Driver");获取连接 // 获取连接String url "jdbc:mysql://127.0.0.1:3306/book";String username "root" …

第14集《佛说四十二章经》

好&#xff01;请大家打开讲义第十九面&#xff0c;第三十九章、教诲无差。 佛言&#xff1a;学佛道者&#xff0c;佛所言说&#xff0c;皆应信顺。譬如食蜜&#xff0c;中边皆甜。吾经亦尔。 大智慧的佛陀说&#xff0c;佛弟子们在修学过程中&#xff0c;对佛陀所说的一切佛…

cloudflare更换第三方证书

由于我的网站一直放在腾讯云上&#xff0c;域名和证书也是在腾讯云上解析的&#xff0c;后来将DNS迁移到了cloudflare&#xff0c;最近SSL证书到期了遇到一些麻烦记录一下。 由于服务器上原来是装的腾讯云发的免费证书&#xff0c;所以这次我也是按部就班的先去申请腾讯云的证…

政安晨:【示例演绎】【Python】【Numpy数据处理】快速入门(四)—— 函数方法

准备工作 这是Numpy数据处理的示例演绎系列文章的第四篇&#xff0c;我的前三篇文章为&#xff1a; 政安晨&#xff1a;【示例演绎】【Python】【Numpy数据处理】快速入门&#xff08;一&#xff09;https://blog.csdn.net/snowdenkeke/article/details/136125773政安晨&#…

【51单片机】AD模数转换DA数模转换(江科大)

1.AD/DA介绍 AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号 DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号 AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理…

C#,二分法(Bisection Method)求解方程的算法与源代码

1 二分法 二分法是一种分治算法&#xff0c;是一种数学思维。 对于区间[a&#xff0c;b]上连续不断且f&#xff08;a&#xff09;f&#xff08;b&#xff09;<0的函数yf&#xff08;x&#xff09;&#xff0c;通过不断地把函数f&#xff08;x&#xff09;的零点所在的区间…

问题:人的安全知识和技能是天生的。() #媒体#知识分享#学习方法

问题&#xff1a;人的安全知识和技能是天生的。&#xff08;) 人的安全知识和技能是天生的。() 参考答案如图所示 问题&#xff1a;&#xff08;&#xff09;是党和国家的根本所在、命脉所在&#xff0c;是全国各族人民的利益所在、幸福所在。 A.人民当家作主 B.坚持和完善…

命令执行讲解和函数

命令执行漏洞简介 命令执行漏洞产生原因 应用未对用户输入做严格得检查过滤&#xff0c;导致用户输入得参数被当成命令来执行 命令执行漏洞的危害 1.继承Web服务程序的权限去执行系统命会或读写文件 2.反弹shell&#xff0c;获得目标服务器的权限 3.进一步内网渗透 远程代…

基于JAVA,SpringBoot和Vue二手房屋销售系统设计

摘要&#xff1a; 本研究旨在设计并实现一个基于JAVA, SpringBoot和Vue技术的二手房屋销售系统。该系统采用当前流行的前后端分离架构&#xff0c;后端使用SpringBoot框架快速搭建RESTful API&#xff0c;提供稳定且高效的服务端应用&#xff1b;前端则通过Vue.js框架构建动态…

vue导出word文档(图文示例)

第076个 查看专栏目录: VUE 本文章目录 示例说明示例效果图导出的文件效果截图示例源代码参数说明&#xff1a;重要提示&#xff1a;API 参考网址 示例说明 在Vue中导出Word文档&#xff0c;可以使用第三方库file-saver和html-docx-js。首先需要安装这两个库&#xff1a; npm …

2024年最新onlyfans虚拟信用卡订阅教程

一、Onlyfans是什么&#xff1f; OnlyFans是一个允许创作者分享自己的独家内容的平台&#xff0c;简称o站。这个平台允许创作者创建一个订阅服务&#xff0c;粉丝需要支付费用才能访问其独家内容。 本文将教你如何使用虚拟卡在OnlyFans上进行充值。 二、如何使用虚拟卡支付 O…

MySQL数据表的约束

已经一个星期没更了&#xff0c;因为过年嘛&#xff0c;比较忙&#xff0c;我玩心也大&#xff0c;就没继续更新&#xff0c;在这里给大家道歉&#xff0c;也祝大家新的一年快快乐乐&#xff0c;新年快乐。 为防止数据表中插入错误的数据&#xff0c;MySQL定义了一些规则维护数…