Константы в MATLAB

Я вступил во владение кучей кода MATLAB и заметил кучу "магических чисел", разбросанных по коду. Как правило, мне нравится делать эти константы на таких языках, как C, Ruby, PHP и т. д. Когда я искал эту проблему, я обнаружил, что" официальный " способ иметь константы-определить функции, которые возвращают постоянное значение. Кажется kludgey, особенно потому, что MATLAB может быть привередливым, когда позволяет более одной функции на файл.

это действительно лучший вариант?

У меня возникает соблазн использовать / сделать что-то вроде препроцессора C, чтобы сделать это для меня. (Я обнаружил, что что-то называется mpp был сделан кем-то еще в аналогичном затруднительном положении, но он выглядит заброшенным. Код не компилируется, и я не уверен, что он удовлетворит мои потребности.)

8 ответов


обычно я просто определяю переменную с UPPER_CASE и помещаю ее в верхнюю часть файла. Но вы должны ответственно отнестись к тому, чтобы не менять его ценность.

в противном случае вы можете использовать классы MATLAB для определения именованных констант.


Matlab теперь имеет константы. Более новый (R2008a+) стиль "classdef" Matlab OOP позволяет определять свойства постоянного класса. Это, вероятно, лучший вариант, если вам не требуется обратная совместимость со старыми Matlabs. (Или, наоборот, это хороший повод отказаться от обратной совместимости.)

определите их в классе.

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

затем ссылаться на них из любого другого кода, используя dot-квалификацию.

>> disp(MyConstants.SECONDS_PER_HOUR)
        3600

см. документацию Matlab для " объектно-ориентированного Программирование" в разделе "Руководство пользователя" для всех деталей.

есть пара незначительных gotchas. Если код случайно попытается записать в константу, вместо получения ошибки он создаст локальную структуру, маскирующую класс констант.

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

другой gotcha заключается в том, что свойства и методы classdef, особенно такая статика, медленны. На моей машине чтение этой константы примерно в 100 раз медленнее, чем вызов простой функции (22 usec против 0,2 usec, см. этот вопрос). Если вы используете константу внутри цикла, скопируйте ее в локальную переменную перед входом в цикл. Если по какой-то причине вы должны использовать прямой доступ констант, перейдите к простая функция, возвращающая значение.

ради вашего здравомыслия, держитесь подальше от препроцессора. Чтобы заставить это работать внутри IDE Matlab и отладчика (которые очень полезны), потребуются глубокие и ужасные хаки.


MATLAB не имеет точного эквивалента const. Я рекомендую не использовать global для констант-во-первых, вам нужно убедиться, что они объявлены везде, где вы хотите их использовать. Я бы создал функцию, которая возвращает значение(ы), которое вы хотите. Вы можете проверить этот блог ради какой-то идеи.


вы могли бы некоторые из этих ответов Как создать перечисляемые типы в MATLAB? полезное. Короче говоря, нет "однострочного" способа задания переменных, значение которых не должно изменяться после начальной настройки в MATLAB.


в любом случае вы это сделаете, это все равно будет своего рода kludge. В прошлых проектах мой подход к этому заключался в определении всех констант как глобальных переменных в одном файле сценария, вызове сценария в начале выполнения программы для инициализации переменных и включении операторов "global MYCONST;" в начале любой функции, которая должна была использовать MYCONST. Независимо от того, превосходит ли этот подход "официальный" способ определения функции для возврата постоянного значения, это вопрос мнение, которое можно оспорить в любом случае. Ни один из способов не идеален.


мой способ работы с константами, которые я хочу передать другим функциям, - использовать структуру:

% 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();

не вызывайте константу с помощью myClass.myconst без создания экземпляра сначала! Если только скорость не проблема. У меня создалось впечатление, что первый вызов свойства constant создаст экземпляр, а затем все будущие вызовы будут ссылаться на этот экземпляр (свойства с постоянными значениями), но я уже не верю, что это так. Я создал очень простую тестовую функцию формы:

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


Я использую скрипт с простыми константами в прописных буквах и включаю скрипт в другие скрипты tr=that beed them.

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

Я не возражаю, что они не являются постоянными. Если я напишу "LEFT=3", тогда я буду просто глупым, и в любом случае нет лекарства от глупости, поэтому я не беспокоюсь. Но я действительно ненавижу тот факт, что этот метод загромождает мое рабочее пространство переменными, которые мне никогда не придется проверять. И я также не люблю использовать sothing, как " turn (MyConstants.ОСТАВИЛ)" потому что это делает больше заявлений в миллион символов в ширину, что делает мой код unreadible.

Мне нужна не переменная, а возможность иметь реальные константы перед компилятором. То есть: строки, которые заменяются значениями непосредственно перед выполнением кода. Так и должно быть. Константа не должна быть переменной. Он предназначен только для того, чтобы сделать ваш код более читаемым и доступным для обслуживания. MathWorks: пожалуйста, пожалуйста, пожалуйста. Это не может быть так сложно реализовать. . .