4.4 函数
4.4.1 M文件函数
M文件函数是可以定义输入参数或返回输出变量的M文件。M文件名称和函数的名称必须一致。
函数文件的第一行为function所引导的函数声明行,该行列出该函数的所有输入输出的变量名称。函数文件对输入输出变量的数量并没有限制,可以完全没有输入变量,也可以是任意数目的组合。常用的M函数文件参数控制命令如表4.3所示。
表4.3 M文件函数参数控制命令
例4-16,查看M函数文件结构。
在命令行窗口输入:
type mean.m
输出结果如下:
function y = mean(x, dim) %MEAN Average or mean value. % ……(省略部分) % $Revision: 5.17.4.5 $ $Date: 2016/09/02 13:35:22 $ if nargin==1, % Determine which dimension SUM will use dim = find(size(x)~=1, 1 ); if isempty(dim), dim = 1; end y = sum(x)/size(x, dim); else y = sum(x, dim)/size(x, dim); end
提示
MATLAB提供的M函数文件内容包括声明行、说明内容、主体和注释。
说明:
● 函数定义名应和文件保存名一致,当两者不一致时,MATLAB将忽视文件首行的函数定义名,而以文件保存名为准。
● MATLAB中的函数文件名必须以字母开头,可以是字母、下划线以及数字的任意组合,但不可以超过31个字符。
函数文件与脚本文件不同的是:函数文件的内部运算流程不可见,而是一般只能看到其输入的参数和输出的运算结果,这种函数文件的主要特点如下:
● MATLAB在实现对函数的调用时,允许使用比声明变量数目少的输入输出变量。
● 当函数文件运行时,MATLAB会专门为它打开一个临时的函数工作区,函数运行中产生的所有的中间变量都存放在函数工作区中。
● 当执行完文件最后一条命令或遇到return命令时,就结束该函数文件的运行,同时该临时的函数空间及其保存的所有中间变量将立即被清除。函数只执行自己工作区内的变量。
● 调用一个函数时,输入变量不会被复制到函数的工作区,但是它们的值在函数内可读。但当改变输入变量内的任何值时,输入变量就会被复制到函数的工作区。
● 函数工作区随着M函数文件的被调用而产生,随着调用的结束而删除。相对于基本空间,函数工作区是独立和临时的,在MATLAB的整个运行期间,可以产生任意多个临时函数空间。
● 如果函数文件对脚本文件进行了调用,那么该脚本文件运行产生的所有变量都存放在函数工作区中,而不是存放在基本空间中。
例4-17,函数文件调用示例。
在命令行窗口输入:
a=magic(3) %调用magic.m函数文件产生矩阵 avg1=mean(a) %调用mean.m函数文件,输入一个参数计算平均值 avg2=mean(a,2) %调用mean.m函数文件,输入一个参数计算平均值
输出结果如下:
a = 8 1 6 3 5 7 4 9 2 avg1 = 5 5 5 avg2 = 5 5 5
4.4.2 匿名函数
匿名函数没有函数名,也不是函数M文件,只有表达式和输入、输出参数。可以在命令行窗口中输入代码,创建匿名函数。匿名函数创建方法为:
f = @(input1, input2, …) expression
其中,f为创建的函数句柄;input1、input2等为输入变量;expression为函数的主体表达式。
注意
如果匿名函数没有输入参数,则在调用函数时,需要用空格来替换input,否则MATLAB将不执行该程序。
例4-18,匿名函数示例。
在命令行窗口输入:
sqr = @(x) x.^2 %创建匿名函数句柄 t= sqr([1.25 2]) whos
输出结果如下:
sqr = @(x)x.^2 t = 1.5625 4.0000 Name Size Bytes Class Attributes sqr 1x1 16 function_handle t 1x2 16 double
4.4.3 子函数
子函数也称为局部函数,是指在MATLAB中,多个函数的代码可以同时写到一个M函数文件中时出现的一种函数。
M函数文件出现的第一个函数称为主函数,其他函数称为子函数。保存时所用的函数文件名应当与主函数定义名相同,而且外部程序只能对主函数进行调用。
子函数的书写规范有如下几条:
● 每个子函数的第一行是其函数声明行。
● 在M函数文件中,主函数的位置不能改变,但是多个子函数的排列顺序可以任意改变。
● 子函数只能被处于同一M文件中的主函数或其他子函数调用。
● 在M函数文件中,任何命令通过名称对函数进行调用时,子函数优先级仅次于MATLAB内置函数。
● 同一M文件的主函数、子函数的工作区都是彼此独立的。各个函数间的信息传递,可以通过输入输出变量、全局变量或跨空间命令来实现。
● help, lookfor等帮助命令不能显示M文件中的子函数的任何相关信息。
例4-19,子函数示例。
创建ex4_19func.m文件,并写入:
function [avg, med] = ex4_18func (x) n = length(x); avg = mymean(x, n); med = mymedian(x, n); end function a = mymean(v, n) % 求平均子函数 a = sum(v)/n; end function m = mymedian(v, n) % 求中位数子函数 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=[1 3 5 9 11]; [mean, median]= ex4_18func(x)
输出结果如下:
mean = 5.8000 median = 5
4.4.4 私有函数
私有函数是指位于私有目录private上的M函数文件,它的主要性质如下:
● 私有函数的构造与普通M函数完全相同。
● 关于私有函数的调用:私有函数只能被private直接父目录内的M文件所调用,而不能被其他目录上的任何M文件或MATLAB命令窗中的命令所调用。
● M文件中任何命令调用函数时,私有函数优先级仅次于MATLAB内置函数和子函数。
● help, lookfor等帮助命令都不能显示私有函数文件的任何相关信息。
4.4.5 重载函数
重载函数经常用于处理功能类似但变量属性不同的函数。
MATLAB内置函数中就有许多重载函数,分别放置在不同的文件路径下。这些文件所在的文件夹通常命名为@+代表MATLAB数据类型的字符,例如@int16路径下的重载函数的输入变量应为16位整形变量,而@double路径下的重载函数的输入变量应为双精度浮点类型。
4.4.6 内联函数
内联函数的属性与编写方式和普通函数文件不同,但相对来说,内联函数的创建要简单得多。其调用形式如下:
inline(expr) inline(expr, arg1, arg2, ...) inline(expr, n)
inline命令的功能为字符串表达式expr转化为输入变量自动生成的内联函数;arg1, arg2, ...为指定的输入变量,n为指定输入变量个数。
MATLAB中关于内联函数的属性的相关命令如表4.4所示。
表4.4 内联函数属性命令集
例4-20,内联函数示例。
在命令行窗口输入:
f = inline('3 *x.^2') ans1=argnames(f) ans2=formula(f) ans3=char(f) ans4=class(f) ans5=f([1 2 3 4 5])
输出结果如下:
f = Inline function: f(x) = 3 *x.^2 ans1 = 'x' ans2 =3 *x.^2 ans3 =3 *x.^2 ans4 =inline ans5 = 3 12 27 48 75
4.4.7 eval、feval函数
eval、feval函数可用于将文本与函数联系起来。
1.eval函数
eval函数用于翻译并执行文本字符串并返回结果,调用形式如下:
eval(expression) [output1, ..., outputN] = eval(expression)
例4-21, eval函数示例。
在命令行窗口输入:
x=3 str='magic(x)' magic3=eval(str)
输出结果如下:
x = 3 str =magic(x) magic3 =8 1 6 3 5 7 4 9 2
2.feval函数
feval函数可以将函数句柄文本与函数连续,提供函数计算输入并返回求解结果。其调用形式如下:
[y1, y2, ...] = feval(fhandle, x1, ..., xn) [y1, y2, ...] = feval(fname, x1, ..., xn)
例4-22, feval函数示例。
在命令行窗口输入:
x=3 str=@magic magic3=feval(str, 3)
输出结果如下:
x = 3 str = @magic magic3 =8 1 6 3 5 7 4 9 2
4.4.8 函数的函数
函数的函数是指以函数名为自变量的函数。这类函数的用户包括:求零点、最优化、求积分和常微分方程等。
例4-23,函数的函数示例。
在命令行窗口输入:
f = @(x, c) x(1).^2+c.*x(2).^2; % 匿名函数 c = 1.5; %参数 X = fminsearch(@(x) f(x, c), [0.3;1]) %使用函数的函数求最小值
输出结果如下:
X = 1.0e-04 * -0.2447 0.3159
4.4.9 内嵌函数
内嵌函数是指完全包含在父函数中的函数。任何函数都可以包含内嵌函数,例如下面的代码中函数parent包含了内嵌函数nestedfx:
function parent disp('This is the parent function') nestedfx function nestedfx disp('This is the nested function') end end
4.4.10 函数编写建议
在编写大型程序时,有必要养成一些好的编程习惯,包括:
(1)为函数语句添加必要的注释。
(2)尽可能地将循环转化为向量,例如下面语句可以进行向量化。
x = 0.01; for k = 1:1001 y(k) = log(x); x = x + 0.01; end
向量化可得到:
x =0 .01:0.01:10; y = log(x);
(3)如果代码不能向量化,可以通过预分配任何输出结果所在的向量或数组以加快循环。例如:
r = zeros(32,1); %创建矩阵为结果预留空间 for n = 1:32 r(n) = rank(magic(n)); end
(4)在编程时应在程序前以注释的形式编写帮助文件,以方便使用和维护。