Константы в MATLAB

39

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

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

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

Теги:
constants
matlab-class

7 ответов

19
Лучший ответ

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

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

  • 6
    Обычно я использую класс MATLAB для хранения всех моих настраиваемых параметров. Это также дает вам возможность создавать несколько конфигураций и легко их менять и заменять. Вы даже можете создать массив конфигураций и выполнить итерацию по всему массиву, выполняя тестовый код для каждой конфигурации по очереди.
33

Теперь Matlab имеет константы. Новый (R2008a +) "classdef" стиль Matlab OOP позволяет определять свойства постоянного класса. Вероятно, это лучший вариант, если вам не нужна обратная совместимость со старыми 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 против 0.2 usec, см. этот вопрос). Если вы используете константу внутри цикла, скопируйте ее в локальную переменную перед входом в цикл. Если по какой-то причине вы должны использовать прямой доступ к константам, перейдите к простой функции, которая возвращает значение.

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

  • 4
    Я хотел бы использовать объектно - ориентированного программирования вещи , введенные в более новых версиях Matlab, но это делает вещи удручающе медленно в наших тестах. (Выполнение простой функции 100 000 раз перешло от 0,0837 до 2,3869 секунд при переходе от вложенных функций к ООП-материалам.) Большая часть того, что мы пишем, должна быть достаточно оптимизирована, так что издержки довольно сдерживающие.
  • 0
    (Я могу опубликовать код, если хотите.)
Показать ещё 3 комментария
7

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

2

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

2

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

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

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

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

  • 0
    Я заметил, что Эндрю недавно сделал обновление скорости Matlab. Возможно, более полезный, чем мой: stackoverflow.com/questions/1693429/…

Ещё вопросы

Сообщество Overcoder
Наверх
Меню