求解線性方程組的三種基本迭代法


前言

  在實際項目的一些矩陣運算模塊中,往往需要對線性方程組進行求解以得到最終結果。

  然而,你無法讓計算機去使用克萊默法則或者高斯消元法這樣的純數學方法來進行求解。

  計算機解決這個問題的方法是迭代法。本文將介紹三種最為經典的迭代法並用經典C++源代碼實現之。

迭代法簡介

  從解的某個近似值出發,通過構造一個無窮序列去逼近精確解的方法。

雅克比迭代法

  計算流程:

    1. 初始化系數矩陣等計算環境

    2. 設置精度控制和迭代次數控制變量

    3. 采用如下式子進行迭代計算

      

    4. 循環執行 3,若(條件a)當前滿足迭代精度控制的解分量數等於解向量維數或者(條件b)迭代次數達到最大次數則跳出循環,進入到 5。

    5. 若是因為條件a跳出循環則迭代成功,打印解向量;若是因為條件b退出循環則表示在指定的迭代次數內方程組未求解完。

  說明:最經典原始的一種解方程組的迭代法。

高斯迭代法

  計算流程:

    1. 初始化系數矩陣等計算環境

    2. 設置精度控制和迭代次數控制變量

    3. 采用如下式子進行迭代計算

      

    4. 循環執行 3,若(條件a)當前滿足迭代精度控制的解分量數等於解向量維數或者(條件b)迭代次數達到最大次數則跳出循環,進入到 5。

    5. 若是因為條件a跳出循環則迭代成功,打印解向量;若是因為條件b退出循環則表示在指定的迭代次數內方程組未求解完。

  說明:相對於雅克比迭代法,該方法不需要一個額外的輔助向量保存上一次迭代計算的結果,節省了空間。

超松弛迭代法

  計算流程:

    1. 初始化系數矩陣等計算環境

    2. 設置精度控制迭代次數控制變量以及松弛因子omiga

    3. 采用如下式子進行迭代計算:

      

    4. 循環執行 3,若(條件a)當前滿足迭代精度控制的解分量數等於解向量維數或者(條件b)迭代次數達到最大次數則跳出循環,進入到 5。

    5. 若是因為條件a跳出循環則迭代成功,打印解向量;若是因為條件b退出循環則表示在指定的迭代次數內方程組未求解完。

  說明:

    1. 該方法同樣不需要一個額外的輔助向量保存上一次迭代計算的結果

    2. 需要設置一個w因子參數,一般取0-2。當小於1時該方法為低松弛迭代法,高於1時為超松弛迭代法。經驗上來看一般取1.4-1.6來實現超松弛迭代。

源代碼實現

  第一部分:迭代類聲明 (Iterator.h)

 1 // 頭文件保護符
 2 #ifndef Iterator_H
 3 #define Iterator_H
 4 
 5 // 迭代計算類
 6 class CIterator
 7 {
 8 public:
 9     // 構造函數
10     CIterator ();
11     // 析構函數
12     ~CIterator ();
13     // 設置計算環境 (如系數矩陣等)
14     bool SetEnvironment ();
15     // 雅克比迭代法計算方程解
16     bool JacobianCalculate ();
17     // 高斯迭代法計算方程解
18     bool GaussCalculate ();
19     // 超松弛迭代法計算方程解
20     bool RelaxationCalculate (double omiga);
21     // 獲取系數矩陣
22     double ** GetMatrixA ();
23     // 獲取系數矩陣的階
24     int GetOrder ();
25     // 獲取方程組右值向量
26     double * GetVectorB ();
27     // 獲取方程解向量
28     double * GetSolution ();
29 
30 private:
31     double **matrixA;    // 系數矩陣
32     int order;            // 系數矩陣的階
33     double *vectorB;    // 方程組右值向量
34     double *solution;    // 解向量
35 };
36 
37 #endif

  第二部分:迭代類實現 (Iterator.cpp)

  1 #include "Iterator.h"
  2 #include <iostream>
  3 #include <iomanip>
  4 
  5 using namespace std;
  6 
  7 // 構造函數
  8 CIterator :: CIterator ()
  9 {
 10     matrixA = NULL;
 11     order = 0;
 12     vectorB = NULL;
 13     solution = NULL;
 14 }
 15 
 16 // 析構函數
 17 CIterator :: ~CIterator ()
 18 {
 19     // 釋放內存空間
 20     if (!vectorB) {
 21         delete [] vectorB;
 22         vectorB = NULL;
 23     }
 24     if (!solution) {
 25         delete [] solution;
 26         solution = NULL;
 27     }
 28     if (matrixA!=NULL) {
 29         for (int i=0; i<order; i++) {
 30             delete [] matrixA[i];
 31             matrixA[i] = NULL;
 32         }
 33         delete [] matrixA;
 34         matrixA = NULL;
 35     }
 36 }
 37 
 38 // 設置計算環境 (如系數矩陣等)
 39 bool CIterator :: SetEnvironment ()
 40 {
 41     cout << "系數矩陣階數: ";
 42     cin >> order;
 43     cout << endl;
 44 
 45     matrixA = new double *[order];
 46     for (int i=0; i<order; i++)
 47         matrixA[i] = new double [order];
 48 
 49     for (int i=0; i<order; i++) {
 50         cout << "" << i << " 行系數: ";
 51         for (int j=0; j<order; j++)
 52             cin >> matrixA[i][j];
 53     }
 54     cout << endl;
 55 
 56     vectorB = new double [order];
 57     cout << "b 向量: ";
 58     for (int i=0; i<order; i++)
 59             cin >> vectorB[i];
 60     cout << endl;
 61 
 62     solution = new double [order];
 63 
 64     cout << "運算環境搭建完畢" << endl << endl;
 65 
 66     return true;
 67 }
 68 
 69 // 雅克比迭代法計算方程解
 70 bool CIterator :: JacobianCalculate ()
 71 {
 72     cout << "下面使用雅克比迭代法計算該線性方程組" << endl << endl;
 73 
 74     // 設置迭代精度控制值
 75     cout << "迭代精度控制值: ";
 76     double bias;
 77     cin >> bias;
 78     cout << endl;
 79 
 80     // 設置迭代次數控制值
 81     cout << "迭代次數控制值: ";
 82     int itMax;
 83     cin >> itMax;
 84     cout << endl;
 85 
 86     // 當前滿足迭代精度控制的解分量數
 87     int meetPrecisionCount = 0;
 88 
 89     // 輔助向量,存放上一次迭代的解向量。
 90     double * auxiliary = new double [order];
 91 
 92     // 初始化解向量
 93     for (int i=0; i<order; i++) {
 94         auxiliary[i] = 0;
 95         solution[i] = 1;
 96     }
 97 
 98     // 當前迭代次數
 99     int itCur = 0;
100 
101     // 若當前滿足迭代精度控制的解分量數等於解向量維數或者迭代次數達到最大次數則跳出循環
102     while (meetPrecisionCount<order && itCur<itMax) {
103         
104         // 當前滿足迭代精度控制的解分量數清零
105         meetPrecisionCount = 0;
106 
107         // 將當前解向量存入輔助向量
108         for (int i=0; i<order; i++)
109             auxiliary[i] = solution[i];
110 
111         // 計算新的解向量
112         for (int i=0; i<order; i++) {
113 
114             // 暫存當前解分量
115             double temp = solution[i];
116 
117             // 清零當前解分量
118             solution[i] = 0;
119 
120             // 雅克比迭代計算
121             for (int j=0; j<i; j++) {
122                 solution[i] += matrixA[i][j]*auxiliary[j];
123             }
124             for (int j=i+1; j<order; j++) {
125                 solution[i] += matrixA[i][j]*auxiliary[j];
126             }
127             solution[i] = (vectorB[i]-solution[i])/matrixA[i][i];
128 
129             // 更新當前滿足迭代精度控制的解分量數
130             if (fabs(temp-solution[i])<bias)
131                 meetPrecisionCount++;
132         }
133 
134         // 當前迭代次數遞增
135         itCur++;
136     }
137 
138     // 若在規定的迭代次數內未完成計算任務,則返回錯誤。
139     if (itCur == itMax) return false;
140 
141     return true;
142 }
143 
144 // 高斯迭代法計算方程解
145 bool CIterator :: GaussCalculate ()
146 {
147     cout << "下面使用高斯迭代法計算該線性方程組" << endl << endl;
148 
149     // 設置迭代精度控制值
150     cout << "迭代精度控制值: ";
151     double bias;
152     cin >> bias;
153     cout << endl;
154 
155     // 設置迭代次數控制值
156     cout << "迭代次數控制值: ";
157     int itMax;
158     cin >> itMax;
159     cout << endl;
160 
161     // 當前滿足迭代精度控制的解分量數
162     int meetPrecisionCount = 0;
163 
164     // 初始化解向量
165     for (int i=0; i<order; i++) {
166         solution[i] = 0;
167     }
168 
169     // 當前迭代次數
170     int itCur = 0;
171 
172     // 若當前滿足迭代精度控制的解分量數等於解向量維數或者迭代次數達到最大次數則跳出循環
173     while (meetPrecisionCount<order && itCur<itMax) {
174         
175         // 當前滿足迭代精度控制的解分量數清零
176         meetPrecisionCount = 0;
177 
178         // 計算新的解向量
179         for (int i=0; i<order; i++) {
180 
181             // 暫存當前解分量
182             double temp = solution[i];
183 
184             // 清零當前解分量
185             solution[i] = 0;
186 
187             // 高斯迭代計算
188             for (int j=0; j<i; j++) {
189                 solution[i] += matrixA[i][j]*solution[j];
190             }
191             for (int j=i+1; j<order; j++) {
192                 solution[i] += matrixA[i][j]*solution[j];
193             }
194             solution[i] = (vectorB[i]-solution[i])/matrixA[i][i];
195             
196             // 更新當前滿足迭代精度控制的解分量數
197             if (fabs(temp-solution[i])<bias)
198                 meetPrecisionCount++;
199         }
200 
201         // 當前迭代次數遞增
202         itCur++;
203     }
204 
205     // 若在規定的迭代次數內未完成計算任務,則返回錯誤。
206     if (itCur == itMax) return false;
207 
208     return true;
209 }
210 
211 // 超松弛迭代法計算方程解
212 bool CIterator :: RelaxationCalculate (double omiga)
213 {
214     cout << "下面使用超松弛迭代法計算該線性方程組" << endl << endl;
215 
216     // 設置迭代精度控制值
217     cout << "迭代精度控制值: ";
218     double bias;
219     cin >> bias;
220     cout << endl;
221 
222     // 設置迭代次數控制值
223     cout << "迭代次數控制值: ";
224     int itMax;
225     cin >> itMax;
226     cout << endl;
227 
228     // 當前滿足迭代精度控制的解分量數
229     int meetPrecisionCount = 0;
230 
231     // 當前滿足迭代精度控制的解分量數
232     for (int i=0; i<order; i++) {
233         solution[i] = 0;
234     }
235 
236     // 當前迭代次數
237     int itCur = 0;
238 
239     // 若當前滿足迭代精度控制的解分量數等於解向量維數或者迭代次數達到最大次數則跳出循環
240     while (meetPrecisionCount<order && itCur<itMax) {
241         
242         // 當前滿足迭代精度控制的解分量數清零
243         meetPrecisionCount = 0;
244 
245         // 計算新的解向量
246         for (int i=0; i<order; i++) {
247 
248             // 暫存當前解分量
249             double temp = solution[i];
250 
251             // 清零當前解分量
252             solution[i] = 0;
253 
254             // 超松弛迭代計算
255             for (int j=0; j<i; j++) {
256                 solution[i] += matrixA[i][j]*solution[j];
257             }
258             for (int j=i+1; j<order; j++) {
259                 solution[i] += matrixA[i][j]*solution[j];
260             }
261             solution[i] = omiga*(vectorB[i]-solution[i])/matrixA[i][i] + (1-omiga)*temp;
262             
263             // 更新當前滿足迭代精度控制的解分量數
264             if (fabs(temp-solution[i])<bias)
265                 meetPrecisionCount++;
266         }
267 
268         // 當前迭代次數遞增
269         itCur++;
270     }
271 
272     // 若在規定的迭代次數內未完成計算任務,則返回錯誤。
273     if (itCur == itMax) return false;
274 
275     return true;
276 }
277 
278 // 獲取系數矩陣
279 double ** CIterator :: GetMatrixA ()
280 {
281     return this->matrixA;
282 }
283 
284 // 獲取系數矩陣的階
285 int CIterator :: GetOrder ()
286 {
287     return this->order;
288 }
289 
290 // 獲取方程組右值向量
291 double * CIterator :: GetVectorB ()
292 {
293     return this->vectorB;
294 }
295 
296 // 獲取方程解向量
297 double * CIterator :: GetSolution ()
298 {
299     return this->solution;
300 }

  第三部分:主函數 (main.cpp)

 1 // 迭代計算類
 2 #include "Iterator.h"
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 // 打印方程解
 8 void printResults (CIterator iterator);
 9 
10 int main()
11 {
12     // 定義迭代類對象
13     CIterator iterator;
14 
15     // 設置計算環境 (如系數矩陣等)
16     iterator.SetEnvironment();
17     
18     // 雅克比迭代法計算方程解
19     if (!iterator.JacobianCalculate()) {
20         cout << "規定次數內未完成迭代計算" << endl;
21         return EXIT_FAILURE;
22     }
23 
24     // 高斯迭代法計算方程解
25     /*
26     if (!iterator.GaussCalculate()) {
27         cout << "規定次數內未完成迭代計算" << endl;
28         return EXIT_FAILURE;
29     }
30     */
31 
32     // 超松弛迭代法計算方程解
33     /*
34     double omiga = 1.5;        // 松弛迭代系數
35     if (!iterator.RelaxationCalculate(omiga)) {
36         cout << "規定次數內未完成迭代計算" << endl;
37         return EXIT_FAILURE;
38     }
39     */
40 
41     // 打印方程解
42     printResults (iterator);
43 
44     return EXIT_SUCCESS;
45 }
46 
47 // 打印方程解
48 void printResults (CIterator iterator)
49 {
50     cout << "計算成功,打印方程解:  " << endl;
51     for (int i=0; i<iterator.GetOrder(); i++)
52         cout << "x" << i << " = " << iterator.GetSolution()[i] << endl;
53 
54     cout << endl;
55 }

程序演示

  使用超松弛迭代法解如下方程組:

  

  將項目主函數中雅克比和高斯迭代計算的部分注釋掉,運行:

  

說明

  不是每個方程組都能迭代得到解,我們通常將系數矩陣轉換為對角占優矩陣(右向量部分也要跟着轉)。滿足此條件的方程組的解向量大都能用這幾種迭代法算出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM