MATLAB 學習筆記:自定義函數
自定義函數是MATLAB編程的基礎,它允許你將重復代碼封裝成可重用的模塊,提高代碼的可讀性和效率。本筆記將覆蓋所有重點知識點,包括語法細節、輸入輸出處理、函數文件管理、錯誤處理等。我會用自然易懂的語言解釋,并輔以代碼示例幫助你理解。篇幅不是問題,我會確保內容全面,從基礎到進階層層展開。
1. 什么是自定義函數?
在MATLAB中,自定義函數是用戶自己定義的代碼塊,用于執行特定任務。與內置函數(如 sin
或 plot
)不同,自定義函數讓你能創建自己的計算邏輯。例如,你可以定義一個函數來計算圓的面積,公式為 $A = \pi r^2$,其中 $r$ 是半徑。函數的核心優勢包括:
- 代碼重用:避免重復編寫相同代碼。
- 模塊化:將復雜程序分解為小函數,便于調試和維護。
- 作用域控制:函數內的變量是局部的,不會影響全局環境。
在MATLAB中,函數分為兩種主要類型:腳本函數(保存在.m文件中)和匿名函數(簡單、內聯定義)。我們先從基本語法開始。
2. 定義基本函數
自定義函數的語法以 function
關鍵字開頭,后跟輸出參數、函數名和輸入參數。基本結構如下:
function [output1, output2, ...] = functionName(input1, input2, ...)% 函數體:執行計算% ...
end
- 函數名:必須符合變量命名規則(以字母開頭,僅包含字母、數字或下劃線),且函數文件名必須與函數名一致(例如,函數
myFunction
必須保存在myFunction.m
文件中)。 - 輸入參數:在括號內列出,多個參數用逗號分隔。輸入可以是數值、向量或矩陣。
- 輸出參數:在方括號內列出,多個輸出用逗號分隔。如果只有一個輸出,方括號可省略。
- 函數體:包含實際計算代碼,以
end
結束(在較新版本中,end
可省略,但建議保留以提高可讀性)。
代碼示例 1:簡單函數(計算平方) 定義一個函數 square
,輸入一個數 $x$,輸出其平方值 $y = x^2$。
function y = square(x)% 計算輸入值的平方y = x^2; % 賦值給輸出參數
end
保存為 square.m
文件后,在命令行調用:
result = square(5); % 輸出:25
disp(result);
- 注意:函數內部變量(如
y
)是局部的,只在函數內有效。這避免了與全局變量沖突。
3. 輸入參數的處理
輸入參數是函數的核心,MATLAB 提供了靈活的方式來處理它們:
- 多個輸入:函數可以有多個輸入參數。
- 默認值:使用
nargin
(輸入參數個數)和條件語句設置默認值,使函數更健壯。 - 參數驗證:用
inputParser
或簡單檢查確保輸入有效。
代碼示例 2:帶默認值的函數(計算矩形面積) 定義一個函數 rectArea
,輸入長度 $l$ 和寬度 $w$,輸出面積 $A = l \times w$。如果只提供一個輸入,默認寬度為 1。
function area = rectArea(length, width)% 檢查輸入參數個數if nargin < 2width = 1; % 默認寬度為1end% 驗證輸入為正數if length <= 0 || width <= 0error('輸入必須為正數'); % 拋出錯誤endarea = length * width;
end
在命令行測試:
a1 = rectArea(3, 4); % 輸出:12
a2 = rectArea(5); % 輸出:5(使用默認寬度)
- 關鍵點:
nargin
返回實際傳入的輸入參數個數,error
用于錯誤處理。
4. 輸出參數的處理
輸出參數可以是單個值或多個值,MATLAB 支持靈活的輸出管理:
- 多個輸出:在方括號內列出多個輸出變量。
- 輸出個數控制:使用
nargout
(輸出參數個數)來優化計算,避免不必要的輸出。 - 返回值:輸出參數在函數體內賦值,調用時通過方括號接收。
代碼示例 3:多輸出函數(計算均值和方差) 定義一個函數 stats
,輸入一個向量,輸出均值 $\mu$ 和方差 $\sigma^2$。公式為: $$ \mu = \frac{1}{n} \sum_{i=1}^{n} x_i, \quad \sigma^2 = \frac{1}{n} \sum_{i=1}^{n} (x_i - \mu)^2 $$ 其中 $n$ 是元素個數。
function [meanVal, varVal] = stats(data)% 計算數據的均值和方差n = length(data);meanVal = sum(data) / n;% 使用 nargout 避免不必要計算if nargout > 1varVal = sum((data - meanVal).^2) / n;end
end
在命令行調用:
data = [1, 2, 3, 4];
[mu, sigma2] = stats(data); % 輸出:mu = 2.5, sigma2 = 1.25
justMean = stats(data); % 只獲取第一個輸出
- 注意:
nargout
幫助優化性能,只在需要時計算額外輸出。
5. 函數文件的管理
自定義函數通常保存在單獨的.m文件中,MATLAB 的路徑系統決定了函數可見性:
- 文件命名:函數文件名必須與函數名一致(如
myFunction.m
)。 - 保存位置:文件應保存在 MATLAB 路徑中(如當前工作目錄或添加到路徑的文件夾),否則調用時會報錯。
- 函數結構:一個.m文件可以包含多個函數,但只有第一個函數是主函數(可被外部調用),其他是局部函數(只在文件內可見)。
- 局部函數:在同一個文件中定義,用于輔助主函數,語法相同但無文件命名限制。
代碼示例 4:帶局部函數的文件(計算階乘) 創建一個文件 factorialCalc.m
,包含主函數和局部函數。
% 主函數:計算階乘
function result = factorialCalc(n)if n < 0error('輸入必須非負');endresult = computeFact(n); % 調用局部函數
end% 局部函數:遞歸計算階乘
function fact = computeFact(k)if k == 0fact = 1;elsefact = k * computeFact(k-1);end
end
調用方式:
f = factorialCalc(5); % 輸出:120
- 最佳實踐:使用局部函數分解復雜邏輯,提高代碼模塊化。
6. 匿名函數
匿名函數是簡單的內聯函數,無需.m文件,適合快速定義小型計算。語法為:
funcHandle = @(input1, input2, ...) expression;
- 特點:簡潔、易于傳遞,但功能有限(不能包含復雜邏輯或多行代碼)。
- 應用場景:作為參數傳遞給其他函數(如
fplot
或integral
)。
代碼示例 5:匿名函數示例 定義一個匿名函數計算平方和 $f(x,y) = x^2 + y^2$。
squareSum = @(x, y) x^2 + y^2;
result = squareSum(3, 4); % 輸出:25
在繪圖中的應用:
f = @(x) sin(x); % 定義正弦函數
fplot(f, [0, 2*pi]); % 繪制圖像
title('正弦函數圖');
- 注意:匿名函數不能訪問工作區變量,除非顯式傳遞。
7. 函數句柄
函數句柄是將函數作為變量傳遞的引用,支持自定義函數、內置函數或匿名函數。語法為:
handle = @functionName;
- 用途:允許函數作為參數(如優化或積分函數中),實現回調機制。
- 優勢:提高代碼靈活性和可擴展性。
代碼示例 6:函數句柄應用(數值積分) 使用 integral
函數計算定積分,傳入自定義函數的句柄。
% 定義自定義函數:計算 e^{-x^2}
function y = gaussian(x)y = exp(-x.^2);
end% 在命令行使用句柄
fHandle = @gaussian;
area = integral(fHandle, -1, 1); % 計算積分,輸出約 1.4936
disp(['積分結果:', num2str(area)]);
- 關鍵點:句柄使函數能動態調用,常用于算法庫。
8. 錯誤處理和輸入驗證
健壯的函數必須處理異常輸入,避免崩潰。MATLAB 提供多種機制:
- 錯誤拋出:用
error
函數中斷執行并顯示消息。 - 警告:用
warning
提示問題但不終止。 - 輸入驗證:使用
validateattributes
或條件檢查確保輸入類型和范圍。 - try-catch:捕獲并處理運行時錯誤。
代碼示例 7:帶錯誤處理的函數(除法函數) 定義一個函數 safeDivide
,輸入 $a$ 和 $b$,輸出 $a/b$,但檢查除數是否為零。
function result = safeDivide(a, b)% 驗證輸入為標量數值if ~isnumeric(a) || ~isnumeric(b)error('輸入必須為數值');endif b == 0error('除數不能為零');endresult = a / b;
end
使用 try-catch
處理錯誤:
tryout = safeDivide(10, 0);
catch ME % ME 是異常對象disp(['錯誤發生:', ME.message]);
end
- 最佳實踐:始終驗證輸入,使用
isnumeric
、isscalar
等函數檢查類型。
9. 作用域和變量管理
函數內的變量是局部的,與工作區隔離:
- 局部變量:只在函數內有效,函數結束后銷毀。
- 全局變量:用
global
關鍵字聲明,但應謹慎使用(易導致副作用)。 - 持久變量:用
persistent
聲明,在函數調用間保留值(類似靜態變量)。
代碼示例 8:持久變量示例(計數器函數) 定義一個函數 counter
,每次調用增加計數。
function count = counter()persistent n; % 持久變量if isempty(n)n = 0;endn = n + 1;count = n;
end
測試:
c1 = counter(); % 輸出:1
c2 = counter(); % 輸出:2
- 警告:全局變量(如
global var;
)可能導致不可預測行為,優先使用局部變量。
10. 文檔和最佳實踐
良好的文檔使函數易于使用和維護:
- Help 文本:在函數開頭添加注釋,用戶輸入
help functionName
可查看。 - 注釋規范:第一行是摘要,后續行描述輸入輸出。
- 命名約定:函數名用駝峰式(如
calculateArea
),變量名描述性強。 - 性能優化:避免在循環中重復計算,使用向量化操作。
代碼示例 9:完整文檔的函數(計算距離) 定義一個函數計算兩點間歐幾里得距離,公式為 $d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}$。
function dist = euclideanDistance(x1, y1, x2, y2)%EUCLIDEANDISTANCE 計算兩點間歐幾里得距離% 輸入:x1, y1 為點1坐標,x2, y2 為點2坐標% 輸出:dist 為距離值% 示例:d = euclideanDistance(0, 0, 3, 4); % 輸出:5dist = sqrt((x2 - x1)^2 + (y2 - y1)^2);
end
調用 help
:
help euclideanDistance
% 輸出:EUCLIDEANDISTANCE 計算兩點間歐幾里得距離 ...
11. 常見錯誤和調試
新手常犯錯誤包括:
- 文件命名錯誤:函數名與文件名不一致,導致 "未定義函數" 錯誤。
- 路徑問題:文件不在路徑中,使用
addpath
添加目錄。 - 作用域混淆:誤用全局變量,導致值被意外修改。
- 參數傳遞錯誤:輸入輸出數量不匹配。
- 調試技巧:使用
dbstop if error
設置斷點,或fprintf
打印中間值。
調試示例:在函數中添加診斷輸出。
function y = debugExample(x)fprintf('輸入值:%f\n', x); % 打印輸入y = x * 2;fprintf('輸出值:%f\n', y); % 打印輸出
end
12. 總結和練習建議
自定義函數是 MATLAB 編程的基石,掌握它能讓你的代碼更高效、可維護。關鍵點回顧:
- 定義函數用
function
語法,注意文件命名。 - 靈活處理輸入輸出,使用
nargin
和nargout
。 - 優先使用局部變量,避免全局變量。
- 添加文檔和錯誤處理,提升健壯性。
- 匿名函數和句柄適合簡單或回調場景。
練習建議:
- 創建一個函數計算 BMI 指數(輸入體重和身高)。
- 編寫一個多輸出函數,返回向量的最大值、最小值和平均值。
- 使用匿名函數繪制 $f(x) = \cos(x) + \sin(x)$ 的圖像。
- 調試一個函數,處理輸入無效的情況。