函數(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),並將計算結果儲存至 u
、 s
與 v
。在多重傳回值算式中,等號左邊事實上是一個逗點分隔序列,其可以是逗點分隔的變數名稱或索引算式,請參考索引算式與指定算式。
Octave 中所有的函數都是使用傳值呼叫(call by value),也就是 Octave 會將函數的參數在傳入前先複製一份,在函數中所使用的值是經過複製的副本,所以改變函數中的值並不會對原來函數外的值造成影響,例如:
function f (x, n) while (n-- > 0) disp (x); endwhile endfunction
這個函數會顯示 x
的值 n
次,在函數中的 n
是由函數參數中的 n
的副本,因此在函數中改變 n
的值,對於函數外的 n
並無影響。傳值呼叫的優點是使用者可以傳入一個常數至函數中,不用擔心此函數是否會改變傳入的值。
函數在呼叫時可以使用變數名稱,但函數本身會將每個參數視為一個算式,只會將其運算值傳入函數中,例如:
foo = "bar";
fcn (foo)
函數 fcn(foo)
的參數會被視為一個字串 "bar"
,而不是一個名稱為 foo
的變數。
雖然 Octave 的函數都是使用傳值呼叫,但事實上 Octave 會避免不必要的副本存在,也就是說當傳入一個值進入函數中時,若在函數中沒有改變這個值,則 Octave 會讓函數內的變數與函數外的變數使用同一份資料,避免浪費記憶體空間,例如:
x = rand (1000); f (x);
這會將一個 1000
乘 1000
的矩陣傳入函數 f()
中,若是在 f()
函數中沒有更動 x
的值,則 Octave 就不會將 x
複製一份一樣的 x
在 f()
中,而會讓兩者共用一份資料,這樣可以節省記憶體空間,增加執行效率。
在 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()
函數可以查詢或設定函數遞迴呼叫的最大次數,若是遞迴呼叫的次數大於此數值,則會產生錯誤訊息,並回到最上一層。
lsode()
函數是以 Fortran 語言所寫成的,其無法以遞迴呼叫的方式使用,否則會產生錯誤。