Wykład 4 Matlab cz.3 Tablice i operacje na tablicach Dr inż. Zb. Rudnicki Tematyka wykładu 1. Macierze, wektory, tablice - wprowadzenie 2. Rozmiary i typy tablic 3. Zapis - nawiasy i znaki specjalne 4. Przydział pamięci dla tablic - deklarowanie 5. Sposoby wprowadzania i generowania tablic 6. Przechowywanie tablic w plikach 7. Działania na macierzach 2 1
1. Tablice jedno i wielowymiarowe Tablica to zbiór elementów jednakowego typu, identyfikowanych przez wspólną nazwę oraz indywidualne numery zwane indeksami W Matlabie indeksy zapisuje się po nazwie tablicy w nawiasach okrągłych, oddzielając przecinkami np.: TAB1(4, 6) Nazwa bez indeksów np.: TAB1 - reprezentuje całą tablicę. Należy rozróżnić pojęcia liczba wymiarów oraz rozmiary tablicy Liczba wymiarów tablicy - to liczba indeksów określających jej pojedynczy element, na przykład: Bt(5), W(j), Sila(j+1) - to elementy tablic jednowymiarowych czyli wektorów; HH(3, 5), Masy(j, k) - to elementy tablic dwuwymiarowych czyli macierzy; ZET(3, 5, 7), Mom(j, k, l), T(j-1,3,1) - to elementy tablic trójwymiarowych. Rozmiary tablicy - określone są maksymalnymi wartościami indeksów i wyznaczają liczbę wszystkich elementów. 3 Tablica jednowymiarowa czyli wektor - domyślnie: kolumnowy, element ma jeden indeks: nr_wiersza Liczba wymiarów tablic Tablica dwuwymiarowa czyli macierz (ciąg wektorów kolumnowych) - element ma dwa indeksy: nr_wiersza, nr_kolumny Tablica trójwymiarowa - element ma trzy indeksy: nr_wiersza, nr_kolumny, nr_strony Można też stosować tablice o większej liczbie wymiarów (kolejne indeksy dopisywane z prawej) 4 2
Tablice czy macierze W Matlabie istnieją tablice (ang.: arrays) jedno i wielowymiarowe. Tablice w Matlabie bywają czasem określane jako macierze (ang.: matrix) - chociaż w matematyce macierzami nazywa się tylko tablice dwuwymiarowe a wektorami tablice jednowymiarowe - wynika to stąd, że Matlab opracowywany był głównie dla macierzy (matrix), i od tego pochodzi jego nazwa: Matlab = MATrix LABoratory - a potem dopiero wprowadzono tablice (arrays) o większej liczbie wymiarów. Domyślnie, tablice mają elementy typu double - liczby rzeczywiste podwójnej precyzji. Typ double musi być użyty jeśli stosowane są obliczenia 5 2. Rozmiary i typy tablic 6 3
2.1. Rozmiary tablic. Funkcja SIZE Każda tablica ma określoną liczbę wierszy i kolumn co można sprawdzić funkcją size: [liczba_wierszy liczba_kolumn] = size(macierz) Skalar to macierz o rozmiarach (1, 1): >> b=2; >> size(b) 1 1 Wektor wierszowy to tablica o tylko jednym wierszu czyli rozmiarach (1, n): >> c=[8,2,6,3] c = 8 2 6 3 >> size(c) 1 4 a wektor kolumnowy to tablica o jednej kolumnie czyli rozmiarach (n, 1): >> d=[4;7;2;1;6]; >> size(d) 5 1 7 2.3. Typy tablicowe Oprócz zwykłych tablic o elementach typu double istnieją: tablice numeryczne o elementach będących liczbami całkowitymi: int8, int16, uint8, uint16,... tablice znakowe - typu char, macierze rzadkie - typu sparse - w których zapamiętywane są tylko elementy niezerowe, tablice komórkowe - typu cell - w których każdy element może być innego typu (także tablicowego), tablice strukturalne - typu struct - w których wiersze są rekordami złożonymi z pól różnych typów, identyfikowanych nazwami 8 4
Tablica znakowa Elementami tablicy znakowej nie mogą być łańcuchy o różnej długości, na przykład: >> TZ=['wewe','ee','o';'f','kk','sss']??? Error using ==> vertcat CAT arguments dimensions are not consistent. Dla takich łańcuchów można użyć opisanej dalej tablicy komórkowej albo usunąć błąd przez dostawienie spacji, tak aby wszystkie łańcuchy miały jednakową długość (po 4 znaki): >> TZ=['wewe',' ee ',' o';' f',' kk',' sss'] TZ = wewe ee f kk sss o 9 Tablica komórkowa Wartości elementów tablicy komórkowej wpisujemy między klamrami {...} W zwykłych tablicach wszystkie elementy muszą być tego samego typu, w tablicy komórkowej każdy element może być innego typu np.: >> TK={3.51, 'ala', 88; 'pp', 12, [3, 4; 9, 1.2] } TK = [3.5100] 'ala' [ 88] 'pp' [ 12] [2x2 double] >> TK(2,3) [2x2 double] Aby uzyskać wartości elementu trzeba indeksy wpisać między klamrami: >> TK{2,3} 3.0000 4.0000 9.0000 1.2000 10 5
3. Zapis - Nawiasy i znaki specjalne 11 3.1. Zapis - Nawiasy prostokątne [ ] Używane są do: definiowania wartości wektorów i macierzy np.: V=[2.5, 3, 12], M=[1, 0, 3; 0.5, 2, 4] elementy wiersza można oddzielać przecinkami lub spacjami: V=[2.5 3 12], M=[1 0 3; 0.5 2 4] sklejania (konkatenacji): - wektorów, - macierzy - łańcuchów znakowych (tekstów) np.: disp([ Sila=, num2str(f1), Moment=, num2str(mg)]) 12 6
3.2. Zapis - Indeksy elementów tablic Indeksy (wskaźniki) należy umieszczać w nawiasach okrągłych np.: V(1), b(16), M(i,j), MACIERZ_A(3, 2) Indeksy mogą być wyrażeniami: sila(2*j+1) MACIERZ_A(w+1, k-2) Indeksy mogą również być ciągami: sila(2:2:8) MACIERZ_A(w:w+5, kp:kk) Dwukropek zamiast indeksu oznacza wszystkie wartości indeksu np.: >> X=[3 7 2; 8 2 5]; >> X(2,:) 8 2 5 13 3.3. Zapis - Rola dwukropka w wybieraniu elementów Dla danej macierzy: >>A= [ 1 2 3 4; 7 8 9 10] A = 1 2 3 4 7 8 9 10 a) wybieramy wszystkie wiersze z drugiej kolumny: >>A(:, 2) 2 8 b) wybieramy kolumnę 2 oraz 3: >>A(:, 2:3) 2 3 8 9 c) wybieramy kolumny od 1 co 2 do 4: A(:, 1:2:4) 1 3 7 9 d) drugi wiersz i wszystkie kolumny : A(2, :) 7 8 9 10 e) zamiana macierzy na wektor (kolumnami): A(:) 1 7 2 8 3 9 4 10 14 7
4. Przydział pamięci dla tablic - deklarowanie W większości języków niezbędne jest deklarowanie typu i wymiarów tablic dla przydzielenia odpowiedniego miejsca w pamięci operacyjnej. W Matlabie przydział pamięci dla tablic odbywa się automatycznie - przez rozpoznanie rodzaju wpisanych wartości oraz maksymalnych wskaźników oraz dynamicznie - to znaczy w trakcie wykonywania programu Tablicę można zadeklarować - wstępnie ustalając wymiary - przez podanie wartości początkowej ostatniego elementu: >> B(2,4)=0 B = 0 0 0 0 0 0 0 0 15 4.1. Dynamiczne zwiększanie rozmiaru tablicy Jeśli potem w programie wystąpią większe wartości wskaźników to macierz zostanie powiększona. Na przykład instrukcja B(3,5)=2 spowoduje następującą zmianę macierzy: >>B(3,5)= 2 B = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 16 8
5. Sposoby wprowadzania i generowania tablic Tablice mogą powstawać na różne sposoby np.: 5.1. wpisanie wszystkich elementów w nawiasach prostokątnych, przy czym elementy wiersza oddzielamy przecinkami lub spacjami a średnik oddziela wiersze: >>A = [ 3.4, 2.7, 1.4; 8.5, 3.5, 6.7] A= 3.4 2.7 1.4 8.5 3.5 6.7 5.2. generowanie na podstawie indeksów - zmienianych w pętlach, 5.3. generowanie na podstawie ciągów indeksów - bez pętli, 5.4. generowanie tablic funkcjami macierzowymi, 5.5. wczytywanie tablic z pliku (i zapis do pliku). 17 Wprowadzanie - w pętli czy bez pętli? W większości języków programowania (jak Basic, Fortran, Pascal, C,...) generowanie wektorów wymaga użycia pętli a generowanie macierzy - użycia podwójnej pętli. Z tego powodu warto poznać metody stosujące pętle. W Matlabie jednak, istnieją metody operowania na macierzach bez zastosowania pętli - co jest szybsze. W Matlabie zalecane jest zastępowanie pętli operacjami macierzowymi, szczególnie dla dużych tablic, gdyż Matlab został zoptymalizowany dla operacji macierzowych wykonywanych bez pętli. 18 9
5.2. Generowanie elementów tablic w pętli (1) Deklarowanie typu i wymiarów tablic odbywa się automatycznie - przez rozpoznanie rodzaju wpisanych wartości oraz maksymalnych wskaźników. Jeśli elementy tablicy generujemy w pętli to może niepotrzebnie wielokrotnie wystąpić operacja deklarowania coraz większych rozmiarów tablicy np.: >> for i=1:4; X(i)=2*i; X, end; X = 2 X = 2 4 X = 2 4 6 X = 2 4 6 8 19 5.2. Generowanie elementów tablic w pętli (c.d.) Aby nie marnować na to czasu komputera wskazane jest przed generowaniem elementów tablicy zarezerwować dla niej miejsce w pamięci przez wstawienie zera do elementu o maksymalnych wartościach wskaźników np.: >> clear >> B(4)=0, for i=1:4; B(i)=2*i; B, end; B = 0 0 0 0 B = 2 0 0 0 B = 2 4 0 0 B = 2 4 6 0 B = 2 4 6 8 20 10
5.2. Generowanie wektorów w pętli Przykład: Tabela i wykres funkcji sinus W pętli FOR wyznaczamy i wstawiamy do wektora X ciąg wartości kąta (w radianach) od zera do 2*pi z przyrostem 0.2, a do wektora Y ciąg odpowiadających im wartości funkcji sinus. k=0; % zerujemy licznik elementów tabeli fprinf('\n x sin(x)'); % nagłówek tabeli for x=0:0.2:2*pi k=k+1; X(k)=x; Y(k)=sin(x); fprinf('\n %7.4f %7.4f',X(k),Y(k)); end plot(x,y); grid on; % to wykres i siatka title('funkcja sinus'); % tytuł wykresu xlabel('x'); ylabel( y'); % etykiety osi 21 5.2. Generowanie macierzy - w podwójnej pętli (1) Przykład 1a. Wygenerować macierz: 1 5 9 13 3 7 11 15 5 9 13 17 7 11 15 19 % Program 1 clear; for w=1:4 el=2*w-1; for k=1:4 a(w,k)=el; el=el+4; end end a, % wyświetli macierz W pętlach otrzymujemy kolejne numery wierszy w oraz kolumn k. Na podstawie w ustalany jest pierwszy element wiersza el a następnie zwiększany z przyrostem 4. Umieszczenie samej nazwy macierzy a spowoduje wyświetlenie jej wszystkich elementów. 22 11
5.2. Generowanie macierzy - w podwójnej pętli (2) Przykład 1b. Wygenerować macierz: 1 5 9 13 3 7 11 15 5 9 13 17 7 11 15 19 Ta sama macierz jest tutaj generowana inaczej. W pętli zewnętrznej otrzymujemy ciąg pierwszych elementów każdego wiersza i a w pętli wewnętrznej kolejne elementy wiersza j Numery wierszy w oraz kolumn k są otrzymywane osobno. % Program 2 clear; w=0; for i=1:2:7 w=w+1; k=0; for j=i:4:i+3*4 k=k+1; a(w,k)=j; end end a 23 5.2. Generowanie macierzy - w podwójnej pętli (3) Przykład 2. Wygenerować macierz trójkątną: 9 0 0 0 0 0 7 9 0 0 0 0 5 7 9 0 0 0 3 5 7 9 0 0 1 3 5 7 9 0 clear; % rezerwujemy pamięć i zerujemy macierz: a(4,6) = 0; for w = 1:5 e = 11-2*w; k = 0; while e<10 k = k+1; a(w,k) = e; e = e+2; end end a 24 12
5.3. Generowanie tablic bez pętli a) Wektory, których elementy stanowią postęp arytmetyczny można generować bez pętli podając trzy parametry oddzielone dwukropkami: pierwszy_element : przyrost : ostatni element np.: >> x = -2 : 0.5 : 2 x= -2.0-1.5-1.0-0.5 0.0 0.5 1.0 1.5 2.0 b) Po wygenerowaniu wektora-indeksu jako ciągu, można wykorzystać go do definiowania innych wektorów np.: >> i=1:9; x=(i-5)/2 x= -2.0-1.5-1.0-0.5 0.0 0.5 1.0 1.5 2.0 >> y=(i-5).^2 y = 16 9 4 1 0 1 4 9 16 25 5.4. Generowanie tablic funkcjami macierzowymi Funkcja: zeros(w,k) - generuje macierz wypełnioną zerami np.: >>A = zeros(2,3) A = 0 0 0 0 0 0 ones(w,k) - generuje macierz wypełnioną jedynkami np.: >>A = ones(2,4) A = 1 1 1 1 1 1 1 1 26 13
5.4. Generowanie tablic bez pętli c.d. ciągi w roli indeksów zeros(w,k) - generuje macierz wypełnioną zerami, a potem do wybieranych cyklicznie elementów wstawiamy np. 11: >>A = zeros(4,5); A(1:2:3, 2:2:5)=11 A = 0 11 0 11 0 0 0 0 0 0 0 11 0 11 0 0 0 0 0 0 27 5.4. Generowanie tablic funkcjami macierzowymi c.d. rand(w,k) - generuje macierz liczb pseudolosowych o rozkładzie równomiernym np.: >>A = rand(2,5) A = 0.9501 0.6068 0.8913 0.4565 0.8214 0.2311 0.4860 0.7621 0.0185 0.4447 eye(n) - generuje macierz jednostkową (kwadratowa N x N z jedynkami na przekątnej głównej i zerami w pozostałych miejscach) np.: >>A = eye(3) A = 1 0 0 0 1 0 0 0 1 28 14
5.5. Wczytywanie tablic z pliku Jeśli w pliku tekstowym o nazwie DANE1.TXT są dwie linie i w każdej po 4 liczby oddzielane odstępami: 2 4 6 8 3 6 9 12 to aby wczytać te liczby do macierzy można napisać następujące instrukcje: [plik1 info] = fopen('dane1.txt'); A = fscanf(plik1, '%f %f %f %f', [4, 2]) close(plik1) Ale UWAGA: dane czytane są z pliku wierszami ale umieszczane w macierzy kolumnami, dlatego po wczytaniu uzyskamy macierz: A = 2 3 4 6 6 9 8 12 Aby uzyskać to samo co w pliku trzeba macierz transponować: A=A. 29 6. Działania na macierzach 30 15
Dodawanie i odejmowanie macierzy - można wykonywać tylko na macierzach typu double o identycznych rozmiarach >> A=[-2, 1, 3; 5, 6, 2], B=[0.5, 1, 1.5; 3, 2, 1] A = -2 1 3 5 6 2 B = 0.5000 1.0000 1.5000 3.0000 2.0000 1.0000 >> A+B -1.5000 2.0000 4.5000 8.0000 8.0000 3.0000 >> A-B -2.5000 0 1.5000 2.0000 4.0000 1.0000 31 Dzielenie, mnożenie, potęgowanie macierzy Są dwie kategorie operacji mnożenia, dzielenia i potęgowania macierzy: Tablicowe - operatory z kropką:.*./.^ = działania na parach elementów macierzy o jednakowych rozmiarach Macierzowe (operatory bez kropki) - zgodne z definicjami działań na macierzach 32 16
Operatory działań Tablicowe - na elementach:.* mnożenie (par elementów).^ potęgowanie (każdego elementu)./ dzielenie (par elementów) Macierzowe - na macierzach: * mnożenie macierzowe ^ potęgowanie macierzowe (a^2 = a*a mnożenie macierzowe) / dzielenie prawostronne (x=a / b jest rozwiązaniem równania: x*b=a) \ dzielenie macierzowe (x=a\b jest rozwiązaniem równania a*x=b) 33 >> A=[1, -1, 2; 1, 2, 3], B=[2, 0, 1; 1, 0, 2] A = 1-1 2 1 2 3 B = 2 0 1 1 0 2 >> C=A.* B C = 2 0 2 1 0 6 >> D=A*B; % Mnożenie macierzowe - niewykonalne??? Error using ==> * Inner matrix dimensions must agree. Przykład mnożenia tablicowego -macierze muszą mieć takie same rozmiary. Przy mnożeniu macierzowym liczba kolumn w pierwszej musi być taka jak liczba wierszy w drugiej 34 17
Mnożenie macierzowe 35 >> M1=[2,0,1;3,2,1], M2=[2;3;4] M1 = 2 0 1 3 2 1 M2 = 2 3 4 >> W=M1*M2 W = 2*2 + 0*3 + 1*4 = 8 3*2 + 2*3 + 1*4 =16 Przykład mnożenia macierzowego - liczba kolumn w pierwszej macierzy musi być równa liczbie wierszy w drugiej 36 18
Transpozycja macierzy [. ] - czyli zamiana wierszy na kolumny: >> A=[1,3,4,5; 2,3,6,7] A = 1 3 4 5 2 3 6 7 >> B=A.' B = 1 2 3 3 4 6 5 7 37 Układ równań liniowych (1) 38 19
Układ równań liniowych (2) 39 Układ równań liniowych (3) 40 20
Układ równań liniowych (4) 41 42 21
Funkcje dla wielomianu roots(a) - pierwiastki wielomianu dla danego wektora współczynników a. Kolejność: począwszy od najwyższej potęgi polyval(a, xp) - wartość wielomianu dla danego wektora współczynników a oraz danej wartości zmiennej xp 43 22