Octave rzadko kiedy bywa używany jak zwykły kalkulator do wyznaczania wartości gotowych wyrażeń matematycznych. Jego prawdziwa siła objawia się bowiem dopiero wtedy, gdy potraktujemy go jak język programowania, w którym przygotowuje się wielolinijkowe skrypty. Takie skrypty z reguły zawierają zmienne i funkcje definiowane przez użytkownika.
Definiowanie zmiennych jest banalnie proste: piszemy jej nazwę, znak =,
a po nim wartość zmiennej, np.:
> a = 1 a = 1
Dużo ciekawsza jest kwestia rodzaju zmiennych, jakich możemy używać w Octave. W niniejszym kursie skoncentrujemy się na najbardziej użytecznych typach danych:
who -l variables
123, -3.14, 1.2e-10.
Niezależnie od zapisu, skalary reprezentowane są przez Octave jako tzw.
liczby zmiennopozycyjne
podwójnej precyzji (IEEE-754 double).
Uwaga: Octave umożliwia też deklarowanie skalarów innych typów, np.
całkowitych (8, 16, 32 i 64 bitowych), zmiennopozycyjnych w pojedynczej precyzji oraz
zespolonych. Przykłady skalarów zespolonych:
i, 1 + 3i, 1.2 - 3.4i.
> a = [1, 2, 3, 4] a = 1 2 3 4Uwaga: przecinki można pominąć, ale może prowadzić to do subtelnych błędów podczas interpretacji wyrażeń.
Dostęp do wartości n-ego elementu wektora a zapewnia wyrażenie a(n):
> a(2)=3 a = 1 3 3 4Jak widać, pierwszy element wektora n-elementowego to
a(1), a element ostatni
to a(n).
Wektory można łatwo rozszerzać o nowe elementy:
> a = [a, 7, [10,100]]
a =
1 3 3 4 7 10 100
Liczbę elementów wektora można zbadać funkcją length
> length(a) ans = 7W powyższych przykładach mieliśmy do czynienia z tzw. wektorami wierszowymi. Octave rozpoznaje też wektory kolumnowe. Kolejne elementy wektorów kolumnach oddziela się od siebie średnikami:
> v = [1; 2; 5] v = 1 2 5
m jako wektora kolumnowego o dwóch elementach, z których każdy jest
dwuelementowym wektorem wierszowym:
> m = [[1, 2]; [3, 4]] m = 1 2 3 4
Takie uogólnione wektory nazywamy macierzami.
Macierz o n wierszach
i m kolumnach zwie się "macierzą n na m".
Jeżeli m = n, macierz zwie się kwadratową. W powyższym przykładzie m
jest więc macierzą kwadratową o dwóch wierszach i dwóch kolumnach, czyli "2 na 2".
Macierze można też interpretować jako wektory wierszowe, których elementy są wektorami kolumnowymi:
m = [[1; 3], [2; 4]] m = 1 2 3 4Zapis macierzy zwykle upraszcza się jeszcze bardziej, po prostu podając wartości elementów w kolejnych wierszach i kolumnach:
m = [1, 2; 3, 4] m = 1 2 3 4Liczbę wierszy dowolnej macierzy zwraca funkcja
rows, liczbę kolumn zwraca funkcja columns, a funkcja size zwraca
liczbę wierszy i kolumn jako wektor "1 na 2":
> rows(m) ans = 2 > columns(m) ans = 2 > size(m) ans = 2 2
Uwaga! Dla Octave skalary i wektory to pewne specjalne rodzaje macierzy: skalary to macierze
"1 na 1", wektory wierszowe to macierze "1 na n", a wektory kolumnowe to
macierze "n na 1".
Aby uzyskać dostęp do elementu leżącego w w-tym wierszu i k-tej kolumnie
macierzy m, piszemy m(w,k):
> m(1,2) ans = 2
> 1:4definiuje zakres odpowiadający ciągowi
[1, 2, 3, 4]. Analogicznie
> 1 : 0.5 : 4.1odpowiada wektorowi
[1, 1.5, 2, 2.5, 3, 3.5, 4].
Zakresy nie tylko upraszczają zapis, ale przede wszystkim umożliwiają optymalizację
działania programu. Np. jeżeli zdefiniujemy zmienną a wyrażeniem
> a = 1:100000to Octave zarezerwuje dla tej zmiennej zaledwie 24 bajty (3 liczby zmiennopozycyjne). Równoważny tej zmiennej wektor musiałby mieć 100 000 elementów i zajmowałby w pamięci operacyjnej aż 800 000 bajtów.
> a = "ala ma kota" a = ala ma kota
Transpozycja macierzy to zamiana jej kolumn na wiersze i wierszy na kolumny.
W Octave transpozycję macierzy wykonuje się za pomocą specjalnego operatora ' (apostrof).
Oto prosty przykład:
> m = [1, 2, 3; 4, 5, 6] m = 1 2 3 4 5 6 > b = m' b = 1 4 2 5 3 6
W powyższym przykładzie b jest macierzą transponowaną do m,
tj. b czytana kolumnami wygląda tak samo, jak m czytana wierszami.
Jednym z najważniejszym zastosowaniem transpozycji jest zamiana wektorów wierszowych na kolumnowe, wektorów kolumnowych na wierszowe i definiowanie „zakresów kolumnowych”. Tę ostatnią cechę ilustruje następujący przykład :
> v = [1:4]' v = 1 2 3 4
Uwaga: Jeżeli macierz m ma elementy zespolone, to wyrażenie
m' oznacza
sprzężenie hermitowskie m. Transpozycję macierzy zespolonej oznacza się operatorem
.' (kropka apostrof), np.
m = v.'
Dla macierzy rzeczywistych oba zapisy (z kropką lub bez) są równoważne.
W przypadku bardziej zaawansowanych obliczeń niezwykle ważna jest umiejętność zapisywania i wczytywania danych z plików. Szczególnie istotne jest zapisywanie końcowych wyników żmudnych obliczeń i wyników obliczeń pośrednich, które być może zechcemy kontynuować w przyszłości.
Aby zapisać dowolną zmienną, np. wektor a = [1,2,3,4,100], posługujemy się
poleceniem save:
> save "a.mat" a
Pierwszym argumentem tego polecenia jest zwykle nazwa pliku (tu: a.txt).
Następnie podajemy wykaz zmiennych, które chcemy w tym pliku zapisać (tu: jedna zmienna a).
Oto przykład instrukcji zapisującej 3 zmienne, a, x i m:
> save "axm.txt" a x m
Jeżeli nie podamy żadnych zmiennych, Octave zapisze w pliku wszystkie zdefiniowane aktualnie zmienne.
> save "sesja.txt"
Aby odczytać tak zapisane zmienne, stosujemy polecenie load:
> load "axm.txt"
Warto zwrócić uwagę na to, że funkcja load nie tylko wczytuje wartości zmiennych,
ale też nadaje im zapisane w piku nazwy.
Po wczytaniu zmiennych z pliku warto wydać polecenie who -l variables
> who -l -variables
które wyświetla podstawowe informacje o wszystkich zdefiniowanych aktualnie zmiennych.
Obie funkcje, save i load, posiadają mnóstwo dodatkowych opcji i potrafią
obsługiwać dane w wielu formatach, w tym w formatach binarnych programu Matlab.
> a = 1 > b = 1.0 > c = 1e0
> a = [1 2 3]; > b = [1, 2, 3]; > c = [1; 2; 3];
v o elementach 1, 2, 5, 10 i zapisz go w pliku v.mat.
v.mat. Sprawdź, że w programie z powrotem pojawiła się zmienna v.
v z poprzedniego punktu sprawdź, jak Octave interpretuje wyrażenia
> v + v > v + 1 > v * 2 > v'
x zapisana w binarnym formacie
hdf5.
x (who -l variables).x (funkcjami rows, columns).x
(funkcjami min, max, mean).