呼叫函數(Calling Functions)

函數(function)是一個特定運算的名稱,由於其永擁有名稱,因此可以在程式中的任何地方呼叫,例如 sqrt() 是用於計算平方根的函數。

Octave 中有一系列的內建函數(built-in function),這些內建函數可以用於任何的 Octave 程式,例如 sqrt() 就是一個內建函數。另外,使用者也可以自行定義函數,關於自訂函數,請參考函數與指令稿(Functions and Scripts)。

要呼叫函數可以使用函數呼叫算,其包含函數的名稱與一連串使用括號包起來的的參數,若有一個以上的參數,則以逗號分隔,若沒有任何參數,可以省略小括號,但建議將小括號保留,這樣可以讓程式碼更容易閱讀,以下是一些呼叫函數的範例:

sqrt (x^2 + y^2)      # One argument
ones (n, m)           # Two arguments
rand ()               # No arguments

每一個函數都會接受特定個數的參數,例如 sqrt() 函數只接受一個參數,並計算此參數的平方根:

sqrt(argument)

有一些內建函數可以依據其不同的使用方式,接受不同個數的參數,而其功能也會因為輸入不同的參數而有所不同。

函數呼叫算式與一般其他的算式一樣都有傳回值,此傳回值是由此函數根據輸入的參數所運算的結果,例如 sqrt(argument) 的傳回值是 argument 的平方根。而函數有時也會有一些其他的邊際效應,例如指定一些變數的值或進行資料的輸入或輸出等。

Octave 的函數與一般程式語言的函數有一個很大的不同,Octave 的函數可以有多個傳回值,例如:

[u, s, v] = svd (a)

會計算矩陣 a 的 SVD 分解(singular value decomposition),並將計算結果儲存至 usv。在多重傳回值算式中,等號左邊事實上是一個逗點分隔序列,其可以是逗點分隔的變數名稱或索引算式,請參考索引算式與指定算式。

傳值呼叫(Call by Value)

Octave 中所有的函數都是使用傳值呼叫(call by value),也就是 Octave 會將函數的參數在傳入前先複製一份,在函數中所使用的值是經過複製的副本,所以改變函數中的值並不會對原來函數外的值造成影響,例如:

function f (x, n)
  while (n-- > 0)
    disp (x);
  endwhile
endfunction

這個函數會顯示 x 的值 n 次,在函數中的 n 是由函數參數中的 n 的副本,因此在函數中改變 n 的值,對於函數外的 n 並無影響。傳值呼叫的優點是使用者可以傳入一個常數至函數中,不用擔心此函數是否會改變傳入的值。

目前 Octave 不支援傳址呼叫(call by reference)。

函數在呼叫時可以使用變數名稱,但函數本身會將每個參數視為一個算式,只會將其運算值傳入函數中,例如:

foo = "bar";
fcn (foo)

函數 fcn(foo) 的參數會被視為一個字串 "bar",而不是一個名稱為 foo 的變數。

雖然 Octave 的函數都是使用傳值呼叫,但事實上 Octave 會避免不必要的副本存在,也就是說當傳入一個值進入函數中時,若在函數中沒有改變這個值,則 Octave 會讓函數內的變數與函數外的變數使用同一份資料,避免浪費記憶體空間,例如:

x = rand (1000);
f (x);

這會將一個 10001000 的矩陣傳入函數 f() 中,若是在 f() 函數中沒有更動 x 的值,則 Octave 就不會將 x 複製一份一樣的 xf() 中,而會讓兩者共用一份資料,這樣可以節省記憶體空間,增加執行效率。

遞迴(Recursion)

在 Octave 中可以使用遞迴(Recursion)的方式來撰寫函數,例如使用遞迴的方式計算階乘(factorial):

function retval = fact (n)
  if (n > 0)
    retval = n * fact (n-1);
  else
    retval = 1;
  endif
endfunction

這個函數是一個遞迴函數,它會自己呼叫自己,每一次呼叫自己時,會將傳入的參數 n 減去 1,直到 n 等於 0 時傳回 1。這裡定義的函數是為了示範遞迴函數的使用方式,若是要計算階乘可以使用較有效率的 prod(1:n)gamma(n+1)

val = max_recursion_depth ()
old_val = max_recursion_depth (new_val)

max_recursion_depth() 函數可以查詢或設定函數遞迴呼叫的最大次數,若是遞迴呼叫的次數大於此數值,則會產生錯誤訊息,並回到最上一層。

在 Octave 中有一些函數不能使用遞迴的方式,例如 lsode() 函數是以 Fortran 語言所寫成的,其無法以遞迴呼叫的方式使用,否則會產生錯誤。