函数文件
许多时候希望将特定的算法写成函数的形式,以提高程序的可重用性和程序设计的效率。
函数文件定义了输出参数和输入参数的对应关系,以方便外部调用。事实上,MATLAB 提供的 标准函数都是由函数文件定义的。
1 函数文件的基本结构
函数文件由function 语句引导,其基本结构如下:
function 输出形参表 = 函数名(输入形参表)
注释说明部分
函数体语句
其中,
-
以 function 开头的一行为引导行,表示定义一个函数。
-
函数名的命名规则与变量名相同。
-
在函数定义时,输入输出参数没有分配存储空间,所以称为形式参数,简称形参。
-
当有多个形参时,形参之间用逗号分隔,组成形参表。
-
当输出形参多于一个时,则应该用方括号括起来, 构成一个输出矩阵。
说明:
(1)关于函数文件名。函数文件名通常由函数名再加上扩展名.m 组成,不过函数文件名与函数名也可以不相同。当两者不同时,MATLAB将忽略函数名,调用时使用函数文件名。为理解和记忆的方便, 一般建议函数文件名和函数名统一。
(2)关于注释说明部分。注释说明包括如下3部分内容。
① 紧随函数文件引导行之后以%开头的第一注释行。这一行一般包括大写的函数文件名和函数功能简要描述,供lookfor 关键词查询和help 在线帮助用。
② 第一注释行及之后连续的注释行。通常包括函数输入输出参数的含义及调用格式说明等信息,构成全部在线帮助文本。
③ 与在线帮助文本相隔一空行的注释行。包括函数文件编写和修改的信息,如作者、修改日期、版本等内容,用于软件档案管理。
(3)关于 return 语句。如果在函数文件中插入了return 语句,则执行到该语句就结束函数的执行,程序流程转至调用该函数的位置。通常,在函数文件中也可不使用return 语句,这时在被调用函数执行完成后自动返回。
例1 编写函数文件,求半径为r的圆的面积和周长。
函数文件如下:
function [s,p]=fcircle(r)
%CIRCLE calculate the area and perimeter of a circle of radii r
%r 圆半径
%s 圆面积
%p 圆周长
%2016年9月20日编
s=pi*r*r;
p=2*pi*r;
将以上函数文件以文件名fcircle.m存盘,然后在MATLAB命令行窗口调用该函数。
>> [s,p]=fcircle(10)
s =
314.1593
p =
62.8319
2 函数调用
1.函数调用的格式
函数文件建立好后,就可以调用该函数了,调用格式如下:
[输出实参表]=函数名(输入实参表)
在调用函数时,函数输入输出参数称为实际参数,简称实参。
要注意的是,函数调用时各实参出现的顺序、个数,应与函数定义时形参的顺序、个数一致,否则会出错。
函数调用时, 先将实参传递给相应的形参,从而实现参数传递,然后再执行函数的功能。
例2 利用函数文件,实现直角坐标(x,y)与极坐标(ρ,θ)之间的转换。
首先编写函数文件tran.m。
function [rho,theta]=tran(x,y)
rho=sqrt(x*x+y*y);
theta=atan(y/x);
再在脚本文件main1.m中调用函数文件tran.m。
x=input('Please input x=');
y=input('Please input y=');
[rho,the]=tran(x,y);
disp(['rho=',num2str(rho)])
disp(['the=',num2str(the)])
最后在命令行窗口运行脚本文件main1.m。
>> main1
Please input x=45
Please input y=45
rho =
63.6396
the =
0.7854
实际上,MATLAB 提供了直角坐标与极坐标之间转换的函数,分别如下。
(1) [th,r]=cart2pol(x,y)
: 将直角坐标转换为极坐标。
(2)[x,y]=pol2cart(th,r)
: 将极坐标转换为直角坐标。
例如:
>>[rho,the]=cart2pol(45,45)
rho =
63.6396
the =
0.7854
2.函数的递归调用
在 MATLAB中,函数可以嵌套调用,即一个函数可以调用其他函数,甚至调用它自身。
一个函数调用它自身称为函数的递归调用。
例3 利用函数的递归调用,求n!。
采用递归调用的函数文件factor.m如下:
function f=factor(n)
if n<=1
f=1;
else
f=factor(n-1)*n; %递归调用求(n-1)!
end
在脚本文件main2.m中调用函数文件factor.m,求s = 1! + 2! + 3! + 4! + 5!。
s=0;
n=input('Please input n=');
for i=1:n
s=s+factor(i);
end
disp(['1到',num2str(n),'的阶乘和为:',num2str(s)])
在命令行窗口运行脚本文件:
>>main2
Please input n=5
1到5的阶乘和为:153
例4 任意排列问题。
MATLAB 提供的函数 randperm(n)可以产生一个从整数1到整数 n的任意排列。编写一个函数来实现 randperm(n) 函数的功能,即给出一个由任意数组成的行向量,然后产生这个行向量元素的任意排列。
① 函数用循环结构。★★
function Y=rndprm1(X)
%RNDPRM1 用for循环产生一个行向量的任意排列
%RNDPRM1(X)产生行向量X的任意排列
[m,n]=size(X);
if m>1
error('RNDPRM1 accepts as inputs only vectors');
end
Y=[]; %从一个空矩阵开始
l=n; %X的元素个数
for i=1:n
k=1+fix(l*rand); %随机选择Y的下一个元素的位置
x=X(k); %被选择的元素
Y=[Y,x]; %将x添加到Y中
X(k)=[]; %从X中删除x元素
l=l-1 ; %更新X的元素个数
end
② 函数用递归调用。
function Y=rndprm2(X)
%RNDPRM2 用递归调用产生一个行向量的任意排列
%RNDPRM2(X)产生一个X的任意排列
[m,n]=size(X);
l=n;
if m>1
error('RNDPRM2 accepts as inputs only vectors')
end
if n<=1
Y=X;
else
k=1+fix(l*rand); %随机选择Y的下一个元素的位置
x=X(k); %被选择的元素
X(k)=[]; %从X中删除x元素
Z=rndprm2(X); %将剩下的元素随机排列
Y=[Z,x]; %构造输出向量
l=l-1;
end
③ 在命令行窗口调用所定义的函数,命令如下:
>> rndprm1([34,6,3,54,2,5,454])
>> rndprm2([34,6,3,54,2,5,454])
>> rndprm1('apple')
>> rndprm2('apple')
3 函数参数的可调性
MATLAB 在函数调用上有一个特点,就是函数所传递参数数目的可调性★。凭借这一点,一个函数可完成多种功能。
在调用函数时,MATLAB 用两个预定义变量nargin 和nargout 分别记录调用该函数时的输入实参和输出实参的个数。
只要在函数文件中包含这两个变量,就可以准确地知道该函数文件 被调用时的输入/输出参数个数,从而决定函数如何进行处理。
例5 nargin用法示例。
建立函数文件charray.m。
function fout=charray(a,b,c)
if nargin==1
fout=a;
elseif nargin==2
fout=a+b;
elseif nargin==3
fout=(a*b*c)/2;
end
建立脚本文件mydemo.m。
a=1:3;b=a';
x=charray(a);
y=charray(a,b');
z=charray(a,b,3);
disp(['x= ',num2str(x)])
disp(['y= ',num2str(y)])
disp(['z= ',num2str(z)])
执行脚本文件mydemo.m 后的输出结果如下:
X= 1 2 3
Y= 2 4 6
Z= 21
4.全局变量与局部变量
在MATLAB中,函数文件中的变量是局部的,与其他函数文件及MATLAB工作空间相互隔离,即在一个函数文件中定义的变量不能被另一个函数文件引用。
如果在若干函数中,都把某一变量定义为全局变量,那么这些函数将共用这个变量。
全局变量的作用域是整个MATLAB 工作空间,即全程有效,所有的函数都可以对它进行存取和修改,因此,定义全局变量是函数间传递信息的一种手段。
全局变量用global 命令定义,格式如下:
global 变量名
例6 全局变量应用示例。
先建立函数文件wadd.m,该函数将输入的参数加权相加。
function f=wadd(x,y)
global ALPHA BETA
f=ALPHA*x+BETA*y;
在命令行窗口中输入命令并得到输出结果。
>> global ALPHA BETA
>> ALPHA=1;
>> BETA=2;
>> s=wadd(1,2)
在实际程序设计时,可在所有需要调用全局变量的函数中定义全局变量,这样就可实现数据共享。
在函数文件中,全局变量的定义语句应放在变量使用之前,为了便于了解所有的全局变量,一般把全局变量的定义语句放在文件的前部。为了在工作空间中使用全局变量,也要定义全局变量。
值得指出的是,在程序设计中,全局变量固然可以带来某些方便,但却破坏了函数对变量的封装,降低了程序的可读性,因此,在结构化程序设计中,全局变量是不受欢迎的,尤其当程序较大,子程序较多时,全局变量将给程序调试和维护带来不便,故不提倡使用全局变量。
如果一定要用全局变量,最好给它起一个能反映变量含义的名字,以免和其他变量混淆。
Matlab学习笔记内容来源于《MATLAB程序设计与应用 第三版》刘卫国主编