Birçok sonsuz gerçek sayıyı sonlu sayıda bit halinde sıkıştırmak, yaklaşık bir gösterim gerektirir. Çoğu program, tamsayı hesaplamalarının sonucunu maksimum 32 veya 64 bitte saklar. Herhangi bir sabit sayıda bit verildiğinde, gerçek sayılarla yapılan çoğu hesaplama, o kadar çok bit kullanılarak tam olarak temsil edilemeyen miktarlar üretecektir. Bu nedenle kayan nokta hesaplamasının sonucunun genellikle sonlu temsiline sığması için yuvarlanması gerekir. Bu yuvarlama hatası kayan nokta hesaplamasının karakteristik bir özelliğidir. Bu nedenle, kayan noktalı sayılarda hesaplamalar yaparken (özellikle hesaplamalar para cinsindense), bir programlama dilindeki yuvarlama hatalarına dikkat etmemiz gerekir. Bir örnek görelim:
Javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
dize yöntemleri
Çıkış:
x = 0.7999999999999999
y = 0.8
false
Burada cevap, Java derleyicisi tarafından yapılan yuvarlama nedeniyle beklediğimiz gibi değil.
Yuvarlama Hatasının Arkasındaki Sebep
Float ve Double veri türleri, IEEE kayan nokta 754 spesifikasyonunu uygular. Bu, sayıların aşağıdaki gibi bir biçimde temsil edildiği anlamına gelir:
SIGN FRACTION * 2 ^ EXP 0,15625 = (0,00101)2kayan nokta formatında şu şekilde temsil edilir: 1,01 * 2^-3
Tüm kesirler tam olarak ikinin kuvvetinin kesirleri olarak temsil edilemez. Basit bir örnek olarak 0,1 = (0,000110011001100110011001100110011001100110011001100110011001… )2 ve bu nedenle kayan noktalı bir değişkenin içinde saklanamaz.
Başka Bir Örnek:
javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
Çıkış:
x = 0.7999999999999999
y = 0.8
false
Başka bir örnek:
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); // Value of a is expected as 0.1 System.out.println('a = ' + a); } }
Çıkış:
a = 0.09999999999999998Yuvarlama Hataları Nasıl Düzeltilir?
- Sonucu yuvarlayın: Round() işlevi, kayan noktalı aritmetik depolama yanlışlığının etkilerini en aza indirmek için kullanılabilir. Kullanıcı, sayıları hesaplamanın gerektirdiği ondalık basamak sayısına yuvarlayabilir. Örneğin para birimiyle çalışırken muhtemelen 2 ondalık basamağa yuvarlarsınız.
- Algoritmalar ve İşlevler: Bu gibi durumlarla başa çıkmak için sayısal olarak kararlı algoritmalar kullanın veya kendi işlevlerinizi tasarlayın. Doğru olduğundan emin olmadığınız rakamları kesebilir/yuvarlayabilirsiniz (işlemlerin sayısal hassasiyetini de hesaplayabilirsiniz)
- BigDecimal Sınıfı: Şunu kullanabilirsiniz: java.math.BigDecimal Özellikle büyük kesirli sayılarda doğruluk sağlamak üzere tasarlanmış sınıf. Aşağıdaki program hatanın nasıl giderilebileceğini gösterir:
import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String args[]) { BigDecimal a = new BigDecimal('1.0'); BigDecimal b = new BigDecimal('0.10'); BigDecimal x = b.multiply(new BigDecimal('9')); a = a.subtract(x); // Rounding to 1 decimal place a = a.setScale(1 RoundingMode.HALF_UP); System.out.println('a = ' + a); } }
Çıkış:
0.1Burada a = a.setScale(1 RoundingMode.HALF_UP);
Turlar aHALF_UP yuvarlama modunu kullanarak 1 ondalık basamağa. Dolayısıyla BigDecimal'in kullanılması, aritmetik ve yuvarlama işlemleri üzerinde daha hassas kontrol sağlar; bu da özellikle finansal hesaplamalar veya hassasiyetin çok önemli olduğu diğer durumlarda yararlı olabilir.
Önemli Not:
Math.round değeri en yakın tam sayıya yuvarlar. 0,10, 0'a 1'den daha yakın olduğundan 0'a yuvarlanır. Yuvarlama ve 1,0'a bölme işleminden sonra sonuç 0,0 olur. Böylece BigDecimal sınıfı ve Maths.round fonksiyonu ile çıktılar arasındaki farkı fark edebilirsiniz.
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); /* We use Math.round() function to round the answer to closest long then we multiply and divide by 1.0 to to set the decimal places to 1 place (this can be done according to the requirements.*/ System.out.println('a = ' + Math.round(a*1.0)/1.0); } }
Çıkış:
0.0