SORU
26 NİSAN 2012, PERŞEMBE


Ne kadar tehlikeli bir kayan nokta değeri karşılaştırmak için mi?

UİKit kullanır çözünürlük bağımsız koordinat sistemi nedeniyle CGFloat biliyorum.

Ama her zaman, örneğin frame.origin.x 0 olup olmadığını kontrol etmek istiyorum ama beni hasta ediyor:

if (theView.frame.origin.x == 0) {
    // do important operation
}

, , , *, >*<>=<=6?ile karşılaştırırken CGFloat yanlış pozitif karşı savunmasız değil Bir kayan nokta ve unprecision sorunları var: örneğin 0.0000000000041.

Objective-C karşılaştırırken dahili kullanım veya sıfır olarak okur origin.x gerçek 0 ile karşılaştırılamaz bir şey olabilir mi?

CEVAP
26 NİSAN 2012, PERŞEMBE


Öncelikle, kayan nokta değerleri "" kendi davranış. rastgele değildir Tam bir karşılaştırma yapabilirsiniz ve gerçek dünya kullanımları çok mantıklı. Ama eğer kayan nokta kullanmak için gidiyoruz nasıl çalıştığını bilmeniz gerekir. Kayan nokta varsayarak tarafında başıboş gerçek sayıları hızla keser kodu alacak gibi çalışır. Başıboş yanında varsayarak kayan noktalı sonuçlar büyük rastgele fuzz ilişkili (en cevapları burada öneririm) alın size kod olarak görünen iş yerinde ilk ama bitiyor olması büyük miktarlı hataları ve kırık köşe durumda.

Eğer kayan nokta ile program yapmak istiyorsanız öncelikle, bu okumalısınız:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Evet, hepsini okudum. Eğer bir yükü çok fazla ise, okumak için zaman kadar hesaplamalar için tamsayılar/sabit nokta kullanmalısınız. :-)

Bunu dedi, tam kayan nokta karşılaştırmalar ile en büyük sorunları aşağı gel

  1. Çok sayıda değerleri aslında kaynağını yazmak, ya da scanf strtod ile okuyabilirsinizyokolarak kayan nokta değerleri ve sessizce en yakın yaklaşım dönüştürülür. Bu demon9733 cevabı bahsediyordu.

  2. Birçok sonuçlar elde aslında gerçek sonucu temsil etmek için yeterince hassas olmaması nedeniyle yuvarlak. Görebileceğiniz kolay bir örnek x = 0x1fffffe y = 1 gibi yüzer ekleme. Burada, x 24 bit hassas mantis (Tamam) ve y sadece 1 bit, ama eklediğinizde onları, onların bit değil çakışan yerler, ve Neden İhtiyaç 25 bit hassas. Bunun yerine, yuvarlak (varsayılan yuvarlama modu 0x2000000) alır.

  3. Birçok sonuçlar elde aslında sonsuz sayıda doğru değeri için bir yerlere ihtiyacı nedeniyle yuvarlak. Bu içerir, hem rasyonel sonuçlar gibi 1/3 (haberiniz ondalık nereye alır sonsuz tane yerler) ama aynı zamanda 1/10 (de alır sonsuz birçok yerde ikili, o zamandan beri yok 5 güç 2) gibi irrasyonel sonuçlar gibi kare kökü bir şey yok mükemmel bir kare.

  4. Çift yuvarlama. Bazı sistemlerde (özellikle) 86, kayan nokta ifadeler nominal türlerine göre daha yüksek hassasiyetle değerlendirilmektedir. Bu demek oluyor ki ne zaman bir yukarıdaki tür yuvarlama olacak, alacaksın iki yuvarlama adımları, ilk yuvarlama sonucu yüksek duyarlıklı yazın, sonra bir yuvarlama için son yazın. Örnek olarak, düşünün ne olur ondalık eğer yuvarlak 1.49 arasında bir tam sayı (1), karşı ne olursa ilk raund için bir ondalık basamağa (1.5) sonra yuvarlak bu sonuç için bir tamsayı (2). Bu aslında derleyici (özellikle arabası olmayan uygun GCC gibi Derleyiciler için) davranışı öngörülemez olduğundan, kayan nokta ile başa çıkmak için en pis yerlerinden biridir.

  5. Transandantal fonksiyonlar (trig, exp, log, vb.) hassasiyet (genellikle olarak anılacaktır . doğru yuvarlanır sonuçları; sonuç sadece son etapta bir ünite içinde doğru olduğu belirtildi olmaması belirtilmedi ^strong>1ulp).

Kayan nokta kod yazılırken, sonuçların hatalı olmasına neden ve karşılaştırmalar buna göre bu numaraları ile ne yaptığını akılda tutmak gerekir. Genellikle mantıklı bir karşılaştırma yapacak kez "epsilon", ama bu epsilon dayalı olmalıdırkarşılaştırma sayıların büyüklükmutlak sabit değil. (Mutlak sürekli bir epsilon işe yarayacağını durumlarda, bu sabit nokta, kayan nokta değil, iş için doğru aracı olduğunu güçlü bir göstergesidir!)

Düzenleme:Özellikle, büyüklük göreli epsilon bir çek gibi bir şey görünmelidir:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x y))

Nerede FLT_EPSILON sürekli float.h (yerine DBL_EPSILONdoubleLDBL_EPSILON long doubles) ve K sürekli tercih gibi birikmiş hata hesaplamalara kesinlikle sınırlı K ünitelerinde son yer (ve eğer sen geldiğinden emin misin hata ilişkili hesaplama doğru olanı yapmak K bir kaç kat daha büyük ne hesaplamaların diyebilirim.

Son olarak, eğer bunu kullanırsanız, bazı özel bakım FLT_EPSILON denormals için anlamsız olduğundan sıfıra yakın gerekli olabilir unutmayın. Hızlı bir düzeltme yapmak olacaktır:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x y) || fabs(x-y) < FLT_MIN)

ve aynı şekilde, eğer çiftler kullanıyorsanız DBL_MIN değiştirin.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Awesomesauce Network

    Awesomesauce

    4 EKİM 2012
  • Elliot Davin

    Elliot Davin

    28 Kasım 2008
  • Murray Winiata

    Murray Winia

    2 ŞUBAT 2009