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 |
SPIS TREŚCI |
|
Podrozdziały |
Macierz trójkątna ( ang. triangular matrix ) jest specjalnym rodzajem macierzy kwadratowej. Występuje ona w dwóch odmianach:
Macierz trójkątna dolna (ang. lower triangular matrix, L ) posiada wszystkie wyrazy leżące ponad główną przekątna równe zero:
Macierz trójkątna górna ( ang. upper triangular matrix, U ) posiada wszystkie wyrazy leżące poniżej przekątnej głównej równe zero:
Rozkład LU ( ang. LU decomposition ) polega na rozłożeniu macierzy kwadratowej A na iloczyn dwóch macierzy trójkątnych, dolnej L o wyrazach przekątnej głównej równych 1 oraz górnej U:
Zgodnie z własnościami wyznaczników, wyznacznik iloczynu macierzy jest równy iloczynowi ich wyznaczników:
Z kolei wyznacznik macierzy trójkątnej jest równy iloczynowi wyrazów na przekątnej głównej, co wynika bezpośrednio z rozwinięcia Laplace'a. Zatem:
Wyznacznik macierzy A jest równy wyznacznikowi macierzy U. Z kolei wyznacznik macierzy U, która jest macierzą trójkątną, jest równy iloczynowi wyrazów na głównej przekątnej macierzy U:
I ostatecznie:
Wynika z tego, iż jeśli uda nam się znaleźć macierz U dla macierzy A, to wyznacznik macierzy A policzymy w prosty sposób przez wymnożenie przez siebie wyrazów głównej przekątnej macierzy U. Zajmijmy się zatem sposobem wyznaczenia macierzy U.
Na przykład wyraz a11 jest sumą iloczynów kolejnych wyrazów z wiersza nr 1 macierzy L przez kolejne wyrazy z kolumny nr 1 macierzy U:
gdzie n jest stopniem macierzy
Ponieważ obie macierze L i U są macierzami trójkątnymi, to część ich elementów ma wartość zero. Np. w macierzy L w wierszu nr 1 tylko pierwszy wyraz jest niezerowy i równy 1, pozostałe wyrazy tego wiersza są równe 0, zatem:
Pozwala to wyznaczyć pierwszy wyraz macierzy U, który jest taki sam jak wyraz macierzy A.
Rozważmy teraz dwa możliwe przypadki dla wyrazu aij:
Wyraz aij leży na głównej przekątnej macierzy A lub ponad nią. Ostatnim niezerowym elementem w macierzy L w wierszu i-tym jest lii. Wzór iloczynowy możemy więc zredukować:
Co więcej, element lii jest elementem przekątnej głównej macierzy L i ma wartość 1, zatem:
Wzór ten pozwala wyznaczyć element uij, jeśli znamy poprzednie elementy macierzy L i U:
Indeksy: i > j
Wyraz aij leży pod główną przekątną macierzy A. Ostatnim potencjalnie niezerowym elementem w kolumnie j-tej w macierzy U jest element ujj. Wszystkie pozostałe elementy macierzy U w tej kolumnie mają wartość zero. Wzór iloczynowy redukuje się do:
Wyprowadźmy poza sumę jej ostatni wyraz:
Wzór ten pozwala wyliczyć wyraz lij macierzy L, jeśli znane są pozostałe wyrazy macierzy L i U:
Otrzymaliśmy wzory na elementy obu macierzy L i U rozkładu LU macierzy A. Wzory te wykorzystuje znany algorytm Doolitle'a, który wygląda następująco:
Dla j od 1 do n wykonujemy dwie poniższe operacje:
Dla i od 1 do j wyznaczamy uij wg wzoru:
Dla i od j = 1 do n wyznaczamy lij wg wzoru:
Uwaga: obliczenia powinny być wykonywane na liczbach zmiennoprzecinkowych.
Przyjrzyj się drugiemu ze wzorów w algorytmie Doolitle'a. Występuje tutaj dzielenie przez element ujj. Jeśli ujj = 0, dzielenie jest niewykonalne i nie można wyznaczyć rozkładu LU macierzy A. Problemem tym zajmiemy się dalej w rozdziale.
Metoda Doolitle'a ma złożoność obliczeniową klasy O(n3), co sprawia iż nadaje się ona do obliczeń wyznaczników nawet dużych macierzy.
Poniższy program wyznacza rozkład LU macierzy wejściowej A, a następnie oblicza jej wyznacznik mnożąc przez siebie elementy głównej przekątnej macierzy U. Macierz A przekazywana jest przez standardowe wejście w następującej postaci:
pierwsza liczba określa stopień macierzy, następne n × n liczb to zawartość kolejnych wierszy macierzy A. Program wyświetla odczytaną macierz oraz wartość jej wyznacznika.
Przykładowe dane ( przekopiuj je do schowka i wklej w programie ):
Macierz:
Dane wejściowe:
5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 |
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: T * A; // Wyrazy macierzy public: int n; // Stopień macierzy matrix(); // Konstruktor matrix(int nn); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void setv(int r, int c, T v); void set1(); // ustawia elementy przekątnej na 1 T det(); // Oblicza wyznacznik }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { cin >> n; // Stopień macierzy int nn = n * n; A = new T [nn]; // Rezerwujemy pamięć na macierz n x n for(int i = 0; i < nn; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Konstruktor - tworzy macierz stopnia n i wypełnia ją zerami //------------------------------------------------------------ template <class T> matrix<T>::matrix(int nn) { n = nn; // Stopień macierzy nn = n * n; A = new T [nn]; // Rezerwujemy pamięć na macierz n x n for(int i = 0; i < nn; i++) A[i] = (T)0; } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * n = c]; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość elementu //------------------------- template <class T> void matrix<T>::setv(int r, int c, T v) { A[r * n + c] = v; } // Ustawia przekatną na 1 //----------------------- template <class T> void matrix<T>::set1() { int i; for(i = 0; i < n; i++) setv(i,i,1); } // Oblicza wyznacznik macierzy template <class T> T matrix<T>::det() { matrix<T> L(n); matrix<T> U(n); L.set1(); int i,j,k; T sum; for(j = 0; j < n; j++) { for(i = 0; i <= j; i++) { sum = (T) 0; for(k = 0; k < i; k++) sum += L.getv(i,k) * U.getv(k,j); U.setv(i,j,getv(i,j) - sum); } for(i = j + 1; i < n; i++) { sum = (T) 0; for(k = 0; k < j; k++) sum += L.getv(i,k) * U.getv(k,j); if(U.getv(j,j)) L.setv(i,j,(getv(i,j) - sum) / U.getv(j,j)); } } sum = (T) 1; for(i = 0; i < n; i++) sum *= U.getv(i,i); return sum; } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << setprecision(2) << fixed; cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<double> A; cout << endl << "Wyznacznik macierzy metodą rozkładu LU Doolitle'a" << endl << "-------------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.n; j++) cout << setw(8) << A.getv(i,j); cout << endl; } cout << endl << "det A = " << A.det(); cout << endl << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 Wyznacznik macierzy metodą rozkładu LU Doolitle'a ------------------------------------------------- 5.00 3.00 7.00 4.00 2.00 9.00 2.00 2.00 1.00 1.00 3.00 6.00 2.00 8.00 9.00 9.00 4.00 -2.00 -1.00 -3.00 0.00 5.00 3.00 -6.00 -11.00 det A = -9368.00 |
Jeśli przyjrzysz się dokładnie wzorom Doolitle'a, to powinieneś zauważyć, że wyrazy macierzy A są wykorzystywane tylko jeden raz w każdym obiegu wyznaczania wyrazów macierzy L i U. Pozwala to umieścić macierze L i U w macierzy A, przez co algorytm działa w miejscu, tzn. nie zużywa dodatkowej pamięci. Jest to możliwe, ponieważ przekątna główna macierzy dolnej L nie jest używana przez algorytm. Zatem obie macierze L i U wypełnią dokładnie macierz A.
Poniższy program wykorzystuje tę koncepcję do wyliczenia wyznacznika. W przypadku próby dzielenia przez zero ustawiany jest znacznik error na true w macierzy A. Pozwala to programowi sprawdzić, czy obliczony wynik jest poprawny.
Przykładowe dane ( przekopiuj je do schowka i wklej w programie ):
Macierz:
Dane wejściowe:
5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 |
Przykładowy
program w języku C++ // Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: T * A; // Wyrazy macierzy T eps; public: int n; // Stopień macierzy bool error; // Błąd obliczania wyznacznika matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void setv(int r, int c, T v); T det(); // Oblicza wyznacznik }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { error = false; eps = (T) 0.000000001; cin >> n; // Stopień macierzy int nn = n * n; A = new T [nn]; // Rezerwujemy pamięć na macierz n x n for(int i = 0; i < nn; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * n + c]; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość elementu //------------------------- template <class T> void matrix<T>::setv(int r, int c, T v) { A[r * n + c] = v; } // Oblicza wyznacznik macierzy template <class T> T matrix<T>::det() { int i,j,k; T sum; for(j = 0; j < n; j++) { if((getv(j,j) > - eps) && (getv(j,j) < eps)) { error = true; // Błąd w obliczaniu wyznacznika return 0; } for(i = 0; i <= j; i++) { sum = (T) 0; for(k = 0; k < i; k++) sum += getv(i,k) * getv(k,j); setv(i,j,getv(i,j) - sum); } for(i = j + 1; i < n; i++) { sum = (T) 0; for(k = 0; k < j; k++) sum += getv(i,k) * getv(k,j); setv(i,j,(getv(i,j) - sum) / getv(j,j)); } } sum = (T) 1; for(i = 0; i < n; i++) sum *= getv(i,i); return sum; } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << setprecision(2) << fixed; cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<double> A; cout << endl << "Wyznacznik macierzy metodą rozkładu LU Doolitle'a w miejscu" << endl << "-----------------------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.n; j++) cout << setw(8) << A.getv(i,j); cout << endl; } cout << endl << "det A = " << A.det(); if(A.error) cout << " - BŁĄD W OBLICZENIACH !!!"; cout << endl << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 Wyznacznik macierzy metodą rozkładu LU Doolitle'a w miejscu ----------------------------------------------------------- 5.00 3.00 7.00 4.00 2.00 9.00 2.00 2.00 1.00 1.00 3.00 6.00 2.00 8.00 9.00 9.00 4.00 -2.00 -1.00 -3.00 0.00 5.00 3.00 -6.00 -11.00 det A = -9368.00 |
Istnieje prostsze rozwiązanie problemu wyznaczania rozkładu LU macierzy. Polega ono na przechodzeniu przez kolejne elementy głównej przekątnej macierzy A od pierwszego do przedostatniego i dla każdego elementu A[k,k] wykonywaniu kolejno dwóch operacji:
Dzięki takiemu podejściu algorytm rozkładu LU znacznie się upraszcza.
Poniższy program wykorzystuje ten algorytm do wyznaczenia rozkładu LU macierzy. Macierz jest wprowadzana tak samo, jak w programie poprzednim. Po dokonaniu rozkładu LU program oblicza wyznacznik macierzy i wyświetla wynik. Jeśli w trakcie pracy program napotka zerowy element na głównej przekątnej, to zakończy działanie z informacją o błędzie.
Przykładowe dane ( przekopiuj je do schowka i wklej w programie ):
Macierz:
Dane wejściowe:
5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 |
Przykładowy
program w języku C++ // Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: T * A; // Wyrazy macierzy T eps; public: int n; // Stopień macierzy bool error; // Błąd obliczania wyznacznika matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void setv(int r, int c, T v); T det(); // Oblicza wyznacznik }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { error = false; eps = (T) 0.000000001; cin >> n; // Stopień macierzy int nn = n * n; A = new T [nn]; // Rezerwujemy pamięć na macierz n x n for(int i = 0; i < nn; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * n + c]; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość elementu //------------------------- template <class T> void matrix<T>::setv(int r, int c, T v) { A[r * n + c] = v; } // Oblicza wyznacznik macierzy template <class T> T matrix<T>::det() { int i,j,k; T sum, akk; for(k = 0; k < n - 1; k++) { // Dzielnik akk = getv(k,k); if((akk > -eps) && (akk < eps)) { error = true; return 0; } // Normalizujemy kolumnę for(i = k + 1; i < n; i++) setv(i,k,getv(i,k) / akk); // Modyfikujemy podmacierz for(i = k + 1; i < n; i++) for(j = k + 1; j < n; j++) setv(i,j,getv(i,j) - getv(i,k) * getv(k,j)); } // Obliczamy wyznacznik; sum = getv(0,0); for(k = 1; k < n; k++) sum *= getv(k,k); return sum; } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << setprecision(2) << fixed; cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<double> A; cout << endl << "Wyznacznik macierzy metodą normalizacji kolumn" << endl << "----------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.n; j++) cout << setw(8) << A.getv(i,j); cout << endl; } cout << endl << "det A = " << A.det(); if(A.error) cout << " - BŁĄD W OBLICZENIACH !!!"; cout << endl << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 5 5 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 Wyznacznik macierzy metodą normalizacji kolumn ---------------------------------------------- 5.00 3.00 7.00 4.00 2.00 9.00 2.00 2.00 1.00 1.00 3.00 6.00 2.00 8.00 9.00 9.00 4.00 -2.00 -1.00 -3.00 0.00 5.00 3.00 -6.00 -11.00 det A = -9368.00 |
Mamy macierz A czwartego stopnia:
Tworzymy dla niej macierz permutacji P:
W takiej postaci permutacja nie zamienia miejscami wierszy/kolumn macierzy A:
Zamieńmy miejscami dwa środkowe wiersze ( lub dwie środkowe kolumny, co daje identyczny wynik ) w macierzy permutacji P:
Teraz mnożenia ( sprawdź to ) dadzą wyniki:
Pierwsze mnożenie dało w wyniku macierz A z zamienionymi dwoma środkowymi wierszami, a drugie mnożenie dało w wyniku macierz A z zamienionymi dwiema środkowymi kolumnami. Zatem macierz permutacji P ma za zadanie odpowiednio pozamieniać ze sobą miejscami wiersze lub kolumny. Taka zamiana nazywa się piwotem ( ang. pivoting ). Termin ten pochodzi z gry w kosza, gdzie oznacza obrót zawodnika z piłką.
Po co to wszystko? Otóż permutacje pozwolą nam tak poukładać wiersze ( lub kolumny ) macierzy, aby na jej przekątnej głównej znalazły się wyrazy o największym module. Jeśli macierz nie jest zdegenerowana, to jest to zawsze możliwe. Permutacje wykonujemy w trakcie wyznaczania rozkładu LU. Musimy jednak zapamiętywać ich liczbę, ponieważ każda zamiana wierszy/kolumn zmienia znak wyznacznika na przeciwny.
Praktycznie nie tworzy się macierzy P. Permutacje wierszy zapamiętujemy w wektorze wierszowym W, poprzez który odwołujemy się do wierszy macierzy A przy wyznaczaniu rozkładu LU. Podobnie postępowaliśmy w trakcie wyliczania wartości wyznacznika za pomocą rozwinięcia Laplace'a. Każdorazowo w pętli rozkładu LU wyznaczamy największy element w pierwszej kolumnie bieżącej podmacierzy i zamieniamy jego wiersz z pierwszym wierszem poprzez wektor kolumnowy. Algorytm jest następujący:
ε | – | dokładność przyrównania do zera |
n | – | stopień macierzy |
A | – | macierz podlegająca rozkładowi LU |
A | – | macierz zawierająca połączone macierze L i U |
W | – | wektor wierszowy |
md | – | mnożnik do korekcji wyznacznika |
i,j,k | – | indeksy |
maxw | – | numer wiersza z elementem maksymalnym |
maxe | – | moduł elementu maksymalnego |
akk | – | element macierzy A leżący na jej przekątnej po piwotowaniu |
K01: | md ← 1 | mnożnik korekcyjny ustawiamy na 1 |
K02: | Dla i = 0,1,...,n – 1: wykonuj: W [ i ] ← i |
ustawiamy wektor wierszowy |
K03: | Dla k = 0,1,...,n – 1: wykonuj kroki K04...K13 |
rozpoczynamy rozkład LU |
K04: | maxw ← k | wiersz z elementem maksymalnym |
K05: | maxe ← | A [ W [ k ], k ] | | moduł elementu maksymalnego |
K06: | Dla i = k + 1, k +
2,..., n – 1: wykonuj krok K07 |
szukamy elementu większego |
K07: |
Jeśli | A [W [ i ], k ] | > maxe, to maxw ← i maxe ← | A [ W [ i ], k ] | |
|
K08: | Jeśli maxe ≤ ε, to zakończ z wynikiem false |
macierz jest zdegenerowana |
K09: | Jeśli maxw ≠
W [ k ], to md ← - md W [ k ] ↔ W [ maxw ] |
znaleziono element maksymalny |
K10: | akk ← A [ W [ k ], k ] | rozkład LU |
K11: | Dla i = k + 1, k +
2,...,n – 1: wykonuj: A [ W [ i ], k ] ← A [ W [ i ], k ] / akk |
normalizacja kolumny |
K12: | Dla i = k + 1,k +
2,...,n – 1: wykonuj krok K13 |
modyfikujemy podmacierz |
K13: | Dla j = k + 1,k +
2,...,n – 1: wykonuj: A [ W [ i ], j ] ← A [ W [ i ], j ] - A [ W [ i ], k ] × A [ W [ k ], j ] |
|
K14: | Zakończ z wynikiem true |
Przy obliczaniu wyznacznika do wierszy macierzy A należy odwoływać się poprzez wektor wierszowy W.
Podany algorytm posiada jeszcze jedną zaletę: redukuje błędy zaokrągleń, ponieważ gwarantuje dzielenie przez największy element.
Poniższy program wykorzystuje ten algorytm do wyliczania wartości wyznacznika. Jest to modyfikacja poprzedniego programu.
Macierz:
Dane wejściowe:
5 0 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 |
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: T * A; // Wyrazy macierzy T eps; public: int n; // Stopień macierzy bool error; // Błąd obliczania wyznacznika matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void setv(int r, int c, T v); T absT(T x); T det(); // Oblicza wyznacznik }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { error = false; eps = (T) 0.000000001; cin >> n; // Stopień macierzy int nn = n * n; A = new T [nn]; // Rezerwujemy pamięć na macierz n x n for(int i = 0; i < nn; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * n + c]; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość elementu //------------------------- template <class T> void matrix<T>::setv(int r, int c, T v) { A[r * n + c] = v; } template <class T> T matrix<T>::absT(T x) { if(x < 0) x = - x; return x; } // Oblicza wyznacznik macierzy template <class T> T matrix<T>::det() { int i, j, k, * W, md, maxw; T sum, akk, maxe; // Mnożnik korekcyjny dla wyznacznika md = 1; // Tworzymy wektor wierszowy W = new int [n]; // Inicjujemy wektor wierszowy numerami wierszy for(i = 0; i < n; i++) W[i] = i; // Rozkład LU for(k = 0; k < n; k++) { maxw = k; // numer wiersza z elementem max maxe = absT(getv(W[k],k)); // Szukamy elementu max for(i = k + 1; i < n; i++) if(absT(getv(W[i],k)) > maxe) { maxw = i; maxe = absT(getv(W[i],k)); } // Jeśli max jest zero, to macierz jest zdegenerowana if(maxe <= eps) { error = false; delete [] W; return 0; } // Jeśli max nie leży na przekątnej, zamieniamy wiersze if(maxw != k) { md = -md; // Modyfikujemy mnożnik swap(W[k], W[maxw]); } // Dzielnik akk = getv(W[k],k); // Normalizujemy kolumnę for(i = k + 1; i < n; i++) setv(W[i],k,getv(W[i],k) / akk); // Modyfikujemy podmacierz for(i = k + 1; i < n; i++) for(j = k + 1; j < n; j++) setv(W[i],j,getv(W[i],j) - getv(W[i],k) * getv(W[k],j)); } // Obliczamy wyznacznik; sum = md * getv(W[0],0); for(k = 1; k < n; k++) sum *= getv(W[k],k); delete [] W; return sum; } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << setprecision(2) << fixed; cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<double> A; cout << endl << "Wyznacznik metodą LU z częściowym wyborem elementu głównego" << endl << "-----------------------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.n; j++) cout << setw(8) << A.getv(i,j); cout << endl; } cout << endl << "det A = " << A.det(); if(A.error) cout << " - BŁĄD W OBLICZENIACH !!!"; cout << endl << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 5 0 3 7 4 2 9 2 2 1 1 3 6 2 8 9 9 4 -2 -1 -3 0 5 3 -6 -11 Wyznacznik metodą LU z częściowym wyborem elementu głównego ----------------------------------------------------------- 0.00 3.00 7.00 4.00 2.00 9.00 2.00 2.00 1.00 1.00 3.00 6.00 2.00 8.00 9.00 9.00 4.00 -2.00 -1.00 -3.00 0.00 5.00 3.00 -6.00 -11.00 det A = -8598.00 |
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.