数值计算笔记之线性方程组的迭代解、迭代方法

一、迭代解

1、直接法与迭代法

直接法:直接求出准确解

迭代法:得到近似解(由截断误差造成)

例:求解方程组

\left\{\begin{matrix} 3x_{1}+x_{2}=5\\ x_{1}+2x_{2}=5 \end{matrix}\right.

解法一:直接法(选择高斯消去法)

1、消元 \begin{bmatrix} 3 &1 &5 \\ 1& 2 &5 \end{bmatrix} \rightarrow \begin{bmatrix} 3 &1 &5 \\ 0&\frac{5}{3} & \frac{10}{3} \end{bmatrix}

2、回代  x=\begin{bmatrix} 1&2 \end{bmatrix}^{T}

解法二:迭代法

迭代法基本原理

f(x) = 0 \Leftrightarrow x = g(x)

给定某初始解x_{0},按  x_{k+1} = g(x_{k})    k = 0,1,2,\cdots

若{{x_{k}}}收敛于x^{*},且 g(x)连续,则x^{*}即为f(x) = 0的解 (\because \lim_{k\rightarrow \infty }x_{k+1} = g(\lim_{k\rightarrow \infty }x_{k})   \therefore x^{*} = g(x^{*})

 详细过程链接。非线性方程的求解(迭代法)

下面是方程组的:

\left\{\begin{matrix} x_{1}=\frac{1}{3}(5-3x_{2})\\ x_{2}=\frac{1}{2}(5-x_{1}) \end{matrix}\right. \Rightarrow \left\{\begin{matrix} x_{1}^{n+1}=\frac{1}{3}(5-3x_{2}^{k})\\ x_{2}^{k+1}=\frac{1}{2}(5-x_{1}^{k}) \end{matrix}\right.

取初始向量 x^{0}=(0,0)^{T}  ,进行迭代运算,其迭代过程取下:

迭代结果
k x_{1}^{k} x_{2}^{k}
0 0 0
1 1.6667 2.5
2 0.8333 1.6667
\vdots \vdots \vdots
9 1.0005 2.0004
10 0.9998 1.9997

最后取 x=(0.9998,1.9997)^{T} 作为方程组的近似解。 

问题:再能求得准确解的情况下,为什么还要用迭代法求它的近似解呢?

因为最终是要通过计算机编写程序来得到计算结果的,当未知数非常多,问题规模非常大的时候,直接法占用的内存非常大,而迭代法就比较少。

2、向量序列和矩阵序列的收敛性

定义:设 {{x^{(k)}}} 为R^{n} 中向量序列x\in R^{n},若\lim_{k\rightarrow\infty }||x^{(k)}-x||=0 (范数),则称 {{x^{k}}} 收敛于 x,记作 \lim_{k\rightarrow \infty }x^{(k)}=x

定义:设 {{A^{(k)}}} 为 n\times n 矩阵序列A = (a_{ij})_{n\times n}。若 \lim_{k\rightarrow \infty }||A^{(k)}-A||=0,则称 {{A^{(k)}}} 收敛于A

3、迭代法的一般形式

AX=b\Leftrightarrow X=GX+d \overset{Iterative formula}{\rightarrow} X^{(k+1)}=GX^{(k)}+d,其中G 被称作迭代矩阵。

二、迭代方法

1、雅可比迭代法(Jacobbi)

一般形式:

\left\{\begin{matrix} 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}\\ \vdots \\ a_{n1}x_{1}+a_{n2}x_{2}+\cdots +a_{nn}x_{n}=b_{n} \end{matrix}\right.

其中 a_{ii}\neq 0 (i=1,2,\cdots ,n)

转化为:

\left\{\begin{matrix} x_{1} = \frac{1}{a_{11}}\cdot (b_{1} - a_{12}x_{2}-\cdots -a_{1n}x_{n}) \\ x_{2} = \frac{1}{a_{22}}\cdot (b_{2} - a_{21}x_{1}-\cdots -a_{2n}x_{n}) \\ \vdots \\ x_{n} = \frac{1}{a_{nn}}\cdot (b_{n} - a_{n1}x_{1}-\cdots -a_{n,n-1}x_{n-1}) \end{matrix}\right.

从而得到 迭代公式:

\left\{\begin{matrix} x_{1}^{(k+1)} = \frac{1}{a_{11}}\cdot (b_{1} - a_{12}x_{2}^{(k)}-\cdots -a_{1n}x_{n}^{(k)}) \\ x_{2}^{(k+1)} = \frac{1}{a_{22}}\cdot (b_{2} - a_{21}x_{1}^{(k)}-\cdots -a_{2n}x_{n}^{(k)}) \\ \vdots \\ x_{n}^{(k+1)} = \frac{1}{a_{nn}}\cdot (b_{n} - a_{n1}x_{1}^{(k)}-\cdots -a_{n,n-1}x_{n-1}^{(k)}) \end{matrix}\right.

具体例子见上一个。

令 A 为系数矩阵,

A=\begin{bmatrix} a_{11} &a_{12} &\cdots &a_{1n} \\ a_{21}&a_{22} & \cdots &a_{2n} \\ \vdots & &\ddots &\vdots \\ a_{n1}&a_{n2} &\cdots & a_{nn} \end{bmatrix} ,现将 A 分为 三个部分,下三角 L,上三角U,对角线 D. 记

L=\begin{bmatrix} 0 & & & \\ a_{21} & 0& & \\ \vdots & \ddots & 0 & \\ a_{n1} & \cdots & a_{n,n-1}& 0 \end{bmatrix} ,U=\begin{bmatrix} 0 & a_{12} &\cdots &a_{1n} \\ & 0 &\ddots &\vdots \\ & & 0 &a_{n-1,n} \\ & & & 0 \end{bmatrix} ,D=\begin{bmatrix} a_{11} & & & \\ & a_{22} & & \\ & & \ddots & \\ & & & a_{nn} \end{bmatrix}

\therefore A = L + D + U

再次观察迭代公式

\left\{\begin{matrix} x_{1}^{(k+1)} = \frac{1}{a_{11}}\cdot (b_{1} - a_{12}x_{2}^{(k)}-\cdots -a_{1n}x_{n}^{(k)}) \\ x_{2}^{(k+1)} = \frac{1}{a_{22}}\cdot (b_{2} - a_{21}x_{1}^{(k)}-\cdots -a_{2n}x_{n}^{(k)}) \\ \vdots \\ x_{n}^{(k+1)} = \frac{1}{a_{nn}}\cdot (b_{n} - a_{n1}x_{1}^{(k)}-\cdots -a_{n,n-1}x_{n-1}^{(k)}) \end{matrix}\right.                  又 数值计算笔记之线性方程组的迭代解、迭代方法_第1张图片

故 雅可比迭代公式为:

X^{(k+1)} = D^{-1}(b-L\cdot X^{(k)}-U\cdot X^{(k)})     或者  X^{(k+1)}= D^{-1}b - D^{-1} (L+U)\cdot X^{(k)} =D^{-1}b-D^{-1}(A-D)\cdot X^{(k)}

\therefore X^{(k+1)}=(I-D^{-1}A)X^{(k)}+D^{-1}b (形如X^{(k+1)}=GX^{(k)}+d),其中 (I-D^{-1}A) 为迭代矩阵  。

2、高斯--赛德尔迭代法(Guass-seidel)

高斯--赛德尔迭代法由雅可比迭代法的基础上得来,加快了雅可比迭代法的收敛速度。

高斯-赛德尔迭代阵: G_{g-s}=-(D+L)^{-1}\cdot U 。

先看看 Jacobbi迭代法 递推公式:

\left\{\begin{matrix} x_{1}^{(k+1)} = \frac{1}{a_{11}}\cdot (b_{1} - a_{12}x_{2}^{(k)}-\cdots -a_{1n}x_{n}^{(k)}) \\ x_{2}^{(k+1)} = \frac{1}{a_{22}}\cdot (b_{2} - a_{21}x_{1}^{(k)}-\cdots -a_{2n}x_{n}^{(k)}) \\ \vdots \\ x_{n}^{(k+1)} = \frac{1}{a_{nn}}\cdot (b_{n} - a_{n1}x_{1}^{(k)}-\cdots -a_{n,n-1}x_{n-1}^{(k)}) \end{matrix}\right.

 高斯--赛德尔迭代法 递推公式为:

x_{1}^{(k+1)} = \frac{1}{a_{11}}\cdot (b_{1} - a_{12}x_{2}^{(k)}-\cdots -a_{1n}x_{n}^{(k)})   ,现 x_{1}^{(k+1)}已知,带入 x_{2}^{(k+1)}的表达式,有:

x_{2}^{(k+1)}=\frac{1}{a_{22}}(b_{2}-a_{21}x_{1}^{(k+1)}-a_{23}x_{3}^{(k)}-\cdots -a_{2n}x_{n}^{(k)})     ,同理,x_{1}^{(k+1)}x_{2}^{(k+1)}已知,带入 x_{3}^{(k+1)}表达式,有:

x_{3}^{(k+1)}=\frac{1}{a_{33}}(b_{3}-a_{31}x_{1}^{(k+1)}-a_{32}x_{2}^{(k+1)}-a_{34}x_{4}^{(k)}\cdots -a_{3n}x_{n}^{(k)})

\cdots \cdots

x_{n}^{(k+1)}=\frac{1}{a_{nn}}(b_{n}-a_{n1}x_{1}^{(k+1)}-a_{n2}x_{3}^{(k+1)}-\cdots -a_{n,n-1}x_{n}^{(k+1)})

例:用 Guass-seidel 解方程组

\begin{bmatrix} 10 & -1 &-2 \\ -1& 10 &-2 \\ -1& -1&5 \end{bmatrix} \cdot \begin{bmatrix} x_{1}\\ x_{2}\\ x_{3} \end{bmatrix}= \begin{bmatrix} 7.2\\ 8.3\\ 4.2 \end{bmatrix}

解:\Rightarrow \left\{\begin{matrix} x_{1}=0.1x_{2}+0.2x_{3}+0.72\\ x_{2}=0.1x_{1}+0.2x_{3}+0.83\\ x_{3}=0.2x_{1}+0.2x_{2}+0.84 \end{matrix}\right.

迭代公式:

\Rightarrow \left\{\begin{matrix} x_{1}=0.1x_{2}^{(k)}+0.2x_{3}^{(k)}+0.72\\ x_{2}=0.1x_{1}^{(k+1)}+0.2x_{3}^{(k)}+0.83\\ x_{3}=0.2x_{1}^{(k+1)}+0.2x_{2}^{(k+1)}+0.84 \end{matrix}\right.    ,取初值 x=(0,0,0)^{T}

结果看下面。

三、代码实现

上个例子结果:

数值计算笔记之线性方程组的迭代解、迭代方法_第2张图片数值计算笔记之线性方程组的迭代解、迭代方法_第3张图片

C++代码:

guassSeidel.h 文件

#pragma once
#include
#include
#include
#include
#include
#include
#include"guassSeidel.h"
using namespace std;
using namespace arma;

const double err = 1e-6;
mat A;
vec X, b, X_temp;

void GreateA_mat(int &n) {
	A.zeros(n, n);
	/*for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			double temp;
			cout << "请输入系数" << '\t' << "A" << "(" << i << "," << j << ")" << " =   ";
			cin >> temp;
			A(i, j) = temp;
		}
	}
	A.print("A:");*/
	ifstream readfileA("A.txt", ios::in);
	if (!readfileA.is_open())
		cout << "Open file failure !" << endl;
	while (!readfileA.eof()) {
		for (int i = 0; i < 3; i++) {
			double a0, a1, a2;
			readfileA >> a0 >> a1 >> a2;
			A(i, 0) = a0;
			A(i, 1) = a1;
			A(i, 2) = a2;
		}
	}
	readfileA.close();
}

void Fillb_mat(int &n) {
	//cout << "请填充矩阵 b" << endl;
	b.zeros(n);
	ifstream readfileb("b.txt", ios::in);
	if (!readfileb.is_open())
		cout << "Open file failure !" << endl;
	while (!readfileb.eof()) {
		for (int i = 0; i < 3; i++) {
			double temp;
			readfileb >> temp;
			b(i) = temp;
		}
	}
	readfileb.close();
	/*for (int i = 0; i < n; i++) {
		double temp;
		cout << "请输入   " << "b" << i  << " =   ";
		cin >> temp;
		b(i) = temp;
	}
	b.print("b:");*/
}

void InitX_mat(int &n) {
	//cout << "请输入X矩阵的初始值 " << endl;
	X.zeros(n);
	/*for (int i = 0; i < n; i++) {
		double temp;
		cout << "请输入初始值   "  << "x"  << i  << " =   ";
		cin >> temp;
		X(i) = temp;
	}
	X.print("X:");*/
	ifstream readfileX("x.txt", ios::in);
	if (!readfileX.is_open())
		cout << "Open file failure !" << endl;
	while (!readfileX.eof()) {
		for (int i = 0; i < 3; i++) {
			double x;
			readfileX >> x;
			X(i) = x;
		}
	}
}

void saveDate(int &n) {
	ofstream outfileX("X_result.txt",ios::app);  //从文件末尾开始写,防止丢失文件中原来就有的内容
	if (!outfileX.is_open())
		cout << "Open file failure !" << endl;

	for (int i = 0; i < n; i++) {
		outfileX << X(i) << '\t';
	}
	outfileX << endl;
	outfileX.close();
}

void Iteration(int &n) {
	saveDate(n);
	cout << setprecision(6) << X(0) << '\t' << X(1) << '\t' << X(2) << endl;

	X_temp = X;
	for (int i = 0; i < n; i++) {
		double sum = 0;
		for (int j = 0; j < n; j++) {
			if (i == j)
				continue;
			sum += A(i, j)*X(j);
		}
		X(i) = 1 / A(i, i) * (b(i) - sum);
	}
	/*cout << setprecision(6) << X(0) << '\t' << X(1) << '\t' << X(2)<< endl;*/
}

void solve(int &n) {
	do {
		Iteration(n);
	} while (fabs(X(0) - X_temp(0)) > err);
}

void GuassSeidel(int &n) {
	cout << setprecision(6) << "x1" << '\t' << "x2" << '\t' << "x3" << endl;
	GreateA_mat(n);
	Fillb_mat(n);
	InitX_mat(n);
	cout << endl;
	solve(n);
}

main.cpp 文件

#include
#include
#include
#include
#include"guassSeidel.h"

int main()
{
	int n;
	cout << "请输入未知数个数n,n = ";
	cin >> n;
	cout << endl;

	GuassSeidel(n);
}

PS:程序中我用到了 armadillo 矩阵库,如果你没有安装,请点击链接。

你可能感兴趣的:(数值计算,C++)