Matlab 版 (精华区)

发信人: bage (最近比较烦), 信区: Matlab
标  题: 精通Matlab(五)
发信站: 哈工大紫丁香 (Sun Feb  4 14:03:47 2001), 转信

发信人: Security (淼水), 信区: MathTools       
发信站: BBS 水木清华站 (Tue Jun  1 22:35:21 1999)


第8章  M文 件 函 数


    使用MATLAB函数时,例如inv, abs, angle和sqrt,MATLAB获取传递给它的变量,利用所给的输入,计算所要求的结果。然后,把这些结果返回。由函数执行的命令,以及由这些命令所创建的中间变量,都是隐含的。所有可见的东西是输入和输出,也就是说函数是一个黑箱。
    
这些属性使得函数成为强有力的工具,用以计算命令。这些命令包括在求解一些大的问题时,经常出现的有用的数学函数或命令序列。由于这个强大的功能,MATLAB提供了一个创建用户函数的结构,并以M文件的文本形式存储在计算机上。MATLAB函数fliplr是一个M文件函数良好的例子。

        function y = fliplr(x)
        %  FLIPLR       Flip matrix in the left/right direction.
        %       FLIPLR(X) returns X with row preserved and columns flipped
        %       in the left/right direction.
        %       
        %       X = 1  2  3     becomes  3  2  1
        %           4  5  6              6  5  4
        %
        %       See also FLIPUD, ROT90.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        [m, n] = size(x);
        y = x(: , n : -1 : 1);

    一个函数M文件与脚本文件类似之处在于它们都是一个有.m 
扩展名的文本文件。如同脚本M文件一样,函数M文件不进入命令窗口,而是由文本编辑器所创建的外部文本文件。一个函数的M文件与脚本文件在通信方面是不同的。函数与MATLAB工作空间之间的通信,只通过传递给它的变量和通过它所创建的输出变量。在函数内中间变量不出现在MATLAB
工作空间,或与MATLAB工作空间不交互。正如上面的例子所看到的,一个函数的M文件的第一行把M文件定义为一个函数,并指定它的名字。它与文件名相同,但没有.m 扩展名。它也定义了它的输入和输出变量。接下来的注释行是所展示的文本,它与帮助命令: ? help 
fliplr相对应。第一行帮助行称为H1 行,是由lookfor 命令所搜索的行。最后,M文件的其余部分包含了MATLAB创建输出变量的命令。

8.1  规则和属性

    M文件函数必须遵循以下特定的规则。除此之外,它们有许多的重要属性。包括:
    1.  函数名和文件名必须相同。例如,函数fliplr 存储在名为fliplr.m 文件中。
    2.  
MATLAB头一次执行一个M文件函数时,它打开相应的文本文件并将命令编辑成存储器的内部表示,以加速执行以后所有的调用。如果函数包含了对其它M文件函数的引用,它们也同样被编译到存储器。普通的脚本M文件不被编译,即使它们是从函数M文件内调用;打开脚本M文件,调用一次就
逐行进行注释。
    3.  在函数M文件中,到第一个非注释行为止的注释行是帮助文本。当需要帮助时,返回该文本。例如, ? help fliplr返回上述前八行注释。
    4.  第一行帮助行,名为H1 行,是由lookfor 命令搜索的行。
    5.  函数可以有零个或更多个输入参量。函数可以有零个或更多个输出参量。
    6.  函数可以按少于函数M文件中所规定的输入和输出变量进行调用,但不能用多于函数M文件中所规定的输入和输出变量数目。如果输入和输出变量数目多于函数M文件中function 语句一开始所规定的数目,则调用时自动返回一个错误。
    7.  当函数有一个以上输出变量时,输出变量包含在括号内。例如,[V,D] = eig(A)。不要把这个句法与等号右边的[V,D] 相混淆。右边的[V,D] 是由数组V和D 所组成。
    8.  当调用一个函数时,所用的输入和输出的参量的数目,在函数内是规定好的。函数工作空间变量nargin 包含输入参量个数;函数工作空间变量nargout 
包含输出参量个数。事实上,这些变量常用来设置缺省输入变量,并决定用户所希望的输出变量。例如,考虑MATLAB函数linspace :

        function y = linspace(d1, d2, n)
        %  LINSPACE Linearly spaced vector.
        %       LINSPACE(x1, x2) generates a row vector of 100 linearly
        %       equally spaced points between x1 and x2.
        %       LINSPACE(x1, x2, N) generates N points between x1 and x2.
        %
        %       See also LOGSPACE, :.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        if nargin == 2
            n = 100;
        end
        y = [d1+(0:n-2)*(d2-d1)/(n-1) d2] ;

    这里,如果用户只用两个输入参量调用linspace ,例如linspace(0,10) ,linspace 产生100个数据点。相反,如果输入参量的个数是3,例如,linspace(0,10,50),第三个参量决定数据点的个数。
    可用一个或两个输出参量调用的函数的一个例子是MATLAB函数size。尽管这个函数不是一个M文件函数(它是一个内置函数),size函数的帮助文本说明了它的输出参量的选择。

        SIZE    Matrix dimensions.
                D = SIZE(X), for M-by-N matrix X, returns the two-element
                row vector D = [M, N] containing the number of rows and columns
                in the matrix.
 
                [M, N] = SIZE(X) returns the number of rows and columns
                in separate output variables.

    如果函数仅用一个输出参量调用,就返回一个二元素的行,它包含行数和列数。相反,如果出现两个输出参量,size 分别返回行和列。在M文件函数里,变量nargout 可用来检验输出参量的个数,并按要求修正输出变量的创建。
    9.  当一个函数说明一个或多个输出变量,但没有要求输出时,就简单地不给输出变量赋任何值。MATLAB函数toc 阐明了这个属性。

        function t = toc
        %  TOC  Read the stopwatch timer.
        %       TOC, by itself, prints the elapsed time since TIC was used.
        %       t = TOC; saves the elapsed time in t, instead of printing it out.
        %
        %       See also TIC, ETIME, CLOCK, CPUTIME.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        %  TOC uses ETIME and the value of CLOCK saved by TIC.
        global TICTOC
        if nargout < 1
           elapsed_time = etime(clock, TICTOC)
        else
           t = etime(clock, TICTOC);
        end

    如果用户用不以输出参量调用toc ,例如, ? toc,就不指定输出变量t 的值,函数在命令窗口显示函数工作空间变量elapsed_time ,但在MATLAB工作空间里不创建变量。相反,如果toc 是以 ? out=toc 调用,则按变量out将消逝的时间返回到命令窗口。
    10.  
函数有它们自己的专用工作空间,它与MATLAB的工作空间分开。函数内变量与MATLAB工作空间之间唯一的联系是函数的输入和输出变量。如果函数任一输入变量值发生变化,其变化仅在函数内出现,不影响MATLAB工作空间的变量。函数内所创建的变量只驻留在函数的工作空间,而且只在函
数执行期间临时存在,以后就消失。因此,从一个调用到下一个调用,在函数工作空间变量存储信息是不可能的。(然而,如下所述,使用全局变量就提供这个特征。)
    11.  如果一个预定的变量,例如,pi, 在MATLAB工作空间重新定义,它不会延伸到函数的工作空间。逆向有同样的属性,即函数内的重新定义变量不会延伸到MATLAB的工作空间中。
    12.  当调用一个函数时,输入变量不会拷贝到函数的工作空间,但使它们的值在函数内可读。然而,改变输入变量内的任何值,那么数组就拷贝到函数工作空间。进而,按缺省,如果输出变量与输入变量相同,例如,函数x=fun(x, y, z) 中的x 
,那么就将它拷贝到函数的工作空间。因此,为了节约存储和增加速度,最好是从大数组中抽取元素,然后对它们作修正,而不是使整个数组拷贝到函数的工作空间。
    13.  如果变量说明是全局的,函数可以与其它函数、MATLAB工作空间和递归调用本身共享变量。为了在函数内或MATLAB工作空间中访问全局变量,在每一个所希望的工作空间,变量必须说明是全局的。全局变量使用的例子可以在MATLAB函数tic 和toc 
中看到,它们合在一起工作如一个跑表。

        function tic
        %  TIC  Start a stopwatch timer.
        %       The sequence of commands
        %           TIC
        %           any stuff
        %           TOC
        %       prints the time required for the stuff.
        %
        %       See also TOC, CLOCK, ETIME, CPUTIME.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        %  TIC simply stores CLOCK in a global variable.
        global TICTOC
        TICTOC = clock;


        function t = toc
        %  TOC  Read the stopwatch timer.
        %       TOC, by itself, prints the elapsed time since TIC was used.
        %       t = TOC; saves the elapsed time in t, instead of printing it out.
        %
        %       See also TIC, ETIME, CLOCK, CPUTIME.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        %  TOC uses ETIME and the value of CLOCK saved by TIC.
        global TICTOC
        if nargout < 1
           elapsed_time = etime(clock,TICTOC)
        else
           t = etime(clock,TICTOC);
        end

    在函数tic 中,变量TICTOC 说明为全局的,因此它的值由调用函数clock 来设定。以后在函数toc 中,变量TICTOC 也说明为全局的,让toc 访问存储在TICTOC 中的值。利用这个值,toc 
计算自执行函数tic以来消逝的时间。值得注意的是,变量TICTOC存在于tic和toc的工作空间,而不在MATLAB工作空间。
    14.  
实际编程中,无论什么时候应尽量避免使用全局变量。要是用了全局变量,建议全局变量名要长,它包含所有的大写字母,并有选择地以首次出现的M文件的名字开头。如果遵循建议,则在全局变量之间不必要的互作用减至最小。例如,如果另一函数或MATLAB工作空间说明TICTOC为全局的
,那么它的值在该函数或MATLAB工作空间内可被改变,而函数toc 会得到不同的、可能是无意义的结果。
    15.  MATLAB以搜寻脚本文件的同样方式搜寻函数M文件。例如,输入? cow 
,MATLAB首先认为cow是一个变量。如果它不是,那么MATLAB认为它是一个内置函数。如果还不是,MATLAB检查当前cow.m的目录或文件夹。如果它不存在,MATLAB就检查cow.m在MATLAB搜寻路径上的所有目录或文件夹。如需要更多的信息,请参阅本书的2.10节或MATLAB用户指南中"MATLAB搜
寻路径"。
    16.  从函数M文件内可以调用脚本文件。在这种情况下,脚本文件查看函数工作空间,不查看MATLAB工作空间。从函数M文件内调用的脚本文件不必用调用函数编译到内存。函数每调用一次,它们就被打开和解释。因此,从函数M文件内调用脚本文件减慢了函数的执行。
    17.  函数可以递归调用。即M文件函数能调用它们本身。例如,考虑一个傻函数iforgot:

        function iforgot(n)
        %  IFORGOT Recursive Function Call Example

        %  Copyright (c) 1996 by Prentice-Hall,Inc

        if nargin==0,n=20;end
        if n>1
           disp(' I will remember to do my homework. ')
           iforgot(n-1)
        else
           disp(' Maybe NOT! ')
        end

调用这个函数产生

                        ? iforgot(10)
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        I will remember to do my homework.
                        Maybe NOT!

    
递归调用函数功能在许多应用场合是有用的。在编制要递归调用的函数时,必须确保会终止,否则MATLAB会陷入死循环。最后,在一个递归函数内,如果变量说明是全局的,则该全局变量对以后所有函数调用是可用的。在这个意义下,全局变量变成静态的,并在函数调用之间不会消失。
    18.  当函数M文件到达M文件终点,或者碰到返回命令return,就结束执行和返回。return命令提供了一种结束一个函数的简单方法,而不必到达文件的终点。
    19.  MATLAB函数error在命令窗口显示一个字符串,放弃函数执行,把控制权返回给键盘。这个函数对提示函数使用不当很有用,如在以下文件片段中:

        if length(val)>1
            error('  VAL must be a scalar.  ')
        end

    这里,如果变量val不是一个标量,error显示消息字符串,把控制权返回给命令窗口和键盘。
    20.  当一个函数的输入参量的个数超出了规定的范围,MATLAB函数nargchk提供了统一的响应。函数nargchk给定为:

        function  msg = nargchk(low, high, number)
        %  NARGCHK  Check number of input arguments. 
        %       Return error message if not between low and high.  
        %       If it is, return empty matrix.

        %       Copyright (c) 1984-94 by The MathWorks, Inc.

        msg = [  ] ;
        if (number < low)
                msg = ' Not enough input arguments. ' ;
        elseif (number  >  high)
                msg = ' Too many input arguments. ' ;
        end

下列的文件片段表明了在一个M文件函数内的典型用法:

      error(nargchk(nargin, 2, 5))

    
如上所示,如果nargin的值小于2,函数error象前面描述的那样进行处理,nargchk返回字符串'没有足够的输入参量。'。如果nargin的值大于5,函数error执行处理,nargchk返回字符串'太多输入参量。'。如果nargin是在2和5之间,函数error简单地将控制传递给下一个语句,nargchk返
回一个空字符串。也就是说,当它的输入参量为空,error函数什么也不做。
    21.  
当MATLAB运行时,它缓存了(caches)存储在Toolbox子目录和Toolbox目录内的所有子目录中所有的M文件的名字和位置。这使MATLAB很快地找到和执行函数M文件。也使得命令lookfor工作更快。被缓存的M文件函数当作是只读的。如果执行这些函数,以后又发生变化,MATLAB将只执行以前编
译到内存的函数,不管已改变的M文件。而且,在MATLAB执行后,如果M文件被加到Toolbox目录中,那么它们将不出现在缓存里,因此不可利用。所以,在M文件函数的使用中,最好把它们存储在Toolbox目录外,或许最好存储在MATLAB目录下,直至它们被认为是完备的(complete)。当它们
是完备时,就将它们移到一个只读的Toolbox目录或文件夹的子目录内。最后,要确保MATLAB搜索路径改变,以确认它们的存在。
    22.  
在Toolbox目录外,MATLAB跟踪M文件的修改日期。所以,当遇到一个以前编译到内存的M文件函数时,MATLAB把已编译的M文件的修改日期与在磁盘上的M文件比较。如果日期是相同的,MATLAB执行已编译的M文件。相反,如果在磁盘上的M文件是新的,MATLAB清除以前已编译的M文件,且编译
这个新的和修改过的M文件。
    23.  M文件的缓存过程按MATLAB版本而稍有不同。例如,MATLAB  
4.2c在Macintosh机上同样可以缓存当前的目录,因为这是第一个所搜索的磁盘位置。这个MATLAB版本也允许有选择地将整个MATLAB搜索路径缓存,并把高速缓存信息存储在一个文件中。这样,使MATLAB引导更快,寻找和编译所有函数M文件更快。退出缓存,不检测已修改的或已增加的M文
件。当新的M文件加到一个缓存区时,只有当高速缓存由命令? path刷新时,MATLAB才能找到它们;另一方面,当修改缓存的M文件时,只有当以前编译过的版本由clear命令从内存中清除,MATLAB才识别这个变化。例如,? clear myfun,从内存中清除M文件函数myfun,或? clear 
functions,从内存中清除所有已编译的函数。
    24.  在变量mfilename函数内,有要执行的M文件的名字。例如,正在执行M文件function.m时,函数的工作空间包含变量mfilename,它包含函数字符串。这个变量也存在于脚本文件里,在这种情况下,它包含了要执行的脚本文件的名字。
    25.  M文件函数可象MATLAB命令一样工作,典型的MATLAB命令包括clear, disp, echo, diary, save, hold, load, more,和format。通常,调用一个函数把参量放在括号内。例如size(A)。然而,如果函数有字符串参量,那么,函数可按通常函数进行调用,如,disp( ' To be or 
not to be ' ),或象一个MATLAB命令来使用,如clear functions。换句话说,当要求MATLAB解释一个表达式? command argument时,MATLAB认为它如同? command( ' argument ' )一样。事实上,MATLAB命令本身能象函数那样调用!例如? format long和? format( ' long ' 
)二者都把数据变成长格式。类似地,? format short e等价于? format( ' short ' , ' e ' )。正如最后的例子所示,空格(逗号,分号)把各个命令参量分开。因此,? disp How about this? 
产生一个错误,因为命令disp只允许一个输入参量,不是三个。如果参量包含在引号里,那么MATLAB就忽略空格;例如,? disp ' How about this? ' 与? disp( ' How about this? ' )等价,并产生所希望的结果。
    总之,函数M文件提供了一个简单的扩展MATLAB功能的方法。事实上,MATLAB本身的许多标准函数就是M文件函数。


 

--

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bage.bbs@smth.org]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:210.766毫秒