MATLAB中的常量
我已经拥有了一大堆MATLAB代码,并且注意到了一堆关于代码的“魔力数字”。 通常,我喜欢用C,Ruby,PHP等语言编写这些常量。当用谷歌search这个问题的时候,我发现常量的“官方”方式是定义返回常量值的函数。 似乎kludgey,特别是因为MATLAB允许每个文件允许多个函数时,可以finicky。
这真的是最好的select吗?
我很想用/做类似C预处理器的东西来为我做这个。 (我发现mpp
是由类似的困境中的其他人制作的,但是看起来被抛弃了,代码不能编译,我不确定它是否能满足我的需求。
我通常只是用UPPER_CASE定义一个variables,并放在文件顶部附近。 但是你必须负责任地不改变它的价值。
否则,你可以使用MATLAB类来定义命名常量。
Matlab现在有常量。 Matlab OOP的更新(R2008a +)“classdef”风格允许您定义常量类属性。 如果您不需要与旧的Matlabs兼容,这可能是最好的select。 (或者相反,放弃后向兼容性是一个很好的理由。)
在一个类中定义它们。
classdef MyConstants properties (Constant = true) SECONDS_PER_HOUR = 60*60; DISTANCE_TO_MOON_KM = 384403; end end
然后使用点限定从其他任何代码中引用它们。
>> disp(MyConstants.SECONDS_PER_HOUR) 3600
有关所有详细信息,请参阅“用户指南”下的“面向对象编程”的Matlab文档。
有一些小小的陷阱。 如果代码意外地尝试写入一个常量,而不是得到一个错误,它将创build一个本地结构,掩盖了常量类。
>> 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()构造函数来防止它,这迫使Matlabparsing它作为该范围内的类名。 (恕我直言,这是矫枉过正,但它在那里,如果你想要的话)。
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,看这个问题 )。 如果在循环中使用常量,则在进入循环之前将其复制到局部variables。 如果由于某种原因,您必须使用直接访问常量,请使用返回值的普通函数。
为了您的理智,远离预处理器的东西。 要在Matlab IDE和debugging器(这非常有用)内部工作,需要深入而可怕的黑客行为。
MATLAB没有一个确切的常量等价物。 我build议不要使用全局常量 – 一方面,你需要确保它们在任何你想要使用它们的地方声明。 我会创build一个函数,返回你想要的值。 你可以看看这个博客文章的一些想法。
任何方式你做它,它仍然有点kludge。 在过去的项目中,我的方法是在一个脚本文件中将所有常量定义为全局variables,在程序执行开始时调用脚本初始化variables,并包含“global MYCONST;” 在需要使用MYCONST的任何函数的开始处的语句。 不pipe这种方法是否优于定义一个返回一个固定值的函数的“官方”方式,都是一个可以争论的问题。 这两种方式都不是理想的。
你可能会这些答案如何在MATLAB中创build枚举types? 有用。 但总之,在MATLAB中初始设置之后,没有一种“单行”的方式来指定其值不应该改变的variables。
我处理常量的方式是我想传递给其他函数的是使用一个结构:
% 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全局variables。 如果你想要在一个单独的文件中定义的常量(例如,getConstants.m),那么也很容易:
params = getConstants();
不要使用myClass.myconst
调用常量,而不要先创build实例! 除非速度不是问题。 我的印象是,第一次调用一个常量属性会创build一个实例,然后所有将来的调用都会引用这个实例( 常量值属性 ),但是我不再相信这种情况。 我创build了一个非常基本的testing函数:
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)
我也创build了一个Java类,并进行了类似的testing:
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可能是要走的路。 我没有调查嵌套函数内的对象调用,但我看到了一些奇怪的事情。 另外,当涉及到很多这些东西的时候,profiler是垃圾的,这就是为什么我切换到手动节省时间的原因。
作为参考,使用的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表和一个matlab函数返回一个结构与列出的值: Matlab FileExchange