Matlab hassasiyeti: basit çıkarma sıfır değildir

Bu basit toplamı Matlab'da hesapladım:

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

ama sonuç sıfır değil. Ne yapabilirim?

1
katma yazar Amro, kaynak
Ayrıca daha belirgin bir örnek: 0.3 - 0.1 * 3 5.5511e-017 değerini verir.
katma yazar Amro, kaynak
eps 'da okuyun.
katma yazar Mike DeSimone, kaynak
5.498 + 0.001 ans = 5.499000000000001 doğru cevap 5.499 olmalıdır.
katma yazar James Do, kaynak

5 cevap

Aabaz ve Jim Clay, neler olduğuyla ilgili iyi açıklamalara sahipler.

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.

DÜZENLE: Önerilen iyileştirme için Jim ve Tal'e teşekkürler. Farkın mutlak değerini, farktan ziyade bir eşikle karşılaştırmak için değiştirilmiştir.

4
katma
İyi bir nokta. Yapacağım tek değişiklik, farkın mutlak değerini "harman" ile karşılaştırmanız gerektiğidir.
katma yazar Jim Clay, kaynak

Matlab, gerçek sayıları saklamak için çift duyarlıklı kayan noktalı sayılar kullanır. Bunlar m * 2 ^ e şeklindeki sayılardır; burada m , 2 ^ 52 ve 2 ^ 53 ( mantissa ) ve e üssüdür. Bu formda bir sayıyı bir kayan noktalı sayıyı arayalım.

Hesaplamalarda kullanılan tüm sayılar, kayan noktalı sayılar olmalıdır. Sıklıkla, bu, ifadenizde 2 ve 0,5 ile olduğu gibi yapılabilir. Fakat diğer sayılar için, en çok sayı, ondalık noktadan sonraki rakamlarla, bu mümkün değildir ve bir yaklaşımın kullanılması gerekir. Bu durumda ne olur, sayı en yakın kayan nokta sayısına yuvarlanır.

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.

Ayrıca, kayan nokta sayılarında toplama ve çarpma gibi işlemlerin kesin sonucu, kayan nokta sayısı olmayabilir. Her zaman m * 2 ^ e biçiminde olmasına rağmen mantis çok büyük olabilir. Böylece, işlemlerin sonuçlarını yuvarlamaktan ek bir hata alırsınız.

Günün sonunda, sizinki gibi basit bir ifade, işlenenlerin boyutunun yaklaşık 2 ^ -52 katı veya yaklaşık 10 ^ -17 olacaktır.

Özetle: ifadenizin sıfıra değerlendirmemesinin nedeni iki katlıdır:

  1. Başladığınız numaralardan bazıları, sağladığınız tam sayılara göre farklıdır (yaklaşık değerler).
  2. Ara sonuçlar aynı zamanda kesin sonuçların tahmini olabilir.
2
katma

Sorununuza uygun olup olmadığını bilmiyorum ama genellikle en basit çözüm, verilerinizi ölçeklendirmektir.

Örneğin:

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
katma
Bunun işe yaramasının bir nedeni var mı, yoksa bu örnekte "doğru" şeyi yapan geçici kod mu?
katma yazar Oliver Charlesworth, kaynak
Dürüst bilmiyorum ama bu tür sorunları çözmek için kesinlikle doğru yönde ilerliyor.
katma yazar Aabaz, kaynak
Bu her zaman çalışır mı, yoksa sadece biraz mı?
katma yazar Jim Clay, kaynak
Bu, her zaman f = @ (x) 1-x/x ^ 2 * x ve daha sonra f (rand ()) 'ı deneyerek görülebilir. zamanlar. Bazen 0; diğer zamanlarda epsilon. Ölçekleme, daha iyi sonuçlar elde etmenize yardımcı olur, ancak doğruluk hala epsilon'dur. Başka bir alternatif de, problemdeki diğer değerlerin ölçeğiyle eşleşmesi için epsilonu ölçeklendirmektir.
katma yazar stardt, kaynak

Gördüğünüz, niceleme hatası . Matlab, sayıları temsil etmek için ikilileri kullanır ve çok fazla hassasiyete sahip olsalar da, tüm gerçek sayıları temsil edemezler çünkü sonsuz sayıda gerçek sayı vardır. Aabaz'ın hile hakkında emin değilim, ama genel olarak, sizin girdilerinize çift-dostu numaralar olmak üzere masaj yapmaktan başka yapabileceğiniz bir şey olmadığını söyleyebilirim.

1
katma

Eminim ki bu bir kayan nokta doğruluk problemi durumunda.

1e-17 doğruluğa ihtiyacınız var mı? Bu sadece 'güzel' çıktı isteyen bir durum mu? Bu durumda, istediğiniz anlamlı basamak sayısını görüntülemek için biçimlendirilmiş bir sprintf kullanabilirsiniz.

Bunun bir matlab problemi olmadığını, sayıların ikili olarak nasıl temsil edildiğine dair temel bir sınırlama olduğunu fark edin.

Eğlenmek için, .1'in ikili olduğu ...

Bazı referanslar: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

1
katma