在 Octave 中算式(Expressions)是一般程式最基本的組成要件,一個算式會計算出一個值,這個值可以直接輸出、傳給判斷式做判斷、儲存在變數中、傳給函數做為輸入參數或是使用指定運算子將其指定給其他的變數。
大部分的判斷式都包含了多個算式,而一個算式也可以直接做為判斷式。Octave 的算式與其他語言類似,包含變數、陣列、常數、函數的呼叫與以上的組合。
索引算式(Index Expressions)
索引算式(Index Expressions)可以用來存取矩陣或向量中指定的元素。索引算式可以式純量、向量、範圍或是一個冒號 :(用來表示所有的行或列)。
向量是使用單一個索引算式;矩陣則可以使用單一個或兩個索引,當矩陣使用單一個索引時,則會將矩陣中的元素以行(column)優先的順序取其索,例如:
A = [1, 2, 3; 4, 5, 6; 7, 8, 9]; A(2)
輸出為
ans = 4
使用索引算式的輸出會依照索引的形式而有不同,例如上面這個範例是使用純量作為索引,則輸出亦為純量。若使用列向量的索引:
A(1:2)
則輸出為列向量
ans = 1 4
而使用行向量的索引:
A([1; 2])
則輸出為行向量
ans = 1 4
若使用單一個冒號作為索引,則會傳回所有元素所組成的行向量,例如:
A(:)
輸出為
ans = 1 4 7 2 5 8 3 6 9
下面這三個寫法都是將矩陣 A
的第一列取出:
A(1, [1, 2, 3]) A(1, 1:3) A(1, :)
三個寫法的輸出皆為
ans = 1 2 3
一般來說,一個 n
維的陣列可以使用 m
個索引來存取,若 n
等於 m
時,則每一個索引會對應一個維度,這些索引(純量、向量或範圍)會以笛卡兒乘積的方式構成最後的結果;若 n
大於 m
,則最後 n-m+1
維的資料會合併成一個維度,例如:
B = rand(3,2,2)
產生一個隨機的多為陣列 B
,輸出為
B = ans(:,:,1) = 0.684732 0.407394 0.165819 0.554558 0.203612 0.016332 ans(:,:,2) = 0.96476 0.83252 0.12081 0.22859 0.22828 0.51808
B 的維度是三,若只使用兩個維度的索引,則最後兩個維度的資料會合併成一維:
B(1,:)
輸出為
ans = 0.68473 0.40739 0.96476 0.83252
若使用都是 1
的矩陣做為純量的索引矩陣,可以建立與索引矩陣相同大小的矩陣,而其中的值皆等於此純量值,例如:
a = 5; a(ones(2, 3))
輸出為
ans = 5 5 5 5 5 5
也可以寫成這樣
5(ones(2, 3))
除了矩陣之外,亦可建立向量:
6(ones(1, 5))
輸出為
ans = 6 6 6 6 6
ones(1, n)
會產生一個元素都是 1
的列向量,但其會以範圍(range)的形式傳回,因此其效率會比使用其他形式的 ones()
來的高。當 r
是一個列向量時,下面兩個寫法所產生的結果是相同的:
r(ones (1, n), :) r(ones (n, 1), :)
但是第一種寫法的執行效率會比較快,尤其是在 r
與 n
非常大的時候,原因在於第一種寫法會將索引向量保持在一個壓縮的狀態,這樣可以讓 Octave 選擇以更有效綠的演算法來處理。
對一般使用者而言,若不想考慮這種細微的差異,最好的方式是直接使用 repmat()
函數來處理這類的問題。
若要建立每個元素都有不同值的矩陣,可以使用迴圈配合索引:
for i = 1:10 A(i) = sqrt (i); endfor
這樣會建立一個矩陣 A
,而第 i
個元素的值為 sqrt(i)
,然而這樣使用迴圈的寫法不是很有效率,以這個例子而言可以改成下面這樣的寫法:
A = sqrt (1:10);
這樣可以避免使用迴圈,若無法避免使用迴圈時,或是要將大量的資料組成一個矩陣時,事先設定好矩陣的大小,而後再使用索引來指定矩陣中的值,可以增加執行的效率,例如:
[nr, nc] = size (a); x = zeros (nr, n * nc); for i = 1:n x(:, (i-1)*nc+1:i*nc) = a; endfor
執行起來會比下面這個寫法快
x = a; for i = 1:n-1 x = [x, a]; endfor
這兩種寫法的差異在矩陣的較大時才會比較明顯,第一種寫法可以避免讓 Octave 重複改變矩陣的大小,所以執行上的效率較高。
要指定矩陣或多維的陣列的元素,可以使用多維的索引,也就是一般的下標(subscripts),例如使用一般下標的方式指定三乘三的矩陣:
但也可以利用一維的索引來指定其中的元素,而其排列的順序是以行為優先:
下標與一維索引可以使用下面的函數做轉換。
ind = sub2ind (dims, i, j) ind = sub2ind (dims, s1, s2, ..., sN)
sub2ind(dims, i, j)
函數會將下標(subscripts)轉換為一維的索引(index),例如下面這個例子會將三乘三矩陣的二維索引 (2, 3)
轉換成一維的索引:
linear_index = sub2ind ([3, 3], 2, 3)
輸出為
linear_index = 8
[s1, s2, ..., sN] = ind2sub (dims, ind)
ind2sub(dims, ind)
函數會將一維的索引(index)轉換為下標(subscripts),例如下面這個例子會將三乘三矩陣的一維索引 (2, 3)
轉換成二維的索引:
[r, c] = ind2sub ([3, 3], 8)
輸出為
r = 2 c = 3