Метод Гаусса для вирішення систем лінійних рівнянь
Метод Гаусса для вирішення систем лінійних рівнянь
Тут описаний алгоритм розв'язання системи лінійних рівнянь за допомогою так званого методу Гаусса. Програму ви можете скачати розділі програми . Алгоритм реалізований на мові С.
Нехай у нас є система N лінійних рівнянь
a11x1 + a12x2 + a13x3 + ... a1NxN = b1
a21x1 + a22x2 + a23x3 + ... a2NxN = b2
a31x1 + a32x2 + a33x3 + ... a3NxN = b3
...
aN1x1 + aN2x2 + aN3x3 + ... aNNxN = bN
де xi - невідомі, aij - коефіцієнти при невідомих, bi - вільні члени в рівняннях, i, j пробігають значення від 1 до N.
Мета завдання - знаючи aij і bi знайти xi.
Суть методу Гаусса полягає в тому, що за допомогою деяких операцій вихідну систему рівнянь можна звести до більш простій системі. Ця проста система має трикутний вигляд:
a11x1 + a12x2 + a13x3 + ... a1NxN = b1 a22x2 + a23x3 + ... a2NxN = b2 a33x3 + ... a3NxN = b3 ... ... aNNxN = bNОсобливість цієї системи - в рядках з номером i все коефіцієнти aij при j <i дорівнюють нулю.
Якщо ми змогли привести нашу систему рівнянь до такого трикутного вигляду, то вирішити рівняння вже просто. З останнього рівняння знаходимо xN = bN / aNN. Далі підставляємо його в передостаннє рівняння і знаходимо з нього xN-1. Підставляємо обидва знайдених рішення в наступне з кінця рівняння і знаходимо xN-2. І так далі, поки не знайдемо x1, на чому рішення закінчується. Така процедура називається зворотної прогоном.
Тепер перейдемо до питання як же домогтися того, щоб система стала трикутної.
З лінійної алгебри (див. Наприклад, Крутицкая Н.І., Тихонравов А.В., Шишкін А.А., Аналітична геометрія і лінійна алгебра з додатками) відомо що якщо до деякої рядку системи рівнянь додати будь-яку лінійну комбінацію будь-яких інших рядків цієї системи, то рішення системи не зміниться. Під лінійною комбінацією рядків розуміється сума рядків, кожна з яких у множаться на деяке число (в принципі, будь-який).
Потрібно, щоб у другому рядку вийшло рівняння, в якій відсутній член при x1. Додамо до цього рядка перший рядок, помножену на деяке число M.
(A11x1 + a12x2 + a13x3 + ... a1NxN = b1) * M +
a21x1 + a22x2 + a23x3 + ... a2NxN = b2
отримаємо
(A11 * М + a21) x1 + ... = b1 * M + b2
Для того, щоб член при x1 дорівнював нулю, потрібно, щоб M = - a21 / a11. Виконавши цю операцію, вийшло рівняння запишемо замість другого і приступимо до третього рівняння. До нього ми додамо перше рівняння, помножене на M = - a31 / a11 і теж отримаємо нуль замість члена при x1. Таку операцію потрібно виконати над усіма іншими рівняннями. В результаті отримаємо систему такого виду:
a11x1 + a12x2 + a13x3 + ... a1NxN = b1 a22x2 + a23x3 + ... a2NxN = b2 a32x2 + a33x3 + ... a3NxN = b3 ... aN2x2 + aN3x3 + ... aNNxN = bNПісля цього будемо позбуватися від членів при x2 в третьому, четвертому, N-му рівнянні. Для цього потрібно до рівняння з j-м номером додати 2-е рівняння, помножене на M = - aj2 / a22. Виконавши цю операцію над усіма іншими рівняннями, отримаємо систему де немає членів з x2 в рівняннях з номером більше 2.
І так далі ... Проробивши це для третього члена, четвертого ... до тих пір, поки не закінчаться рівняння, отримаємо в підсумку систему трикутного виду.
Нижче наведено текст програми.
// HOWTO solve system of linear equations // ax = b // where a [N] [N] is square matrix, // b [N] and x [N] are columns // data are stored in input text file: // input file format: // a_11 a_12 a_13 ... a_1N b_1 // a_21 a_22 a_23 ... a_2N b_2 // ... // a_N1 a_N2 a_N3 ... a_NN b_N #include <stdio.h> #include <process.h> float ** a, * b, * x; int N; char filename [256]; FILE * InFile = NULL; void count_num_lines () {// count number of lines in input file - number of equations int nelf = 0; // non empty line flag do {nelf = 0; while (fgetc (InFile)! = '\ n' &&! feof (InFile)) nelf = 1; if (nelf) N ++; } While (! Feof (InFile)); } Void freematrix () {// free memory for matrixes int i; for (i = 0; i <N; i ++) {delete [] a [i]; } Delete [] a; delete [] b; delete [] x; } Void allocmatrix () {// allocate memory for matrixes int i, j; x = new float [N]; b = new float [N]; a = new float * [N]; if (x == NULL || b == NULL || a == NULL) {printf ( "\ nNot enough memory to allocate for% d equations. \ n", N); exit (-1); } For (i = 0; i <N; i ++) {a [i] = new float [N]; if (a [i] == NULL) {printf ( "\ nNot enough memory to allocate for% d equations. \ n", N); }} For (i = 0; i <N; i ++) {for (j = 0; j <N; j ++) {a [i] [j] = 0; } B [i] = 0; x [i] = 0; }} Void readmatrix () {int i = 0, j = 0; // read matrixes a and b from input file for (i = 0; i <N; i ++) {for (j = 0; j <N; j ++) {fscanf (InFile, "% f", & a [i] [ j]); } Fscanf (InFile, "% f", & b [i]); }} Void printmatrix () {// print matrix "a" int i = 0, j = 0; printf ( "\ n"); for (i = 0; i <N; i ++) {for (j = 0; j <N; j ++) {printf ( "% + f * X% d", a [i] [j], j); } Printf ( "=% f \ n", b [i]); }} Void testsolve () {// test that ax = b int i = 0, j = 0; printf ( "\ n"); for (i = 0; i <N; i ++) {float s = 0; for (j = 0; j <N; j ++) {s + = a [i] [j] * x [j]; } Printf ( "% f \ t% f \ n", s, b [i]); }} Void printresult () {int i = 0; printf ( "\ n"); printf ( "Result \ n"); for (i = 0; i <N; i ++) {printf ( "X% d =% f \ n", i, x [i]); }} Void diagonal () {int i, j, k; float temp = 0; for (i = 0; i <N; i ++) {if (a [i] [i] == 0) {for (j = 0; j <N; j ++) {if (j == i) continue; if (a [j] [i]! = 0 && a [i] [j]! = 0) {for (k = 0; k <N; k ++) {temp = a [j] [k]; a [j] [k] = a [i] [k]; a [i] [k] = temp; } Temp = b [j]; b [j] = b [i]; b [i] = temp; break; }}}}} Void cls () {for (int i = 0; i <25; i ++) printf ( "\ n"); } Void main () {int i = 0, j = 0, k = 0; cls (); do {printf ( "\ nInput filename:"); scanf ( "% s", filename); InFile = fopen (filename, "rt"); } While (InFile == NULL); count_num_lines (); allocmatrix (); rewind (InFile); // read data from file readmatrix (); // check if there are 0 on main diagonal and exchange rows in that case diagonal (); fclose (InFile); printmatrix (); // process rows for (k = 0; k <N; k ++) {for (i = k + 1; i <N; i ++) {if (a [k] [k] == 0) {printf ( "\ nSolution is not exist. \ n "); return; } Float M = a [i] [k] / a [k] [k]; for (j = k; j <N; j ++) {a [i] [j] - = M * a [k] [j]; } B [i] - = M * b [k]; }} Printmatrix (); for (i = N-1; i> = 0; i -) {float s = 0; for (j = i; j <N; j ++) {s = s + a [i] [j] * x [j]; } X [i] = (b [i] - s) / a [i] [i]; } InFile = fopen (filename, "rt"); readmatrix (); fclose (InFile); printmatrix (); testsolve (); printresult (); freematrix (); }Оскільки весь метод вже описаний, коротко опишу, як ця програма отримує рівняння на вхід, що видає в результаті рішення.
Щоб скористатися цією програмою, потрібно запустити скомпільований виконуваний файл. В першу чергу програма запитає, звідки їй брати коефіцієнти для рівнянь. Створіть в будь-якому текстовому редакторі (але тільки не в Word-е а, наприклад в notepad-е) файл, де напишіть коефіцієнти рівнянь через підрядник через пробіл, приблизно так:
a11 a12 a13 ... a1N b1 a21 a22 a23 ... a2N b2 a31 a32 a33 ... a3N b3 aN1 aN2 aN3 ... aNN bNнаприклад:
2 -3 1 5-1 -1 2 0
1 2 -1 3
Цей файл необхідно створити в тій директорії, де лежить програма, інакше вона його не знайде. В результаті роботи програми, вона видасть результат, щось на кшталт:
X0 = 3.000000
X1 = 1.000000
X2 = 2.000000
Це і є рішення системи рівнянь, тобто набір невідомих Х.
Коротко опишемо, для чого служить така велика кількість підпрограм в даній програмі:
- void count_num_lines () - підраховує кількість рівнянь в системі
- void allocmatrix () - виділяє пам'ять для масивів для зберігання коефіцієнтів рівнянь, вільних членів і рішення
- void readmatrix () - прочитує з файлу коефіцієнти і вільні члени в масиви
- void printmatrix () - роздруковує систему рівнянь
- void diagonal () - робить так, щоб на головній діагоналі не було нулів, щоб не довелося одного разу ділити на нуль в процесі приведення матриці до трикутного вигляду
- void testsolve () - підставляє рішення в систему і роздруковує поруч те, що виходить в лівій частині рівняння і для порівняння друкує поруч вільні члени, ті, що в правій частині рівняння; отримані два стовпці повинні збігатися, якщо рівняння вирішені правильно
- void printresult () - роздруковує вийшов стовпець рішень
- void freematrix () - звільняє пам'ять, яка була виділена раніше
- void cls () - стирає екран на початку роботи програми
- void main () - основна функція з якої послідовно викликаються всі перераховані вище функції, і проходить процес приведення системи рівнянь до трикутного вигляду і зворотна прогін.
Програма забезпечена коментарями, що полегшує її розуміння.
Сподіваюся, що вам стало все зрозуміло.
На головну >>>