anlak.com

Kayan noktalı (floating point) sayı kıyaslama

, Friday 29 March 2013
Sayılamaz sonsuzlukta reel sayıların ancak çok sınırlı sayıda bir kısmını bilgisayarda temsil edebiliyoruz. Bu yüzden yaptığımız hesaplarda gerçek sonuçtan biraz farklı bir değer elde ediyoruz. Kimi zaman da bu küsüratlı sayıları kıyaslamamız gerekiyor.

Bu kıyaslama işlemi fazlasıyla sıkıntılı bir iş. Pratikte çoğunlukla işe yarayacak ipuçlarını paylaşayım dedim. Kolaylık olsun diye yazının geri kalanında kayan noktalı sayılar için double kelimesini kullanacağım, söylediğim şeyler float gibi herhangi bir kayan noktalı sayı gösterimi için geçerlidir.

Altın kural: Asla, ama asla, iki double'ı == ya da != gibi karşılaştırma operatörleriyle doğrudan kıyaslamayın. Çoğunlukla eşit olmayacaklardır.
  1. Yaklaşık eşitliği sınayan fonksiyonunuz olsun, heryerde aynısını kullanın.
    approxEqual(double a, double b, double eps=machine_epsilon) 
        return abs(a-b) <= max(a,b)*eps;
    max() yerine min() de kullanılabilir. Bunu yapınca tabi ki fonksiyonun davranışı değişecek, mühim olan hassasiyetinizi kıyaslanacak sayılara göre ölçeklemek.
  2. Bir double'ı sıfırla kıyaslayacaksanız işler karışıyor. Genelde kıyaslayacağınız sayı kabul edilebilir seviyede küçük, fakat sıfırdan hatrı sayılır derecede (hatta sonsuz kat) büyük olacaktır. Yukarıdaki approxEqual()bu durumda işe yaramayacaktır. Sıfırla kıyaslama durumunu ayrıca değerlendirin.
    approxZero(double d, double eps=machine_epsilon)
        return abs(d)<=eps;
  3. İki sayının farkını sıfırla kıyaslamak yerine, iki sayıyı birbiriyle kıyaslayın. Bir önceki maddede açıkladığım gibi sıfırla kıyaslama daha problemli bir iş.
  4. Bu iki yaklaşım da tam olarak doğru yaklaşımlar değil aslında, ama çoğunlukla işinizi görecektir. Hassasiyet hatalarıyla başetmenin kesin yolu hatanın analizini yapıp yukarıdaki fonksiyonlarda eps değişkeninin varsayılan değerini kullanmak yerine hesapladığınız teorik hataya göre bir eps seçmek. Bunu yapmak genelde çok zor. İkinci yol ise deneme yanılma; işinize yarayacak epsilon değerini el yordamıyla bulacaksınız.
  5. Kayan noktalı sayılarla işlem yapmaca göründüğünden ve sandığınızdan çok daha zor ve karmaşık bir iş. Örneğin kıyasladığınız iki sayıdan birinin sıfır olma ihtimali varsa allah yardımcınız olsun.
Yukarıda machine_epsilon diye kodladığım değişkeni genelde kullandığınız programlama dili size bir sabit olarak verir, dökümantasyonunuza bakın.

Dediğim gibi kayan noktalı sayılar çok derin bir konu ve ancak şöyle bir üzerinden yalayıp geçtim. Yazdığım kadarı günlük kullanım için yeterli olur herhalde.

No comments:

Post a Comment