Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
Należy znaleźć rozwiązanie układu równań liniowych postaci:
a1,1×x1+a1,2×x2+…+a1,n×xn=b1 a2,1×x1+a2,2×x2+…+a2,n×xn=b2 … an,1×x1+an,2×x2+…+an,n×xn=bn |
wykorzystując metodę eliminacji Gaussa-Crouta
Opisany w poprzednim rozdziale algorytm eliminacji Gaussa posiada dosyć istotną wadę. Bazuje on na dzieleniu przez elementy przekątnej głównej macierzy współczynników. Otóż może się zdarzyć, iż element przekątnej głównej jest równy zero lub zostanie wyzerowany w wyniku obliczeń. W takim przypadku algorytm zostanie przerwany z błędem dzielenia przez zero. Jako przykład niech posłuży poniższy układ równań:
0x1+2x2+3x3+4x4 = 49 1x1+0x2+3x3+4x4 = 45 1x1+2x2+0x3+4x4 = 36 1x1+2x2+3x3+0x4 = 23
Dane dla programów dla tego układu są następujące:
4 0 2 3 4 49 1 0 3 4 45 1 2 0 4 36 1 2 3 0 23
Po wprowadzeniu tych danych do przykładowego programu umieszczonego w poprzednim rozdziale otrzymujemy komunikat "DZIELNIK ZERO". Tymczasem rozwiązanie równania istnieje i jest następujące:
x1 = 2 x2 = 3 x3 = 5 x4 = 7
Ulepszeniem algorytmu eliminacji Gaussa jest metoda Crouta, która polega
na tym, iż na początku eliminacji wyszukujemy w wierszu
Tak zmodyfikowany algorytm eliminacji Gaussa wymaga zapamiętania, które
kolumny zostały zamienione, ponieważ na etapie wyznaczania niewiadomych musimy
znać numery wyliczanych niewiadomych. Osiągniemy to wprowadzając do algorytmu
dodatkowy
Na powyższym rysunku widzimy odwołanie
K01:r ← false ; zakładamy porażkę K02:ε ← 10-12 ; określamy dokładność porównania z zerem K03: Dlai = 1, 2, …,n +1: ; do wektora wpisujemy kolejne numery kolumn wykonuj:W [i ] ←i K04: Dlai = 1, 2, …,n -1: ; dokonujemy eliminacji współczynników wykonuj kroki K05…K11 K05:k ←i K06: Dlaj =i +1,i +2, …,n : wykonuj: ; wyszukujemy element o największym module jeśli |AB [i ,W [k ]]| < |AB [i ,W [j ]]|, tok ←j K07:W [k ] ↔W [i ] ; w wektorze zamieniamy numery ; kolumn wg znalezionego elementu
K08: Jeśli |AB [i ,W [i ]]| <ε , ; jeśli znaleziony element jest zerem, to zakończ ; kończymy K09: Dlaj =i +1,i +2, …,n : wykonuj kroki K10…K11 K10:m ←AB [j ,W [i ]]:AB [i ,W [i ]] ; wyznaczamy mnożnik K11: Dlak =i +1,i +2, …,n +1: wykonuj: ; sumujemy wiersz j-ty z wierszem i-tymAB [j , W[k ]] ←AB [j ,W [k ]]+m ×AB [i ,W [k ]] ; przemnożonym przez m K12: Dlai =n ,n -1, …, 1: ; wyliczamy kolejne niewiadome wykonuj kroki K13…K16 K13: Jeśli |AB [i ,W [i ]]| <ε , to zakończ K14:s ←AB [i ,n +1] ; do s trafia współczynnik b K15: Dlaj =n ,n -1, …,i +1: wykonuj:s ←s -AB [i ,W [j ]]×X [W [j ]] ; zliczamy sumę iloczynów ; współczynników przez niewiadome K16:X [W [i ]] ← -s :AB [i ,W [i ]] ; obliczamy kolejną niewiadomą K17:r ← true ; zaznaczamy sukces K18: Zakończ
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
Program wczytuje dane definiujące
macierz Dane dla
Pierwsza liczba określa liczbę Następne
Poniżej mamy przykładowe dane wejściowe dla programu: |
Równanie: 2x2+3x3+4x4 = 49 x1+3x3+4x4 = 45 x1+2x2+4x4 = 36 x1+2x2+3x3 = 23 Dane przykładowe (przekopiuj do schowka i wklej do okna konsoli): 4 0 2 3 4 49 1 0 3 4 45 1 2 0 4 36 1 2 3 0 23 |
Pascal// Eliminacja Gaussa-Crouta // Data: 3.03.2010 // (C)2020 mgr Jerzy Wałaszek //--------------------------- program gausscrout; type NInt = array of integer; // typ wektora kolumn NReal = array of double; // typ tablic wierszy MReal = array of NReal; // typ tablicy wskaźników const eps = 1e-12; // Funkcja realizuje algorytm // eliminacji Gaussa-Crouta //--------------------------- function Gauss(n : integer; AB : MReal; X : NReal; W : NInt) : boolean; var i, j, k : integer; m, s : double; begin for i := 0 to n do W[i] := i; // eliminacja współczynników for i := 0 to n-2 do begin k := i; for j := i+1 to n-1 do if abs(AB[i][W[k]]) < abs(AB[i][W[j]]) then k := j; j := W[k]; W[k]:= W[i]; W[i] := j; for j := i+1 to n-1 do begin if abs(AB[i][W[i]]) < eps then exit(false); m := -AB[j][W[i]]/AB[i][W[i]]; for k := i+1 to n do AB[j][W[k]] := AB[j][W[k]]+m*AB[i][W[k]]; end; end; // wyliczanie niewiadomych for i := n-1 downto 0 do begin if abs(AB[i][W[i]]) < eps then exit(false); s := AB[i][n]; for j := n-1 downto i+1 do s := s-AB[i][W[j]]*X[W[j]]; X[W[i]] := s/AB[i][W[i]]; end; Gauss := true; end; // Program główny var AB : MReal; X : NReal; W : NInt; n, i, j : integer; begin // odczytujemy liczbę niewiadomych read(n); // tworzymy macierze AB, X i W // o odpowiednich rozmiarach SetLength(AB, n); SetLength(X, n); SetLength(W, n+1); for i := 0 to n-1 do SetLength(AB[i], n+1); // odczytujemy dane dla macierzy AB for i := 0 to n-1 do for j := 0 to n do read(AB[i][j]); if Gauss(n, AB, X, W) then begin for i := 0 to n-1 do writeln('x', i+1, ' = ', X[i]:9:4); end else writeln('DZIELNIK ZERO'); // usuwamy macierze z pamięci for i := 0 to n-1 do SetLength(AB[i], 0); SetLength(AB, 0); SetLength(X, 0); SetLength(W, 0); end. |
// Eliminacja Gaussa-Crouta // Data: 3.03.2010 // (C)2020 mgr Jerzy Wałaszek //--------------------------- #include <iostream> #include <iomanip> #include <cmath> using namespace std; const double eps = 1e-12; // Funkcja realizuje algorytm // eliminacji Gaussa-Crouta //--------------------------- bool gauss(int n, double ** AB, double * X, int * W) { int i, j, k; double m, s; for(i = 0; i <= n; i++) W[i] = i; // eliminacja współczynników for(i = 0; i < n-1; i++) { k = i; for(j = i+1; j < n; j++) if(fabs(AB[i][W[k]]) < fabs(AB[i][W[j]])) k = j; swap(W[k], W[i]); for(j = i+1; j < n; j++) { if(fabs(AB[i][W[i]]) < eps) return false; m = -AB[j][W[i]]/AB[i][W[i]]; for(k = i+1; k <= n; k++) AB[j][W[k]] += m*AB[i][W[k]]; } } // wyliczanie niewiadomych for(i = n-1; i >= 0; i--) { if(fabs(AB[i][W[i]]) < eps) return false; s = AB[i][n]; for(j = n-1; j >= i+1; j--) s -= AB[i][W[j]]*X[W[j]]; X[W[i]] = s/AB[i][W[i]]; } return true; } // Program główny int main() { double **AB, *X; int n, i, j, *W; cout << setprecision(4) << fixed; // odczytujemy liczbę niewiadomych cin >> n; // tworzymy macierze AB, X i W AB = new double * [n]; X = new double[n]; W = new int[n+1]; for(i = 0; i < n; i++) AB[i] = new double[n+1]; // odczytujemy dane dla macierzy AB for(i = 0; i < n; i++) for(j = 0; j <= n; j++) cin >> AB [i][j]; if(gauss(n, AB, X, W)) { for(i = 0; i < n; i++) cout << "x" << i+1 << " = " << setw(9) << X[i] << endl; } else cout << "DZIELNIK ZERO\n"; // usuwamy macierze z pamięci for(i = 0; i < n; i++) delete [] AB[i]; delete [] AB; delete [] X; delete [] W; return 0; } |
Basic' Eliminacja Gaussa-Crouta ' Data: 3.03.2010 ' (C)2020 mgr Jerzy Wałaszek '--------------------------- Const eps As Double = 1e-12 ' Funkcja realizuje algorytm ' eliminacji Gaussa-Crouta '--------------------------- Function Gauss(n As Integer, _ AB As Double Ptr Ptr, _ X As Double Ptr, _ W As Integer Ptr) _ As Integer Dim As Integer i, j, k Dim As Double m, s For i = 0 To n W[i] = i Next ' eliminacja współczynników For i = 0 To n-2 k = i For j = i+1 To n-1 If Abs(AB[i][W[k]]) < Abs(AB[i][W[j]]) _ Then k = j Next Swap W[k], W[i] For j = i+1 To n-1 If Abs(AB[i][W[i]]) < eps Then _ Return 0 m = -AB[j][W[i]]/AB[i][W[i]] For k = i+1 To n AB[j][W[k]] += m*AB[i][W[k]] Next Next Next ' wyliczanie niewiadomych For i = n-1 To 0 Step -1 If Abs(AB[i][W[i]]) < eps Then _ Return 0 s = AB[i][n] For j = n-1 To i+1 Step -1 s -= AB[i][W[j]]*X[W[j]] Next X[W[i]] = s/AB[i][W[i]] Next Gauss = 1 End Function ' Program główny '--------------- Dim AB As Double Ptr Ptr Dim X As Double Ptr Dim W As Integer Ptr Dim As Integer n, i, j Open Cons For Input As #1 ' odczytujemy liczbę niewiadomych Input #1, n ' tworzymy macierze AB, X i W ' o odpowiednich rozmiarach AB = New Double Ptr[n] X = New Double[n] W = New Integer[n+1] For i = 0 To n-1 AB[i] = New Double[n+1] Next ' odczytujemy dane dla macierzy AB For i = 0 To n-1 For j = 0 To n Input #1, AB[i][j] Next Next Close #1 If Gauss(n, AB, X, W) = 1 Then For i = 0 To n-1 Print Using "x# = ####.####";i+1;X[i] Next Else Print "DZIELNIK ZERO" End If ' usuwamy macierze z pamięci For i = 0 To n-1 Delete [] AB[i] Next Delete [] AB Delete [] X Delete [] W End |
Python
(dodatek)# Eliminacja Gaussa-Crouta # Data: 19.04.2024 # (C)2024 mgr Jerzy Wałaszek #--------------------------- EPS = 1e-12 # Funkcja realizuje algorytm # eliminacji Gaussa-Crouta #--------------------------- def gauss(ab, x): n = len(ab) w = [i for i in range(n+1)] # eliminacja współczynników for i in range(n-1): k = i for j in range(i+1, n): if abs(ab[i][w[k]]) < abs(ab[i][w[j]]): k = j w[k], w[i] = w[i], w[k] for j in range(i+1, n): if abs(ab[i][w[i]]) < EPS: return False m = -ab[j][w[i]]/ab[i][w[i]] for k in range(i+1, n+1): ab[j][w[k]] += m*ab[i][w[k]] # wyliczanie niewiadomych for i in reversed(range(n)): if abs(ab[i][w[i]]) < EPS: return False s = ab[i][n] for j in reversed(range(i+1, n)): s -= ab[i][w[j]]*x[w[j]] x[w[i]] = s/ab[i][w[i]] return True # Program główny #--------------- # odczytujemy liczbę niewiadomych n = int(input()) # tworzymy macierze AB i X ab = [] x = [0.0]*n # odczytujemy dane dla macierzy AB for i in range(n): arr = input().split() arr = [float(arr[j]) for j in range(n+1)] ab.append(arr) if gauss(ab, x): for i in range(n): print("x%d = %9.4f" % (i+1, x[i])) else: print("DZIELNIK ZERO") print() # usuwamy macierze z pamięci ab = None x = None |
Wynik: |
4 0 2 3 4 49 1 0 3 4 45 1 2 0 4 36 1 2 3 0 23 x1 = 2.0000 x2 = 3.0000 x3 = 5.0000 x4 = 7.0000 |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.