Constants in MATLAB

谁都会走 提交于 2019-11-28 17:47:48

I usually just define a variable with UPPER_CASE and place near the top of the file. But you have to take the responsibly of not changing its value.

Otherwise you can use MATLAB classes to define named constants.

Andrew Janke

Matlab has constants now. The newer (R2008a+) "classdef" style of Matlab OOP lets you define constant class properties. This is probably the best option if you don't require back-compatibility to old Matlabs. (Or, conversely, is a good reason to abandon back-compatibility.)

Define them in a class.

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

Then reference them from any other code using dot-qualification.

>> disp(MyConstants.SECONDS_PER_HOUR)
        3600

See the Matlab documentation for "Object-Oriented Programming" under "User Guide" for all the details.

There are a couple minor gotchas. If code accidentally tries to write to a constant, instead of getting an error, it will create a local struct that masks the constants class.

>> 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              

But the damage is local. And if you want to be thorough, you can protect against it by calling the MyConstants() constructor at the beginning of a function, which forces Matlab to parse it as a class name in that scope. (IMHO this is overkill, but it's there if you want it.)

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

The other gotcha is that classdef properties and methods, especially statics like this, are slow. On my machine, reading this constant is about 100x slower than calling a plain function (22 usec vs. 0.2 usec, see this question). If you're using a constant inside a loop, copy it to a local variable before entering the loop. If for some reason you must use direct access of constants, go with a plain function that returns the value.

For the sake of your sanity, stay away from the preprocessor stuff. Getting that to work inside the Matlab IDE and debugger (which are very useful) would require deep and terrible hacks.

Loren

MATLAB doesn't have an exact const equivalent. I recommend NOT using global for constants - for one thing, you need to make sure they are declared everywhere you want to use them. I would create a function that returns the value(s) you want. You might check out this blog post for some ideas.

mtrw

You might some of these answers How do I create enumerated types in MATLAB? useful. But in short, no there is not a "one-line" way of specifying variables whose value shouldn't change after initial setting in MATLAB.

Any way you do it, it will still be somewhat of a kludge. In past projects, my approach to this was to define all the constants as global variables in one script file, invoke the script at the beginning of program execution to initialize the variables, and include "global MYCONST;" statements at the beginning of any function that needed to use MYCONST. Whether or not this approach is superior to the "official" way of defining a function to return a constant value is a matter of opinion that one could argue either way. Neither way is ideal.

My way of dealing with constants that I want to pass to other functions is to use a struct:

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

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

It's not as clean as C header files, but it does the job and avoids MATLAB globals. If you wanted the constants all defined in a separate file (e.g., getConstants.m), that would also be easy:

params = getConstants();

Don't call a constant using myClass.myconst without creating an instance first! Unless speed is not an issue. I was under the impression that the first call to a constant property would create an instance and then all future calls would reference that instance, (Properties with Constant Values), but I no longer believe that to be the case. I created a very basic test function of the form:

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

With classes defined like:

classdef TestObj
    properties
        field = 10;
    end
end

or:

classdef TestHandleObj < handle
    properties
        field = 10;
    end
end

or:

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

For different cases of objects, handle-objects, nested objects etc (as well as assignment operations). Note that these were all scalars; I didn't investigate arrays, cells or chars. For N = 1,000,000 my results (for total elapsed time) were:

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)

I also created a Java class and ran a similar test:

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

The overhead in calling the Java object is high, but within the object, simple access and assign operations happen as fast as regular matlab objects. If you want reference behavior to boot, Java may be the way to go. I did not investigate object calls within nested functions, but I've seen some weird things. Also, the profiler is garbage when it comes to a lot of this stuff, which is why I switched to manually saving the times.

For reference, the Java class used:

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;
        }
     }
  }

On a related note, here's a link to a table of NIST constants: ascii table and a matlab function that returns a struct with those listed values: Matlab FileExchange

I use a script with simple constants in capitals and include teh script in other scripts tr=that beed them.

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

I do not mind about these being not constant. If I write "LEFT=3" then I wupold be plain stupid and there is no cure against stupidity anyway, so I do not bother. But I really hate the fact that this method clutters up my workspace with variables that I would never have to inspect. And I also do not like to use sothing like "turn(MyConstants.LEFT)" because this makes longer statements like a zillion chars wide, making my code unreadible.

What I would need is not a variable but a possibility to have real pre-compiler constants. That is: strings that are replaced by values just before executing the code. That is how it should be. A constant should not have to be a variable. It is only meant to make your code more readible and maintainable. MathWorks: PLEASE, PLEASE, PLEASE. It can't be that hard to implement this. . .

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!