суббота, 22 ноября 2014 г.

Octave. Функции

Поговорим о создании функций в Octave, но начнём с вызова. Основной способ выполнить функцию - указать её имя и список аргументов, например sin(pi/3). Можно, однако, использовать вызов через feval, при котором всё выражение записывается как список аргументов: feval("sin",pi/3). Ещё вариант - создать псевдоним для имени функции с помощью знака @, например f = @sin. После этого можно использовать вызов f(pi/3) или feval(f,pi/3).


Большинство функций Octave хранит в виде m-файлов, при этом имена файла и функции должны совпадать. Узнать место их размещения можно с помощью команды path. Редактировать список используемых программой директорий можно с помощью следующих функций. 
addpath("путь к каталогу") - добавить каталог.
genpath("путь к каталогу") - использует указанный каталог и все вложенные подкаталоги.
rmpath("путь к каталогу") - удаляет каталог из списка.

Теперь о функциях. Простейшее определение функции, которая не принимает аргументов и ничего не возвращает, будет иметь вид
function имя
    тело
endfunction
Если мы хотим что-то функции передать, то должны указать список аргументов (в круглых скобках).
function имя (аргументы)
    тело
endfunction
Наконец, если мы ожидаем получить какой-то результат, нужно также задать список возвращаемых значений (в квадратных скобках).
function результат = имя (аргументы)
    тело
endfunction

Иногда число аргументов функции заранее неизвестно. В этом случае список должен завершаться словом vagargin, которое становится именем вектора, содержащего вводимые значения.
function res = my_avg(varargin)
    res = sum(varargin)/length(varargin);
endfunction
Если по каким-то причинам неизвестно количество выходных данных, можно использовать вектор varargout = f (...).

Порой бывает удобно задать значения некоторых аргументов по умолчанию. Если при вызове функции данный аргумент не будет указан, то используется значение, указанное в определении.
function res = sin_amp(t,freq,phi=0)
    res = sin(2*pi*freq*t-phi);
endfunction
Т.к. начальная фаза здесь задана по умолчанию, при вызове её можно опустить: sin_amp(0.5,3).

Octave поддерживает рекурсию, т.е. вызов функцией самой себя. Исключение - некоторые встроенные функции, например, lsode. Вот "хрестоматийный" пример факториала
function res = fact (n)
    if (n > 0)
        res = n * fact(n-1);
    else
        res = 1;
    endif
endfunction

Сложную функцию можно разбить на более простые, записанные в пределах одного m-файла. При этом сначала записывается определение основной функции, а затем вспомогательных (вложенных).
function res = f(x)
    res = x * g(x);
endfunction
function res = g(x)
    res = x * x;
endfunction
Возможен и другой вариант.
function res = f(x)
    res = x * g();
    function t = g()
        t = x * x;
    endfunction
endfunction
Во втором примере вложенная функция имеет доступ к пространству переменных той функции, в которой она определена, поэтому стало возможным опустить список аргументов.

Наконец, если вашими функциями будет пользоваться кто-то ещё, полезно добавить проверку правильности обращения к ним. В частности, длина списка аргументов вызываемой функции хранится в переменной nargin, а списка возвращаемых значений - nargout. Есть функции для проверки типа данных isvector(), isreal() и пр. Если же обнаружена ошибка, завершить выполнение и вывести сообщение можно с помощь функции error("сообщение").

3 комментария:

  1. А зачем сделано чтобы имя функции совпадало с именем файла и как можно это отключить?

    ОтветитьУдалить
    Ответы
    1. Потому, что функция может быть только отдельным файлом, как в matlab до недавнего времени. Вызывая функцию, интерпретатор обращается к соответствующему файлу. Если имя будет другим, функция просто не найдётся.

      Удалить
    2. Потому, что функция может быть только отдельным файлом, как в matlab до недавнего времени. Вызывая функцию, интерпретатор обращается к соответствующему файлу. Если имя будет другим, функция просто не найдётся.

      Удалить