To convert MATLAB® code to efficient C/C++ code, the code generator introduces optimizations that intentionally cause the generated code to behave differently, and sometimes produce different results, than the original source code.
Here are some of the differences:
When you run your program, run-time error checks can detect some of these differences. By default, run-time error checks are enabled for MEX code and disabled for standalone C/C++ code. To help you identify and address differences before you deploy code, the code generator reports a subset of the differences as potential differences.
Certain mathematical operations, such as singular value decomposition and eigenvalue decomposition of a matrix, can have multiple answers. Two different algorithms implementing such an operation can return different outputs for identical input values. Two different implementations of the same algorithm can also exhibit the same behavior.
For such mathematical operations, the corresponding functions in the generated
code and MATLAB might return different outputs for identical input values. To see if a
function has this behavior, in the corresponding function reference page, see the
C/C++ Code Generation section under Extended
Capabilities. Examples of such functions include svd
and eig
.
ans
VariableWhen you run MATLAB code that returns an output without specifying an output argument,
MATLAB implicitly writes the output to the ans
variable. If the variable
ans
already exists in the workspace, MATLAB updates its value to the output returned.
The code generated from such MATLAB code does not implicitly write the output to an ans
variable.
For example, define the MATLAB function foo
that explicitly creates an
ans
variable in the first line. The function then implicitly
updates the value of ans
when the second line executes.
function foo %#codegen ans = 1; 2; disp(ans); end
Run foo
at the command line. The final value of
ans
, which is 2
, is displayed at the
command line.
foo
2
Generate a MEX function from foo
.
codegen foo
Run the generated MEX function foo_mex
. This function
explicitly creates the ans
variable and assigns the value
1
to it. But foo_mex
does not implicitly
update the value of ans
to 2
.
foo_mex
1
Suppose that your MATLAB code has the logical operators &
and |
placed inside square brackets
([
and ]
). For such code patterns, the
generated code does not employ short-circuiting behavior for these logical
operators, but MATLAB execution might employ short-circuiting behavior. See Logical Short-Circuiting.
For example, define the MATLAB function foo
that uses the &
operator inside square brackets in the conditional expression of an
if...end
block.
function foo if [returnsFalse() & hasSideEffects()] end end function out = returnsFalse out = false; end function out = hasSideEffects out = true; disp('This is my string'); end
The first argument of the &
operator is always
false
and determines the value of the conditional expression. So,
in MATLAB execution, short-circuiting is employed and the second argument is not
evaluated. So, foo
does not call the
hasSideEffects
function during execution and does not display
anything at the command line.
Generate a MEX function for foo
. Call the generated MEX
function foo_mex
.
foo_mex
This is my string
In the generated code, short-circuiting is not employed. So, the
hasSideEffects
function is called and the string is displayed
at the command line.
Suppose that a for
-loop end value is equal to or close to
the maximum or minimum value for the loop index data type. In the generated code, the last
increment or decrement of the loop index might cause the index variable to overflow. The
index overflow might result in an infinite loop.
When memory integrity checks are enabled, if the code generator detects that the loop index might overflow, it reports an error. The software error checking is conservative. It might incorrectly report a loop index overflow. By default, memory-integrity checks are enabled for MEX code and disabled for standalone C/C++ code. See Why Test MEX Functions in MATLAB? and Run-Time Error Detection and Reporting in Standalone C/C++ Code.
To avoid a loop index overflow, use the workarounds in this table.
Loop Conditions Causing the Potential Overflow | Workaround |
---|---|
| If the loop does not have to cover the full range of the integer type, rewrite the loop so that the end value is not equal to the maximum value of the integer type. For example, replace: N=intmax('int16') for k=N-10:N for k=1:10 |
| If the loop does not have to cover the full range of the integer type, rewrite the loop so that the end value is not equal to the minimum value of the integer type. For example, replace: N=intmin('int32') for k=N+10:-1:N for k=10:-1:1 |
| If the loop must cover the full range of the integer type, cast the type of the loop start, step, and end values to a bigger integer or to double. For example, rewrite: 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 |
| Rewrite the loop so that the loop index in the last loop iteration is equal to the end value. |
for
LoopIn your MATLAB code and generated code, after a for
-loop execution
is complete, the value of the index variable is equal to its value during the final
iteration of the for
-loop.
In MATLAB, if the loop does not execute, the value of the index variable is stored as [ ] (empty matrix). In generated code, if the loop does not execute, the value of the index variable is different than the MATLAB index variable.
If you provide the for
-loop start and end variables at
run time, the value of the index variable is equal to the start of the
range. For example, consider this MATLAB code:
function out = indexTest(a,b) for i = a:b end out = i; end
Suppose that a
and b
are passed as
1
and -1
. The
for
-loop does not execute. In MATLAB, out
is assigned [ ]. In the generated
code, out
is assigned the value of a
,
which is 1
.
If you provide the for
-loop start and end values before
compile time, the value of the index variable is equal to
0
. Consider this MATLAB code:
function out = indexTest for i = 1:-1 end out = i; end
Suppose that you call this function. In MATLAB, out
is assigned [ ]. In the generated
code, out
is assigned the value
0
.
MATLAB supports 16-bit characters, but the generated code represents characters in 8 bits, the standard size for most embedded languages like C. See Encoding of Characters in Code Generation.
Generated code does not enforce order of evaluation in expressions. For most expressions, order of evaluation is not significant. However, for expressions with side effects, the generated code may produce the side effects in different order from the original MATLAB code. Expressions that produce side effects include those that:
Modify persistent or global variables
Display data to the screen
Write data to files
Modify the properties of handle class objects
In addition, the generated code does not enforce order of evaluation of logical operators that do not short circuit.
For more predictable results, it is good coding practice to split expressions that depend on the order of evaluation into multiple statements.
Rewrite
A = f1() + f2();
as
A = f1(); A = A + f2();
so that the generated code calls f1
before
f2
.
Assign the outputs of a multi-output function call to variables that do not depend on one another. For example, rewrite
[y, y.f, y.g] = foo;
as
[y, a, b] = foo; y.f = a; y.g = b;
When you access the contents of multiple cells of a cell array, assign the results to variables that do not depend on one another. For example, rewrite
[y, y.f, y.g] = z{:};
as
[y, a, b] = z{:}; y.f = a; y.g = b;
MATLAB and code generation follow different precedence rules for resolving
names that follow the symbol @
. These rules do not apply to
anonymous functions. The precedence rules are summarized in this table.
Expression | Precedence Order in MATLAB | Precedence Order in Code Generation |
---|---|---|
An expression that does not contain periods, for example
@x | Nested function, local function, private function, path function | Local variable, nested function, local function, private function, path function |
An expression that contains exactly one period, for example
@x.y | Local variable, path function | Local variable, path function (Same as MATLAB) |
An expression that contains more than one period, for example
@x.y.z | Path function | Local variable, path function |
If x
is a local variable that is itself a function handle,
generated code and MATLAB interpret the expression @x
differently:
MATLAB produces an error.
Generated code interprets @x
as the function handle of
x
itself.
Here is an example that shows this difference in behavior for an expression that contains two periods.
Suppose that your current working folder contains a package x
,
which contains another package y
, which contains the function
z
. The current working folder also contains the entry-point
function foo
for which you want to generate code.
This is the definition for the file 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
This is the definition for function z
:
function out = z out = 'x.y.z is a package function'; end
Generate a MEX function for foo
. Separately call both the
generated MEX function foo_mex
and the MATLAB function foo
.
codegen foo
foo_mex
foo
ans = 'x.y.z is an anonymous function' ans = 'x.y.z is a package function'
The generated code produces the first output. MATLAB produces the second output. Code generation resolves
@x.y.z
to the local variable x
that is
defined in foo
. MATLAB resolves @x.y.z
to z
, which is
within the package x.y
.
Generated code does not match the termination behavior of MATLAB source code. For example, if infinite loops do not have side effects, optimizations remove them from generated code. As a result, the generated code can possibly terminate even though the corresponding MATLAB code does not.
For variable-size N-D arrays, the size
function might return a
different result in generated code than in MATLAB source code. The size
function sometimes returns
trailing ones (singleton dimensions) in generated code, but
always drops trailing ones in MATLAB. For example, for an N-D array X
with
dimensions [4 2 1 1]
, size(X)
might return
[4 2 1 1]
in generated code, but
always returns [4 2]
in
MATLAB. See Incompatibility with MATLAB in Determining Size of Variable-Size N-D Arrays.
The size of an empty array in generated code might be different from its size in MATLAB source code. See Incompatibility with MATLAB in Determining Size of Empty Arrays.
Deleting all elements of an array results in an empty array. The size of this empty array in generated code might differ from its size in MATLAB source code.
Case | Example Code | Size of Empty Array in MATLAB | Size of Empty Array in Generated Code |
---|---|---|---|
Delete all elements of an
m-by-n array by using the colon operator
(: ). |
coder.varsize('X',[4,4],[1,1]);
X = zeros(2);
X(:) = [];
| 0-by-0 | 1-by-0 |
Delete all elements of a row
vector by using the colon operator
(: ). |
coder.varsize('X',[1,4],[0,1]);
X = zeros(1,4);
X(:) = []; | 0-by-0 | 1-by-0 |
Delete all elements of a
column vector by using the colon operator
(: ). |
coder.varsize('X',[4,1],[1,0]);
X = zeros(4,1);
X(:) = []; | 0-by-0 | 0-by-1 |
Delete all elements of a column vector by deleting one element at a time. |
coder.varsize('X',[4,1],[1,0]); X = zeros(4,1); for i = 1:4 X(1)= []; end | 1-by-0 | 0-by-1 |
If your MATLAB code contains a binary element-wise operation that involves a single type operand and a double type operand, the generated code might not produce the same result as MATLAB.
For such an operation, MATLAB casts both operands to double type and performs the operation with the double types. MATLAB then casts the result to single type and returns it.
The generated code casts the double type operand to single type. It then performs the operation with the two single types and returns the result.
For example, define a MATLAB function foo
that calls the binary element-wise
operation plus
.
function out = foo(a,b) out = a + b; end
Define a variable s1
of single type and a variable
v1
of double type. Generate a MEX function for
foo
that accepts a single type input and a double type
input.
s1 = single(1.4e32); d1 = -5.305e+32; codegen foo -args {s1, d1}
Call both foo
and foo_mex
with inputs
s1
and d1
. Compare the two results.
ml = foo(s1,d1); mlc = foo_mex(s1,d1); ml == mlc
ans = logical 0
The output of the comparison is a logical 0
, which indicates
that the generated code and MATLAB produces different results for these inputs.
The generated code might not produce the same floating-point numerical results as MATLAB in these:
When computer hardware uses extended precision registers
The generated code might not produce exactly the same pattern of
NaN
and Inf
values as MATLAB code when these values are mathematically meaningless. For
example, if MATLAB output contains a NaN
, output from the
generated code should also contain a NaN
, but not necessarily
in the same place.
The bit pattern for NaN
can differ between MATLAB code output and generated code output because the C99 standard
math library that is used to generate code does not specify a unique bit pattern
for NaN
across all
implementations. Avoid comparing bit patterns across different implementations,
for example, between MATLAB output and SIL or PIL output.
In a floating-point type, the value 0
has either a positive
sign or a negative sign. Arithmetically, 0
is equal to
-0
, but some operations are sensitive to the sign of a 0
input. Examples include rdivide
, atan2
,
atan2d
, and angle
. Division by
0
produces Inf
, but division by
-0
produces -Inf
. Similarly,
atan2d(0,-1)
produces 180
, but
atan2d (-0,-1)
produces -180
.
If the code generator detects that a floating-point variable takes only integer
values of a suitable range, then the code generator can use an integer type for the
variable in the generated code. If the code generator uses an integer type for the
variable, then the variable stores -0
as +0
because an integer type does not store a sign for the value 0
. If
the generated code casts the variable back to a floating-point type, the sign of
0
is positive. Division by 0
produces
Inf
, not -Inf
. Similarly,
atan2d(0,-1)
produces 180
, not
-180
.
The coder.target
function returns different values in
MATLAB than in the generated code. The intent is to help you determine
whether your function is executing in MATLAB or has been compiled for a simulation or code generation target.
See coder.target
.
Before code generation, at class loading time, MATLAB computes class default values. The code generator uses the values that MATLAB computes. It does not recompute default values. If the property definition uses a function call to compute the initial value, the code generator does not execute this function. If the function has side effects such as modifying a global variable or a persistent variable, then it is possible that the generated code can produce different results that MATLAB produces. For more information, see Defining Class Properties for Code Generation.
When you assign a value to a handle object property, which is itself a property of another object, and so on, then the generated code can call set methods for handle classes that MATLAB does not call.
For example, suppose that you define a set of variables such that
x
is a handle object, pa
is an object,
pb
is a handle object, and pc
is a
property of pb
. Then you make a nested property assignment, such
as:
x.pa.pb.pc = 0;
In this case, the generated code calls the set method for the object
pb
and the set method for x
. MATLAB calls only the set method for pb
.
The behavior of handle class destructors in the generated code can be different from the behavior in MATLAB in these situations:
The order of destruction of several independent objects might be different in MATLAB than in the generated code.
The lifetime of objects in the generated code can be different from their lifetime in MATLAB.
The generated code does not destroy partially constructed objects. If
a handle object is not fully constructed at run time, the generated code
produces an error message but does not call the
delete
method for that object. For a System object™, if there is a run-time
error in setupImpl
, the generated code does not call
releaseImpl
for that object.
MATLAB does call the delete
method to destroy
a partially constructed object.
For more information, see Code Generation for Handle Class Destructors.
See Incompatibilities with MATLAB in Variable-Size Support for Code Generation.
double
Converting a string that contains multiple, consecutive unary operators to
double
can produce different results between MATLAB and the generated code. Consider this
function:
function out = foo(op) out = double(op + 1); end
For an input value "--"
, the function converts the string
"--1"
to double
. In MATLAB, the answer is NaN
. In the generated code, the
answer is 1
.