Matlabの精度:簡単な減算はゼロではない

私はこの単純な和をMatlabで計算します:

2*0.04-0.5*0.4^2 = -1.387778780781446e-017

結果はゼロではありません。私に何ができる?

1
同様の質問:なぜ24.0000は24.0000と等しくないのですか? MATLABで?
追加された 著者 Amro,
さらにもっと明白な例: 5.5511e-017 を与える 0.3 - 0.1 * 3
追加された 著者 Amro,
eps で読んでください。
追加された 著者 Mike DeSimone,
5.498 + 0.001 ans = 5.499000000000001正解は5.499である必要があります
追加された 著者 James Do,

5 答え

AabazとJim Clayは何が起こっているのかをよく説明しています。

It's often the case that, rather than exactly calculating the value of 2*0.04 - 0.5*0.4^2, what you really want is to check whether 2*0.04 and 0.5*0.4^2 differ by an amount that is small enough to be within the relevant numerical precision. If that's the case, than rather than checking whether 2*0.04 - 0.5*0.4^2 == 0, you can check whether abs(2*0.04 - 0.5*0.4^2) < thresh. Here thresh can either be some arbitrary smallish number, or an expression involving eps, which gives the precision of the numerical type you're working with.

編集: ジムとタルの改善のために感謝します。差分の絶対値とその差ではなく、しきい値とを比較するように変更されました。

4
追加された
いい視点ね。私が行う1つの変更は、差の絶対値を「しきい値」と比較する必要があることです。
追加された 著者 Jim Clay,

Matlabは倍精度浮動小数点数を使用して実数を格納します。これらは、 m ^ 2 ^ e の形式の番号で、 m2 ^ 522 ^ 53 < code>(仮数)、 e は指数です。このフォームの場合、数値を浮動小数点数と呼ぶことにしましょう。

計算に使用されるすべての数値は、浮動小数点数でなければなりません。多くの場合、これは式の 20.5 のように正確に行うことができます。しかし、他の数字、特に小数点以下の数字のほとんどの数字については、これは不可能であり、近似を使用する必要があります。この場合、数値は最も近い浮動小数点数に丸められます。

So, whenever you write something like 0.04 in Matlab, you're really saying "Get me the floating-point number that is closest to 0.04. In your expression, there are 2 numbers that need to be approximated: 0.04 and 0.4.

さらに、浮動小数点数の加算や乗算などの演算結果は、浮動小数点数ではない可能性があります。常に m * 2 ^ e の形式ですが、仮数が大きすぎる可能性があります。したがって、操作の結果を丸めることから追加のエラーが発生します。

一日の終わりには、あなたのような単純な式は、オペランドのサイズの約2 ^ -52倍、つまり約10 ^ -17だけ離れています。

要約すると、式がゼロに評価されない理由は2つあります。

  1. 始める数字の中には、入力した数字と異なるもの(近似値)があります。
  2. 中間結果は正確な結果の近似でもあります。
2
追加された

あなたの問題に適用できるかどうかは分かりませんが、しばしば最も簡単な解決策はデータを拡大することです。

例えば:

a=0.04;
b=0.2;
a-0.2*b
ans=-6.9389e-018
c=a/min(abs([a b]));
d=b/min(abs([a b]));
c-0.2*d
ans=0

EDIT: of course I did not mean to give a universal solution to these kind of problems but it is still a good practice that can make you avoid a few problems in numerical computation (curve fitting, etc ...). See Jim Clay's answer for the reason why you are experiencing these problems.

1
追加された
これがうまくいく理由はありますか、このインスタンスでは "正しい"ことを行うアドホックコードですか?
追加された 著者 Oliver Charlesworth,
私は正直に分かりませんが、確かにこの種の問題を解決するには正しい方向に進みます。
追加された 著者 Aabaz,
これはいつもうまくいくのですか、それともちょっとの時間ですか?
追加された 著者 Jim Clay,
これは、 f = @(x)1-x/x ^ 2 * x 、次に f(rand())回。時には0です。それ以外の時はイプシロンです。スケーリングはよりよい結果を得るのに役立ちますが、精度はまだイプシロンの範囲内です。もう1つの選択肢は、問題の他の値のスケールと一致するようにイプシロンをスケーリングすることです。
追加された 著者 stardt,

あなたが見ているのは、量子化エラーです。 Matlabは倍数を使用して数値を表しますが、精度は非常に高いものの、実数が無限に存在するため、すべての実数を表すことはできません。私はAabazのトリックについてはわかりませんが、一般的には、あなたの入力をダブルフレンドリーな数字にマッサージする以外に、できることは何もないと言います。

1
追加された

私はこれが浮動小数点精度の問題であることは間違いないと確信しています。

1e-17の精度が必要ですか?これは単なる「かなり」の出力を望む場合ですか? その場合、フォーマットされたsprintfを使用して、必要な有効数字の数を表示できます。

これはmatlabの問題ではなく、数値がどのようにバイナリで表現されるかの基本的な制限であることを理解してください。

楽しみのために、.1バイナリで何かを試してみてください...

いくつかの参考文献: http://ja.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

1
追加された