Şamandıra yanlışlığından kaynaklanan eşitsizlik


15

En azından Java'da, bu kodu yazarsam:

float a = 1000.0F;
float b = 0.00004F;
float c = a + b + b;
float d = b + b + a;
boolean e = c == d;

değeri olacaktır f bir L s e . Bunun şamandıraların sayıları doğru bir şekilde temsil etme biçiminde çok sınırlı olmasından kaynaklandığına inanıyorum. Sadece pozisyonunu değiştirerek Ama neden anlamıyorum bir bu eşitsizlik neden olabilir.efalsea

Ben, indirgenmiş aşağıdaki gibi her iki hat 3 ve 4'ten s, değeri e ancak olur t r u E :betrue

float a = 1000.0F;
float b = 0.00004F;
float c = a + b;
float d = b + a;
boolean e = c == d;

3. ve 4. satırda tam olarak ne oldu? Şamandıralarla yapılan ekleme işlemleri neden ilişkili değildir?

Şimdiden teşekkürler.


16
Senin örneğin gösterdiği gibi, nokta eklenmesini yüzen olduğunu değişmeli. Ancak çağrışımsal değildir.
Yuval Filmus

1
Temel tanımlara bakmanızı öneririm. Derleyicinin ( r + s ) + t (ekleme solla ilişkilendirilir ) olarak ayrıştırdığına dikkat edin . r+s+t(r+s)+t
Yuval Filmus

2
Bunun neden böyle olması gerektiğini anlamanın kolay bir yolu için, Xçok büyük bir sayı ve Yçok küçük bir sayı düşünün X + Y = X. Burada X + Y + -Xsıfır olacak. Ama X + -X + Yolacak Y.
David Schwartz


Yanıtlar:


20

Tipik kayan nokta uygulamalarında, tek bir işlemin sonucu, işlem sonsuz bir hassasiyetle gerçekleştirilmiş gibi üretilir ve daha sonra en yakın kayan nokta sayısına yuvarlanır.

Karşılaştırması ve b + a : sonsuz duyarlık ile yapılan her işlemin sonucu dolayısıyla bu aynı sonsuz hassas sonuçlar aynı şekilde yuvarlanır aynıdır. Başka bir deyişle, kayan nokta ilavesi değişmeli.a+bb+a

Al : b bir kayan nokta sayısıdır. İle ikili kayan nokta sayıları, 2 b böylece kayan nokta sayısı (üs tek büyük), aynı zamanda b + b herhangi yuvarlama hatasız ilave edilir. Daha sonra , bir ilave edilir tam değeri b + b . Sonuç, en yakın kayan nokta sayısına yuvarlanan tam 2 b + a değeridir .b+b+ab2bb+bab+b2b+a

alın : a + b eklenir ve yuvarlama hatası r olur , bu nedenle sonucu a + b + r alırız . Ekleme b ve sonuç kesin değeri 2 b + bir + r , en yakın kayan nokta sayıya yuvarlanır.a+b+ba+bra+b+rb2b+a+r

Yani bir durumda, , yuvarlak. Diğer durumda, 2 b + a + r , yuvarlak.2b+a2b+a+r

PS. İki belirli sayı için ve b'nin her iki hesaplamanın da aynı sonucu verip vermediği sayılara ve a + b hesaplamasındaki yuvarlama hatasına bağlıdır ve tahmin edilmesi zordur. Tek veya çift kesinlik kullanmak, prensipte problem için bir fark yaratmaz, ancak yuvarlama hataları farklı olduğundan, tek kesinlikte sonuçların eşit olduğu ve çift kesinlikte olmadığı veya tersi olduğu durumlarda a ve b değerleri olacaktır. Kesinlik çok daha yüksek olacaktır, ancak kayan nokta aritmetiğinde iki ifadenin matematiksel olarak aynı olduğu ancak aynı olmadığı sorunu aynı kalmaktadır.aba+b

PPS. Bazı dillerde, kayan nokta aritmetiği, gerçek ifadelerde belirtilenden daha yüksek bir hassasiyetle veya daha yüksek bir sayı aralığıyla gerçekleştirilebilir. Bu durumda, her iki toplamın da aynı sonucu vermesi çok daha olasıdır (ancak yine de garanti edilmez).

Bitki koruma ürünlerinin. Bir yorum, kayan nokta sayılarının eşit olup olmadığını sormamamız gerektiğini sordu. Kesinlikle ne yaptığını biliyorsan. Örneğin, bir diziyi sıralarsanız veya bir kümeyi uygularsanız, "yaklaşık olarak eşit" kavramını kullanmak istiyorsanız, kendinizi büyük bir belaya sokarsınız. Bir grafik kullanıcı arayüzünde, bir nesnenin boyutu değiştiyse nesne boyutlarını yeniden hesaplamanız gerekebilir - pratikte neredeyse aynı boyutlara sahip olmadığınızı ve programınızın doğru olduğunu bilerek, yeniden hesaplamayı önlemek için oldSize == newSize değerini karşılaştırırsınız. gereksiz bir yeniden hesaplama olsa bile.


Bu özel durumda, b, ikiliye dönüştürüldüğünde periyodik hale gelir, bu nedenle her yerde yuvarlama hataları vardır.
André Souza Lemos

1
bBu cevaptaki @ AndréSouzaLemos 0.00004 değil, dönüşüm ve yuvarlamadan sonra elde ettiğiniz şey .
Alexey Romanov

"Tipik kayan nokta uygulamalarında, tek bir işlemin sonucu, işlem sonsuz bir hassasiyetle yapılmış ve daha sonra en yakın kayan nokta sayısına yuvarlanmış gibi üretilir." bunu gerçekten mantık kapıları açısından uygulamaya çalıştığımda (simülatör sadece 64 bitlik otobüsleri işleyebilir).
John Dvorak

Naif soru: Şamandıra eşitliği testi hiç mantıklı mı? Çoğu programlama dili neden aa == b testinin her ikisinin veya birinin kayan nokta olduğunu belirtir?
curious_cat

Wikipedia'dan ilgili tanım: " Makine Epsilon , kayan nokta aritmetiğindeki yuvarlama nedeniyle bağıl hatada bir üst sınır verir."
Blackhawk

5

Bilgisayarlar tarafından desteklenen ikili kayan noktalı biçim, temelde insanlar tarafından kullanılan ondalık bilimsel gösterime benzer.

Kayan nokta sayısı, bir işaret, mantis (sabit genişlik) ve üs (sabit genişlik) içerir, örneğin:

+/-  1.0101010101 × 2^12345
sign   ^mantissa^     ^exp^

Düzenli bilimsel gösterim benzer bir biçime sahiptir:

+/- 1.23456 × 10^99

Eğer bilimsel gösterimde sonlu hassasiyetle aritmetik yaparsak, her işlemden sonra yuvarlanırsak, ikili kayan nokta ile aynı kötü etkileri elde ederiz.


Misal

Göstermek için, ondalık noktadan sonra tam olarak 3 basamak kullandığımızı varsayalım.

a = 99990 = 9.999 × 10^4
b =     3 = 3.000 × 10^0

(a + b) + b

Şimdi hesaplıyoruz:

c = a + b
  = 99990 + 3      (exact)
  = 99993          (exact)
  = 9.9993 × 10^4  (exact)
  = 9.999 × 10^4.  (rounded to nearest)

Bir sonraki adımda, elbette:

d = c + b
  = 99990 + 3 = ...
  = 9.999 × 10^4.  (rounded to nearest)

Bu nedenle, (a + b) + b = 9.999 x 10 4 .

(b + b) + a

Ancak işlemleri farklı bir sırayla yapsaydık:

e = b + b
  = 3 + 3  (exact)
  = 6      (exact)
  = 6.000 × 10^0.  (rounded to nearest)

Sonra hesaplıyoruz:

f = e + a
  = 6 + 99990      (exact)
  = 99996          (exact)
  = 9.9996 × 10^4  (exact)
  = 1.000 × 10^5.  (rounded to nearest)

Dolayısıyla (b + b) + a = 1.000 × 10 5 , ki bu bizim diğer cevabımızdan farklı.


5

Java, IEEE 754 ikili kayan nokta temsilini kullanır, bu mantis için 23 ikili haneyi ayırır, bu ilk önemli basamakla başlamak için normalleştirilir (yer kazanmak için atlanır).

0.0000410=0,00000000000000101001111100010110101100010001110001101101000111 ...2=[1.]01001111100010110101100010001110001101101000111 ...2x2-15

100010+0.0000410=1111101000,00000000000000101001111100010110101100010001110001101101000111 ...2=[1.]11110100000000000000000101001111100010110101100010001110001101101000111 ...2x29

Kırmızı kısımlar, aslında (yuvarlamadan önce) temsil edildikleri için mantislerdir.

(100010+0.0000410)+0.0000410(0.0000410+0.0000410)+100010


0

Son zamanlarda benzer bir yuvarlama sorunuyla karşılaştık. Yukarıda belirtilen cevaplar doğrudur, ancak oldukça tekniktir.

Aşağıdakilerin yuvarlama hatalarının neden olduğu konusunda iyi bir açıklama olduğunu gördüm. http://csharpindepth.com/Articles/General/FloatingPoint.aspx

TLDR: ikili kayan noktalar, ondalık kayan noktalara tam olarak eşlenemez. Bu, matematiksel işlemler sırasında bileşik olabilecek yanlışlıklara neden olur.

Ondalık kayan sayıları kullanan bir örnek: 1/3 + 1/3 + 1/3 normalde 1'e eşittir. Ancak, ondalık basamaklarda: 0.333333 + 0.333333 + 0.333333 asla tam olarak 1.000000'e eşit değildir

İkili ondalık sayılar üzerinde matematiksel işlemler yaparken de aynı şey olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.