1、1,第七章 M文件和函数句柄,2,7.1 matlab控制流,matlab提供了五种控制程序流的结构:for循环结构,while循环结构,if-else-end分支结构,switch-case结构,try-catch结构,(1) for循环结构,for k=k1:inc:k2 %(和一维数组冒号法定义相同)(command) % 循环体 end % i, j虚数单位,尽量不用,例7.1-1 for循环示例,for ii=1:10x(ii)=ii; end,x =1 2 3 4 5 6 7 8 9 10,3,例7.1-2 多重循环生成9x9乘法表,for ii=1:9; % 行for kk=1:
2、9; % 列if kk=iia(ii,kk)=ii*kk;elsea(ii,kk)=0;endend; end;,x=1:1:9; y=x; x=x*y; x=tril(x),矩阵的运算得到,4,table =1 0 0 0 0 0 0 0 02 4 0 0 0 0 0 0 03 6 9 0 0 0 0 0 04 8 12 16 0 0 0 0 05 10 15 20 25 0 0 0 06 12 18 24 30 36 0 0 07 14 21 28 35 42 49 0 08 16 24 32 40 48 56 64 09 18 27 36 45 54 63 72 81,5,说明: 循环不
3、会因为在循环体内对循环变量更新设置而中断 在for后面的表达式中的数组可以为任何合法的matlab数组 循环结构可以嵌套使用 为了得到高效率的代码,应尽量提高代码的向量化程度,避免使用循环结构,在循环指令之前应尽量对数组进行预定义 由于i和j是预定义变量,作虚单位使用.建议不作为循环变量,6,(2) while循环结构,while expression(command) % 循环体 end,说明: 在while和end之间的组命令为循环体. 当执行到while指令时, 首先检测expression的值,如其值为逻辑真(非0),则执行循环体中的命令(组命令).当组命令执行完毕,继续检测表达式的值
4、,若仍为真,循环执行组命令,一旦表达式为假,就结束循环 while和for两种循环的区别在于:while循环结构的循环体被执行的次数是不确定的,而for结构中循环体的执行次数是确定的 当while指令后的表达式是空数组时,认为表达式值为假 使用while循环条件时要小心出现无限循环,如果出现按Ctrl+C可终止,7,a(1)=1; a(2)=1; k=2; ak=10000; while a(k)=aka(k+1)=a(k)+a(k-1);k=k+1; enda(end),例7.1-3 fibonacci数组元素满足规则:ak+2=ak+ak+1,(k=1,2,);且a1=a2=1.求出该数组
5、中第一个大于10 000的元素,8,例7.1-4 级数收敛性判断:,当收敛到终值s=2/6,的0.01%以内时,项数N是多少.,sn=1; k=2; exact=pi2/6; while abs(sn-exact)/exact)1e-4;sn=sn+1/k2;k=k+1; end,9,验证,syms n; s=1/(n2); sums=symsum(s,1,inf); sumn=symsum(s,1,k); err=abs(sums-sumn)/sums; err=double(err),err =9.9980e-005,10,(3) if-else-end分支结构,if-else-end指令
6、为程序流提供了一种分支结构,它的最常用的方式为:,11, 如果判决条件expression为一个空数组,认为条件为假 表达式由多个逻辑子表达式组成时,将尽可能少地检测子表达式的值 if指令判决和break指令配合使用,可以强制终止for或while循环,12,例7.1-5 分支结构,cost=10; number=12; if number5sums=number*1.0*cost; else sums=number*0.9*cost; end,13,例7.1-6 用for实现例7.1-3,n=100; a=ones(1,n); for k=3:na(k)=a(k-1)+a(k-2);if a
7、(k)=10000a(k),break;end; end,14,(4) switch-case结构,switch excase test1command1case test2case testkcommandkotherwisecommands end,15,说明: 当遇到switch结构时, matlab将表达式的值依次和各个case指令后面的检测值进行比较.如果比较结果为假,则取下一个检测值再比较,一旦比较结果为真, matlab将执行相应的一组命令,然后跳出该结构。如果所有的比较结果都为假,即表达式和所有的检测值都不等, matlab将执行otherwise后面的一组命令.可见该结构保证
8、至少有一组命令会得到执行。 switch指令后面的表达式为一个标量或者一个字符串。对于标量形式的表达式,比较这样进行:表达式=检测值i.对于字符串,将调用函数strcmp来实现比较。 case指令后面的检测值不仅可以是一个标量值或字符串,还可以是一个单元数组。如果一个检测值是一个单元数组,matlab将把表达式的值和该单元数组中的所有元素进行比较,如果单元数组中某个元素和表达式的值相等,就认为此次比较结果为真。 当matlab检测到某个检测值和表达式相等时,将执行相应的一组命令,执行完毕,自动跳出swith结构,无需使用break指令。,16,% 划分区域:满分(100),优秀(90-99),
9、良好(80-89),及格(60-79),不及格(60),for k=1:1:10a(k)=89+k; % 90-99 b(k)=79+k; % 80-89 c(k)=69+k; % 70-79d(k)=59+k; % 60-69 endc=d,c; Name=Jack, Marry, Peter,Rose, Tom; Mark=72,83,56,94,100; Rank=cell(1,5); S=struct(Name, Name, Marks, Mark, Rank, Rank);,例7.1-7 学生的成绩管理,使用switch-case结构,17,for k=1:1:5switch S(k
10、).Markscase 100S(k).Rank=满分;case aS(k).Rank=优秀;case bS(k).Rank=良好;case cS(k).Rank=及格;otherwiseS(k).Rank=不及格;end end,18,(5) try-catch结构 处理出错信息,trycommand1 % 组命令1总被执行,若正确,则跳出此结构 catchcommand2 % 仅当组命令1出现执行错误,组命令2才被执行 end,说明: 只有在执行组命令1出现错误后,组命令2才被执行 可调用lasterr函数查询出错原因,如果函数lasterr运行结构为一个空 串,则表明命令1被成功执行了。
11、 当执行组命令2时出错,则终止该结构,19,例7.1-6 try-catch结构应用,N=4; A=magic(3); % A为3x3矩阵 tryA_N=A(N, : ); % 取A的第N行元素 catchA_end=A(end, : ); end lasterr,20,(6) 控制程序流的其他常用指令,1) v=input(msg)v=input(msg, s ) 该指令执行时,控制权交给键盘,待输入结束,按Enter键,控制权 交换matlab, msg是提示用的字符串,告诉用户输入什么.第一种 格式用于键入数值,字符串等数据,最后v是一个数值(包括数组) 或者一个字符串第二种格式,不管键
12、入什么,总以字符串形式 赋给变量v,21,2) keyboard 从M文件中激活键盘,遇到该命令时,将控制权交给键盘,用户可以从键盘输入各种matlab指令,仅当用户输入return指令后,控制权才交还给程序. 与input指令的区别是: 该指令允许输入任意多个matlab指令, 而input只能输入赋给变量的值. 该指令在调试M文件时非常有用.,22,3) continue 跳过位于其后的循环中的其他指令,执行循环的下一个迭代,例7.1-7 更改数组中的值,a=ones(1,12); for k=1:12if rem(k,3)=0continueelsea(k)=k;end end,23,4
13、) break 终止while,for循环,也可以在if-end, switch-case, try-catch中导致中断,5) pause, pause(n) 第一种格式使程序暂停执行,等待用户按任意键继续,第二种格式使程序暂停n秒后,再继续执行,6) return 结束return指令所在函数的执行,把控制转至主调函数或指令 窗.否则,只有整个被调函数执行完毕才转出,24,8) lasterr 显示最新出错原因,并终止程序,9) lastwarn显示matlab自动给出的最新警告程序并继续运行,7) error(msg) 显示出错信息msg, 终止程序,10) warning(msg) 显
14、示警告信息msg, 程序继续执行,25,例7.1-8 warning, pause使用示例,t=-pi:2*pi/200:pi; y=sin(t); z=t; kk=size(t); kk=kk(2); for k=1:1:kkif z(k)=0warning(注意,出现除数为零的情况);str= 此时k = , int2str(k), , 请按任意键继续执行;disp(str);a(k)=1.1;pause;elsea(k)=y(k)/z(k);end end plot(t,a), axis(-3.2,3.2,0,1.2),26,7.2 脚本文件和函数文件,7.2.1 M脚本文件,对于比较简
15、单的问题,可以直接从matlab指令窗中输入相应指令进行解决,而当随着指令数的增加或控制流复杂度的增加,以及需要重复计算的情况下,直接从指令窗进行计算就显得烦琐.此时,脚本文件最适宜.matlab将按照文件所写的指令执行,脚本文件的特点:,(1) 它是一串按用户意图排列而成的(包括控制流指令)matlab指令集合,(2) 脚本文件运行后,所产生的所有变量都驻留在matlab基本工作空间中.只要用户不使用clear指令加以清除,且指令窗不关闭,这些变量将一直保存在基本工作空间中.基本空间随matlab的启动而产生,只有关闭matlab,该基本空间才被删除,例7.2-1 脚本文件产生的变量,27,
16、7.2.2 M函数文件,与脚本文件不同,函数文件是一个黑箱,外界只能看到传给它的输入量和送出来的计算结果,内部运行是不可见的.其特点是:,(1) 从形式上看, 与脚本文件不同, 函数文件的第一行总是以 “function”引导的函数申明行,该行还罗列出函数与外界联系的全部标称输入输出宗量.对与输入输出宗量的数目没有限制.即可以没有输入输出宗量,也可以是任意多个数目,(2) matlab允许使用比标称数目少的输入输出宗量,实现对函数的调用.,(3) 从运行上看,与脚本文件不同. 函数文件运行时,matlab会专门为它开辟一个临时工作空间, 称为函数工作空间.所有中间变量都存放在函数工作空间. 当
17、执行完文件最后一条指令或遇到return时,就结束该函数文件的运行, 同时该临时函数空间及其所有的中间变量就立即被清除,28,(4) 函数空间随具体M函数文件的调用而产生,随调用结束而删除.函数空间是相对基本空间独立的, 临时的. 在matlab整个运行期间,可以产生任意多个临时函数空间,(5) 假如在函数文件中,发生对某脚本文件的调用,那么该脚本文件运行产生的所有变量都存放在该函数空间中, 而不是在基本空间.,29,7.2.3 局部变量和全局变量,(1) 局部变量 它存在于函数空间内部的中间变量,产生于该函数的运行过程中,其影响范围 也仅限于该函数本身,(2) 全局变量 通过global指令
18、,matlab也允许几个不同的函数空间以及基本工作空间共享同一个变量.这种共享的变量称为全局变量.每个希望共享全局变量的函数或matlab基本工作空间,必须逐个用global对具体变量加以专门定义.没采用global定义的函数或基本工作空间,将无权享用全局变量,对全局变量的定义必须在该变量被使用之前进行,建议把全局变量的定义放在函数体的首行位置,并使用大写字符命名全局变量由于全局变量损害函数的封装性,因此不提倡使用全局变量,30,7.2.4 M文件的一般结构,典型M函数文件的结构为:,(1) 函数申明行:位于函数文件的首行,以matlab关键字function 开头,函数名以及函数的输入输出宗
19、量都在这一行定义,(2) H1行:紧随函数申明行之后以%开头的第一注释行.包括:大写体的函数文件名,运用关键词简要描述函数功能.该行供lookfor关键词查询和help在线帮助使用,(3) 在线帮助文本区:H1行及其之后的连续以%开头的所有注释行构成的整个在线帮助文本.通常包括:函数输入输出宗量的含义,调用格式说明.,(4) 编写和修改记录:以%开头,注释编写和修改的日期,版本记录.,(5) 函数体:是实现M文件功能的指令集.它接收输入宗量,进行程序流程控制,得到输出宗量. 如果仅从运算角度看, 只有函数申明行和函数体两部分是构成M函数文件必不可少的,31,例7.2-2 M函数文件示例,% c
20、ircle.m function sa=circle(r,s) % 函数申明行 % CIRCLE plot a cirlce of radia r in the line specified by s % r 指定半径数值 % s 指定线型颜色的字符串 % sa 圆面积 % % circle(r) 利用蓝实线画半径为r的圆 % circle(r,s) 利用s指定的颜色画半径为r的圆 % sa=circle(r) 计算圆面积,并画半径为r的兰色圆周 % sa=circle(r,s) 计算圆面积,并画半径为r的圆,s指定线的颜色% 编写与x年x月x日,修改于x年x月x日,32,if nargin2
21、error(输入宗量太多); end; if nargin=1s=b; end; clf; t=0:pi/100:2*pi; x=r*exp(i*t); if nargout=0plot(x,s); elsesa=pi*r*r;fill(real(x),imag(x),s) end axis(square),33,说明: 从结构上看,M脚本文件仅比M函数文件少一个函数申明行,其余各部分的构造和作用都相同 函数定义名和保存文件名一致.两者不一致时,将忽视文件首行的函数定义名,而以保存文件名为准 函数文件的名字必须以字母开头,后面可以是字母,下划线以及数字的任意组合.,34,例7.2-3 M函数文
22、件, 分数转换为级别,function grade=trans(score);% TRANS 将学生分数转换为级别 % score 分数 % grade 级别,90-100, A; 80-89, B; 70-79,C; 60-69,D; others, E; % trans(score) 将分数 score 转换为级别if score100 |score=90grade=A; elseif score=80 ,35,elseif score=60 ,36,调用:grade=trans(78); 帮助:help trans 显示M文件内容:type trans,37,7.2.6 matlab的搜
23、索过程,假设matlab在一个文件中碰到指令cow时,它将按以下步骤逐步进行检索,(1) 检查cow是否一个变量名,如果不是,执行下一步; (2) 检查cow是不是内建函数(Built-in Function),不是则执行下一步. (3) 检查cow是否cow所在的M文件的一个子函数,否则往下执行 (4) 检查cow是不是它所在M文件的一个私有函数(先找cow.p,然后是 cow.m),不是则往下执行 (5) 检查cow是否当前目录下的文件(先找cow.p,然后是cow.m),不是则往下执行 (6) 检查搜索路径上是否有cow存在(先找cow.p,然后cow.m) matlab将使用最先找到的
24、那个cow,如果一直找不到,就给出错误提示,38,7.3 变量的检测传递和限权使用函数,7.3.1 输入输出宗量检测指令,nargin-在函数体内,用于获取实际输入宗量 nargout-在函数体内,用于获取实际输出宗量 nargin(fun)-获取fun指定函数的标称输入宗量 nargout(fun)-获取fun指定函数的标称输出宗量 inputname(n)-在函数体内使用,给出第n个输入宗量的实际调用变量名,例如: 函数体内 if nargin2 函数体外 nargin(trans),39,7.4.2 跨空间变量传递,(1) 跨空间计算串表达式的值,前面已经介绍了不同工作空间之间变量传递的
25、两种方法:函数的输入输出宗量和全局变量这里介绍第三种方法:跨空间计算串表达式值的指令,evalin(workspace, expr)-跨空间计算串表达式值 evalin(workspace, expr1, expr2)-跨空间计算替代表达式值,说明: workspace可取两个值:base和caller 第一种调用的执行机理是: 根据工作空间的不同计eval(expr), base表示从基本工作空间获得变量,celler表示从主调函数工作空间获得变量这里主调函数是指evalin所在的函数 第二种调用的执行机理是:先从所在函数空间获取变量值,用eval(expr1) 计算原串表达式,若失败,则从
26、指定空间获取变量,再通过用eval(expr2)计算替代串表达式,40,例7.4-1 evalin运行机理与eval的异同,1) 编写M函数文件,% evalinzzy.m function y1=evalinzzy(a,s) t=(0:a)/a*2*pi; y1=subevalinzzy(4,s);%-subfunction-function y2=subevalinzzy(4,s) t=(0:a)/a*2*pi; ss=a*exp(i*t); switch s case base, callery2=evalin(s,ss); case selfy2=eval(ss); end,41,2)
27、 在matlab指令窗中运行指令,a=30;t=(0:a)/a*2*pi; sss=base,caller,self; for k=1:3y0=evalinzzy(8,sssk);subplot(1,3,k);plot(real(y0),imag(y0),r,LineWidth,3), axis square image end,(2) 跨空间赋值,实现不同工作空间之间变量传递的第四种方法是跨空间赋值指令,assignin(workspace, VN, x)-跨空间向VN变量赋值,说明: 把当前工作空间变量x的值赋给workspace指定空间的VN变量,42,7.4.3 子函数和私用函数,(1
28、) 子函数,matlab允许一个M函数文件包含多个函数的代码,其中,第一个出现的函数称为主函数该文件中的其他函数称为子函数保存时所用函数文件名与主函数定义名相同外部程序只能对主函数进行调用,子函数性质:,1) 每个子函数的第一行是其函数申明行 2) 在M函数文件内,主函数的位置是不可改变的,但子函数的排列次序可以任意变动 3) 子函数只能被处于同一文件的主函数或其他子函数调用 4) 在M函数文件中,任何指令通过函数名对函数进行调用时,子函数的优先级仅次于内建函数 5) 同一文件的主函数,子函数的工作空间都是彼此独立的,各函数间的信息,或通过输入输出宗量,或通过全局变量传递,或通过跨空间指令传递
29、,43,(2) 私用函数,所谓私用函数,是指位于private目录上的M文件函数其性质如下:,1) 私用函数的构造与普通M函数完全相同 2) 私用函数只能被private目录的直接父目录上的M文件函数所调用,它不能被其他目录上的任何M函数, M脚本文件或matlab指令窗中的命令所调用也不能被直接父目录上的M脚本文件调用 3) M文件中,任何指令通过函数名对函数进行调用时,私用函数的优先级虽低于内建函数和子函数,但高于其他任何目录上的函数,44,7.5 串演算函数,指令,表达式,语句以及由他们综合组成的M文件,是用户为达到计算目的时最常用的形式为提高计算的灵活性,matlab还提供了两种演算函
30、数:一是串演算函数eval,它具有对字符串表达式进行计算的能力;另一种是函数句柄演算函数feval,它具有对函数句柄进行操作的能力这两种函数为matlab提供了所谓的宏操作能力,也被广泛使用于GUI的回调操作,(1) eval y1=eval(CEM)-执行CEM指定的计算 y1,y2,=eval(CEM)-执行对CEM代表的函数文件调用,并输出计算结果,说明: eval指令的输入宗量必须是字符串 构成字符串的CEM,可以是任何合法的指令,表达式,语句或M文件名 第二种格式的CEM只能是M函数文件名,45,例7.5-1 计算语句串,clear t=pi; eval(theta=t/2, y=s
31、in(theta);,例7.5-2 计算合成串,CEM=cos,sin,tan; for k=1:1:3theta=pi*k/12;y(1,k)=eval(CEMk, (, num2str(theta), ); end,46,(2) feval y1,y2,=feval(FH,arg1,arg2,)-执行函数句柄FH指定的计算,feval与函数句柄配套使用,而eval与字符串配套使用,例7.5-3 feval的使用,1) 定义M文件 %add.m function total=add(a,b) total=a+b;2)通过函数句柄调用 hadd=add; a=100; b=200; c=fev
32、al(hadd,a,b),47,7.6 函数句柄,引如函数句柄的理由是:使feval及借助于它的泛函指令工作更可靠;使函数调用象变量调用一样灵活方便;可迅速获得同名重载函数的位置,类型信息;可在更大范围内调用子函数和私用函数,提高软件重用性;提高函数调用速度,函数句柄并不是伴随函数文件而自动形成的文件属性,是必须通过专门的定义才会生产的,为一个函数定义句柄的方法有两种:利用符号,或利用转换函数str2func.,例7.6-1 为内建函数创建函数句柄,并观察其内涵,1) 类别判断 hsin=sin; class(hsin) size(hsin),ans =function_handle ans
33、=1 1,48,2) 借助指令functions观察内涵,CC=functions(hsin),说明: 指令hsin=sin的功能可以用hsin=str2func(sin)替代 定义函数句柄时,所指定的函数名不应包括路径信息,也不包括扩展名. 观察指令functions只能接受(1x1)的函数句柄数组,并返回一个单结构.该结构包含若干个域.其信息见表,49,50,函数句柄的基本用法,如果一个函数的调用格式为: argout1,argout2,argoutn=FunName(argin1,argin2,arginn) 假设该函数的句柄为hfun,那么通过函数句柄实现函数运算的调用格式为: arg
34、out1,argout2,argoutn=feval(hfun,argin1,argin2,arginn),例7.6 函数句柄的使用,1) 函数句柄的创建,fhandle=str2func(sin); (fhandle=sin),2) 函数句柄在数值计算中的应用,ys=sin(pi/4); yfold=feval(sin, pi/4); yfnew=feval(fhandle,pi/4),51,3) 函数句柄在符号计算中的应用,alpha=sym(pi/4); yss=sin(alpha); ysold=feval(sin,alpha); ysnew=feval(fhandle,alpha),
35、4) 函数句柄在泛函指令中的应用,xold=fminbnd(sin, 0, 2*pi) xnew=fminbnd(fhandle, 0, 2*pi),52,文件的操作, 文件操作是一种重要的输入输出方式,matlab 提供了一系列输入输出函数,专门用于文件操作。, matlab文件操作主要有三个步骤:首先打开文件,然后对文件进行读写操作,最后要关闭文件。, matlab中的输入输出函数是以C语言标准库函数中的输入输出函数为基础开发的,所以这些函数与 C语言的输入输出函数相类似。,53,1. 文件的打开,fid=fopen(文件名,打开方式),常见的打开方式有:,其中文件名用字符串形式表示(可以
36、带路径名),54,fid 为文件句柄, 其它函数可以用它对该文件进行操作.如果句柄值大于 0,则表示文件打开成功;若打开失败, fid 的返回值为 -1.,fid=fopen(output.txt,wt+); fprintf(fid,Hello world!n); fclose(fid);,55,2.文件的关闭, 打开文件进行读写操作后,应立即关闭文件,删除文件指针. status为关闭文件指针所指文件的状态,如果成功则返回0,如果失败则返回-1; fid为所打开的文件指针。,status=fclose(fid),fid=fopen(output.txt,wt+); fprintf(fid,Hello world!n); fclose(fid);,