Her şeyden önce, kayan nokta değerleri davranışlarında "rastgele" değildir. Tam karşılaştırma, birçok gerçek dünya kullanımında mantıklı olabilir ve mantıklıdır. Ancak kayan nokta kullanacaksanız, nasıl çalıştığının farkında olmanız gerekir. Gerçek sayılar gibi çalışır gibi kayan nokta varsayım yan tarafında erring hızlı bir şekilde kırmak kodu alacak. Kayan nokta sonuçlarının yanılsama tarafındaki erringler, kendileriyle ilişkili büyük rastgele tüylere sahiptir (buradaki cevapların çoğunun önerdiği gibi), ilk başta çalışıyor gibi görünen ancak büyük büyüklükteki hatalara ve kırık köşe vakalarına sahip olan kodu alacaktır.
Her şeyden önce, kayan nokta ile programlamak istiyorsanız, bunu okumalısınız:
Her Bilgisayar Bilimcisinin Kayan Nokta Aritmetiği Hakkında Bilmesi Gerekenler
Evet, hepsini oku. Bu çok fazla bir yük ise, okumalarınız için zamanınız olana kadar hesaplamalarınızda tamsayılar / sabit nokta kullanmalısınız. :-)
Şimdi, bununla birlikte, tam kayan nokta karşılaştırmalarıyla ilgili en büyük sorunlar şöyledir:
Değerlerin çoğu da kaynağında yazabilir veya giriş okuyabilirsiniz gerçeği scanf
ya strtod
, var olmayan kayan nokta değerleri olarak ve sessizce yakın yakınlaştırılmasına dönüştürülür. Bu demon9733'ün cevabından bahsediyordu.
Gerçek sonucu temsil etmek için yeterli hassasiyete sahip olmadığı için birçok sonucun yuvarlanması. Bunu görebileceğiniz kolay bir örnek ekleme x = 0x1fffffe
ve y = 1
kayan reklamlardır. Burada, x
mantiste 24 bit hassasiyete sahiptir (ok) ve y
sadece 1 bit vardır, ancak bunları eklediğinizde, bitleri çakışan yerlerde değildir ve sonuç 25 bit hassasiyete ihtiyaç duyar. Bunun yerine yuvarlanır ( 0x2000000
varsayılan yuvarlama modunda).
Doğru sonuç için sonsuz sayıda yere ihtiyaç duyulması nedeniyle birçok sonucun yuvarlanması. Bu, 1/3 (sonsuz sayıda yer aldığı ondalıktan bildiğiniz) gibi rasyonel sonuçları da içerir, ancak 1/10 (5'in gücü olmadığı için ikili olarak da sonsuz sayıda yer alır), mükemmel bir kare olmayan her şeyin karekökü gibi irrasyonel sonuçların yanı sıra.
Çift yuvarlama. Bazı sistemlerde (özellikle x86), kayan nokta ifadeleri nominal türlerinden daha yüksek hassasiyetle değerlendirilir. Bu, yukarıdaki yuvarlama türlerinden biri gerçekleştiğinde, ilk önce daha yüksek hassasiyetli türe yuvarlama, ardından son türe yuvarlama olmak üzere iki yuvarlama adımı alacağınız anlamına gelir. Örnek olarak, 1.49 değerini bir tamsayıya (1) yuvarlarsanız ondalık basamakta ne olacağını düşünün; ilk önce bir ondalık basamağa (1.5) yuvarlarsanız, ardından bu sonucu bir tamsayıya (2) yuvarlarsanız ne olacağını düşünün. Bu aslında kayan nokta ile başa çıkmak için en nazik alanlardan biridir, çünkü derleyicinin davranışı (özellikle GCC gibi buggy, uygun olmayan derleyiciler için) tahmin edilemez.
Transendental işlevleri ( trig
, exp
, log
vs.) doğru yuvarlatılmış sonuçlara sahip olduğu belirtilmemiştir; sonuç sadece son bir hassasiyet yerinde (genellikle 1ul olarak adlandırılır ) bir birim içinde doğru olarak belirtilir .
Kayan nokta kodu yazarken, sonuçların hatalı olmasına neden olabilecek sayılarla ne yaptığınızı akılda tutmanız ve buna göre karşılaştırmalar yapmanız gerekir. Çoğu zaman bir "epsilon" ile karşılaştırmak mantıklı olacaktır, ancak bu epsilon , karşılaştırdığınız sayıların büyüklüğüne dayanmalıdır, mutlak bir sabit değil. (Mutlak sabit bir epsilonun işe yarayacağı durumlarda, bu, kayan nokta değil, sabit noktanın iş için doğru araç olduğunu güçlü bir şekilde gösterir!)
Düzenle: Özellikle, göreceli bir epsilon kontrolü şöyle görünmelidir:
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))
Burada FLT_EPSILON
bir sürekli float.h
(ile değiştirin DBL_EPSILON
için double
s veya LDBL_EPSILON
için long double
s) veK
size hesaplamaların biriken hata kesinlikle sınırlanmış şekildedir seçim bir sabittir K
son sırada birimlere (eğer emin değilseniz ve hata var bağlı hesaplama hakkı, K
hesaplamalarınızın olması gerektiği gibi birkaç kat daha büyük yapın).
Son olarak, bunu kullanırsanız, sıfıra yakın bir miktar özel bakım gerekebilir, çünkü FLT_EPSILON
denormaller için mantıklı olmadığı için . Hızlı bir düzeltme bunu yapmak olacaktır:
if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)
ve aynı şekilde DBL_MIN
iki kat kullanıldığında ikame edilir.
fabs(x+y)
x
vey
( eğer ) farklı işarete sahipse sorunludur . Yine de, kargo kült karşılaştırmaları gelgit karşı iyi bir cevap.