Различия между сгенерированным кодом и кодом MATLAB

Для преобразования MATLAB® генератор кода вводит оптимизацию, которая намеренно заставляет сгенерированный код вести себя по-другому, и иногда приводит к другим результатам, чем исходный исходный код.

Вот некоторые из различий:

Функции, которые имеют несколько возможных выходов

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

Для таких математических операций соответствующие функции в сгенерированном коде и MATLAB могут возвращать различные выходы для идентичных входных значений. Чтобы увидеть, имеет ли функция такое поведение, на соответствующей странице с описанием функции, смотрите раздел C/C++ Code Generation под Extended Capabilities. Примеры таких функций включают svd и eig.

Запись в ans Переменная

Когда вы запускаете код MATLAB, который возвращает выход, не задавая выходной аргумент, MATLAB неявно записывает выход в ans переменная. Если переменная ans уже существует в рабочей области, MATLAB обновляет свое значение до выхода, возвращенного.

Код, сгенерированный из такого кода MATLAB, неявно не записывает выход в ans переменная.

Для примера задайте функцию MATLAB foo который явно создает ans переменная в первой линии. Затем функция неявно обновляет значение ans при выполнении второй линии.

function foo %#codegen
ans = 1;
2;
disp(ans);
end

Выполняйте foo в командной строке. Окончательное значение ans, что 2, отображается в командной строке.

foo
2

Сгенерируйте MEX-функцию из foo.

codegen foo

Запустите сгенерированную MEX-функцию foo_mex. Эта функция явно создает ans переменная и присваивает значение 1 к нему. Но foo_mex неявно обновляет значение ans на 2.

foo_mex
1

Логическое короткое замыкание

Предположим, что ваш код MATLAB имеет логические операторы & и | размещен внутри квадратных скобок ([ и ]). Для таких шаблонов кода сгенерированный код не использует поведение короткого замыкания для этих логических операторов, но выполнение MATLAB может использовать поведение короткого замыкания. См. «Логическое короткое замыкание».

Для примера задайте функцию MATLAB foo который использует & оператор внутри квадратных скобок в условном выражении if...end блок.

function foo
if [returnsFalse() & hasSideEffects()]
end
end

function out = returnsFalse
out = false;
end

function out = hasSideEffects
out = true;
disp('This is my string');
end

Первый аргумент & оператор всегда false и определяет значение условного выражения. Таким образом, в выполнении MATLAB используется короткое замыкание, и второй аргумент не оценивается. Итак, foo не вызывает hasSideEffects функция во время выполнения и ничего не отображает в командной строке.

Сгенерируйте MEX-функцию для foo. Вызовите сгенерированную MEX-функцию foo_mex.

foo_mex
This is my string

В сгенерированном коде короткое замыкание не используется. Итак, hasSideEffects вызывается функция, и строка отображается в командной строке.

Переполнение индекса цикла

Предположим, что for-loop end value равно или близко к максимальному или минимальному значению для типа индексных данных цикла. В сгенерированном коде последний шаг или уменьшение индекса цикла может привести к переполнению индексной переменной. Переполнение индекса может привести к бесконечному циклу.

Когда проверки целостности памяти включены, если генератор кода обнаруживает, что индекс цикла может переполниться, он сообщает об ошибке. Проверка программных ошибок является консервативной. Это может неправильно сообщить о переполнении индекса цикла. По умолчанию проверки целостности памяти включены для кода MEX и отключены для автономного кода C/C + +. Смотрите, зачем тестировать MEX-функции в MATLAB? (MATLAB Coder) и Сгенерируйте автономный код C/C + +, который обнаруживает и сообщает об ошибках времени выполнения (MATLAB Coder).

Чтобы избежать переполнения индекса цикла, используйте обходные пути в этой таблице.

Условия цикла, вызывающие потенциальное переполнениеРабота
  • Индекс цикла увеличивается на 1.

  • Конечное значение равняется максимальному значению целого типа.

Если цикл не должен покрывать полную область значений целого типа, перепишите цикл так, чтобы конечное значение не равнялось максимальному значению целого типа. Для примера замените:

N=intmax('int16')
for k=N-10:N
с:
for k=1:10

  • Индекс цикла уменьшается на 1.

  • Конечное значение равняется минимальному значению целого типа.

Если цикл не должен покрывать полную область значений целого типа, перепишите цикл так, чтобы конечное значение не равнялось минимальному значению целого типа. Для примера замените:

N=intmin('int32')
for k=N+10:-1:N
с:
for k=10:-1:1

  • Индекс цикла увеличивается или уменьшается на 1.

  • Начальное значение равняется минимальному или максимальному значению целого типа.

  • Конечное значение равняется максимальному или минимальному значению целого типа.

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

M= intmin('int16');
N= intmax('int16');
for k=M:N
	% Loop body
end
как:
M= intmin('int16');
N= intmax('int16');
for k=int32(M):int32(N)
	% Loop body
end

  • Индекс цикла увеличивается или уменьшается на значение, не равное 1.

  • При последней итерации цикла индекс цикла не равен конечному значению.

Перепишите цикл так, чтобы индекс цикла в последней итерации цикла был равен конечному значению.

Индексация for Циклы при помощи операндов с одной точностью

Предположим, в вашем MATLABcode вы индексируете for цикл, который имеет оператор двоеточия, где, по крайней мере, один из операндов двоеточия является одним типом операнда, и количество итераций больше flintmax('single') = 16777216. Когда все эти условия верны, генерация кода может сгенерировать ошибки во время выполнения или во время компиляции, потому что сгенерированный код вычисляет другие значения для цикла индексной переменной, чем значения, которые вычисляет MATLAB.

Для примера рассмотрим этот код MATLAB:

function j = singlePIndex
n = flintmax('single') + 2;
j = single(0);
for i = single(1):single(n)
    j = i;
end
end

Этот фрагмент кода выполняется в MATLAB, но он вызывает компиляцию или ошибку времени выполнения, потому что значение цикла индексной переменной, i, вычисляется по-разному в сгенерированном коде. Генератор кода отображает время компиляции или ошибки времени выполнения и останавливает генерацию или выполнение кода, чтобы предотвратить это расхождение.

Чтобы избежать этого расхождения, замените операнды одинарного типа на операнды двойного или целого типа.

Для получения дополнительной информации об ошибках во время выполнения смотрите Генерация автономного кода C/C + +, который обнаруживает и сообщает об ошибках времени выполнения (MATLAB Coder).

Индекс неактивного for Цикл

В коде MATLAB и сгенерированном коде, после for выполнение цикла завершено, значение индексной переменной равно ее значению во время окончательной итерации for цикл.

В MATLAB, если цикл не выполняется, значение индексной переменной сохранено как [] (пустая матрица). В сгенерированном коде, если цикл не выполняется, значение индексной переменной отличается от индексной переменной.

  • Если вы предоставляете for начальная и конечная переменные цикла во время исполнения, значение индексной переменной равно началу области значений. Для примера рассмотрим этот код MATLAB:

    function out = indexTest(a,b)
    for i = a:b
    end
    out = i;
    end

    Предположим, что a и b передаются как 1 и -1. The for цикл не выполняется. В MATLAB, out присваивается []. В сгенерированном коде out присваивается значение a, что 1.

  • Если вы предоставляете for цикл начала и конца значений перед временем компиляции, значение индексной переменной равно 0. Рассмотрим этот код MATLAB:

    function out = indexTest
    for i = 1:-1
    end
    out = i;
    end

    Предположим, что вы вызываете эту функцию. В MATLAB, out присваивается []. В сгенерированном коде out присваивается значение 0.

Размер символа

MATLAB поддерживает 16-битные символы, но сгенерированный код представляет символы в 8 битах, стандартный размер для большинства встраиваемых языков, таких как C. См. Кодирование символов в генерации кода.

Порядок вычисления в выражениях

Сгенерированный код не применяет порядок вычисления в выражениях. Для большинства выражений порядок вычисления не является значимым. Для выражений, которые имеют побочные эффекты, сгенерированный код может привести к побочным эффектам в отличном от оригинального кода MATLAB порядке. Выражения, которые вызывают побочные эффекты, включают те, которые:

  • Изменение стойких или глобальных переменных

  • Отображение данных на экране

  • Запись данных в файлы

  • Изменение свойств объектов класса handle

В сложение сгенерированный код не применяет порядок оценки логических операторов, которые не замыкаются.

Для более предсказуемых результатов рекомендуется разделить выражения, которые зависят от порядка оценки, на несколько операторов.

  • Переписать

    A = f1() + f2();

    как

    A = f1();
    A = A + f2();

    так, что сгенерированный код вызывает f1 перед f2.

  • Назначьте выходные параметры мультивыходной функции вызова переменным, которые не зависят друг от друга. Для примера перепишите

    [y, y.f, y.g] = foo;

    как

    [y, a, b] = foo;
    y.f = a;
    y.g = b;
    

  • Когда вы получаете доступ к содержимому нескольких камер массива ячеек, присваивайте результаты переменным, которые не зависят друг от друга. Для примера перепишите

    [y, y.f, y.g] = z{:};
    

    как

    [y, a, b] = z{:};
    y.f = a;
    y.g = b;
    

Разрешение имен при построении указателей на функции

MATLAB и генерация кода следуют различным правилам приоритета для разрешения имен, которые следуют за символом @. Эти правила не применяются к анонимным функциям. Правила приоритета приведены в этой таблице.

ВыражениеПорядок приоритета в MATLABПорядок приоритета в генерации кода
Выражение, которое не содержит периодов, например @x

Вложенная функция, локальная функция, частная функция, функция пути

Локальная переменная, вложенная функция, локальная функция, частная функция, функция пути

Выражение, которое содержит только один период, например @x.y

Локальная переменная, функция пути

Локальная переменная, функция пути (то же, что и MATLAB)

Выражение, которое содержит более одного периода, например @x.y.z

Функция Path

Локальная переменная, функция пути

Если x является локальной переменной, которая сама является указателем на функцию, сгенерированный код и MATLAB интерпретируют выражение @x по-разному:

  • MATLAB создает ошибку.

  • Сгенерированный код интерпретирует @x как указатель на функцию x сам.

Вот пример, который показывает это различие в поведении для выражения, которое содержит два периода.

Предположим, что текущая рабочая папка содержит пакет x, который содержит другой пакет y, который содержит функцию z. Текущая рабочая папка также содержит функцию точки входа foo для которого вы хотите сгенерировать код.

Image of current folder showing the files z.m and foo.m with respect to the packages x and y.

Это определение файла foo:

function out = foo
    x.y.z = @()'x.y.z is an anonymous function';
    out = g(x);
end

function out = g(x)
    f = @x.y.z;
    out = f();
end

Это определение функции z:

function out = z
    out = 'x.y.z is a package function';
end

Сгенерируйте MEX-функцию для foo. Отдельно вызовите обеих сгенерированные MEX-функции foo_mex и функцию MATLAB foo.

codegen foo
foo_mex
foo
ans =

    'x.y.z is an anonymous function'


ans =

    'x.y.z is a package function'

Сгенерированный код создает первый выход. MATLAB выдает второй выход. Генерация кода разрешает @x.y.z к локальной переменной x который определен в foo. MATLAB разрешает @x.y.z на z, который находится в пакете x.y.

Поведение при разрыве

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

Размер N-D массивов переменного размера

Для N-D массивов переменного размера, size функция может вернуть другой результат сгенерированного кода, чем в исходном коде MATLAB. size функция иногда возвращает конечные таковые (синглтонные размерности) в сгенерированном коде, но всегда отбрасывает конечные таковые в MATLAB. Для примера - для N-D массива X с размерностями [4 2 1 1], size(X) может вернуться [4 2 1 1] в сгенерированном коде, но всегда возвращается [4 2] в MATLAB. См. «Несовместимость с MATLAB в определении размера массивов N-D переменного размера».

Размер пустых массивов

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

Размер пустого массива, который возникает в результате удаления элементов массива

Удаление всех элементов массива приводит к образованию пустого массива. Размер этого пустого массива в сгенерированном коде может отличаться от его размера в исходном коде MATLAB.

СлучайПример кодаРазмер пустого массива в MATLABРазмер пустого массива в сгенерированном коде
Удалите все элементы массива m-на-n с помощью colon оператор (:).
coder.varsize('X',[4,4],[1,1]);
X = zeros(2);
X(:) = [];
0-by-01-by-0
Удалите все элементы массива вектора-строки при помощи colon оператор (:).
coder.varsize('X',[1,4],[0,1]);
X = zeros(1,4);
X(:) = [];
0-by-01-by-0
Удалите все элементы массива вектора-столбца с помощью colon оператор (:).
coder.varsize('X',[4,1],[1,0]);
X = zeros(4,1);
X(:) = [];
0-by-00-by-1
Удалите все элементы массива вектора-столбца путем удаления одного элемента за раз.
coder.varsize('X',[4,1],[1,0]);
X = zeros(4,1);
for i = 1:4
    X(1)= [];
end
1-by-00-by-1

Двоичные элементно-мудрые операции с одним и двумя операндами

Если ваш код MATLAB содержит двоичную поэлементную операцию, которая включает один операнд типа и операнд двойного типа, сгенерированный код может не привести к тому же результату, что и MATLAB.

Для такой операции MATLAB переводит оба операнда в двойной тип и выполняет операцию с двойными типами. MATLAB затем приводит результат к одному типу и возвращает его.

Сгенерированный код переводит операнд двойного типа в один тип. Затем он выполняет операцию с двумя отдельными типами и возвращает результат.

Для примера задайте функцию MATLAB foo который вызывает двоичную поэлементную операцию plus.

function out = foo(a,b)
out = a + b;
end

Задайте переменную s1 одного типа и переменной v1 двойного типа. Сгенерируйте MEX-функцию для foo который принимает вход одного типа и вход двойного типа.

s1 = single(1.4e32); 
d1 = -5.305e+32; 
codegen foo -args {s1, d1} 

Вызовите оба foo и foo_mex с входами s1 и d1. Сравните два результата.

ml = foo(s1,d1); 
mlc = foo_mex(s1,d1);
ml == mlc
ans =

  logical

   0

Выходы сравнения являются логическим 0, что указывает, что сгенерированный код и MATLAB дают различные результаты для этих входов.

Численные результаты с плавающей точкой

Сгенерированный код может не привести к таким же численным результатам с плавающей точкой, как MATLAB в следующих:

 Когда компьютерное оборудование использует расширенные регистры точности

 Для некоторых расширенных библиотечных функций

 Для реализации функций библиотеки BLAS

NaN и бесконечность

Сгенерированный код может не создать точно такой же шаблон NaN и Inf значения как код MATLAB, когда эти значения математически бессмысленны. Например, если выход MATLAB содержит NaN, выход из сгенерированного кода должен также содержать NaN, но не обязательно там же.

Битовый шаблон для NaN может отличаться между выходом кода MATLAB и выходом сгенерированного кода, потому что C99 стандартная математическая библиотека, которая используется для генерации кода, не задает уникальный битовый шаблон для NaN во всех реализациях. Избегайте сравнения битовых шаблонов в различных реализациях, например, между выходом MATLAB и выходом SIL или PIL.

Отрицательный нуль

В типе с плавающей точкой значение 0 имеет либо положительный, либо отрицательный знак. Арифметически 0 равно -0, но некоторые операции чувствительны к знаку входа 0. Примеры включают rdivide, atan2, atan2d, и angle. Деление по 0 производит Inf, но деление по -0 производит -Inf. Точно так же atan2d(0,-1) производит 180, но atan2d (-0,-1) производит -180.

Если генератор кода обнаруживает, что переменная с плавающей точкой принимает только целочисленные значения подходящей области значений, то генератор кода может использовать целый тип для переменной в сгенерированном коде. Если генератор кода использует целый тип для переменной, то переменная сохраняет -0 как +0 поскольку целый тип не хранит знак значения 0. Если сгенерированный код возвращает переменную к типу с плавающей точкой, знак 0 положительно. Деление по 0 производит Inf, не -Inf. Точно так же atan2d(0,-1) производит 180, не -180.

Существуют другие контексты, в которых сгенерированный код может обрабатывать -0 по-другому, чем MATLAB. Например, предположим, что ваш код MATLAB вычисляет минимум два скалярных двойки x и y при помощи z = min(x,y). Соответствующая линия в сгенерированном коде C может быть z = fmin(x,y). Функция fmin определяется в математической библиотеке во время выполнения компилятора C. Потому что операция сравнения 0.0 == -0.0 возвращает true на C/C + +, реализация компилятором fmin может вернуться либо 0.0 или -0.0 для fmin(0.0,-0.0).

Цель генерации кода

coder.target функция возвращает в MATLAB другие значения, чем в сгенерированном коде. Цель состоит в том, чтобы помочь вам определить, выполняется ли ваша функция в MATLAB или была скомпилирована для цели симуляции или генерации кода. Посмотрите coder.target.

Инициализация свойства класса MATLAB

Перед генерацией кода, во время загрузки класса, MATLAB вычисляет значения по умолчанию класса. Генератор кода использует значения, которые вычисляет MATLAB. Значения по умолчанию не пересчитываются. Если в определении свойства используется вызов функции для вычисления начального значения, генератор кода не выполняет эту функцию. Если функция имеет побочные эффекты, такие как изменение глобальной переменной или постоянной переменной, то возможно, что сгенерированный код может привести к другим результатам, чем MATLAB. Для получения дополнительной информации смотрите Определение свойств класса для Генерации кода.

Классы MATLAB в назначениях вложенных свойств, которые имеют установленные методы

Когда вы присваиваете значение свойству указателя объекта, которое само является свойством другого объекта, и так далее, то сгенерированный код может вызвать методы set для классов handle, которые MATLAB не вызывает.

Например, предположим, что вы задаете набор переменных, таких что x является указатели объекта, pa является объектом, pb является указатели объекта и pc является свойством pb. Затем вы делаете вложенное назначение свойств, такое как:

x.pa.pb.pc = 0;

В этом случае сгенерированный код вызывает метод set для объекта pb и метод набора для x. MATLAB вызывает только метод set для pb.

Классы Handle MATLAB

Поведение деструкторов классов handle в сгенерированном коде может отличаться от поведения в MATLAB в таких ситуациях:

  • Порядок уничтожения нескольких независимых объектов может отличаться в MATLAB, чем в сгенерированном коде.

  • Время жизни объектов в сгенерированном коде может отличаться от времени их жизни в MATLAB.

  • Сгенерированный код не уничтожает частично построенные объекты. Если объект указатель не полностью построен во время исполнения, сгенерированный код выдает сообщение об ошибке, но не вызывает delete метод для этого объекта. Для системного object™, если существует ошибка времени выполнения в setupImplсгенерированный код не вызывает releaseImpl для этого объекта.

    MATLAB вызывает delete способ уничтожения частично построенного объекта.

Для получения дополнительной информации смотрите Генерацию кода для деструкторов классов Handle.

Данные переменного размера

Смотрите Несовместимость с MATLAB в поддержке переменного размера для генерации кода.

Комплексные числа

Смотрите Генерацию кода для комплексных данных.

Преобразование строк с последовательными унарными операторами в double

Преобразование строки, которая содержит несколько последовательных унарных операторов в double может привести к различным результатам между MATLAB и сгенерированным кодом. Рассмотрим эту функцию:

function out = foo(op)
out = double(op + 1);
end

Для значения входа "--"функция преобразует строку "--1" на double. В MATLAB ответ следующий NaN. В сгенерированном коде ответ следующий 1.