解線性方程組迭代法之Jacobi迭代法及其算法實現

在上一篇博客裏面,筆者介紹瞭解線性方程組的LU分解法,這篇來介紹一個新的方法,迭代法.解線性方程組的迭代法有多種,其中就有Jacobi迭代法,它的原理是什麼呢?有如下的線性方程組Ax=b,可將其變形爲=>Mx=Nx+b=>x=M-1Nx+M-1b,設B=M-1N=M-1(M-A)=E-M-1A,f=M-1b,即可得到迭代式:X(k+1)=Bx(k)+f,這裏我們只需要設置一個初始的x向量,依次將前一步的xk代入到迭代式中,就可以得到x(k+1)的結果
關於迭代法的兩個注意事項:
1.迭代法相比於其他方法在計算大型稀疏矩陣矩陣方面,是有優勢的,但不意味着只能解大型稀疏矩陣
2.並非所有的線性方程組都可以用迭代法進行求解,這是因爲不是所有的迭代方程都是收斂的,可能會出現的情況就是,在迭代的過程中,會出現迭代解偏離精確解的情況,並且隨着迭代的次數增多,會越偏越大
3.遇到不收斂的情況,就不能用迭代法求解,可以選用前面的Guass消元法或者LU分解法
接下來看代碼實現~
老規矩,初始化

double** init_Matrix(int r, int c)
{
	double** p = new double* [r];
	int d = c + 1;
	for (int i = 0; i < r; i++)
	{
		p[i] = new double[d];
		memset(p[i], 0, sizeof(double) * d);
	}
	cout << "請輸入線性方程組對應的增廣矩陣:" << endl;
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < d; j++)
		{
			cin >> p[i][j];
		}
	}
	return p;
}

檢測是否達到精度要求

bool isRight(double**p,int r,double*x)
{
	double sum1 = 0, flag = 0,sum2=0;
	for (int i = 0; i < r; i++)
	{
		sum1 = 0,flag=0;
		for (int j = 0; j < r; j++)
		{
			sum1 += x[j] * p[i][j];
		}
		flag= fabs(p[i][r] - sum1);
		if (flag>(1e-5))//解代入單個方程式的誤差過大
		{
			return false;
		}
		else
		{
			sum2 += flag;
		}
	}
	if (sum2>(1e-4))//整體誤差過大
	{
		return false;
	}
	return true;
}

這一步就是檢測迭代得到的解是否達到了我們所要求的精度,也就是終止條件,這裏我設置的檢測的標準有兩個:一個是將解代入單個方程,計算偏差值,若是大於設定的偏差值,就繼續迭代,否則就將其偏差值相加,再次進行判斷,若未達到設定的偏差值,就說明已經得到了滿足精度要求的解,否則,繼續判斷,函數裏面的精度可以自行調整
開始進行迭代

void Iteration(double**p,int r,double*x,double*xx) 
{
	int k = 0,max_time=300;//最大迭代次數
	double sum = 0;
	while (true)
	{
		for (int i = 0; i < r; i++)
		{
			sum = 0;
			for (int j=0;j<r;j++)
			{
				if (j==i)
				{
					continue;
				}
				else
				{
					sum -= p[i][j]* xx[j];
				}
			}
			x[i] = (p[i][r] + sum) / p[i][i];
		}
		for (int i = 0; i < r; i++)
		{
			xx[i] = x[i];
		}
		printf("第%d次迭代結果爲:",++k);
		for (int i = 0; i < r; i++)
		{
			printf("%f\t", x[i]);
		}
		cout << endl;
		if (k>=max_time)
		{
			cout << "超出迭代次數上限!停止迭代" << endl;
			return;
		}
		if (isRight(p, r, x))//精度符合要求
		{
			cout << "精度符合要求,停止迭代,共迭代:" << k << "次" << endl;
			return;
		}
	}
}

每次迭代打印其解向量的值,然後進行精度判斷,若不符合要求,則繼續迭代,同時爲了防止因出現不收斂的情況而導致死循環的情況,設置了一個次數爲300的最大迭代次數
綜合運用

void Jacobi_main() 
{
	int i = 0, j = 0;
	cout << "請輸入線性方程組對應係數矩陣的行和列:" << endl;
	cin >> i >> j;
	double** p = init_Matrix(i, j);
	double* X = new double[i];//第n+1次跌代
	double* x = new double[i];//第n次迭代
	memset(x, 0, sizeof(double) * i);
	memset(X, 0, sizeof(double) * i);
	Iteration(p, i, X,x);
	for (int i = 0; i < j; i++)
	{
		delete[]p[i];
	}
	delete []p;
	delete []x;
}

這裏動態分配兩個數組,一個存儲第n+1次迭代的解,一個存儲第n次迭代的解,同時在計算結束後,記得釋放動態分配的內存,防止內存泄漏
完整代碼及測試數據

#include<iostream>
#include<cmath>
#include<Windows.h>
using namespace std;
/*
測試數據
3 3
10 -1  0 9
-1 10 -2 7
0  -2 10 6


3 3
20 -1 2 74
2   8 1 -4
1  -2 4 56

3 3
8 -3  2  20
4 11 -1  33
2  1  4  12

5 5
28 -3   0 0  0  10
-3 38 -10 0 -5  0
0 -10 25 -15 0  0
0  0 -15  45 0  0
0 -5   0  0  30 0
*/
double** init_Matrix(int r, int c)
{
	double** p = new double* [r];
	int d = c + 1;
	for (int i = 0; i < r; i++)
	{
		p[i] = new double[d];
		memset(p[i], 0, sizeof(double) * d);
	}
	cout << "請輸入線性方程組對應的增廣矩陣:" << endl;
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < d; j++)
		{
			cin >> p[i][j];
		}
	}
	return p;
}
//檢測是否爲精確解 設置合格精度爲10的-3方
bool isRight(double**p,int r,double*x)
{
	double sum1 = 0, flag = 0,sum2=0;
	for (int i = 0; i < r; i++)
	{
		sum1 = 0,flag=0;
		for (int j = 0; j < r; j++)
		{
			sum1 += x[j] * p[i][j];
		}
		flag= fabs(p[i][r] - sum1);
		if (flag>(1e-5))//解代入單個方程式的誤差過大
		{
			return false;
		}
		else
		{
			sum2 += flag;
		}
	}
	if (sum2>(3e-5))//整體誤差過大
	{
		return false;
	}
	return true;
}
//用一維數組x存儲每次迭代的解向量
void Iteration(double**p,int r,double*x,double*xx) 
{
	int k = 0,max_time=300;//最大迭代次數
	double sum = 0;
	while (true)
	{
		for (int i = 0; i < r; i++)
		{
			sum = 0;
			for (int j=0;j<r;j++)
			{
				if (j==i)
				{
					continue;
				}
				else
				{
					sum -= p[i][j]* xx[j];
				}
			}
			x[i] = (p[i][r] + sum) / p[i][i];
		}
		for (int i = 0; i < r; i++)
		{
			xx[i] = x[i];
		}
		printf("第%d次迭代結果爲:",++k);
		for (int i = 0; i < r; i++)
		{
			printf("%f\t", x[i]);
		}
		cout << endl;
		if (k>=max_time)
		{
			cout << "超出迭代次數上限!停止迭代" << endl;
			return;
		}
		if (isRight(p, r, x))//精度符合要求
		{
			cout << "精度符合要求,停止迭代,共迭代:" << k << "次" << endl;
			return;
		}
	}
}
void Jacobi_main() 
{
	int i = 0, j = 0;
	cout << "請輸入線性方程組對應係數矩陣的行和列:" << endl;
	cin >> i >> j;
	double** p = init_Matrix(i, j);
	double* X = new double[i];//第n+1次跌代
	double* x = new double[i];//第n次迭代
	memset(x, 0, sizeof(double) * i);
	memset(X, 0, sizeof(double) * i);
	Iteration(p, i, X,x);
	for (int i = 0; i < j; i++)
	{
		delete[]p[i];
	}
	delete []p;
	delete []x;
}
int main(void)
{
	Jacobi_main();
	system("pause");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章