主要内容

生成的代码和MATLAB代码

MATLAB转换®代码转换为高效的C/ c++代码,代码生成器引入优化,有意地导致生成的代码的行为与原始源代码不同,有时产生不同的结果。

以下是一些不同之处:

运行程序时,运行时错误检查可以检测到其中一些差异。默认情况下,运行时错误检查对MEX代码启用,对独立的C/ c++代码禁用。为了帮助您在部署代码之前识别和处理差异,代码生成器将差异的一个子集报告为潜在的差异

具有多个可能输出的函数

某些数学运算,如矩阵的奇异值分解和特征值分解,可以有多个答案。实现这种操作的两种不同算法可以对相同的输入值返回不同的输出。同一算法的两个不同实现也可以表现出相同的行为。

对于这样的数学运算,生成的代码和MATLAB中对应的函数对于相同的输入值可能会返回不同的输出。若要查看函数是否具有此行为,请在相应的函数参考页中参阅C/ c++代码生成下节扩展功能.此类函数的示例包括圣言会而且eig

写信给变量

运行返回输出而不指定输出参数的MATLAB代码时,MATLAB隐式地将输出写入变量。如果变量如果工作空间中已经存在,MATLAB将其值更新为返回的输出。

从这样的MATLAB代码生成的代码并不隐式地将输出写入变量。

例如,定义MATLAB函数喷火显式地创建变量。函数然后隐式地更新值当第二行执行时。

函数喷火% # codegenAns = 1;2;disp (ans);结束

运行喷火在命令行。的最终值,即2,在命令行显示。

喷火
2

生成一个MEX函数喷火

codegen喷火

运行生成的MEX函数foo_mex.此函数显式地创建变量并赋值1到它。但foo_mex的值未隐式更新2

foo_mex
1

逻辑短路

假设你的MATLAB代码有逻辑运算符而且|放在方括号内(而且).对于这种代码模式,生成的代码不会为这些逻辑运算符使用短路行为,但MATLAB执行可能会使用短路行为。看到逻辑短路

例如,定义MATLAB函数喷火它使用类的条件表达式中方括号内的运算符如果……块。

函数喷火如果[returnsFalse() & hasSideEffects()]结束结束函数out = returnsFalse out = false;结束函数out = hasSideEffects out = true;disp (“这是我的绳子”);结束

的第一个参数运算符总是并确定条件表达式的值。因此,在MATLAB执行中,采用短路,不计算第二个参数。所以,喷火不调用hasSideEffects函数,并且不会在命令行中显示任何内容。

生成的MEX函数喷火.调用生成的MEX函数foo_mex

foo_mex
这是我的字符串

在生成的代码中,不使用短路。所以,hasSideEffects函数被调用,字符串显示在命令行上。

循环索引溢出

假设a-loop结束值等于或接近循环索引数据类型的最大值或最小值。在生成的代码中,循环索引的最后一个递增或递减可能导致索引变量溢出。索引溢出可能导致无限循环。

当启用内存完整性检查时,如果代码生成器检测到循环索引可能溢出,它将报告一个错误。软件错误检查比较保守。它可能错误地报告循环索引溢出。默认情况下,对MEX代码启用内存完整性检查,对独立C/ c++代码禁用内存完整性检查。看到为什么在MATLAB中测试MEX函数?而且生成独立的C/ c++代码来检测和报告运行时错误

要避免循环索引溢出,请使用本表中的变通方法。

导致潜在溢出的循环条件 解决方案
  • 循环索引增加1。

  • 结束值等于该整型的最大值。

如果循环不必覆盖整型的全部范围,则重写循环,使结束值不等于整型的最大值。例如,replace:

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

  • 循环索引减1。

  • 结束值等于整数类型的最小值。

如果循环不必覆盖整型的全部范围,则重写循环,使结束值不等于整型的最小值。例如,replace:

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

  • 循环索引加或减1。

  • 起始值等于整数类型的最小值或最大值。

  • 结束值等于整数类型的最大值或最小值。

如果循环必须覆盖整型类型的全部范围,则将循环开始值、步骤值和结束值的类型强制转换为更大的整数或加倍。例如,重写:

M = intmin(“int16”);N = intmax(“int16”);对于k=M:N %环体端
为:
M = intmin(“int16”);N = intmax(“int16”);for k=int32(M):int32(N) %循环体结束

  • 循环索引以不等于1的值递增或递减。

  • 在最后一次循环迭代中,循环索引不等于结束值。

重写循环,使最后一次循环迭代中的循环索引等于结束值。

索引使用单精度操作数进行循环

假设在你的MATLAB代码中,你索引a具有冒号操作符的循环,其中冒号操作数中至少有一个是单一类型操作数,且迭代次数大于Flintmax ('single') = 16777216.当所有这些条件都为真时,代码生成可能会生成运行时或编译时错误,因为生成的代码为循环索引变量计算的值与MATLAB计算的值不同。

例如,考虑下面的MATLAB代码:

函数j = singlePIndex n = flintmax(“单一”) + 2;J =单(0);I = single(1):single(n) j = I;结束结束

这段代码在MATLAB中执行,但它会导致编译时或运行时错误,因为循环索引变量的值,,在生成的代码中以不同的方式计算。代码生成器显示编译时或运行时错误,并停止代码生成或执行以防止这种差异。

要避免这种差异,请将单类型操作数替换为双类型或整型操作数。

有关运行时错误的详细信息,请参见生成独立的C/ c++代码来检测和报告运行时错误

Unentered的索引循环

在你的MATLAB代码和生成的代码之后循环执行完成后,索引变量的值等于其在最后迭代期间的值循环。

在MATLAB中,如果循环没有执行,则索引变量的值存储为[](空矩阵)。在生成的代码中,如果循环没有执行,则索引变量的值与MATLAB索引变量的值不同。

  • 如果你提供循环开始和结束变量在运行时,索引变量的值等于范围的开始。例如,考虑下面的MATLAB代码:

    函数out = indexTest(a,b)I = a:b结束Out = i;结束

    假设一个而且b传递为1而且-1.的循环不执行。在MATLAB中,赋值为[]。在生成的代码中,赋值为一个,即1

  • 如果你提供循环的开始值和结束值在编译之前,索引变量的值在MATLAB和生成的代码中都被赋值[]。考虑下面的MATLAB代码:

    函数out = indexTestI = 1:-1结束Out = i;结束

    在MATLAB和生成的代码中,赋值为[]。

字符长度

MATLAB支金宝app持16位字符,但生成的代码表示8位字符,这是大多数嵌入式语言(如c)的标准尺寸代码生成中的字符编码

表达式的求值顺序

生成的代码不会强制表达式中的求值顺序。对于大多数表达式,求值的顺序并不重要。对于有副作用的表达式,生成的代码可能会以与原始MATLAB代码不同的顺序产生副作用。产生副作用的表达式包括:

  • 修改持久变量或全局变量

  • 将数据显示到屏幕上

  • 将数据写入文件

  • 修改句柄类对象的属性

此外,生成的代码不会强制执行不会短路的逻辑运算符的求值顺序。

为了获得更可预测的结果,将依赖于求值顺序的表达式拆分为多个语句是一种良好的编码实践。

  • 重写

    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

路径功能

局部变量,路径函数

如果x局部变量本身就是一个函数句柄,生成的代码和MATLAB解释的表达式@x不同:

  • MATLAB产生一个错误。

  • 生成的代码解释@x的函数句柄x本身。

下面的示例显示了包含两个句点的表达式的这种行为差异。

假设您当前的工作文件夹包含一个包x,其中包含另一个包y,其中包含函数z.当前工作文件夹还包含入口点函数喷火你想为它生成代码。

显示文件z.m和foo的当前文件夹的图像。M相对于x和y。

这是文件的定义喷火

函数Out = foo X.Y.Z = @()x.y.z是一个匿名函数;Out = g(x);结束函数Out = g(x) f = @x.y.z;Out = f();结束

这就是函数的定义z

函数Out = z Out =x.y.z是一个包函数结束

生成的MEX函数喷火.分别调用两个生成的MEX函数foo_mex和MATLAB函数喷火

codegen喷火foo_mex foo
Ans = 'x.y.z是一个匿名函数'

生成的代码产生第一个输出。MATLAB生成第二个输出。代码生成解决@x.y.z到局部变量x它被定义为喷火.MATLAB解决@x.y.zz,这是在包内x.y

终止的行为

生成的代码与MATLAB源代码的终止行为不匹配。例如,如果无限循环没有副作用,优化将从生成的代码中删除它们。因此,即使相应的MATLAB代码没有终止,生成的代码也可能终止。

可变大小N-D数组的大小

对于可变大小的N-D数组,大小函数可能会在生成的代码中返回与MATLAB源代码不同的结果。的大小函数有时在生成的代码中返回尾随数(单例维度),但在MATLAB中总是删除尾随数。例如,对于N-D数组X与维[4 2 1 1]大小(X)可能会返回[4 2 1 1],但总是返回(4 - 2)在MATLAB。看到变尺寸N-D数组尺寸的确定与MATLAB不兼容

空数组的大小

生成代码中的空数组的大小可能与MATLAB源代码中的大小不同。看到在确定空数组的大小与MATLAB不兼容

删除数组元素导致的空数组大小

删除数组的所有元素将导致数组为空。生成代码中此空数组的大小可能与MATLAB源代码中的大小不同。

情况下 示例代码 MATLAB中空数组的大小 生成代码中空数组的大小
方法删除m × n数组的所有元素结肠操作符().
coder.varsize (“X”(4, 4), [1]);X = 0 (2);X(:) = [];
0-by-0 1-by-0
方法删除行向量的所有元素结肠操作符().
coder.varsize (“X”[1,4], [0, 1]);X = 0 (1,4);X(:) = [];
0-by-0 1-by-0
方法删除列向量的所有元素结肠操作符().
coder.varsize (“X”(4,1), (1,0));X = 0 (4,1);X(:) = [];
0-by-0 0-by-1
通过每次删除一个元素来删除列向量的所有元素。
coder.varsize (“X”(4,1), (1,0));X = 0 (4,1);i = 1:4 X(1)= [];结束
1-by-0 0-by-1

具有单操作数和双操作数的二元元素操作

如果MATLAB代码包含二进制元素操作,其中涉及单类型操作数和双类型操作数,则生成的代码可能不会产生与MATLAB相同的结果。

对于这样的操作,MATLAB将两个操作数强制转换为双类型,并使用双类型执行操作。然后MATLAB将结果转换为单一类型并返回。

生成的代码将双类型操作数转换为单类型。然后,它对两个单一类型执行操作并返回结果。

例如,定义一个MATLAB函数喷火调用二进制元素的操作+

函数Out = foo(a,b) Out = a + b;结束

定义一个变量s1单一类型和一个变量v1双型的。生成的MEX函数喷火它接受单类型输入和双类型输入。

S1 = single(1.4e32);D1 = -5.305e+32;codegen喷火arg游戏{s1, d1}

叫两个喷火而且foo_mex与输入s1而且d1.比较这两个结果。

Ml = foo(s1,d1);MLC = foo_mex(s1,d1);Ml == MLC
Ans =逻辑0

比较的输出是逻辑的0,这表明所生成的代码和MATLAB对这些输入产生不同的结果。

浮点数值结果

生成的代码可能不会产生与MATLAB相同的浮点数值结果:

当计算机硬件使用扩展精度寄存器时

用于某些高级库函数

用于实现BLAS库功能

NaN和无穷大

所生成的代码可能不会产生完全相同的模式而且当这些值在数学上没有意义时,可以用MATLAB代码来表示。例如,如果MATLAB输出包含一个,生成代码的输出也应该包含,但不一定在同一个地方。

的位模式MATLAB代码输出和生成的代码输出之间可能存在差异,因为用于生成代码的C99语言标准没有为在所有实现中。避免在不同的实现之间比较位模式,例如MATLAB输出和SIL或PIL输出之间。

负0

在浮点类型中,值0有正号或负号。用算术方法,0等于-0,但有些操作对0输入的符号很敏感。例子包括rdivide量化atan2d,.除0生产,但除以-0生产.同样的,atan2d (0, 1)生产180,但atan2d (0, 1)生产-180年

如果代码生成器检测到浮点变量只接受合适范围内的整数值,则代码生成器可以在生成的代码中为该变量使用整型。如果代码生成器对变量使用整数类型,则变量存储-0作为+ 0因为整数类型不存储值的符号0.如果生成的代码将变量转换回浮点类型,则0是正的。除0生产,而不是.同样的,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返回真正的在C/ c++中,编译器的实现fmin也可能返回0.0-0.0fmin (0.0, -0.0)

代码生成目标

coder.target函数在MATLAB中返回的值与在生成代码中返回的值不同。目的是帮助您确定函数是在MATLAB中执行,还是已为模拟或代码生成目标编译。看到coder.target

MATLAB类属性初始化

在代码生成之前,在类加载时,MATLAB计算类的默认值。代码生成器使用MATLAB计算的值。它不重新计算默认值。如果属性定义使用函数调用来计算初始值,则代码生成器不会执行此函数。如果函数有副作用,比如修改全局变量或持久变量,那么生成的代码可能会产生与MATLAB不同的结果。有关更多信息,请参见为代码生成定义类属性

MATLAB具有Set方法的嵌套属性赋值中的类

当您将一个值赋给句柄对象属性时,该属性本身是另一个对象的属性,等等,那么生成的代码可以为MATLAB没有调用的句柄类调用set方法。

例如,假设您定义了一组这样的变量x是句柄对象,巴勒斯坦权力机构是一个对象,pb句柄对象,和个人电脑的属性。pb.然后你做一个嵌套的属性赋值,比如:

X.pa.pb.pc = 0;

在这种情况下,生成的代码调用对象的set方法pb和set方法x.MATLAB只调用set方法forpb

MATLAB句柄类析构函数

在这些情况下,生成的代码中句柄类析构函数的行为可能与MATLAB中的行为不同:

  • 在MATLAB中,几个独立对象的破坏顺序可能与生成的代码中不同。

  • 生成的代码中对象的生存期可能与MATLAB中的生存期不同。

  • 生成的代码不会破坏部分构造的对象。句柄对象在运行时未完全构造,则生成的代码将生成错误消息,但不会调用删除方法。对于系统对象™,如果中存在运行时错误setupImpl时,生成的代码不调用releaseImpl对于那个对象。

    MATLAB调用删除方法销毁部分构造的对象。

有关更多信息,请参见句柄类析构函数的代码生成

适应数据

看到在代码生成的可变大小支持中与MATLAB不兼容金宝app

复数

看到复杂数据的代码生成

将具有连续一元运算符的字符串转换为

将包含多个连续一元运算符的字符串转换为可以在MATLAB和生成的代码之间产生不同的结果。考虑这个函数:

函数Out = foo(op) Out = double(op + 1);结束

对于输入值”——“,函数转换字符串“- 1”.在MATLAB中,答案是.在生成的代码中,答案是1

相关的话题