MATLAB 函數(shù)(二)


概述

盡可能趁有空更一次的 MATLAB 筆記丸边。

這次內(nèi)容講講 MATALB 中的函數(shù)的高級部分塘辅。

  • MATLAB 函數(shù)的原理:使用函數(shù)的好處在于簡化了代碼同時增加了代碼的可讀性嚣艇。但是在使用函數(shù)的時候可能會有一些有偏差的理解讽坏,因此需要從機(jī)器的尺度上取解釋 MATLAB 函數(shù)的原理目木。
  • MATLAB 可選參數(shù):同一個可能要求不同的使用方法溃列,如果逐一編寫單獨的函數(shù)實現(xiàn)不僅浪費(fèi)而且難以使用劲厌,因此調(diào)用函數(shù)的使用要能夠自適應(yīng)不同的輸入?yún)?shù)和輸出參數(shù)。
  • MATLAB 函數(shù)的其他類型:MATLAB 官方定義 MATLAB 函數(shù)有四種其他類型:匿名函數(shù)听隐、局部函數(shù)补鼻、嵌套函數(shù)和私有函數(shù)。(私以為前兩種可能更常用)

MATLAB 函數(shù)的原理

對于某一個 MATLAB 函數(shù)而言,它就像一個黑盒子(Black Box)风范,用戶只需要知道函數(shù)的用途而不必知道函數(shù)內(nèi)部是怎么實現(xiàn)的咨跌。在主程序調(diào)用函數(shù)時,計算機(jī)開辟另一塊內(nèi)存空間硼婿,進(jìn)入函數(shù)內(nèi)部锌半,運(yùn)行函數(shù)命令,函數(shù)運(yùn)行結(jié)束后寇漫,系統(tǒng)自動將這塊內(nèi)存空間回收刊殉,除了輸出參數(shù)以外的所有函數(shù)內(nèi)容都不再存在。

請務(wù)必記得:在函數(shù)內(nèi)部做的一切不會對外部造成任何影響猪腕。

以下方這個函數(shù)為例

function add_1(x)
    x = x + 1;
    disp(['In function: x = ' num2str(x)]);
end

運(yùn)行如下命令

x = 1;
add_1(x); % 在函數(shù)內(nèi)部冗澈,x 的值被修改了
disp(['In main: x = ' num2str(x)]); % 主程序的 x 并沒有被修改

結(jié)果得到

In function: x = 2
In main: x = 1

這又是什么情況呢?事實上陋葡,兩個 x 是不同的值(函數(shù)并不執(zhí)行“手遞手式”地傳遞參數(shù)亚亲,而是將原來的變量拷貝一份放進(jìn)函數(shù)的內(nèi)存空間中),因此修改了函數(shù)內(nèi)部的 x 后腐缤,在函數(shù)結(jié)束時就被回收捌归,而外部的 x 并沒有受到任何影響。

你可以將主程序的 x 替換成 a 岭粤,并在函數(shù)內(nèi)部的“x = x + 1;”添加斷點(只需單擊每一行最左側(cè)行號后的區(qū)域惜索,即顯示一個紅色的斷點;再次單擊可以取消斷點)剃浇。運(yùn)行時巾兆,會在函數(shù)內(nèi)部暫停,觀察 Workspace 可以發(fā)現(xiàn)函數(shù)內(nèi)部的 x = 1虎囚。點擊工具欄中的 Continue 則可以繼續(xù)運(yùn)行看到主程序仍然是 a = 1角塑。

a = 1;
add_1(a); % 在函數(shù)內(nèi)部,x 的值被修改了
disp(['In main: a = ' num2str(a)]); % 主程序的 a 并沒有被修改

由此可見淘讥,函數(shù)內(nèi)部的變量在主程序中是“看不見”圃伶,函數(shù)內(nèi)部無法使用主程序中的變量,同樣地蒲列,主程序也無法使用函數(shù)內(nèi)部的變量窒朋。因此,函數(shù)與主程序的“交流”就依賴于輸入?yún)?shù)和輸出參數(shù)蝗岖。

將函數(shù)需要使用的變量傳入侥猩,將函數(shù)計算所得結(jié)果傳出。

MATLAB 可選參數(shù)

MATLAB 中的許多函數(shù)都有著各種靈活的輸入方式抵赢,可以支持不同數(shù)量的輸入?yún)?shù)和輸出參數(shù)欺劳,比如常用的 zeros 函數(shù)就可以根據(jù)不同數(shù)量的輸入?yún)?shù)創(chuàng)建不同維度的零矩陣洛退。這種靈活性就基于 MATLAB 函數(shù)中的可選參數(shù)。

MATLAB 提供的可選參數(shù)有如下:

  • nargin 函數(shù)輸入?yún)?shù)數(shù)目
  • nargout 函數(shù)輸出參數(shù)數(shù)目
  • varargin 可變長度輸入?yún)?shù)列表
  • varargout 可變長度的輸出參數(shù)列表
  • narginchk 驗證輸入?yún)?shù)數(shù)目
  • nargoutchk 驗證輸出參數(shù)數(shù)目
  • validateattributes 檢查數(shù)組的有效性
  • validatestring 檢查文本的有效性
  • inputParser 函數(shù)的輸入解析器
  • inputname 函數(shù)輸入的變量名稱
  • mfilename 當(dāng)前正在運(yùn)行的代碼的文件名

樣例一:對于不同輸入?yún)?shù)執(zhí)行不同操作

有時候?qū)τ谝粋€函數(shù)希望有多種的調(diào)用方式時杰标,使用可選參數(shù) nargin。同理對于不同的輸出參數(shù)采用不同的調(diào)用方式時彩匕,使用可選參數(shù) nargout腔剂。

function report_name_id(name,id)
    switch nargin % 在函數(shù)中 nargin 就是調(diào)用函數(shù)時輸入?yún)?shù)的數(shù)量
        case 2
            disp(['name: ' name ' id:' num2str(id)]); 
            % 兩個輸入?yún)?shù)時輸出名字和 id
        case 1
            disp(['name: ' name ' without id information.']);
            % 僅輸入一個參數(shù)名字(就是第一個參數(shù))時輸出名字和 無 id 信息
        otherwise
            disp('null');
            % 不給輸入?yún)?shù)時,輸出 null驼仪。
    end
end

執(zhí)行以下命令

report_name_id('Tom',153412); % 兩個輸入?yún)?shù)時輸出名字和 id
report_name_id('Tom'); % 輸出名字和 無 id 信息
report_name_id(); % 輸出 null

樣例二:對于未知數(shù)量參數(shù)執(zhí)行不同操作

有時候調(diào)用函數(shù)甚至不知道有多少個輸入?yún)?shù)時掸犬,又該如何處置呢?這時就可以使用 varargin 來接收任意個輸入?yún)?shù)绪爸,通過 varargin{index)}來訪問對應(yīng)的輸入?yún)?shù)湾碎。

function information_items(name,varargin)
    disp(name);
    for index = 1:nargin-1
        disp(varargin{index});
    end
end

三種調(diào)用方式會導(dǎo)致不同的結(jié)果,可以看到 varargin 都可以將多余的任意數(shù)量個參數(shù)都取得奠货,并且可以通過 varargin{index}來訪問介褥。(事實上,varargin 是一個 cell 型變量)

information_items('Tom','height:180','weight:72kg','age:17');
information_items('Jack','height:169','weight:74kg');
information_items('Bill','height:171','weight:88kg','age:23','shcool:Stanford');

同理递惋,也可以對應(yīng)地向 varargout{index} 賦值柔滔,將任意數(shù)量個輸出參數(shù)傳出。

樣例三:驗證輸入?yún)?shù)數(shù)目

narginchk 是基于給定的輸入?yún)?shù)上下限來驗證輸入?yún)?shù)是否符合要求的命令萍虽。

function two_or_three_inputs(varargin)
    narginchk(2,3);
    disp('There are two or three inputs');
end

同樣使用三種調(diào)用方式

two_or_three_inputs(1); % 報錯 error睛廊,輸入?yún)?shù)不夠
two_or_three_inputs(1,1);
two_or_three_inputs(1,1,1,1); % 報錯 error,輸入?yún)?shù)過多

同理也可以使用 nargoutchk 對輸出參數(shù)驗證杉编,此外超全,不妨嘗試自己使用 error 函數(shù)給出合適的調(diào)用函數(shù)提示信息。

樣例四:函數(shù)輸入的變量名稱

你可能會想函數(shù)輸入的變量名稱肯定是已知的邓馒,為什么還要特地設(shè)計這樣一個函數(shù)呢嘶朱?這個函數(shù)是有一定作用的。

function y = data_to_string(varargin)
    y = [];
    for index = 1:nargin
        y = [y inputname(index) ':' varargin{index} ';'];
    end
end

這個函數(shù)可以將數(shù)據(jù)根據(jù)對應(yīng)的變量類型串成一個數(shù)據(jù)包绒净。

name = 'Tom';
age = '18';
height = '180cm';
weight = '70kg';
str = data_to_string(name,age,height,weight);

MATLAB 函數(shù)其他類型

MATLAB 官方確定的其他類型的函數(shù)包括四種:

  • 匿名函數(shù)
  • 局部函數(shù)
  • 嵌套函數(shù)
  • 私有函數(shù)

匿名函數(shù)

匿名函數(shù)是僅包含一句 MATLAB 命令的函數(shù)见咒。匿名函數(shù)的優(yōu)點在于無需另外創(chuàng)建保存一個 m 文件,甚至可以在腳本文件和命令行中隨時定義隨時使用挂疆。形如下式的命令可以創(chuàng)建一個匿名函數(shù):

fun = @(x,y)x.^2+y.^2-2*x*y+4;

其中 fun 是函數(shù)句柄改览,@ 運(yùn)算符則用于創(chuàng)建一個句柄。

局部函數(shù)

局部函數(shù)也叫做子函數(shù)缤言,相當(dāng)于某個完整函數(shù)的附屬函數(shù)宝当。局部函數(shù)編寫于某個函數(shù)最后一行之后,是該函數(shù)的附屬函數(shù)胆萧。這意味著局部函數(shù)使用范圍有限:僅能被同一個文件中的其他函數(shù)調(diào)用庆揩,對其他函數(shù)和命令行不可見俐东。

function [avg, med] = mystats(x)
% 主函數(shù) 可以被外部檢索調(diào)用
n = length(x);
avg = mymean(x,n);
med = mymedian(x,n);
end

function a = mymean(v,n)
% 子函數(shù) 1 
% 只能被主函數(shù)和其他子函數(shù)調(diào)用
a = sum(v)/n;
end

function m = mymedian(v,n)
% 子函數(shù) 2
% 只能被主函數(shù)和其他子函數(shù)調(diào)用
w = sort(v);
if rem(n,2) == 1
    m = w((n + 1)/2);
else
    m = (w(n/2) + w(n/2 + 1))/2;
end
end

特別地,如果你習(xí)慣省略函數(shù)體結(jié)尾的 end订晌,在同一個文件中應(yīng)當(dāng)保證子函數(shù)和主函數(shù)使用同一種格式虏辫。

嵌套函數(shù)

嵌套函數(shù)是定義在函數(shù)中的函數(shù),外層函數(shù)可以調(diào)用內(nèi)層函數(shù)并且如果內(nèi)層函數(shù)變量在外層函數(shù)中有定義锈拨,那么嵌套函數(shù)可以訪問和修改在其父函數(shù)中定義的變量砌庄。

function main1
x = 5;
nestfun1

   function nestfun1 
     x = x + 1;
   end 

end

私有函數(shù)

假設(shè)當(dāng)前工作路徑為 “/xxx”,在文件夾 xxx 創(chuàng)建一個名為“private”子文件夾奕枢,可以指定一個函數(shù)為私有函數(shù)娄昆。這樣一來,只有文件夾 xxx下的函數(shù)可以調(diào)用這個私有函數(shù)缝彬。

小結(jié)

到此函數(shù)的內(nèi)容也告一段落萌焰,本文除了 MATLAB 函數(shù)的內(nèi)容外,還有一個額外的點就是斷點調(diào)試(快速地中斷和保留中斷時的變量谷浅,能夠讓你加快調(diào)試的步驟)扒俯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市壳贪,隨后出現(xiàn)的幾起案子陵珍,更是在濱河造成了極大的恐慌,老刑警劉巖违施,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件互纯,死亡現(xiàn)場離奇詭異,居然都是意外死亡磕蒲,警方通過查閱死者的電腦和手機(jī)留潦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辣往,“玉大人兔院,你說我怎么就攤上這事≌鞠鳎” “怎么了坊萝?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長许起。 經(jīng)常有香客問我十偶,道長,這世上最難降的妖魔是什么园细? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任惦积,我火速辦了婚禮,結(jié)果婚禮上猛频,老公的妹妹穿的比我還像新娘狮崩。我一直安慰自己蛛勉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布睦柴。 她就那樣靜靜地躺著诽凌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坦敌。 梳的紋絲不亂的頭發(fā)上皿淋,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音恬试,去河邊找鬼。 笑死疯暑,一個胖子當(dāng)著我的面吹牛训柴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妇拯,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼幻馁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了越锈?” 一聲冷哼從身側(cè)響起仗嗦,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甘凭,沒想到半個月后稀拐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡丹弱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年德撬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躲胳。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜓洪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坯苹,到底是詐尸還是另有隱情隆檀,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布粹湃,位于F島的核電站恐仑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏再芋。R本人自食惡果不足惜菊霜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望济赎。 院中可真熱鬧鉴逞,春花似錦记某、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勾徽,卻和暖如春滑凉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喘帚。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工畅姊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吹由。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓若未,卻偏偏與公主長得像,于是被迫代替她去往敵國和親倾鲫。 傳聞我的和親對象是個殘疾皇子粗合,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容