MATLAB中的常量

时间:2009-11-20 23:24:17

标签: matlab constants matlab-class

我已经掌握了一堆MATLAB代码,并注意到代码中散布着一堆“神奇的数字”。通常,我喜欢用C,Ruby,PHP等语言制作这些常量。当谷歌搜索这个问题时,我发现拥有常量的“官方”方式是定义返回常量值的函数。看似kludgey,特别是因为当每个文件允许多个函数时,MATLAB可能很苛刻。

这真的是最好的选择吗?

我很想使用/制作类似C预处理器的东西来为我做这件事。 (我发现名为mpp的东西是由处于类似困境的其他人制作的,但它看起来已经废弃。代码无法编译,我不确定它是否能满足我的需求。)

8 个答案:

答案 0 :(得分:35)

Matlab现在有常量。 Matlab OOP的较新(R2008a +)“classdef”样式允许您定义常量类属性。如果您不需要与旧Matlabs的后兼容性,这可能是最佳选择。 (或者,反过来说,这是放弃兼容性的一个很好的理由。)

在课堂上定义它们。

classdef MyConstants
    properties (Constant = true)
        SECONDS_PER_HOUR = 60*60;
        DISTANCE_TO_MOON_KM = 384403;
    end
end

然后使用点限定从任何其他代码引用它们。

>> disp(MyConstants.SECONDS_PER_HOUR)
        3600

有关所有详细信息,请参阅“用户指南”下的“面向对象编程”的Matlab文档。

有一些小问题。如果代码意外地尝试写入常量而不是出错,它将创建一个掩盖常量类的本地结构。

>> MyConstants.SECONDS_PER_HOUR
ans =
        3600
>> MyConstants.SECONDS_PER_HOUR = 42
MyConstants = 
    SECONDS_PER_HOUR: 42
>> whos
  Name             Size            Bytes  Class     Attributes

  MyConstants      1x1               132  struct              
  ans              1x1                 8  double              

但是伤害是局部的。如果你想要彻底,你可以通过在函数的开头调用MyConstants()构造函数来防止它,这迫使Matlab将其解析为该范围中的类名。 (恕我直言,这是矫枉过正,但如果你想要的话,它会在那里。)

function broken_constant_use
MyConstants(); % "import" to protect assignment
MyConstants.SECONDS_PER_HOUR = 42 % this bug is a syntax error now

另一个问题是classdef属性和方法,特别是像这样的静态,很慢。在我的机器上,读取此常量比调用普通函数慢约100倍(22 usec vs. 0.2 usec,请参阅this question)。如果在循环内使用常量,则在进入循环之前将其复制到局部变量。如果由于某种原因必须使用常量的直接访问,请使用返回值的普通函数。

为了您的理智,远离预处理器的东西。让它在Matlab IDE和调试器(非常有用)中工作将需要深刻而可怕的黑客攻击。

答案 1 :(得分:19)

我通常只使用UPPER_CASE定义一个变量并放在文件顶部附近。但你必须负责任地不改变它的价值。

否则你可以use MATLAB classes来定义命名常量。

答案 2 :(得分:7)

MATLAB没有精确的const等价物。我建议不要使用global作为常量 - 首先,你需要确保它们在你想要使用它们的任何地方声明。我会创建一个返回所需值的函数。您可以查看this blog post了解一些想法。

答案 3 :(得分:4)

您可能会对其中一些答案How do I create enumerated types in MATLAB?有用。但简而言之,没有一种“单行”方式可以指定在MATLAB中初始设置后值不应该改变的变量。

答案 4 :(得分:2)

无论你怎么做,它仍然会成为一种混乱。在过去的项目中,我的方法是在一个脚本文件中将所有常量定义为全局变量,在程序执行开始时调用脚本以初始化变量,并包括“global MYCONST;”需要使用MYCONST的任何函数开头的语句。这种方法是否优于定义函数以返回常量值的“官方”方式,这是一个人们可以争论的方式。这两种方式都不理想。

答案 5 :(得分:1)

我处理我想传递给其他函数的常量的方法是使用struct:

% Define constants
params.PI = 3.1416;
params.SQRT2 = 1.414;

% Call a function which needs one or more of the constants
myFunction( params ); 

它不像C头文件那样干净,但它可以完成工作并避免使用MATLAB全局变量。如果你想要在一个单独的文件中定义的常量(例如,getConstants.m),这也很容易:

params = getConstants();

答案 6 :(得分:0)

不首先使用myClass.myconst调用常量而不创建实例!除非速度不是问题。我的印象是,对常量属性的第一次调用会创建一个实例,然后所有将来的调用都将引用该实例(Properties with Constant Values),但我不再相信这种情况。我创建了一个非常基本的测试函数:

tic;
for n = 1:N
    a = myObj.field;
end
t = toc;

定义类如下:

classdef TestObj
    properties
        field = 10;
    end
end

或:

classdef TestHandleObj < handle
    properties
        field = 10;
    end
end

或:

classdef TestConstant
    properties (Constant)
        field = 10;
    end
end

对于对象,句柄对象,嵌套对象等的不同情况(以及赋值操作)。请注意,这些都是标量;我没有调查数组,单元格或字符。对于N = 1,000,000,我的结果(总耗用时间)为:

Access(s)  Assign(s)  Type of object/call
  0.0034    0.0042    'myObj.field' 
  0.0033    0.0042    'myStruct.field'  
  0.0034    0.0033    'myVar'                   //Plain old workspace evaluation
  0.0033    0.0042    'myNestedObj.obj.field'   
  0.1581    0.3066    'myHandleObj.field'   
  0.1694    0.3124    'myNestedHandleObj.handleObj.field'   
 29.2161         -    'TestConstant.const'      //Call directly to class(supposed to be faster)
  0.0034         -    'myTestConstant.const'    //Create an instance of TestConstant
  0.0051    0.0078    'TestObj > methods'       //This calls get and set methods that loop internally
  0.1574    0.3053    'TestHandleObj > methods' //get and set methods (internal loop)

我还创建了一个Java类并运行了类似的测试:

 12.18     17.53      'jObj.field > in matlab for loop'
  0.0043    0.0039    'jObj.get and jObj.set loop N times internally'

调用Java对象的开销很高,但在对象内,简单的访问和分配操作的发生速度与常规的matlab对象一样快。如果您想要引用引用行为,那么Java可能就是您的选择。我没有调查嵌套函数中的对象调用,但我看到了一些奇怪的事情。此外,当涉及到很多这样的东西时,探查器是垃圾,这就是我切换到手动保存时间的原因。

供参考,使用的Java类:

public class JtestObj {
    public double field = 10;

    public double getMe() {
        double N = 1000000;
        double val = 0;
        for (int i = 1; i < N; i++) {
            val = this.field;
        }

        return val;
     }

     public void setMe(double val) {
        double N = 1000000;
        for (int i = 1; i < N; i++){
            this.field = val;
        }
     }
  }

在相关的说明中,这里是一个NIST常量表的链接:ascii table和一个matlab函数,它返回一个包含这些列出值的结构:Matlab FileExchange

答案 7 :(得分:0)

我在大写字母中使用带有简单常量的脚本,并在其他脚本中包含teh脚本tr =将它们作为它们。

LEFT  = 1;
DOWN  = 2;
RIGHT = 3; etc.

我不介意这些不恒定。如果我写“LEFT = 3”那么我觉得很愚蠢,无论如何都没有治愈愚蠢的方法,所以我不打扰。 但我真的很讨厌这个方法使用我永远不必检查的变量来混乱我的工作空间这一事实。而且我也不喜欢使用像“turn(MyConstants.LEFT)”之类的东西,因为这会使得更长的语句像zillion chars一样广泛,使我的代码变得不可读。

我需要的不是变量,而是有可能拥有真正的预编译器常量。即:在执行代码之前由值替换的字符串。应该是这样的。常量不应该是变量。它只是为了使您的代码更易读和可维护。 MathWorks:请,请,请。实现这一点并不难。 。 。