22 Mart 2016 Salı

Java Notları – Parasal Problemler

English version is at DZone

İlkokulda çözmeye alıştığımız basit bir problemi bir de Java’da yazacağımız kodla çözmeye çalışalım.

Klasik problem şöyle:

Ali’nin cebinde 1 TL’si vardır, Ali cebindeki para ile bakkaldaki, 10 Kr’luk şekerlerden kaç tane alabilir?

Java Kodumuz:
public static void main(String[] args) { float alininParasi = 1.00f; float sekerinFiyati = 0.10f; int aldigiSekerlerinSayisi = 0; System.out.println("Ali'nin cebinde, " + alininParasi + " TL'si vardir."); System.out.println("Bakkaldaki sekerin tanesi " + sekerinFiyati + " TL'dir."); while (alininParasi >= sekerinFiyati) { aldigiSekerlerinSayisi++; alininParasi -= sekerinFiyati; } System.out.println("Hesaplamamiza gore, Ali bakkaldan " + aldigiSekerlerinSayisi + " seker alabilir ve cebinde de " + alininParasi + " TL'si kalir."); }
Program Çıktısı:

Ali'nin cebinde, 1.0 TL'si vardir.
Bakkaldaki sekerin tanesi 0.1 TL'dir.
Hesaplamamiza gore, Ali bakkaldan 9 seker alabilir ve cebinde de 0.09999993 TL'si kalir.

Nasıl olur?

Burada, beklentimizden farklı bir sonuç görmemizin nedeni, kodumuzda parasal değerleri float(veya abisi double) veri tiplerinde tutmamızdır. Java’da float ve double veri tipleri, bilimsel ve mühendislik hesaplamalarında, hızlı ve doğru sonuçlar elde etmek üzere tasarlanmışlardır. Bu sebepten, tam(exact) sonuçlar beklediğimiz parasal hesaplamalarda bu veri tiplerini kullanmamamız gerekir. Bunun yerine BigDecimal, int veya long veri tiplerini kullanmamız gerekir.

Yukarıdaki Java kodumuzu float yerine BigDecimal kullanarak tekrar yazalım:
public static void main(String[] args) { BigDecimal alininParasi = new BigDecimal("1.00"); BigDecimal sekerinFiyati = new BigDecimal("0.10"); int aldigiSekerlerinSayisi = 0; System.out.println("Ali'nin cebinde, " + alininParasi + " TL'si vardir."); System.out.println("Bakkaldaki sekerin tanesi " + sekerinFiyati + " TL'dir."); while (alininParasi.compareTo(sekerinFiyati) >= 0) { aldigiSekerlerinSayisi++; alininParasi = alininParasi.subtract(sekerinFiyati); } System.out.println("Hesaplamamiza gore, Ali bakkaldan " + aldigiSekerlerinSayisi + " seker alabilir ve cebinde de " + alininParasi + " TL'si kalir."); }
Program Çıktısı:

Ali'nin cebinde, 1.0 TL'si vardir.
Bakkaldaki sekerin tanesi 0.1 TL'dir.
Hesaplamamiza gore, Ali bakkaldan 10 seker alabilir ve cebinde de 0.0 TL'si kalir.

Evet şimdi oldu.

Burada BigDecimal kullanımı ile ilgili iki dezavantajdan bahsedebiliriz:
  1.  Primitive tipler kadar kullanışlı değil
  2.  Yavaş

Basit hesaplamalar için ikincisi pek canımızı sıkmasa da, ilki bazen sinir bozucu olabilir. 

BigDecimal’e alternatif olarak, int veya long veri tiplerini kullanmayı seçebiliriz. Bu durumda ondalık kısımları bizim yönetmemiz gerekiyor. Yani yukarıdaki örneğimizde hesaplamalarımızı lira olarak değil de kuruş olarak yapmamız gerekir:
public static void main(String[] args) { int alininParasi = 100; int sekerinFiyati = 10; int aldigiSekerlerinSayisi = 0; System.out.println("Ali'nin cebinde, " + (alininParasi*0.01) + " TL'si vardir."); System.out.println("Bakkaldaki sekerin tanesi " + (sekerinFiyati*0.01) + " TL'dir."); while (alininParasi >= sekerinFiyati) { aldigiSekerlerinSayisi++; alininParasi -= sekerinFiyati; } System.out.println("Hesaplamamiza gore, Ali bakkaldan " + aldigiSekerlerinSayisi + " seker alabilir ve cebinde de " + (alininParasi *0.01) + " TL'si kalir."); }
Program Çıktısı:

Ali'nin cebinde, 1.0 TL'si vardir.
Bakkaldaki sekerin tanesi 0.1 TL'dir.
Hesaplamamiza gore, Ali bakkaldan 10 seker alabilir ve cebinde de 0.0 TL'si kalir.

BigDecimal ve int veri tipleri arasındaki performans farkını, Ali’nin parasını 1.000.000 TL’ye çıkardığımız aşağıdaki program çıktılarında görebiliriz.

Program Çıktısı(BigDecimal):

Ali'nin cebinde, 1000000.0 TL'si vardir.
Bakkaldaki sekerin tanesi 0.1 TL'dir.
Hesaplamamiza gore, Ali bakkaldan 10000000 seker alabilir ve cebinde de 0.0 TL'si kalir.
islem suresi: 460 ms

Program Çıktısı(int):

Ali'nin cebinde, 1000000.0 TL'si vardir.
Bakkaldaki sekerin tanesi 0.1 TL'dir.
Hesaplamamiza gore, Ali bakkaldan 10000000 seker alabilir ve cebinde de 0.0 TL'si kalir.

ali kemal taşçı

2 yorum:

Dr. Binnur Kurt dedi ki...

Aşağıdaki yazıyı okumak faydalı olabilir:
http://binkurt.blogspot.com.tr/2015/04/temel-tipler-uzerinde-karslastrma.html

. dedi ki...

Teşekkürler Binnur Hocam