在 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), :)

但是第一種寫法的執行效率會比較快,尤其是在 rn 非常大的時候,原因在於第一種寫法會將索引向量保持在一個壓縮的狀態,這樣可以讓 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),例如使用一般下標的方式指定三乘三的矩陣:

octave-expressions-subscript

但也可以利用一維的索引來指定其中的元素,而其排列的順序是以行為優先:

octave-expressions-index

下標與一維索引可以使用下面的函數做轉換。

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