实验三_M_文件及_MATLAB_程序设计与调试
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三M 文件及MATLAB 程序设计与调试
一、实验目的
全面掌握在MA TLAB 下进行程序设计的有关问题,具体涉及到M 脚本文件和M 函数文件的编写、全局和局部变量的使用、流程控制结构、提高程序执行效率的设计技术、程序调试等问题。
二、实验内容
1、关于M 脚本文件和M 函数文件
MATLAB 的M 文件有两类:脚本文件和函数文件。
(1)脚本文件——将原本要在MATLAB 的指令窗口中直接输入的语句,放在一个以.m 为后缀的,称为脚本文件中。
有了脚本文件,可直接在MATLAB 中输入脚本文件名(不含后缀)。
MATLAB 会打开这一脚本文件,并依次执行脚本文件中的每一条语句,这与在MATLAB 中直接输入语句的结果完全一致。
(2)函数文件——它的第一行必须是函数定义行。
M 函数文件由5 部分构成:
◆函数定义行
◆H1 行
◆函数帮助文本
◆函数体
◆注释
注意:在函数文件中,除了函数定义行之外,其它部分都是可以省略的。
但作为一个函数,为了提高函数的可用性,应加上H1 行和函数帮助文本,为了提高函数的可读性,应加上适当的注释。
例如:
function y = mean(x)
% MEAN Average or mean value.
% For vectors, MEAN(X) is the mean value of the elements in X.
% For matrices, MEAN(X) is a row vector containing the mean value of each column.
[m,n]=size(x);
if m==1
% Determine whether x is a vector
m=n;
end
y = sum(x)/m;
①函数定义行:function y = mean(x)
function 为函数定义的关键字,mean 为函数名,y 为输出变量,x 为输入变量当函数具有多个输出变量时,则以方括号括起;当函数具有多个输入变量时,则直接用圆括号括起。
例如:function [x,y,z]=sphere(theta, phi, rho)。
当函数不含输出变量时,则直接略去输出部分或采用空方括号表示,
例如:function printresults(x) 或function [ ]=printresults(x)
所有在函数中使用和生成的变量都为局部变量(除非利用global 语句定义),这些变量值只能通过输入和输出变量进行传递。
因此,在调用函数时应通过输入变量将参数传递给函数;函数调用返回时也应通过输出变量将运算结果传递给函数调用者;其它在函数中产生的变量在返回时被全部清除。
②H1 行:描述了函数的“功能”信息(很重要!)
函数文件中第二行一般是注释行,这一行称为H1 行,实际上它是帮助文本中的第一行。
H1 行不仅可以由help funtion-name 命令显示,而且,lookfor 命令只在H1 行内搜索,
③函数帮助文本:用来比较详细地说明这一函数的用法
以%开头,输入时help funtion-name 命令,可显示出H1 行和函数帮助文本。
④函数体:完成指定功能的语句实体
可采用任何可用的MATLAB 命令,包括MA TLAB 提供的函数和用户自己设计的M 函数。
⑤注释
●备注:
⏹函数定义名和保存文件名必须一致。
两者不一致时,MATLAB 将忽视文件首行的
函数定义名,而以保存文件名为准;
⏹函数文件的名字必须以字母开头,后面可以是字母、下划线以及数字的任意组合,
但不得超过63 个字符;
⏹建议在编写H1 行时,采用英文表达。
这样处理是为了以后关键词检索方便。
成了基本工作空间中的变量,这会带来几个问题:
●基本工作空间中与脚本文件中同名的变量会引起冲突
●使基本工作空间中变量数急剧增加,造成内存紧张
●编程时要细心考虑各个脚本文件所用到的变量
这些问题在函数文件中不复存在,MATLAB 通过实参与形参一一对应的方式来实现函数的调用,这极大地方便了程序设计。
举例:分别编写出求取平均值与标准差的脚本文件stat1.m 和函数文件stat 2.m。
stat1.m %脚本文件
%求阵列x 的平均值和标准差
[m,n]=size(x);
if m==1
m=n;
end
s1=sum(x);
s2=sum(x.^2);
mean1=s1/m;
stdev=sqrt(s2/m-mean1 ^2);
stat2.m %函数文件
function [mean1,stdev]=stat2(x)
%STA T2函数文件
%求阵列x 的平均值和标准差
[m,n]=size(x);
if m==1
m=n;
end
s1=sum(x);
s2=sum(x.^2);
mean1=s1/m;
stdev=sqrt(s2/m-mean1 ^2);
在命令窗口依次输入如下命令:
clear
x=rand(4,4)+2;
stat1 %执行stat1.m 后,观察基本空间中的变量情况。
whos %可见:脚本文件所产生的所有变量都返回了工作空间
Name Size Bytes Class
m 1x1 8 double array
mean1 1x4 32 double array
n 1x1 8 double array
s1 1x4 32 double array
s2 1x4 32 double array
stdev 1x4 32 double array
x 4x4 128 double array
Grand total is 34 elements using 272 bytes
disp([mean1;stdev]) %观察计算结果
2.7891 2.3084 2.2860 2.3083
0.2192 0.3196 0.1852 0.2699
在命令窗口顺序输入如下命令:
clear m n s1 s2 mean1 stdev
[m1,std1]=stat2(x); %执行stat2.m 后,观察基本基本空间中的变量情况whos %只增加了由函数返回的结果
Name Size Bytes Class
m1 1x4 32 double array
std1 1x4 32 double array
x 4x4 128 double array
Grand total is 24 elements using 192 bytes
disp([m1;std1]) %观察计算结果,和stat1.m 一致
2.7891 2.3084 2.2860 2.3083
0.2192 0.3196 0.1852 0.2699
★备注:
1)运行脚本文件,产生的所有变量都驻留在MA TLAB 基本工作空间(Base workspace),只要不使用clear 且不关闭指令窗口,这些变量将一直保存着。
(基本工作空间随MATLAB 的启动而产生,只有关闭MATLAB 时,该基本空间才被删除。
)
2)运行函数文件,MATLAB 就会专门开辟一个临时工作空间,称为函数工作空间(Function workspace),所有中间变量都存放在函数工作空间中,当执行完最后一条指令或遇到return 时,就结束该函数文件的运行,同时该临时函数工作空间及其所有中间变量就立即被清除。
(函数工作空间随具体M 函数文件的被调用而产生,随调用结束而删除。
函数工作空间是相对基本工作空间对立的、临时的。
在MA TLAB 这个运行期间,可以产生任意多个临时函数工作空间,而基本工作空间。
)
3)如果在函数文件中,调用了某脚本文件,那么该脚本文件运行所产生的所有变量都放在该函数工作空间中,而不是放在基本工作空间中。
2、函数的变量:局部变量和全局变量,输入变量和输出变量
(1)局部变量(Local variable):函数工作空间内部的中间变量,产生于函数的运行过程中,其影响范围仅限于该函数本身。
(2)全局变量(Global variabl):被不同函数工作空间和基本工作空间共享的变量希望共享全局变量的函数空间或基本空间必须逐个用global 对具体变量加以专门定义。
如果某函数的运行使全局变量的内容发生变化,那么其他空间中的同名变量也随之变化,除非与全局变量联系的所有工作空间都被删除,否则全局变量依然存在。
●备注:
⏹对全局变量的定义必须在被使用之前,建议把对全局变量的定义放在函数体的首行
位置
⏹为了提高M 文件的可读性,建议选用大写字符命名全局变量
⏹实际编程中,并不提倡使用全局变量(因它损害了函数的封装性)
(3)输入和输出变量数:nargin、nargout(可获取函数实际输入/输出变量数)在MATLAB 函数中,引用的输入/输出函数的数目可少于编写的变量数目,但这时在函数设计中必须进行适当处理。
举例:编写一个测试函数testarg1.m,要求:当输入为一个变量时,计算出这一变量的平方,当输入为两个变量时,求出这两个变量的乘积。
可编写函数文件:
testarg1.m
function c=testarg1(a,b)
if (nargin==1)
c=a.^2;
elseif
(nargin==2)
c=a*b;
end
在命令窗口输入如下指令调用:
>>x=[2 4], y=[5 6 7;2 4 9]
t1=testarg1(x), t2=testarg1(x,y)
t1 =
4 16
t2 =
18 28 50
3、子函数
从 5.x 版开始,MATLAB 允许一个M 函数文件包含多个函数的代码。
第一个出现的函数——主函数(Primary function),其函数名与文件名相同。
其他出现的函数——子函数(Subfunction)有如下性质:
●每个子函数的第一行是自己的函数定义行
●在M 函数内,主函数的位置不可改变,但子函数的排列次序可以随意改变
●子函数只能被处于同一文件的主函数或其他子函数调用
●M 函数文件中任何指令通过“名字”对函数调用时,子函数的优先级仅次于内部函数。
●同一文件的主函数、子函数的工作空间都是彼此独立的。
●help、lookfor 等帮助指令都不能提供关于子函数的任何帮助信息
4、MATLAB 程序流程控制
(1)for 循环结构:完成指定次重复的循环
语法形式:
for x = array
(commands)
end
说明:x——循环变量,依次取数组array 的各列
commands——循环体,重复执行的次数由数组array的列数决定
【例】一个简单的for 循环示例。
>>for i=1:10; %i 依次取1,2,…10,.
x(i)=i; %对每个i 值,重复执行由该指令构成的循环
end;
>>x %要求显示运行后数组x 的值。
x =
1 2 3 4 5 6 7 8 9 10
说明:
●循环不会因为在循环体内对循环变量重新设置而中断
●for 后面的表达式中的数组可以为任何合法的MATLAB 数组
●循环结构可以嵌套使用
●为了得到高效代码,在循环指令之前应尽量对数组进行预定义(预分配)
(2)while 循环结构:完成不定次重复的循环
语法形式:
while expression
(commands)
end
碰到while 语句时,首先检测expression 的值,为逻辑真(非0),则执行循环体(组命令);执行完毕,继续检测expression的值,为真就再执行循环体;……直到expression 为假,结束循环。
【例】Fibonacci 数组的元素满足Fibonacci 规则:a k+2= a k + a k+1,(k =1,2,L);且a1 = a2 = 1。
现要求该数组中第一个大于10000 的元素。
>>a(1)=1;a(2)=1;i=2;
while a(i)<=10000
a(i+1)=a(i-1)+a(i); %当现有的元素仍小于10000 时,求解下一个元素。
i=i+1;
end;
>> i, a(i)
i =
21
ans =
10946
说明:
●while 循环和for 循环的区别在于:循环体被执行的次数,前者不确定而后者是确
定的
●一般情况下,表达式expression 的值都是标量,但是MATLAB 允许它为一个数组,
此时只有当该数组所有元素均为真时,MATLAB 才会执行循环体。
●如果while 指令后的表达式expression 为空数组,认为expression 值为假,不执
行循环体
(3)if-else-end 分支结构
语法形式1:
if expression
(commands)
end
语法形式2:
if expression1
(commands1)
23
elseif expression2
(commands2)
…………
else (commandsk)
end
语法形式3:
if expression
(commands1)
else (commands2
end
【例】一个简单的分支结构。
>>cost=10; number=12;
if number>8
sums=number*0.95*cost;
end
>>sums
sums =
114.0000
【例】用for 循环指令来寻求Fibonacc 数
>>n=100;a=ones(1,n);
for i=3:n
a(i)=a(i-1)+a(i-2);
if a(i)>=10000
a(i),
break; %跳出所在的一级循
end;
end
>>i
i =
21
(4)switch-case 结构
语法形式:
switch var
case test1
(commands1)
case test2
(commands2)
……
case testk
(commandsk)
otherwise
(commands)
说明:
var——标量或字符串;testi——检测值i
遇到switch 结构时,将var 的值依次和各个case 后的检测值比较。
●标量比较:var==testi
●字符串比较:strcmp(var,testi)
1)若比较结果为假,则取下一个检测值再比较;
2)一旦比较结果为真,就执行相应的命令组,然后自动跳出该结构(与 C 语言不同,不必使用break 指令);
3)若所有比较结果为假,就执行otherwise 后的命令组(这部分可以不存在)。
【例】演示switch 结构的应用。
var1=input('var1= '); %让用户通过键盘输入数值、字符串或表达式
switch var1
case {-2,-1}
disp('var1 is negative one or two.')
case 0
disp('var1 is zero.')
case {1,2,3}
disp('var1 is positive one ,two, or three.')
otherwise
disp('var1 is other value.')
end
var1= 2
var1 is positive one ,two, or three.
(5)try-catch 结构
语法形式:
try
(commands1)
catch
(commands2)
end
说明:commands1 总被执行,若正确,则跳出结构;仅当commands1 出现执行错误后,commands2 才被执行,若再出错,MATLAB 将终止该结构。
可调用lasterr 函数查询出错原因,若lasterr 运行结果为一个空串则表明commands1 被成功执行。
【例】try-catch 结构应用实例。
clear,N=4;A=magic(3) %设置3 行3 列矩阵A。
try
A_N=A(N,:), %取A 的第N 行元素
catch
A_end=A(end,:), %如果取A(N,:)出错,则改取A 的最后一行。
end
lasterr %显示出错原因
注:MAGIC(N) is an N-by-N matrix constructed from the integers 1 through N^2 with equal row, column, and diagonal sums. 魔方矩阵行、列、对角线元素之和都相等,且数据是由1~N2之间的正整数构成。
只要数>2魔方矩阵总存在。
A =
8 1 6
3 5 7
4 9 2
A_end =
4 9 2
ans =
Index exceeds matrix dimensions.
(6) 控制程序流程的其他常用指令
return 指令:可以强制MATLAB 结束被调函数的执行,并把控制转出
●break 指令:使while、for 循环(在满足某种条件时)终止退出,而不必等待循环的
自然结束
●input 指令:暂时把“控制权”交给用户,通过键盘输入数值、字符串或表达式,并经
“回车”把键入内容输入工作空间,同时再把“控制权”交还给MATLAB
v=input('message')将用户键入的内容赋给变量v
v=input('message', 's')将用户键入的内容作为字符串赋给变量v
●keyboard 指令:把“控制权”交给用户,让用户通过键盘输入各种MATLAB 指令(任
意多个);只有当用户使用return 指令结束输入后,“控制权”才交还给程序。
5、程序设计技术——提高程序执行效率
(1)循环的向量化
在实际运用中,有些循环可直接转换成向量操作,这样可大大提高程序的执行速度。
因此在编写程序时,应尽量避免采用循环.将它转变成向量进行处理。
为测试程序执行的效率.可采用tic 和toc 函数。
例如,可编写名为techl.m 和tech2.m 的脚本文件,用两种不同方法来产生正弦函数:
%以下是tech1.m:
>> tic
i=0;
for t=0:.01:100
i=i+1;
y(i)=sin(t);
end
toc
Elapsed time is 0.297000 seconds %执行结果
%以下是tech2.m:
>> tic
t=0:.01:100;
y=sin(t);
toc
Elapsed time is 0.062000 seconds. %执行结果
(2)阵列预分配
利用预分配结果阵列可减少程序执行时间。
在程序设计中,经常会涉及到循环,每次循环至少会得到一个结果元素,如y〔k)。
如果我们不对y 阵列预分配存贮单元,则y 阵列每次都将自动增大,从而大大降
低计算效率。
通过对y 预分配,我们可免去了每次增大y 的操作,从而大大地减
少计算时间。
(变量维数越大越明显)
6、MATLAB 程序调试
MATLAB 的调试器(Debugger)可帮助找出编程中的错误,使用调试器可在执行中随时显示出工作空间的内容,查看函数调用的栈关系,并且可单步执行M 函数代码。
(1)MATLAB 程序调试主要用来纠正两类错误
◆格式错误:
比如函数名的格式错误、缺括号等,MATLAB 可在运行程序时检测出大多数格式错误,并显示出出错信息和出错位置。
这类错误可很容易找到,并加以纠正。
◆运行错误:
这些错误通常发生在算法和设计错误上,例如修改了错误的变量,计算不正确等。
运行错误一般不易找出位置,因此要利用调试器工具来诊断。
(2)为查找运行错误,可采用下列技术
●在运行错误可能发生的M 函数文件中,删去某些语句句未的分号。
这样可显示出一些
中间计算结果、从中可发现一些问题;
●在M 文件的适当位置加上keyboard 语句,当执行到这条语句时,MATLAB 会暂停
执行,并将控制权交给用户,这时我们可检查和修改局部工作空间的内容,从中找到出错的线索,利用return 命令可恢复程序的执行;
●注释掉M 函数文件中的函数定义行,即在该行之前加上%,将M 函数文件转变成M
脚本文件,这样,在程序运行出错时就可查看M 文件中产生的变量;
●使用调试器可查找程序的运行错误,因为它允许访问函数空间,可设置和清除运行断点,
还可以单步执行M 文件,这些功能都有助于找到出错的位置。
7、补充函数文件示例
【例1】M 函数文件编写及调用示例。
(1)在M 文件编辑器中编写如下函数文件,保存为circle.m
function sa = circle(r,s)
%CIRCLE plot a circle of radii 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 色圆面.
% 编写于1999 年4 月7 日,修改于1999 年8 月27 日。
if nargin>2
error('输入宗量太多。
');
end;
if nargin==1
s='b';
end;
clf;
t=0:pi/100:2*pi;
x=r*exp(i*t);
if nargout==0
plot(x,s);
else
sa=pi*r*r;
fill(real(x),imag(x),s)
end
axis('square')
(2)编写M 脚本文件或在MATLAB 命令窗口中直接运行以下指令调用函数,以得到相应结果:
circle(5)
circle(4, ‘r’)
s1=circle(6)
s2=circle(8,‘y’)
【例2】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(a,s)
t=(0:a)/a*2*pi;ss='a*exp(i*t)';
switch s
case {'base','caller'}
y2=evalin(s,ss);
case 'self'
y2=eval(ss);
end
(2)编写M 脚本文件或在MATLAB 命令窗口中直接运行以下指令:
clear,a=30;t=(0:a)/a*2*pi;sss={'base','caller','self'};
for k=1:3
y0=evalinzzy(8,sss{k});
subplot(1,3,k)
plot(real(y0),imag(y0),'r','LineWidth',3),axis square image
end
-505-4-2024 8. 禁忌搜索算法示例。