生成的代码和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++代码来检测和报告运行时错误.
要避免循环索引溢出,请使用本表中的变通方法。
导致潜在溢出的循环条件 | 解决方案 |
---|---|
|
如果循环不必覆盖整型的全部范围,则重写循环,使结束值不等于整型的最大值。例如,replace: N=intmax('int16') for k=N-10:N k = 1:10 |
|
如果循环不必覆盖整型的全部范围,则重写循环,使结束值不等于整型的最小值。例如,replace: N=intmin('int32') for k=N+10:-1:N k = 10: 1:1 |
|
如果循环必须覆盖整型类型的全部范围,则将循环开始值、步骤值和结束值的类型强制转换为更大的整数或加倍。例如,重写: M = intmin(“int16”);N = intmax(“int16”);对于k=M:N %环体端 M = intmin(“int16”);N = intmax(“int16”);for k=int32(M):int32(N) %循环体结束 |
|
重写循环,使最后一次循环迭代中的循环索引等于结束值。 |
索引为
使用单精度操作数进行循环
假设在你的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 = indexTest为I = 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
.当前工作文件夹还包含入口点函数喷火
你想为它生成代码。
这是文件的定义喷火
:
函数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.z
来z
,这是在包内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相同的浮点数值结果:
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.0
为fmin (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和生成的代码之间产生不同的结果。考虑这个函数:
函数Out = foo(op) Out = double(op + 1);结束
对于输入值”——“
,函数转换字符串“- 1”
来双
.在MATLAB中,答案是南
.在生成的代码中,答案是1
.