高斯列主消元法
1. 高斯列主消元法的基本思想
列主元素消去法是为控制舍入误差而提出来的一种算法。列主元素消去法计算基本上能控制舍入误差的影响,其基本思想是:在进行第 k ( k = 1 , 2 , ... , n − 1 ) k(k=1,2,...,n-1) k(k=1,2,...,n−1)步消元时,从第 k k k列的 a k k a_{kk} akk及其以下的各元素中选取绝对值最大的元素 ,然后通过行变换将它交换到主元素 a k k a_{kk} akk的位置上,再进行消元。
误差来源:由于计算机表示浮点数有位数限制(IEEE 754 标准中,单精度浮点数(float)是16位,双精度浮点数(double)为32位),在高斯消元法中,计算行乘数 m i j = a i j a i i m_{ij}=\frac{a_{ij}}{a_{ii}} mij=aiiaij,如果 a i i a_{ii} aii很小,那么行乘数就可能溢出。例如:
( A , b ) = ( 1 0 − 8 2 3 1 − 1 3.712 4.623 2 − 2 1.072 5.643 3 ) , \begin{aligned}(A,b)&=\left(\begin{array}{llll}10^{-8}&2&3&1\\-1&3.712&4.623&2\\-2&1.072&5.643&3\end{array}\right),\end{aligned} (A,b)= 10−8−1−223.7121.07234.6235.643123 ,
如果直接使用 1 0 − 8 10^{-8} 10−8作为 a i i a_{ii} aii,假设计算机使用的是8位十进制尾数,那么在计算 a 22 a_{22} a22时, a 22 = a 22 − m 21 a 12 = a 22 − a 21 a 11 a 12 = 3.712 − − 1 1 0 − 8 × 2 = 0.0000000 × 1 0 9 + 0.2 × 1 0 9 = 0.2 × 1 0 9 , a_{22}=a_{22}-m_{21}a_ {12}=a_{22}-\frac{a_{21}}{a_{11}}a_{12}=3.712-\frac{-1}{10^{-8}}\times 2=0.0000000\times10^9+0.2\times10^9=0.2\times10^9, a22=a22−m21a12=a22−a11a21a12=3.712−10−8−1×2=0.0000000×109+0.2×109=0.2×109,
由于减数在规格化以后为 1 0 9 10^9 109,导致3.712在进行浮点运算的对阶操作时阶码为9,尾数右移为机器0,这样在进行后续的消元后导致方程的解误差过大甚至是错误:经过两步消元后,有:
( A ( 3 ) , b ( 3 ) ) = ( 1 0 − 8 2 3 1 0.2 × 1 0 9 0.3 × 1 0 9 0.1 × 1 0 9 0 0 ) . (A^{(3)},b^{(3)})=\left(\begin{array}{cccc}10^{-8}&2&3&1\\&0.2\times10^9&0.3\times10^9&0.1\times10^9\\&&0&0\end{array}\right). (A(3),b(3))= 10−820.2×10930.3×109010.1×1090 .
该方程在使用很小的数作为主元时导致方程没有唯一解,实际上该方程是有解的( d e t A ≠ 0 detA\neq 0 detA=0)。因此需要在进行高斯消元法时选择该列的绝对值最大元素作为主元,然后在进行消元
2. 高斯列主消元法的基本步骤
其中 e p s eps eps是一个阈值,当某一列的所有列主元都小于 e p s eps eps时,该方程的解误差会很大,因此直接放弃使用计算机求解
3. 高斯列主消元法的程序设计
python
# 高斯列主消元法
import numpy as np
eps=1e-8
def gaussian_elimination_with_pivoting(A, b):
n = A.shape[0]
# 增广矩阵
Ab = np.hstack([A, b.reshape(-1, 1)])
for i in range(n):
# 找到列主元的行号
max_row_index = np.argmax(np.abs(Ab[i:n, i])) + i
if abs(Ab[max_row_index][i]) <eps:
print(Ab[max_row_index][i])
print("数值不稳定/无解")
return None
# 交换当前行和列主元所在的行
if i != max_row_index:
Ab[[i, max_row_index]] = Ab[[max_row_index, i]]
# 消元
for j in range(i + 1, n):
factor = Ab[j, i] / Ab[i, i]
Ab[j, i:] = Ab[j, i:] - factor * Ab[i, i:]
# 回带求答案
x = np.zeros(n)
for i in range(n-1, -1, -1):
x[i] = (Ab[i, -1] - Ab[i, i+1:n]@x[i+1:]) / Ab[i, i]
return x
4.计算复杂度
根据算法中的消元过程中,第 k k k步运算做乘法 ( n − k )( n − k + 1 ) (n-k)(n-k+1) (n−k)(n−k+1)次,做除法 n − k n-k n−k 次,完成 n − 1 n-1 n−1 步消元共需做乘除法的总次数为 ∑ k = 1 n − 1 ( n − k ) ( n − k + 2 ) = n 3 3 + n 2 2 − 5 n 6 , \sum_{k=1}^{n-1}(\left.n-k\right)(\left.n-k+2\right)=\frac{n^3}3+\frac{n^2}2-\frac{5n}6, k=1∑n−1(n−k)(n−k+2)=3n3+2n2−65n,
在回带带计算解时,乘除法计算次数为 ∑ i = 1 n ( n − i + 1 ) = n 2 2 + n 2 \sum_{i=1}^n (n-i+1)=\frac{n^2}{2}+\frac{n}{2} i=1∑n(n−i+1)=2n2+2n
因此全部乘除法运算次数为 M D = n 3 3 + n 2 − n 3 MD=\frac{n^3}{3}+n^2-\frac{n}{3} MD=3n3+n2−3n