版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
流程控制1選擇結(jié)構(gòu)如前所述,當人們判斷某一條件是否滿足,根據(jù)判斷的結(jié)果來選擇不同的解決問題的方法時,就需要使用選擇結(jié)構(gòu)。和C語言類似,MATLAB的條件判斷可以使用if語句或者switch語句。
1.1if語句if語句的基本語法結(jié)構(gòu)有三種,分別如下:(1)if(關系運算表達式) MATLAB語句end
這種形式的選擇結(jié)構(gòu)表示,當關系運算表達式計算的結(jié)果為邏輯真的時候,執(zhí)行MATLAB語句,這里的MATLAB語句可以是一個MATLAB表達式,也可以是多個MATLAB表達式。在MATLAB語句的結(jié)尾處,必須有關鍵字end。
(2)if(關系運算表達式) MATLAB語句Aelse MATLAB語句Bend
這種選擇結(jié)構(gòu)表示,當關系運算表達式的計算結(jié)果為邏輯真的時候,執(zhí)行MATLAB語句A,否則執(zhí)行MATLAB語句B,在語句B的結(jié)尾必須具有關鍵字end。(3)if(關系運算表達式a) MATLAB語句A
elseif(關系運算表達式b) MATLAB語句Belse(關系運算表達式c)
end
這種選擇結(jié)構(gòu)可以判斷多條關系運算表達式的計算結(jié)果,然后按照執(zhí)行的邏輯關系執(zhí)行相應的語句。根據(jù)類似的C語言知識或者前面兩種選擇結(jié)構(gòu)的介紹判斷這種結(jié)構(gòu)的執(zhí)行方式?!璱f(關系表達式a) if(關系表達式b)MATLAB語句A elseMATLAB語句B endelse if(關系表達式c)MATLAB語句C elseMATLAB語句D endend注意:在使用嵌套的選擇結(jié)構(gòu)時,需要小心if語句和end關鍵字的配對。和C語言類似,if-elseif-else的語句結(jié)構(gòu)也可以嵌套地使用,也就是可以存在這樣的語句結(jié)構(gòu):1.2switch語句另外一種構(gòu)成選擇結(jié)構(gòu)的關鍵字就是switch。在處理實際問題的時候,往往要處理多個分支,這時如果使用if-else語句處理多分支結(jié)構(gòu)往往使程序變得十分冗長,從而降低了程序的可讀性。switch語句就可以用于處理這種多分支的選擇,它的基本語法結(jié)構(gòu)如下:switch(表達式) case常量表達式a:MATLAB語句A case常量表達式b:MATLAB語句B
case常量表達式m:MATLAB語句M otherwise:MATLAB語句Nend…在switch語句之后的表達式可以是一個數(shù)值類型表達式或者是一個數(shù)值類型的變量,當這個表達式的值同case后面的某一個常量表達式相等時,則執(zhí)行該case后面的常量表達式后面的語句。注意:
MATLAB的switch和C語言的switch語句結(jié)構(gòu)不同。在C語言中,每一個case后面的語句中必須包含類似break語句的流程控制語句,否則程序會依次執(zhí)行符合條件的case語句后面的每一個case分支。但是在MATLAB中就不必如此,程序僅僅執(zhí)行符合條件的case分支。補充例題3中需要用戶在執(zhí)行程序的過程中輸入一個字符串,switch語句根據(jù)用戶的輸入判斷執(zhí)行相應的case分支。若沒有符合條件的case分支,則switch執(zhí)行otherwise后面的語句。若switch結(jié)構(gòu)中沒有定義otherwise及其相應的代碼,則程序不會進行任何操作,而是直接退出switch結(jié)構(gòu)。提示:在處理以字符串變量或者常量參與的關系判斷操作時,使用switch結(jié)構(gòu)要比if-else結(jié)構(gòu)效率高一些。由于MATLAB的switch結(jié)構(gòu)沒有C語言的fall-through特性,所以,如果需要針對多個條件而使用同一個case分支的時候,需要使用元胞數(shù)組與之配合。例子
4switch結(jié)構(gòu)使用示例——switch_examp2.m。001 clearall002003 var=input('InputaNumer:');004 switchvar005 case1006 disp('1')007 case{2,3,4}008 disp('2or3or4')009 case5010 disp('5')011 otherwise012 disp('somethingelse')013 end例子4運行的方法和效果如下:>>switch_examp2InputaNumer:11>>switch_examp2InputaNumer:32or3or4>>switch_examp2InputaNumer:7somethingelse例子4代碼的核心部分為007行,這里使用元胞數(shù)組增加判斷條件的個數(shù),當輸入的數(shù)字為2、3或者4時,switch結(jié)構(gòu)將使用同一個case分支進行判斷、計算。注意:從代碼的完整性和可靠性角度出發(fā),在使用switch語句時,一定要包含otherwise分支,這是一種良好的編程習慣。2循環(huán)結(jié)構(gòu)在解決很多問題的時候需要使用循環(huán)結(jié)構(gòu),例如求解數(shù)列的和或者進行某種迭代法求解數(shù)值方程時,都需要循環(huán)結(jié)構(gòu)配合完成計算。在MATLAB中,包含兩種循環(huán)結(jié)構(gòu),一種是循環(huán)次數(shù)不確定的while循環(huán),而另一種是循環(huán)次數(shù)確定的for循環(huán)。
1.while循環(huán)結(jié)構(gòu)while語句可以用來實現(xiàn)“當”型的循環(huán)結(jié)構(gòu),它的一般形式如下:while(表達式)MATLAB語句end
當表達式為真時,循環(huán)將執(zhí)行由語句構(gòu)成的循環(huán)體,其特點是先判斷循環(huán)條件,如果循環(huán)條件成立,即表達式運算結(jié)果為“真”,再執(zhí)行循環(huán)體。循環(huán)體執(zhí)行的語句可以是一句也可以是多句,在MATLAB語句之后必須使用關鍵字end作為整個循環(huán)結(jié)構(gòu)的結(jié)束。另外,在循環(huán)過程中一定要能夠改變關系表達式或者布爾類型變量的值,或者使用其他方法來跳出循環(huán),否則會陷入死循環(huán)(無法正常退出的循環(huán)叫作死循環(huán))。例子5
使用while語句求解 。001 i=1;002 sum=0;003 while(i<=1000)004 sum=sum+i;005 i=i+1;006 end007 str=['計算結(jié)果為:',num2str(sum)];008 disp(str)例子5的運行結(jié)果為
>>while_example
計算結(jié)果為:500500
例子5的使用了while循環(huán)結(jié)構(gòu),在循環(huán)結(jié)構(gòu)中進行了累加的操作。需要注意的是,在MATLAB中沒有類似C語言的++或者+=等運算操作符,因此在進行諸如累加或者遞減的運算時,不得不給出完整的表達式。另外,例子5求數(shù)列和的算法的運算效率很低,在MATLAB中不要使用這樣的結(jié)構(gòu)完成類似的運算,而需要采用向量化的計算。注意:
while循環(huán)結(jié)構(gòu)的關系表達式可以是某個數(shù)據(jù)變量或者常量,這時,將按照非零值為邏輯真進行相應的操作。另外,在進行上述操作時,若數(shù)據(jù)變量為空矩陣,則while語句將空矩陣作為邏輯假處理,也就是說,在whileAMATLAB語句S1end結(jié)構(gòu)中,若A為空矩陣,則MATLAB語句S1永遠不會被執(zhí)行。
2.for循環(huán)結(jié)構(gòu)使用for語句構(gòu)成循環(huán)是最靈活、簡便的方法,不過,使用for語句循環(huán)需要預先知道循環(huán)體執(zhí)行的次數(shù),所以這種循環(huán)一般叫作確定循環(huán)。在MATLAB中for循環(huán)的基本結(jié)構(gòu)如下:forindex=start:increment:end MATLAB語句end其中,index的取值取決于start和end的值,一般地,這里通常使用等差的數(shù)列向量,參見例子6。例子6
使用for語句求解 。001 sum=0;002 fori=1:1000003 sum=sum+i;004 end 005 str=['計算結(jié)果為:',num2str(sum)];006 disp(str)例子6運行的結(jié)果為>>for_example計算結(jié)果為:500500
在例子6中,使用了確定次數(shù)的for循環(huán)結(jié)構(gòu),循環(huán)次數(shù)使用行向量進行控制,而且索引值i按照默認的數(shù)值1進行遞增。在for循環(huán)語句中,不僅可以使用行向量進行循環(huán)迭代的處理,也可以使用矩陣作為循環(huán)次數(shù)的控制變量,這時循環(huán)的索引值將直接使用矩陣的每一列,循環(huán)的次數(shù)為矩陣的列數(shù),參見例子7。例子7for循環(huán)示例。001 A=rand(3,4);002003 fori=A004 sum=mean(i)005 end例子7運行的結(jié)果為>>for_matricessum=0.2728sum=0.6649sum=0.4275sum=0.5220例子7盡管只有短短的幾行,但是使用了一個矩陣作為循環(huán)的索引值,于是,循環(huán)結(jié)果就分別計算矩陣的每一列元素的均值。和其他高級語言類似,MATLAB的循環(huán)結(jié)構(gòu)也可以進行嵌套使用,使用嵌套的循環(huán)需要注意for關鍵字和end關鍵字之間的配對使用,根據(jù)高級語言的一般特性來推斷其運行的方式。3break語句和continue語句在循環(huán)結(jié)構(gòu)中還有兩條語句會影響程序的流程,這就是break語句和continue語句,這兩條語句的基本功能如下:●當break語句使用在循環(huán)體中的時候,其作用是能夠在執(zhí)行循環(huán)體的時候強迫終止循環(huán),即控制程序的流程,使其提前退出循環(huán),它的使用方法是
break;●continue語句出現(xiàn)在循環(huán)體中的時候,其作用是能夠中斷本次的循環(huán)體運行,將程序的流程跳轉(zhuǎn)到判斷循環(huán)條件的語句處,繼續(xù)下一次的循環(huán),它的使用方法是
continue;例子8break語句示例——break_example.m。001 i=0;002 j=0;003 k=0;004 fori=1:2005 forj=1:2006 fork=1:2007 if(k==2)008 disp('退出循環(huán)');009 break;010 end011 str=sprintf('I=%d,J=%d,K=%d',i,j,k);012 disp(str);013 end014 end015 end016 disp('程序運行結(jié)束');例子8的運行結(jié)果如下:>>break_exampleI=1,J=1,K=1退出循環(huán)I=1,J=2,K=1退出循環(huán)I=2,J=1,K=1退出循環(huán)I=2,J=2,K=1退出循環(huán)程序運行結(jié)束
break語句的作用是退出當前的循環(huán)結(jié)構(gòu)運行,所以在例子8中,位于最內(nèi)層循環(huán)的break語句執(zhí)行的結(jié)果是退出了最內(nèi)層的循環(huán)k,位于外層的循環(huán)i和j還是都運行完畢了。例子9continue語句示例。001 i=0;002 fori=1:6003 if(i>3)004 continue005 else006 str=sprintf('I=%d',i);007 disp(str);008 end009 end010 str=sprintf('循環(huán)結(jié)束I=%d',i);011 disp(str);例子9的運行結(jié)果如下:>>continue_exampleI=1I=2I=3循環(huán)結(jié)束I=6continue語句的作用在例子9中得到了充分說明,該語句終止當前的循環(huán),然后繼續(xù)下一次循環(huán)運算,直到所有的循環(huán)迭代運算結(jié)束為止。4提高運算性能
M語言和其他的高級語言不同,由于采用了解釋型語言,所以M語言的執(zhí)行效率肯定低于編譯型語言(例如C語言)。然而,隨著MATLAB版本的不斷升級,再加之合理利用MATLAB向量運算等特點可以較大幅度地提高M語言代碼的執(zhí)行效率。在本小節(jié)結(jié)合一些具體的例子來講述M語言編程以及MATLAB軟件本身在提高程序執(zhí)行效率方面的一些特性。
1.向量化運算首先,希望讀者牢記這樣一點,MATLAB最初的目的是提供便利的矩陣數(shù)據(jù)操作能力。所以在大多數(shù)的應用程序中,不要使用循環(huán)結(jié)構(gòu)操作矩陣的元素,應直接使用矩陣元素的索引或者矩陣運算的函數(shù),這樣做不僅能夠提高代碼的執(zhí)行效率,而且還能夠提高程序的可讀性,這就是所謂的向量化的運算,也就是說,盡量將使用while循環(huán)或者for循環(huán)的語句結(jié)構(gòu)轉(zhuǎn)換成等價的向量或者矩陣運算,以提高程序的運算速度,參見例子10。例子10
向量化運算——array_vs_loops.m。001 Mass=rand(5,10000);002 Length=rand(5,10000);003 Width=rand(5,10000);004 Height=rand(5,10000);005 006 [rows,cols]=size(Mass);007 008 disp([char(10),'使用數(shù)組運算:'])009 tic010 Density=Mass./(Length.*Width.*Height);011 toc
012013 disp([char(10),'使用循環(huán)結(jié)構(gòu):'])014 tic;015 forI=1:rows016 forJ=1:cols017 Density(I)=Mass(I,J)/(Length(I,J)*Width(I,J)*Height(I,J));018 end019 end020 toc
例子10比較了循環(huán)結(jié)構(gòu)和數(shù)組運算的執(zhí)行效率,程序中分別在010行使用數(shù)組運算和在015~019行使用循環(huán)結(jié)構(gòu)完成了同樣的工作。程序的運行結(jié)果如下:>>array_vs_loops使用數(shù)組運算:elapsed_time=*使用循環(huán)結(jié)構(gòu):elapsed_time=*
2.預分配存儲空間另外一種能夠提高運算效率的方法就是進行內(nèi)存變量存儲空間的預分配,首先察看例子11。例子11內(nèi)存預分配的例子——pre_allocate.m。001 disp([char(10),'使用內(nèi)存預分配:'])002 pre_allo=zeros(10000,1);003 tic;004 forI=1:10000005 pre_allo(I)=rand(1);006 end007 toc008 009 disp([char(10),'不使用內(nèi)存預分配:'])010 tic;011 forJ=1:10000012 not_pre_allo(J)=rand(1);013 end014 toc
例子11的執(zhí)行結(jié)果如下:
>>pre_allocate使用內(nèi)存預分配:elapsed_time=*不使用內(nèi)存預分配:elapsed_time=*上面兩種不同的運算惟一的區(qū)別就是程序002行,執(zhí)行這行語句之后,MATLAB自動分配了10000個連續(xù)的內(nèi)存空間用于存儲數(shù)據(jù),MATLAB將一次創(chuàng)建足夠的存儲空間,然后依次賦值。而后者not_pre_alloc變量沒有進行相應的操作,所以帶來了兩次運算結(jié)果的不同。在不使用內(nèi)存預分配的運算中,MATLAB是如何進行操作的呢?當I=1時,MATLAB將使用一小塊長度為一個單元大小的內(nèi)存保存一位隨機數(shù)。當I=2時,MATLAB尋找一塊兩單元大小的內(nèi)存區(qū),一個單元放第一個隨機數(shù),第二個放另外一個隨機數(shù)?!擨=10000時,MATLAB尋找一塊容納10000單元的內(nèi)存區(qū)存放以前的9999個隨機數(shù),同時把最新的一個隨機數(shù)加入進去。代碼運行的結(jié)果造成了存儲空間的浪費,降低了程序的執(zhí)行速度。所以,在編寫M語言程序的時候需要盡量使用內(nèi)存的預分配,而少使用或者不使用數(shù)組內(nèi)存空間的自動擴充方式。MATLAB針對不同的數(shù)據(jù)類型有不同的內(nèi)存預分配函數(shù),見表1。表1內(nèi)存預分配函數(shù)表1中說明了不同數(shù)據(jù)類型所要使用的內(nèi)存預分配函數(shù),其中結(jié)構(gòu)類型的數(shù)組需要兩個函數(shù)配合使用,利用struct函數(shù)構(gòu)造結(jié)構(gòu),而使用repmat函數(shù)創(chuàng)建數(shù)組。對于非雙精度類型的數(shù)據(jù),例如整數(shù)類型或者單精度類型,進行內(nèi)存的預分配時,需要使用相應的構(gòu)造函數(shù)或者類型轉(zhuǎn)換函數(shù),例如:
Y=int16(zeros(1:10000));
在上面的表達式中創(chuàng)建了連續(xù)的10000個16位整數(shù)的存儲空間。當預先分配的內(nèi)存空間無法容納數(shù)據(jù)時,則可以通過repmat函數(shù)來擴充數(shù)組的存儲空間。
3.MATLAB加速器盡管利用了上述的特性可以明顯提高M語言的運行效率,但是在同等條件下,M語言的效率還是無法和第四代高級編程語言的執(zhí)行效率相媲美,于是,在MATLAB6.5版本中,新增加了MATLAB性能加速器這樣一個新特性。MATLAB性能加速器能夠明顯改善循環(huán)結(jié)構(gòu)、內(nèi)建函數(shù)調(diào)用等方面的運行效率,特別是在處理循環(huán)迭代次數(shù)確定的for循環(huán)結(jié)構(gòu)中,其運算速度較早期的MATLAB版本有很大的提高,在表2中總結(jié)了MATLAB加速器能夠發(fā)揮作用的M語言元素。表2加速器能夠影響的M語言元素表3性能加速器不起作用的M語言元素3腳本文件腳本文件是最簡單的一種M語言文件,在本章前面章節(jié)的例子中都使用了腳本文件。所謂腳本文件,就是由一系列的MATLAB指令和命令組成的純文本格式的M文件,執(zhí)行腳本文件時,文件中的指令或者命令按照出現(xiàn)在腳本文件中的順序依次執(zhí)行。腳本文件沒有輸入?yún)?shù),也沒有輸出參數(shù),執(zhí)行起來就像早期的DOS操作系統(tǒng)的批處理文件一樣,而腳本文件處理的數(shù)據(jù)或者變量必須在MATLAB的公共工作空間中。例子12
腳本文件示例。001 %注釋行002 %M腳本文件示例003 %"flowerpetal"004 %以下為代碼行005 %計算006 theta=-pi:0.01:pi;007 rho(1,:)=2*sin(5*theta).^2;008 rho(2,:)=cos(10*theta).^3;009 rho(3,:)=sin(theta).^2;010 rho(4,:)=5*cos(3.5*theta).^3;011 fork=1:4012 %圖形輸出013 subplot(2,2,k)014 polar(theta,rho(k,:))015 end016 disp('程序運行結(jié)束!')在MATLAB命令行中運行該腳本文件:>>script_example程序運行結(jié)束!圖2例子12腳本文件的運行結(jié)果仔細察看例子12的腳本文件,在腳本文件中,主要由注釋行和代碼行組成。M文件的注釋行需要使用%定義符,在%之后的所有文本都認為是注釋文本,不過,M文件的注釋定義符僅能影響一行代碼,類似于C++語言中的“//”。然而在M語言中,沒有類似C語言的注釋定義符“/*”和“*/”,所以無法一次定義多行注釋。給程序添加適當?shù)淖⑨屖橇己玫木幊塘晳T,希望讀者能夠在日常編程中多多使用。腳本文件中的代碼行都是一些簡單的MATLAB指令或者命令,這些命令可以用來完成相應的計算處理數(shù)據(jù)、繪制圖形結(jié)果的操作,也可以在腳本文件中調(diào)用其他的函數(shù)完成復雜的數(shù)學運算,在例子12中就完成了這些工作。另外,在MATLAB中還有一些指令用來處理程序和用戶之間的交互,在表4-4中進行了總結(jié)。表4腳本文件中常用的MATLAB指令
MATLAB一般使用腳本文件作為某種批處理文件,其中,有兩個批處理文件經(jīng)常被MATLAB自動調(diào)用,這兩個腳本文件分別為startup.m和finish.m。
startup.m文件在MATLAB啟動時自動被執(zhí)行,用戶可以自己創(chuàng)建并定義編寫該文件,例如在文件中添加物理常量的定義、系統(tǒng)變量的設置或者MATLAB搜索路徑的設置。當用戶安裝MATLAB之后,在<MATLABROOT>\toolbox\local路徑下有一個M文件,名為Starupsav.m,該文件可以看作是startup.m文件的模板,可以修改該文件,然后將其以文件名startup.m的形式保存在<MATLABROOT>\toolbox\local路徑下。與startup.m文件相對應的是finish.m文件,該文件在MATLAB退出時自動執(zhí)行,用戶可以自己創(chuàng)建并定義編寫該文件,例如在文件中添加保存數(shù)據(jù)等指令,這樣可以將每次退出前的工作結(jié)果進行保留。同樣,在<MATLABROOT>\toolbox\local路徑下有兩個文件,分別為finishsav.m和finishdlg.m,這兩個文件可以用來作為finish.m文件的模板,相關的具體內(nèi)容介紹請讀者自己察看相應的文件和幫助文檔。4函數(shù)文件4.1基本結(jié)構(gòu)
M函數(shù)文件和腳本文件不同,函數(shù)文件不僅有自己特殊的文件格式,不同的函數(shù)還分別具有自己的工作空間。同其他高級語言類似,M函數(shù)文件也有局部變量和全局變量。讀者首先需要了解的是函數(shù)文件的基本結(jié)構(gòu),參見例子13。例子13
函數(shù)文件示例——average.m。001 functiony=average(x)002 %AVERAGE求向量元素的均值003 %語法:004 %Y=average(X)005 %其中,X是向量,Y為計算得到向量元素的均值006 %若輸入?yún)?shù)為非向量則出錯007 008 %代碼行009 [m,n]=size(x);010 %判斷輸入?yún)?shù)是否為向量011 if(~((m==1)|(n==1))|(m==1&n==1))012 %若輸入?yún)?shù)不是向量,則出錯013 error('Inputmustbeavector')014 end015 %計算向量元素的均值016 y=sum(x)/length(x);在MATLAB命令行中,鍵入下面的指令運行例子13的代碼:>>z=1:99;>>y=average(z)y=50M語言函數(shù)文件具有下面的不同部分:*函數(shù)定義行。*在線幫助。*注釋行。*M語言代碼。下面結(jié)合例子13分別說明這些部分的構(gòu)成。函數(shù)定義行,例子13的函數(shù)定義行為代碼的001行:
001 functiony=average(x)這一行代碼中包括關鍵字function、函數(shù)輸出參數(shù)y、函數(shù)的名稱average和函數(shù)的輸入?yún)?shù)x。需要讀者注意的是函數(shù)的名稱,函數(shù)的名稱定義要求必須以字符開頭,后面可以用字符、數(shù)字和下劃線的組合構(gòu)成函數(shù)名稱。MATLAB對函數(shù)名稱的長度有限定,讀者可以在自己的MATLAB中,通過執(zhí)行namelengthmax函數(shù)獲取相應的數(shù)值。假設該函數(shù)返回的數(shù)值為N,若函數(shù)的名稱長度超過了N,則MATLAB使用函數(shù)名稱的前N個字符作為函數(shù)名稱。一般推薦將函數(shù)名稱用小寫的英文字符表示,同時函數(shù)的M文件名稱最好和函數(shù)名稱保持一致,若文件名稱和函數(shù)名稱不一致,則調(diào)用函數(shù)的時候需要使用文件名稱而非函數(shù)名稱。
M函數(shù)文件的在線幫助為緊隨在函數(shù)定義行的注釋行。在例子13中,average函數(shù)的在線幫助為002~006行的注釋行。若在MATLAB命令行中鍵入下面的指令:
>>helpaverage在MATLAB的命令窗口中就會出現(xiàn):
AVERAGE求向量元素的均值語法:
Y=average(X)
其中,X是向量,Y為計算得到向量元素的均值 若輸入?yún)?shù)為非向量則出錯其中,在線幫助中比較重要而且特殊的是在線幫助的第一行,在MATLAB中將這行注釋稱為H1幫助行,它是在線幫助的第一行,若使用lookfor函數(shù)查詢函數(shù)時,僅查詢并顯示函數(shù)的H1幫助行,例如,在MATLAB命令行中鍵入下面的指令:
>>lookforaverage在MATLAB的命令窗口中就會出現(xiàn):AVERAGE求向量元素的均值MEANAverageormeanvalue.…由于H1幫助行的特殊作用,所以在用戶自己定義M函數(shù)文件時,一定要編寫相應的H1幫助行,對函數(shù)進行簡明、扼要的說明或者解釋。例子13的008、010、012、015行代碼分別是程序具體的注釋行,這些注釋行不會顯示在在線幫助中,主要原因就是這些注釋行沒有緊隨在H1幫助行的后面,其中008行的注釋與在線幫助之間有一個空行。其實從008行開始一直到文件的結(jié)尾都是M函數(shù)文件的代碼行,這些代碼行需要完成具體的算法,實現(xiàn)用戶的具體功能。代碼行就是用戶開發(fā)的算法M語言的實現(xiàn)。4.4.2輸入輸出參數(shù)
M語言函數(shù)文件的輸入、輸出參數(shù)和其他高級語言的輸入、輸出參數(shù)不同,在定義這些輸入、輸出參數(shù)的時候不需要指出變量的類型,因為MATLAB默認這些參數(shù)都使用雙精度類型,這樣可以簡化程序的編寫。而且在定義參數(shù)時,也沒有確定輸入?yún)?shù)的維數(shù)或者尺寸,也就是說,直接從參數(shù)上無法判斷輸入來的是標量、向量還是矩陣,只有通過程序內(nèi)部的具體代碼來加以判斷。
M語言的函數(shù)文件不僅可以有一個輸入?yún)?shù)和一個返回值,還可以為M語言函數(shù)文件定義多個輸入?yún)?shù)和多個輸出參數(shù),見例子14。例子14
多個輸入、輸出參數(shù)的M函數(shù)。001 function[avg,stdev,r]=ourstats(x,tol)002 %OURSTATS多輸入輸出參數(shù)示例003 %該函數(shù)計算處理矩陣,得到相應的均值、004 %標準差和矩陣的秩005 [m,n]=size(x);006 ifm==1007 m=n;008 end009 %Average010 avg=sum(x)/m;011% Sandaddeviation012 stdev=sqrt(sum(x.^2)/m-avg.^2);013 %Rank014 s=svd(x);015 r=sum(s>tol);運行例子4-15,在MATLAB命令行中,鍵入下面的指令:>>A=[123;456]A=123456>>[a,s,r]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000r=2>>ourstats(A,0.1)ans=2.50003.50004.5000>>[a,s]=ourstats(A,0.1)a=2.50003.50004.5000s=1.50001.50001.5000例子14的M代碼具有兩個輸入?yún)?shù)、三個輸出參數(shù),所以在使用該函數(shù)的時候,需要將必要的輸入、輸出參數(shù)寫明。注意調(diào)用該函數(shù)時的語法,將輸出參數(shù)依次寫在一個向量中,若輸出參數(shù)的個數(shù)與函數(shù)定義的輸出參數(shù)個數(shù)不一致,則在例子14中,將計算得到的前幾個輸出參數(shù)作為返回值,個數(shù)等于用戶指定的輸出參數(shù)個數(shù)。計算的結(jié)果依次賦值給不同的變量。在使用多個輸入、輸出參數(shù)的時候,往往需要判斷用戶寫明的輸入、輸出參數(shù)的個數(shù),若個數(shù)與函數(shù)定義不符合的時候,將給出錯誤或者警告信息,這個時候,需要使用函數(shù)nargin和nargout來獲取函數(shù)的輸入、輸出參數(shù)個數(shù),見例子15。例子15nargin和nargout示例。001 functionc=testarg(a,b)002 %TESTARG檢測輸入輸出參數(shù)個數(shù)003 %該函數(shù)根據(jù)不同的輸入輸出參數(shù)個004 %數(shù)進行相應的操作005 if(nargout~=1)006 disp('使用該函數(shù)必須指定一個輸出參數(shù)!');007 return008 end009 switchnargin010 case0011 disp('使用該函數(shù)至少需要一個輸入?yún)?shù)!');012 c=[];013 return014 case1015 c=a.^2;016 case2017 c=a+b;018 end運行例子4-16,在MATLAB命令行窗口中,鍵入下面的指令:>>A=[123];>>B=[235];>>testarg(A,B)使用該函數(shù)必須指定一個輸出參數(shù)!>>C=testarg使用該函數(shù)至少需要一個輸入?yún)?shù)!C=[]>>C=testarg(A)C=149>>C=testarg(A,B)C=358>>C=testarg(A,B,C)???Errorusing==>testargToomanyinputarguments.運行例子15的代碼時,使用不同的輸入、輸出參數(shù),函數(shù)本身和MATLAB系統(tǒng)將自動檢測參數(shù)的個數(shù),在最后一次調(diào)用時,由于使用的輸入?yún)?shù)個數(shù)超過了函數(shù)定義的個數(shù),所以MATLAB給出了錯誤信息。
MATLAB的M函數(shù)文件還可以具有個數(shù)不確定的輸入、輸出參數(shù),也就是說,在定義M函數(shù)文件的時候,不指明輸入、輸出參數(shù)的個數(shù),而是在程序中通過編寫程序完成具體參數(shù)的確定,完成該功能主要依靠varargin和varargout函數(shù)。當函數(shù)的定義具有以下形式的時候
functiony=function_name(varargin)函數(shù)function_name可以接受任意個數(shù)的輸入?yún)?shù);而當函數(shù)具有下面的形式時
functionvarargout=function_name(n)函數(shù)function_name可以輸出任意個數(shù)的輸出參數(shù)??梢詫arargin函數(shù)和varargout函數(shù)結(jié)合在同一個M文件函數(shù)中使用。例子16
不確定的輸入?yún)?shù)個數(shù)。001 functiony=varargin_example(varargin)002 %VARARGIN_EXAMPLE不確定輸入?yún)?shù)例子003 str=sprintf('輸入?yún)?shù)的個數(shù):=%d',length(varargin));004 disp(str);005 y=0;006 %varargin的類型007 class(varargin)008 fori=1:length(varargin)009 %varargin為元胞數(shù)組010 if(isnumeric(varargin{i}))011 %將每個為數(shù)值數(shù)組的輸入?yún)?shù)012 %的第一個元素累加求和013 y=y+varargin{i}(1);014 end015 end運行例子16,在MATLAB命令行中鍵入下面的指令:>>varargin_example輸入?yún)?shù)的個數(shù):=0ans=cellans=0>>varargin_example('a',[123],3,rand(2,5))輸入?yún)?shù)的個數(shù):=4ans=cellans=4.0153通過例子16的運行結(jié)果和例子的代碼可以看出varargin函數(shù)的使用方法。它相當于在MATLAB的函數(shù)入口處開辟了足夠大的空間,用于接受各種用戶的輸入。在使用這個函數(shù)的時候,需要在程序中判別函數(shù)輸入?yún)?shù)的類別,并且從元胞數(shù)組中正確提取變量,在MATLAB中將這一過程稱之為unpacking。與之相對應的,將函數(shù)的輸入?yún)?shù)傳遞給varargout函數(shù)被稱之為packing,在這一過程中,需要將所有必要的輸出參數(shù)傳遞給varargout元胞數(shù)組,在傳遞參數(shù)的時候,還需要注意參數(shù)的順序,在例子17中介紹了這一過程。例子17
不確定的輸出參數(shù)。001 functionvarargout=varargout_example(varargin)002 %VARARGOUT_EXAMPLE不確定個數(shù)的輸出參數(shù)003 004 %判斷輸出參數(shù)的個數(shù)005 %下面注釋行中的代碼執(zhí)行有錯誤006 %str=sprintf('輸出參數(shù)的個數(shù):=%d',length(varargout));007 %必須使用nargout008 str=sprintf('輸出參數(shù)的個數(shù):=%d',nargout);009 disp(str);010 if(nargout<=nargin)011 fork=1:nargout012 varargout{k}=varargin{nargin-k+1};013 end014 end運行例子17的代碼,在MATLAB命令行中,鍵入下面的指令:>>[ab]=varargout_example(1,2,3,4)輸出參數(shù)的個數(shù):=2a=4b=3例子17的第006行代碼,若將注釋行符號“%”刪除,則程序運行會出現(xiàn)錯誤。在程序中,若需要判斷輸出參數(shù)的個數(shù)不能使用length函數(shù),而需要使用nargout函數(shù)。另外,在操作輸出參數(shù)時,需要判斷輸出參數(shù)的個數(shù),根據(jù)輸出參數(shù)的個數(shù)完成相應的操作。在使用不確定的輸入、輸出參數(shù)時,還可以像下面的代碼行一樣使用這兩個參數(shù):function[out1,out2]=example1(a,b,varargin)function[i,j,varargout]=example2(x1,y1,x2,y2,flag)
若使用varargout和varargin參數(shù),除了必須給定的參數(shù)以外,其余的參數(shù)是任意數(shù)量可變的,具體的操作參閱例子18。例子18可變的輸入、輸出參數(shù)。001 function[x,y,varargout]=vararginout(a,b,c,d,varargin)002 %VARARGINOUT可變的輸入輸出參數(shù)003 str=sprintf('輸入?yún)?shù)的個數(shù):=%d',nargin);004 disp(str);005 str=sprintf('輸出參數(shù)的個數(shù):=%d',nargout);006 disp(str);007 if(nargin<=4)008 error('輸入?yún)?shù)必須多于4個');009 end010 %處理輸入輸出參數(shù)011 x=a+b+c+d;012 y=a-b+c-d;013 if(nargout>2&&nargin>4)014 for(i=1:nargout-2)015 %這里也許會出錯,小心!016 varargout{i}=varargin{end-i-1};017 end018 end運行例子18的代碼,在MATLAB命令行中,鍵入下面的指令:>>vararginout(1,2,3,4,5)輸入?yún)?shù)的個數(shù):=5輸出參數(shù)的個數(shù):=0ans=10>>[a,b,c]=vararginout(1,2,3,4,5,6,7,8)輸入?yún)?shù)的個數(shù):=8輸出參數(shù)的個數(shù):=3a=10b=-2c=64.3子函數(shù)和私有函數(shù)同一個M函數(shù)文件中可以包含多個函數(shù)。如果在同一個M函數(shù)文件中包含了多個函數(shù),那么將出現(xiàn)在文件中的第一個M函數(shù)稱為主函數(shù)(primaryfunction),其余的函數(shù)稱為子函數(shù)(subfunction)。M函數(shù)文件的名稱一般與主函數(shù)的名稱保持一致,其他函數(shù)都必須按照函數(shù)的基本結(jié)構(gòu)來書寫,每一個函數(shù)的開始都是函數(shù)定義行,函數(shù)的結(jié)尾是另一個函數(shù)的定義行的開始或者整個M文件的結(jié)尾(最后一個子函數(shù)的結(jié)尾就是文件結(jié)束符)。不過,子函數(shù)不像主函數(shù),一般子函數(shù)沒有在線幫助,子函數(shù)的作用范圍有限,它只能被那些在定義子函數(shù)的M文件中定義的函數(shù)(包括主函數(shù)和其他子函數(shù))調(diào)用,不能被其他M文件定義的函數(shù)調(diào)用。例子19子函數(shù)應用例子。001 function[avg,med]=newstats(u)%主函數(shù)002 %NEWSTATS計算均值和中間值003 n=length(u);004 avg=mean(u,n); %調(diào)用子函數(shù)005 med=median(u,n); %調(diào)用子函數(shù)006 007 functiona=mean(v,n) %子函數(shù)008 %計算平均值009 a=sum(v)/n;010011 functionm=median(v,n) %子函數(shù)012 %計算中間值013 w=sort(v);014 ifrem(n,2)==1015 m=w((n+1)/2);016 else017 m=(w(n/2)+w(n/2+1))/2;018 end運行例子19,在MATALB命令行窗口中,鍵入下面的指令:>>x=1:11;>>[mean,mid]=newstats(x)mean=6mid=6在MATLAB中有一類函數(shù)被稱為私有函數(shù),這類函數(shù)被放置在名稱為private的子目錄中。每一個函數(shù)文件都是標準的M語言函數(shù)文件,沒有特殊的關鍵字。但是,這些函數(shù)僅能被那些位于private子目錄的上一層目錄中的函數(shù)調(diào)用。例如,假設在MATLAB的搜索路徑中包含路徑\ProjectA
,那么所有位于\ProjectA\private路徑下的函數(shù),只能在其上一層路徑\ProjectA中的函數(shù)文件中調(diào)用。由于私有函數(shù)作用范圍的特殊性,不同父路徑下的私有函數(shù)可以使用相同的函數(shù)名。由于MATLAB搜索函數(shù)時優(yōu)先搜索私有函數(shù),所以如果同時存在私有函數(shù)名func1.m和非私有函數(shù)名func1.m,則私有函數(shù)func1.m被優(yōu)先執(zhí)行。創(chuàng)建私有函數(shù)的方法非常簡單,只要將那些需要設置為私有的函數(shù)都拷貝到一個private子目錄中,則這些函數(shù)就能被那些位于父層目錄中的M函數(shù)調(diào)用了。在表4中總結(jié)了子函數(shù)和私有函數(shù)的區(qū)別。表4私有函數(shù)和子函數(shù)比較例子20
私有函數(shù)的例子。創(chuàng)建一個新的函數(shù)文件,代碼如下:001 functionx=pmean(v,n)002 %MEAN私有函數(shù)例子003 %將該函數(shù)文件保存在pivae子目錄中,004 %則該函數(shù)僅能在上層目錄的函數(shù)文件005 %中調(diào)用006 disp('私有函數(shù)mean');007 x=sum(v)/n;圖3將pmean.m文件保存在private目錄下接著,修改newstats函數(shù),并將其另存為newstats1.m。001 function[avg,med]=newstats1(u)%主函數(shù)002 %NEWSTATS計算均值和中間值003 n=length(u);004 avg=mean(u,n); %調(diào)用子函數(shù)005 avg1=pmean(u,n) %調(diào)用私有函數(shù)006 med=median(u,n); %調(diào)用子函數(shù)007 008 functiona=mean(v,n)%子函數(shù)009 %計算平均值010 disp('子函數(shù)mean');011 a=sum(v)/n;012 ......然后在MATLAB命令行中,執(zhí)行newstats1.m函數(shù):>>newstats1(1:10);子函數(shù)meanavg= 5.5000私有函數(shù)meanavg1= 5.50004.4局部變量和全局變量同C語言類似,在M語言函數(shù)中也存在局部變量和全局變量。所謂局部變量,就是那些在M函數(shù)內(nèi)部聲明并使用的變量。這些變量僅能在函數(shù)調(diào)用執(zhí)行期間被使用,一旦函數(shù)結(jié)束運行,則這些變量占用的內(nèi)存空間將自動被釋放,變量的數(shù)值也就不存在了。這是由于MATLAB的解釋器在解釋執(zhí)行函數(shù)的時候,為不同的函數(shù)創(chuàng)建不同的工作空間,函數(shù)彼此的工作空間相互獨立,一旦函數(shù)執(zhí)行完畢,則函數(shù)的工作空間就不存在了。在本章前面的例子中,每個例子的函數(shù)內(nèi)部聲明使用的變量都是局部變量,所以函數(shù)執(zhí)行完畢后,MATLAB的基本工作空間中沒有這些變量存在,參見例子4-21。例子21
局部變量的例子。001 functionlocal002 %LOCAL察看局部變量的例子003 x=rand(2,2);004 y=zeros(2,2);005 z='函數(shù)中的變量';006 u={x,y,z};007 disp(z)008 whos
運行例子21,在MATLAB命令行中,鍵入下面的指令:>>local函數(shù)中的變量
Name SizeBytesClassu 1x3256cellarrayx 2x232doublearrayy 2x232doublearrayz 1x612chararrayGrandtotalis31elementsusing332bytes>>whos
通過運行l(wèi)ocal函數(shù)可以看到,所有在函數(shù)中創(chuàng)建的變量在函數(shù)運行結(jié)束后就不存在了。也就是說,局部變量的生存周期僅在函數(shù)的活動期間內(nèi)。與局部變量相對應的就是全局變量。MATLAB將全局變量保存在特殊的工作空間進行統(tǒng)一維護、管理,而將變量聲明為全局變量的方法就是在使用變量前,用關鍵字global聲明,例如聲明全局變量gXY:>>globalgXY>>whosName SizeBytesClass
gXY 0x00doublearray(global)Grandtotalis0elementsusing0bytes需要強調(diào)一點,MATLAB管理、維護全局變量和局部變量使用了不同的工作空間,所以使用global關鍵字創(chuàng)建全局變量的時候有三種情況:
(1)若聲明為全局的變量在當前的工作空間和全局工作空間都不存在,則創(chuàng)建一個新的變量,然后為這個變量賦值為空數(shù)組,該變量同時存在于局部工作空間和全局工作空間。
(2)若聲明為全局的變量已經(jīng)存在于全局工作空間中,則不會在全局工作空間創(chuàng)建新的變量,其數(shù)值同時賦值給局部工作空間中的變量。
(3)若聲明為全局的變量存在于局部工作空間中,而全局工作空間不存在,則系統(tǒng)會提示一個警告信息,同時將局部的變量“挪”到全局工作空間中。例子22
全局變量的例子。在MATLAB命令行窗口中,鍵入下面的指令:>>%創(chuàng)建全局變量并賦值>>globalmyx>>myx=10;>>%變量的信息>>whosNameSizeBytesClass
myx1x18doublearray(global)Grandtotalis1elementusing8bytes>>%清除變量>>clearmyx>>%察看信息>>whos>>whosglobalNameSizeBytesClass
myx1x18doublearray(global)Grandtotalis1elementusing8bytes>>%在局部工作空間再次創(chuàng)建變量>>myx=23myx=23>>%變量的信息>>whosNameSizeBytesClass
myx1x18doublearrayGrandtotalis1elementusing8bytes>>%將其修改為全局變量(注意警告信息)>>globalmyxWarning:Thevalueoflocalvariablesmayhavebeenchangedtomatchthe
globals.FutureversionsofMATLABwillrequirethatyoudeclareavariabletobeglobalbeforeyouusethatvariable.>>%看看變量的數(shù)值>>myxmyx=10>>%清除當前的工作空間>>clear>>whosglobalNameSizeBytesClass
myx1x18doublearray(global)Grandtotalis1elementusing8bytes>>%清除所有的內(nèi)存空間>>clearall>>whosglobal使用全局變量時,需要小心留意,因為全局變量可以在任何的函數(shù)中進行讀寫,這樣,可能在比較復雜的程序中查找全局變量錯誤的時候就非常的麻煩。在MATLAB中還有一類變量被聲明為persistent,本書將其稱之為保留變量,這類變量類似于C語言函數(shù)中被聲明為static類型的變量。這類變量在函數(shù)退出的時候不被釋放,當函數(shù)再一次被調(diào)用的時候,這些變量保留上次函數(shù)退出時的數(shù)值。被聲明為persistent的變量具有以下特征:*變量僅能在聲明變量的函數(shù)內(nèi)使用,其他函數(shù)不能直接使用這些變量。*函數(shù)執(zhí)行退出后,MATLAB不清除這些變量占用的內(nèi)存。*當函數(shù)被清除或者重新編輯后,保留的變量被清除。例子23persistent關鍵字。001 functiony=persistent_example(x)002 %PERSISTENT_EXAMPLE保留變量使用示例003 fori=1:x004 y=myfun;005 end006 007 functiony=myfun008 %子函數(shù)009 %persistent關鍵字的使用010 persistentcount;011 %count記錄函數(shù)調(diào)用的次數(shù)012 if(isempty(count))013 count=1;014 else015 count=count+1;016 end017 str=sprintf('第%d次調(diào)用該函數(shù)',count);018 disp(str);019 y=count;在MATLAB命令行窗口中,執(zhí)行該函數(shù):>>persistent_example(2)第1次調(diào)用該函數(shù)第2次調(diào)用該函數(shù)ans=2>>persistent_example(3)第3次調(diào)用該函數(shù)第4次調(diào)用該函數(shù)第5次調(diào)用該函數(shù)ans=5從例子23的執(zhí)行情況可以看出變量count記錄了函數(shù)被調(diào)用的次數(shù),如果在MATLAB命令行中鍵入如下指令:>>clearall則所有的變量都會被清除,此時再次執(zhí)行例子23:>>persistent_example(3)第1次調(diào)用該函數(shù)第2次調(diào)用該函數(shù)第3次調(diào)用該函數(shù)ans=3count數(shù)值又重新計數(shù)了。由于使用全局變量有這樣那樣的危險性,所以建議讀者盡量使用函數(shù)參數(shù)傳遞的方式來完成函數(shù)之間的數(shù)據(jù)共享,或者可以使用persistent關鍵字將必要的變量保護起來。另外,isglobal
命令可以用來測試本地變量與全局工作區(qū)中的變量是否存在聯(lián)系,該命令并不能判斷全局工作區(qū)中是否存在該變量。如果全局工作區(qū)中存在某個變量,但與本地工作區(qū)中的相應變量沒有聯(lián)系,isglobal函數(shù)返回值為0(假)。5M文件調(diào)試
M語言文件的編輯器——meditor不僅僅是一個文件編輯器,同時還是一個
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 食品機械代理加盟協(xié)議
- 風力發(fā)電安全帽管理辦法
- 攝影作品收藏管理準則
- 淄博市物業(yè)節(jié)能技術(shù)應用
- 影視娛樂公司股權(quán)規(guī)則
- 環(huán)境資源保護訴訟指南
- 辦公室地板磚鋪設合同
- 產(chǎn)業(yè)轉(zhuǎn)移項目異議處理程序時效
- 高層自建住宅施工合同
- 藥品生產(chǎn)廠房建筑施工合同
- 垃圾焚燒發(fā)電廠消防系統(tǒng)安裝施工方案
- 加油站安全生產(chǎn)例會制度安全生產(chǎn)
- 中心小學綜合樓建設項目可行性研究報告
- 《可愛的中國讀》書分享會PPT課件(帶內(nèi)容)
- GB/T 6581-2007玻璃在100℃耐鹽酸浸蝕性的火焰發(fā)射或原子吸收光譜測定方法
- GB/T 34676-2017兒童房裝飾用內(nèi)墻涂料
- GB/T 11446.4-2013電子級水電阻率的測試方法
- 跟腱斷裂術(shù)后護理-課件
- 腹外疝病人的護理-腹股溝疝病人的護理(課件ppt)
- 創(chuàng)傷評分幻燈片
- 男性不育課件
評論
0/150
提交評論