40

私は一連の MATLAB コードを所有するようになり、コードに散在する一連の「マジック ナンバー」に気付きました。通常、私はこれらの定数を C、Ruby、PHP などの言語で作成するのが好きです。この問題をグーグルで検索すると、定数を持つ「公式の」方法は、定数値を返す関数を定義することであることがわかりました。特に、ファイルごとに複数の関数を許可する場合、MATLAB は扱いにくい場合があるため、面倒に思えます。

これは本当に最良の選択肢ですか?

私はこれを行うためにCプリプロセッサのようなものを使用/作成したいと思っています。(同じような苦境にある誰かが作ったものを見つけましたmppが、放棄されたようです。コードはコンパイルされず、私のニーズを満たすかどうかわかりません。)

4

8 に答える 8

35

Matlabには現在定数があります。新しい(R2008a +)「classdef」スタイルのMatlab OOPを使用すると、定数クラスのプロパティを定義できます。古いMatlabとの下位互換性が必要ない場合は、これがおそらく最良のオプションです。(または、逆に、下位互換性を放棄する正当な理由です。)

それらをクラスで定義します。

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

もう1つの落とし穴は、classdefのプロパティとメソッド、特にこのような静的メソッドが遅いことです。私のマシンでは、この定数の読み取りは、プレーン関数を呼び出すよりも約100倍遅くなります(22usec対0.2usec、この質問を参照)。ループ内で定数を使用している場合は、ループに入る前に定数をローカル変数にコピーしてください。何らかの理由で定数への直接アクセスを使用する必要がある場合は、値を返す単純な関数を使用してください。

あなたの正気のために、プリプロセッサのものから離れてください。これをMatlabIDEとデバッガー(非常に便利です)内で機能させるには、深くてひどいハックが必要になります。

于 2009-11-23T17:06:42.407 に答える
21

私は通常、変数を UPPER_CASE で定義し、ファイルの先頭近くに配置します。ただし、その値を変更しないという責任を負う必要があります。

それ以外の場合は、MATLAB クラスを使用して名前付き定数を定義できます。

于 2009-11-20T23:31:40.430 に答える
8

MATLAB には、正確に等価な const はありません。定数に global を使用しないことをお勧めします。1 つには、使用するすべての場所で宣言されていることを確認する必要があります。必要な値を返す関数を作成します。いくつかのアイデアについては、このブログ投稿をチェックしてください。

于 2010-10-21T14:09:04.393 に答える
4

MATLAB で列挙型を作成するにはどうすればよいですか? 使える。しかし要するに、MATLAB での初期設定後に値が変更されるべきではない変数を指定する「1 行」の方法はありません。

于 2009-11-20T23:28:48.873 に答える
2

いずれにせよ、それはまだやや面倒です。過去のプロジェクトでは、これに対する私のアプローチは、すべての定数を 1 つのスクリプト ファイルでグローバル変数として定義し、プログラム実行の開始時にスクリプトを呼び出して変数を初期化し、「global MYCONST;」を含めることでした。MYCONST を使用する必要がある関数の先頭にあるステートメント。このアプローチが、定数値を返す関数を定義する「公式」の方法よりも優れているかどうかは、どちらの方法でも議論できる意見の問題です。どちらの方法も理想的ではありません。

于 2009-11-20T23:56:17.027 に答える
1

他の関数に渡したい定数を処理する私の方法は、構造体を使用することです。

% 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();
于 2014-11-26T20:07:50.820 に答える
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 テーブルと、それらのリストされた値を含む構造体を返す matlab 関数: Matlab FileExchange

于 2012-02-24T17:57:07.580 に答える