1

matlab で正弦近似をシミュレートしようとすると、奇妙な問題が見つかりました。問題は、関数を配列に適用すると 1 つの結果が返されるのに対し、個々の値に関数を適用すると結果がわずかに異なることです。

この例でも同じ動作を得ることができました:

z = single(0:0.001:1);
F = @(x) (x.^2 - single(1.2342320e-001)).*x.^2;  %some test function

z(999)        % Returns 9.9800003e-001
F(z(999))     % Returns 8.6909407e-001
temp = F(z);  
temp(999)     % Voila! It returns 8.6909401e-001

また、いくつかのことを見つけました。1 つは、最初の結果が正しい (後者ではない) ことです。2 つ目は、用語を並べ替えると問題が解決する場合があることです。だから私はそれを取り除く方法がわかりません。

4

5 に答える 5

3

単精度には意味のある精度の 10 進数 7 桁までしかないため、この状況ではそれが「正しく」「間違っている」8.6909407e-001と言うことはあまり意味がありません。8.6909401e-001

既におわかりのように、浮動小数点演算は演算の順序にも影響されます。スカラーではなく行列を操作する場合、Matlab が計算の順序を微妙に変更する可能性があります。

于 2012-06-09T19:22:16.073 に答える
1

ベクトル演算の場合、MatLab の線形代数ライブラリは x87 FPU の代わりに SIMD 命令を使用する場合があり、精度はわずかに異なります。

相対誤差は非常に小さく、合理的に設計された計算を壊すことはありません。浮動小数点の等価性をテストしていますか?

于 2012-06-09T19:21:34.580 に答える
1

実際、浮動小数点演算を使用するデバイスは、数学と等価の式に対してバイナリと等価の結果を提供しないことを保証できます。さまざまなプラットフォームで、次の MATLAB と同等のものを試してください。

a = [repmat(1, 10000, 1); 1e16];
format long
sum(a)
sum(flipud(a))

結果:

1.000000000001000e+16
1.000000000000000e+16

加算は交換可能であるため、式は数学的に同等です。しかし、浮動小数点の世界では順序が重要です。明らかに、10000 個の 1 を順番に追加しても、累積値が約 0 の場合、浮動小数点には問題はありません。追加した。

ここに余分な問題があります: x87 FPU は内部的に拡張精度 (80 ビット) で計算します。そのため、コンパイラが中間結果を FPU 内に保持することを決定した場合、FPU コードは別の答えを返します。代わりに、中間結果をスタックにスピルすることにした場合は、64 に戻ります。SSE 命令を使用して計算することにした場合は、64 に戻ります。

他の回答で提案されているこれらのさまざまな MATLAB トリックにより、問題に十分近づくことができます。しかし、システムの完全なモデル化を本当に求めているのであれば、より制御しやすいシミュレーション フレームワークが必要になるでしょう。おそらく を使用してvpa、各ステップで正しいビット数に変換します。または、C または C++ に切り替えて、オプティマイザ コントロールの設定に細心の注意を払ってください。

または、入力スケーリングに基づいて誤差の境界を数学的に計算し、答えが常に境界を下回っていることを確認します。

于 2012-06-11T13:47:28.447 に答える
0

単精度数を使用すると、両方の結果が「等しい」(差はsingle型の相対精度より小さい)。次のステートメントは true と評価されます。

max(abs( arrayfun(F,z) - F(z) )) < eps('single')

編集

これを本当に制御したい場合は、MATLAB アクセラレータを無効にして、通常のコードとベクトル化されたコードの両方に同じ実行パスを使用するように強制することができます。

feature('jit', 'off')
feature('accel', 'off')
max(abs( arrayfun(F,z) - F(z) ))

feature('jit', 'on')
feature('accel', 'on')
max(abs( arrayfun(F,z) - F(z) ))

それぞれ1番目/2番目の結果:

ans =
     0
ans =
   5.9605e-08

明らかに、既定では、アクセラレータとジャストインタイム コンパイラの両方がオンになっています。

于 2012-06-10T21:34:44.197 に答える
0

わかった。すべての答えは正しいですが、問題は解決しません。私が望むのは、スカラー演算を使用するかベクトル演算を使用するかに関係なく、数学的に等しい式がバイナリと等しい結果をもたらすことだけです。その結果、Cortex-M4、電卓、その他多くのプログラムやデバイスで FPU を使用できますが、Matlab では使用できません。

これまでのところ、私が目にする唯一の解決策はfor、ベクトル演算の代わりに -loops を使用することです。醜いですが、うまくいきます。

編集

回答のおかげで、この問題に対するいくつかの解決策があります。

于 2012-06-11T10:04:14.763 に答える