主要内容

生成代码与MATLAB代码

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

以下是一些不同之处:

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

具有多个可能输出的函数

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

对于这种数学操作,所生成的代码和MATLAB中的相应函数可能会返回相同输入值的不同输出。要查看函数是否具有此行为,请在相应的功能参考页面中查看C / c++代码生成下节扩展功能。这些函数的例子包括SVD.eig

写信给ANS.变量

当运行返回输出而不指定输出参数的MATLAB代码时,MATLAB会隐式地将输出写入ANS.变量。如果变量ANS.Matlab已存在于工作区中,将其值更新其返回的输出。

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

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

函数喷火%#codegen.ans = 1;2;DISP(ANS);结束

喷火在命令行。的最终值ANS.,这是2,显示在命令行中。

喷火
2

生成一个MEX函数喷火

codegen喷火

运行生成的MEX函数foo_mex。函数显式地创建ANS.变量并赋值1到它。但foo_mex不隐式更新的值ANS.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。

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

如果循环不必覆盖整数类型的全部范围,则重写循环,使得终端值不等于整数类型的最大值。例如,替换:

N = intmax (k = N-10 int16): N
和:
k = 1:10

  • 循环索引减少1。

  • 终端值等于整数类型的最小值。

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

N = intmin (int32) k = N + 10: 1: N
和:
k = 10: 1:1

  • 循环索引增加或减少1。

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

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

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

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

  • 循环索引增加或减少一个不等于1的值。

  • 在最后的循环迭代中,循环索引不等于最终值。

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

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

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

例如,考虑此MATLAB代码:

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

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

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

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

未输入的索引循环

在您的MATLAB代码和生成的代码,后一个的执行完成后,索引变量的值等于它在最后一次迭代期间的值循环。

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

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

    函数= indexTest (a, b)我= a: b结束=我;结束

    假设一个b都通过了1-1。的循环不执行。在MATLAB中,赋值为[]。在生成的代码中,赋值为一个,这是1

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

    函数出= indexTesti = 1: 1结束=我;结束

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

字符长度

MATLAB支金宝app持16位字符,但生成的代码表示8位中的字符,标准大小为C.如C如C.看到代码生成中的字符编码

表达式中的求值顺序

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

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

  • 在屏幕上显示数据

  • 将数据写入文件

  • 修改句柄类对象的属性

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

为了更加可预测的结果,拆分表达式的良好编码实践是依赖于评估顺序到多个语句的拆分表达。

  • 重写

    A = f1() + f2();

    作为

    a = f1();a = a + f2();

    这样生成的代码调用f1之前f2

  • 将多输出函数调用的输出赋值给不相互依赖的变量。例如,重写

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

    作为

    [y, a, b] = foo;y.f =一个;Y.G = B;

  • 当您访问单元格数组的多个单元格的内容时,请将结果分配给彼此不依赖的变量。例如,重写

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

    作为

    [y,a,b] = z {:};y.f =一个;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是一个匿名函数';= g (x);结束函数Out = g(x) f = @x.y.z;= f ();结束

这是函数的定义z

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

生成MEX功能喷火。分别调用生成的MEX函数foo_mexMATLAB函数喷火

codegen喷火foo_mex foo.
Ans = 'x.y.z is an匿名函数' 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,1]);x =零(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将两个操作数强制转换为double类型,并使用double类型执行操作。MATLAB然后将结果转换为单一类型并返回它。

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

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

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

定义变量S1单一类型和变量的v1.双型。生成MEX功能喷火它接受单个类型输入和双类型输入。

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

打电话给两者喷火foo_mex与输入S1d1。比较两个结果。

毫升= foo (s1、d1);多层陶瓷= foo_mex (s1、d1);毫升= =多层陶瓷
逻辑0

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

浮点数值结果

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

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

用于某些高级库函数

用于实现BLAS库函数

南和无穷

生成的代码可能不会生成完全相同的模式值作为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代码计算两个标量双精度的最小值xy通过使用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嵌套属性分配的类,具有设置方法

当你给句柄对象属性赋值时,它本身也是另一个对象的属性,等等,然后生成的代码可以为MATLAB没有调用的句柄类调用set方法。

例如,假设您定义了一组这样的变量x是句柄对象,pa是一个对象,PB.是句柄对象吗个人电脑是一种属性PB.。然后进行嵌套属性赋值,例如:

x.pa.pb.pc = 0;

在本例中,生成的代码调用对象的set方法PB.和集合方法x。MATLAB仅调用SET方法PB.

MATLAB处理类的析构函数

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

  • 在MATLAB中,多个独立对象的销毁顺序可能与生成的代码不同。

  • 生成代码中的对象的生命周期可能与它们在MATLAB中的生命周期不同。

  • 生成的代码不会销毁部分构造的对象。如果句柄对象在运行时没有完全构造,则生成的代码将生成一条错误消息,但不会调用删除该对象的方法。对于系统对象™,如果存在运行时错误setupImpl,生成的代码不调用删除歧杆子的对象。

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

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

适应数据

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

复数

看到复杂数据的代码生成

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

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

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

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

相关话题