主要内容

このページの翻訳は最新ではありません。ここをクリックして,英語の最新版を参照してください。

生成されたコードとMATLABコードの相違点

MATLAB®コードを効率良く動作するC / c++コードに変換するため,コードジェネレーターに,元のソースコードと生成後のコードの動作が意図的に異なる(場合によっては異なる結果が出る)ように最適化が導入されています。

次のような相違点があります。

プログラムを実行すると,実行時エラーチェックで次の相違点が検出される可能性があります。既定では,実行時エラーチェックは墨西哥人コードに対して有効化され,スタンドアロンC / c++コードに対しては無効化されています。コードを配布する前に相違点を識別して解決できるように,コードジェネレーターは,潜在的な相違として相違点のサブセットを報告します。

可能な出力が複数ある関数

行列の特異値分解や固有値分解などの特定の数学演算では,複数の解が得られる場合があります。このような演算を実装する2つの異なるアルゴリズムは,同じ入力値に対して異なる出力を返す場合があります。同じアルゴリズムの2つの異なる実装でも同じ動作になることがあります。

このような数学演算では,生成されたコードとMATLABの対応する関数が同じ入力値に対して異なる出力を返す場合があります。関数がこの動作を示すかどうかを確認するには,対応する関数のリファレンスページで,「拡張機能」“C / c++コードの生成”セクションを参照してください。このような関数の例には,圣言会eigなどがあります。

変数への書き込み

出力引数を指定せずに出力を返すMATLABコードを実行すると,MATLABは変数に出力を暗黙的に書き込みます。変数が既にワークスペースに存在する場合,MATLABはその値を返された出力に更新します。

このようなMATLABコードから生成されたコードは,変数に出力を暗黙的に書き込みません。

たとえば1行目で変数を明示的に作成するMATLAB関数喷火を定義します。この関数は2行目が実行されるとの値を暗黙的に更新します。

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

コマンドラインで喷火を実行します。の最終値2がコマンドラインに表示されます。

喷火
2

喷火から墨西哥人関数を生成します。

codegen喷火

生成された墨西哥人関数foo_mexを実行します。この関数は変数を明示的に作成し,その変数に値1を代入します。ただし,foo_mexの値を2に暗黙的に更新しません。

foo_mex
1

論理ショートサーキット

MATLABコードで論理演算子および|が大かっこ()内に配置されているとします。このようなコードパターンの場合,生成コードではこれらの論理演算子のショートサーキットの動作は使用されませんが,MATLABの実行ではショートサーキットの動作が使用されることがあります。論理ショートサーキットを参照してください。

たとえば,如果……ブロックの条件式の大かっこ内で演算子を使用するMATLAB関数喷火を定義します。

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

演算子の最初の引数は常にで,条件式の値を決定します。そのため,MATLABの実行ではショートサーキットが使用され,2番目の引数は評価されません。したがって,喷火では実行時に関数hasSideEffectsは呼び出されず,コマンドラインに何も表示されません。

喷火の墨西哥人関数を生成します。生成された墨西哥人関数foo_mexを呼び出します。

foo_mex
这是我的绳子

生成コードでは,ショートサーキットは使用されません。したがって,関数hasSideEffectsが呼び出され,コマンドラインに文字列が表示されます。

ループインデックスのオーバーフロー

ループの終了値がループインデックスのデータ型の最大値または最小値と等しいか近いと仮定します。生成コードでは,ループインデックスの最後のインクリメントまたはデクリメントによって,インデックス変数のオーバーフローが発生する可能性があります。インデックスのオーバーフローの結果,無限ループが発生する可能性があります。

メモリの整合性チェックが有効になっている場合,ループインデックスのオーバーフローが発生する可能性があることをコードジェネレーターが検出すると,エラーが報告されます。ソフトウェアのエラーチェックは保守的です。ループインデックスのオーバーフローを誤って報告する可能性があります。既定では、メモリの整合性チェックは MEX コードに対して有効化され、スタンドアロン C/C++ コードに対しては無効化されています。MATLABで墨西哥人関数をテストする理由および生成独立的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コードで,コロン演算子があるループのインデックス付けを行うとします。ここでは,コロンオペランドの少なくとも1つが单一型のオペランドで,反復回数はflintmax('单')= 16777216を超えます。これらすべての条件が満たされている場合,コード生成でランタイムエラーまたはコンパイル時エラーが発生する可能性があります。これは,生成されたコードで計算されるループインデックス変数の値がMATLABで計算される値とは異なることが原因です。

たとえば,以下のMATLABコードについて考えます。

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

このコードの抜粋はMATLABで実行されていますが,生成されたコードではループインデックス変数に対する値が異なる方法で計算されているため,コンパイル時エラーまたはランタイムエラーが発生します。コードジェネレーターでコンパイル時エラーまたはランタイムエラーが表示され,この不一致を回避するためにコードの生成または実行が停止します。

この不一致を回避するには,单一型のオペランドを双型または整数型のオペランドに置き換えます。

ランタイムエラーの詳細については,生成独立的C/ c++代码,检测和报告运行时错误を参照してください。

未入力のループのインデックス

MATLABコードと生成されたコードでは,ループの実行が完了した後,インデックス変数の値はループの最終反復時の値と等しくなります。

MATLABでループが実行されない場合,インデックス変数の値は[](空行列)として保存されます。生成されたコードでループが実行されない場合、インデックス変数の値は MATLAB のインデックス変数とは異なります。

  • ループの開始変数と終了変数を実行時に指定する場合,インデックス変数の値は範囲の開始値と等しくなります。たとえば,以下のMATLABコードについて考えます。

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

    一个b1-1として渡されると仮定します。ループは実行されません。MATLABでは,に[]が代入されます。生成されたコードでは,一个の値1が代入されます。

  • ループの開始値と終了値をコンパイルの前に指定する場合,インデックス変数の値は0と等しくなります。以下のMATLABコードについて考えます。

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

    この関数を呼び出すと仮定します。MATLABでは,に[]が代入されます。生成されたコードでは,に値0が代入されます。

文字サイズ

MATLABは16ビットの文字をサポートしていますが,生成されたコードでは文字をC言語などの多くの埋め込み型言語の標準サイズである8ビットで表現します。コード生成での文字のエンコードを参照してください。

式の評価順番

生成されたコードは,式の評価順番を強制しません。ほとんどの式において,評価の順序は重要な意味をもちません。副作用を含む式では,生成コードと元のMATLABコードとで副作用が異なる順序で生成される場合があります。副作用を伴う式には,以下のようなものがあります。

  • 永続変数またはグローバル変数を変更する

  • 画面にデータを表示する

  • データをファイルに書き込む

  • ハンドルクラスのオブジェクトのプロパティを変更する

また,生成されたコードは,ショートサーキットしない論理演算子の実行順番を強制しません。

結果を予測しやすくするために,実行順序に依存する式を複数のステートメントに分割してコードを書くことをお勧めします。

  • たとえば,次のコードを書き換えます。

    A = f1() + f2();

    以下のように書き換えます。

    一个= 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など)

入れ子関数,ローカル関数,プライベート関数,パス関数

ローカル変数,入れ子関数,ローカル関数,プライベート関数,パス関数

ピリオドを1つだけ含む式(@x.yなど)

ローカル変数,パス関数

ローカル変数,パス関数(MATLABと同じ)

複数のピリオドを含む式(@x.y.zなど)

パス関数

ローカル変数,パス関数

xがそれ自体が関数ハンドルとなるローカル変数である場合,生成されたコードとMATLABでは式@xの解釈が異なります。

  • MATLABではエラーが発生します。

  • 生成されたコードでは@xx自体の関数ハンドルとして解釈されます。

次の例では2つのピリオドを含む式の動作におけるこの相違点を示します。

現在の作業フォルダーにパッケージxが含まれ,これに関数zを含む別のパッケージyが含まれていると仮定します。また,現在の作業フォルダーには,コードの生成対象となるエントリポイント関数喷火も含まれています。

当前文件夹显示文件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是一个包函数'结束

喷火の墨西哥人関数を生成します。生成された墨西哥人関数foo_mexとMATLAB関数喷火の両方を個別に呼び出します。

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

生成されたコードによって最初の出力が生成されます。MATLABによって 2 番目の出力が生成されます。コード生成では、@x.y.z喷火で定義されているローカル変数xに解決されます。MATLABでは、@x.y.zはパッケージx.y内のzに解決されます。

終了動作

生成されたコードの終了動作は,MATLABソースコードの動作と一致しません。たとえば,無限ループに副次的影響がない場合、無限ループは最適化によって生成されたコードから除去されます。その結果、対応する MATLAB コードが終了しなくても生成コードは終了する場合があります。

可変サイズN次元配列のサイズ

可変サイズのN次元配列では,関数大小で返す結果が,生成されたコードとMATLABソースコードで異なる場合があります。関数大小は,生成されたコードでは後に1を続けて返すことがありますが(大きさが1の次元),MATLABでは後続する1は常に切り捨てられます。たとえばN次元の配列Xが次元[4 2 1 1]をもっている場合,大小(X)は,生成されたコードでは[4 2 1 1]を返す場合がありますが,MATLABでは常に(4 - 2)を返します。可変サイズのN次元配列のサイズを判定する上での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
一度に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は実行結果を单一型にキャストし,その結果を返します。

生成コードでは、双型のオペランドを单一型にキャストします。そして2つの单一型で演算を実行し,その結果を返します。

たとえば,要素単位の二項演算+を呼び出すMATLAB関数喷火を定義します。

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

单一型の変数s1と、双型の変数v1を定義します。单一型の入力と双型の入力を受け入れる喷火の墨西哥人関数を生成します。

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

入力s1およびd1を指定して,喷火foo_mexの両方を呼び出します。2つの結果を比較します。

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

比較の出力は逻辑0になります。これは,これらの入力について,生成コードとMATLABで異なる結果を生成することを示しています。

浮動小数点の数値結果

生成されたコードは,以下の場合のMATLABにおける浮動小数点の数値結果とは,異なる可能性があります。

コンピューターハードウェアが拡張精度レジスタを使用する

特定の高度なライブラリ機能

布拉斯特区ライブラリ関数の実装

南と無限大

生成されたコードでは,およびの値が数学的に無意味の場合,値のパターンがMATLABコードと異なる場合があります。たとえば,MATLAB出力にが含まれる場合,生成されたコードの出力にもが含まれますが,必ずしも同じ場所に含まれるとは限りません。

のビットパターンがMATLABコードの出力と生成されたコードで異なる場合があります。それは,コードの生成に使用されるC99標準の数学ライブラリが,すべての実装でに一意のビットパターンを指定しないからです。MATLAB出力と SIL 出力または PIL 出力など異なる実装でビット パターンを比較しないでください。

負のゼロ

浮動小数点型の場合,値0は正の記号または負の記号のいずれかをもちます。算術的に,00と等価ですが,一部の演算では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コードで,z = min (x, y)を使用して2つの双型のスカラーxyの最小値を計算するとします。生成されたCコードの対応する行はz = fmin (x, y)となる可能性があります。関数fminはCコンパイラのランタイム数学ライブラリで定義されています。比較演算子0.0 = = -0.0真正的をC / c++で返すため,fminのコンパイラの実装ではfmin (0.0, -0.0)に対して0.0または-0.0のいずれかが返される可能性があります。

コード生成ターゲット

関数coder.targetは,生成されたコードとMATLABで異なる値を返します。これは,関数がMATLABで実行されているのか,それともシミュレーションまたはコード生成ターゲット用にコンパイルされたのかを判断できるようにすることを目的としています。coder.targetを参照してください。

MATLABクラスプロパティの初期化

MATLABでは,クラスの読み込み時にクラスの既定値を計算してからコード生成を行います。コードジェネレーターでは,MATLABで計算される値が使用されます。既定値は再計算されません。プロパティ定義で関数呼び出しを使って初期値を計算する場合,コードジェネレーターはこの関数を実行しません。関数にグローバル変数や永続変数の変更といった副作用がある場合、生成されたコードから得られる結果が MATLAB の結果とは異なる可能性があります。詳細は、コード生成のためのクラスプロパティの定義を参照してください。

设置メソッドをもつ入れ子のプロパティ割り当てにおけるMATLABクラス

ハンドルオブジェクトのプロパティに値を割り当てるときに,そのプロパティ自体が別のオブジェクトのプロパティでもある場合,生成されたコードは,MATLABが呼び出さないハンドルクラスの设置メソッドを呼び出すことができます。

たとえば,xがハンドルオブジェクト,巴勒斯坦权力机构がオブジェクト,pbがハンドルオブジェクト,个人电脑pbのプロパティになるように,一連の変数を定義すると仮定します。以下のように,入れ子にされたプロパティの割り当てを行います。

x.pa.pb.pc = 0;

この場合,生成されたコードはオブジェクトpbの设置メソッドとxの设置メソッドを呼び出します。MATLABはpbの设置メソッドのみを呼び出します。

MATLABハンドルクラスのデストラクター

生成されたコードでのハンドルクラスのデストラクターの動作は,次の状況ではMATLABでの動作とは異なる場合があります。

  • 複数の独立したオブジェクトを破棄する順序は,生成されたコードとMATLABでは異なる場合があります。

  • 生成されたコードでのオブジェクトの存続期間は,MATLABでの存続期間と異なる可能性があります。

  • 生成されたコードは,部分的に作成されたオブジェクトを破棄しません。ハンドルオブジェクトが実行時に完全に作成されていない場合,生成されたコードはエラーメッセージを作成しますが,そのオブジェクトの删除メソッドは呼び出しません。系统对象™について,setupImplで実行時エラーがある場合,生成されたコードは,そのオブジェクトのreleaseImplは呼び出しません。

    MATLABは,删除メソッドを呼び出して,部分的に作成されたオブジェクトを破棄します。

詳細については,ハンドルクラスデストラクターのコード生成を参照してください。

可変サイズデータ

コード生成時の可変サイズのサポートに関するMATLABとの非互換性を参照してください。

複素数

複素数データのコード生成を参照してください。

連続する単項演算子をものつ字符串への変換

複数の連続する単項演算子を含をむ字符串に変換すると,MATLABと生成されたコードで結果が異なる場合があります。次の関数を考えてみます。

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

入力値”——“の場合,関数によって字符串“- 1”に変換されます。MATLABでは、回答がになります。生成されたコードの回答は1です。

関連するトピック