İçeriği atlamak için "Enter"'a basın

Effective Java Madde 60: Net Sonuçlar Almak İstiyorsanız double ve float Kullanmaktan Kaçının

Java’da double ve float bilimsel ve mühendislik hesaplamaları için tasarlanmış türlerdir. Bu türler, ikili kayan noktalı işlemler (binary floating-point arithmetic) yapmak için tasarlarlanmıştır ancak net sonuçlar almak istediğinizde doğru çalışmazlar. Özellikle de parasal hesaplamalar yapmak için hiç uygun değildirler çünkü 0.1 değerini (ya da 10’un diğer negatif kuvvetlerini) double veya float kullanarak ifade etmek imkansızdır.

Örneğin, cebinizde 1.03 dolar olduğunu varsayalım ve 42 cent harcadınız. Ne kadar paranız kalmış olması lazım? Bunu öğrenmek için aşağıdaki kod satırını yazdığımızı düşünelim:

System.out.println(1.03 - 0.42);

Maalesef bu satır 0.6100000000000001 yazdıracaktır ve bu istisnai bir durum değildir. Cebinizde 1 dolar olsa ve her biri 10 cent olan 9 tane çivi almış olsanız, ne kadar para üstü almanız gerekir?

System.out.println(1.00 - 9 * 0.10);

Yukarıdaki kod satırına göre cevap 0.09999999999999998 olacaktır.

Bunu çözmek için sonucu yuvarlamak isteyebilirsiniz ama bu da her zaman çalışmaz. Diyelim ki cebinizde yine bir dolar var ve karşınızdaki rafta 10 cent, 20 cent, 30 cent şeklinde sıralanmış tanesi 1 dolara kadar giden şekerler var. Siz de 10 cent olandan başlayıp her birinden birer tane olacak şekilde olabildiğince çok sayıda şeker almak istiyorsunuz. Kaç tane şeker alabilirsiniz ve ne kadar para üstü kalır? Aşağıdaki programla bunu cevaplamaya çalışalım:

// Bozuk - parasal hesaplama için double kullanılıyor
public static void main(String[] args) {
    double funds = 1.00;
    int itemsBought = 0;
    for (double price = 0.10; funds >= price; price += 0.10) {
        funds -= price;
        itemsBought++;
    }
    System.out.println(itemsBought + " items bought.");
    System.out.println("Change: $" + funds);
}

Bu programı çalıştırırsanız, sadece üç tane şeker alabildiğinizi ve para üstü olarak $0.3999999999999999 alacağınızı gösterir. Bu cevap yanlıştır! Bu kodu doğru yazmak için, parasal hesaplamalarda BigDecimal, int veya long kullanmalıyız.

Aşağıda aynı kodu double yerine BigDecimal kullanarak yazdık. Dikkat ederseniz BigDecimal yaratırken double değil String alan yapıcı metodu kullanmamız gerekmektedir.

public static void main(String[] args) {
    final BigDecimal TEN_CENTS = new BigDecimal(".10");
    int itemsBought = 0;
    BigDecimal funds = new BigDecimal("1.00"); 
    for (BigDecimal price = TEN_CENTS; funds.compareTo(price) >= 0; price = price.add(TEN_CENTS)) {
        funds = funds.subtract(price);
        itemsBought++;
    }
    System.out.println(itemsBought + " items bought.");
    System.out.println("Money left over: $" + funds);
}

Bu programı çalıştırdığınız zaman size dört tane şeker alabildiğinizi ve para üstü olarak $0.00 kaldığını gösterecektir, doğru cevap da budur.

BigDecimal kullanmanın iki tane de dezavantajı vardır. Bunlardan birincisi temel türlere kıyasla kullanması pratik değildir ve ikincisi de yine temek türlere kıyasla çok yavaştır. Yavaşlık problemi kısa problemler için sorun yaratmayabilir ama kullanımının pratik olmaması biraz canınızı sıkabilir.

BigDecimal kullanmak yerine int veya long gibi temel türler kullanabilir ve duruma göre ondalık değerleri kendiniz takip edebilirsiniz. Bu örnekte, bütün parasal değerleri dolar yerine cent cinsinden tutarsak aşağıdaki gibi bir kod yazabiliriz:

 public static void main(String[] args) {
     int itemsBought = 0;
     int funds = 100;
     for (int price = 10; funds >= price; price += 10) {
         funds -= price;
         itemsBought++;
    }
    System.out.println(itemsBought + " items bought.");
    System.out.println("Cash left over: " + funds + " cents");
}

Özetle, bir matematiksel hesaplama yaparken tam cevaplar almak istiyorsanız float veya double kullanmaktan kaçınmalısınız. Eğer ondalık değerlerle uğraşmak istemiyorsanız ve performans kaybı önemli değilse BigDecimal kullanabilirsiniz. BigDecimal kullanmanın bir avantajı da size sekiz farklı yuvarlama modu sunmasıdır. Eğer yasal sebeplerden ötürü belli bir yuvarlama davranışı kullanmanız gerekiyorsa bunun faydasını görebilirsiniz. Eğer performans çok önemliyse ve ondalık değerleri kendiniz takip edebiliyorsanız, değerlerin büyüklüğüne göre int veya long kullanın.

Share

Bir Cevap Yazın

%d blogcu bunu beğendi: