İçeriğe geç

BigDecimal — Parada Kuruş Kaybetmemek

Başlangıç 8 dk Çok sık karşılaşılır

Önce şunu oku: String — Hiç Değişmeyen Metin

30 saniyede özet

double ondalık sayıları yaklaşık tutar, bu yüzden para hesabında kuruş kaçırır. BigDecimal her haneyi tam tutar; onu metinden kurar, bölerken yuvarlama kuralını söyler ve karşılaştırırken compareTo kullanırsın.

Üç arkadaş 100 liralık bir kafe hesabını bölüşüyorsunuz ve biri “herkes 33 lira 33 kuruş” diyor. Geriye bir kuruş kaldı; kim ödeyecek?

Para hesabında bu küçük soru hep vardır. Java’da onu doğru cevaplamanın aracı tek bir sınıftır.

İki kasa aynı toplamayı yapıyor: biri kıl payı kaçırıyor, öteki kuruşu kuruşuna tutuyor.
Adım adım oku
  1. İki kasa da 0.10 ile 0.20'yi topluyor.
  2. double ile çalışan kasa 0.30000000000000004 buluyor: tam değil.
  3. BigDecimal ile çalışan kasa tam olarak 0.30 buluyor.
  4. Parada kıl payı da bir hatadır; bu yüzden para BigDecimal ile tutulur.
  1. Bayt: 0.1 ile 0.2'yi topladım, 0.30000000000000004 çıktı. Bilgisayar bozuk mu?

  2. Sen: Belki toplamayı yanlış yazdın?

  3. Bayt: Hayır, toplama doğru. Sorun sayının kendisinde: 0.1 tam olarak saklanamıyor.

  4. Bayt: Para için tam saklayan bir tip var. Gel onunla tanışalım.

double neden kuruş kaçırır?

double sayıları ikilik sistemde, sınırlı sayıda haneyle tutar. Buna kayan noktaSayıları ikilik sistemde sınırlı sayıda haneyle, yaklaşık olarak tutan gösterim. Java'da float ve double böyledir.0.5 gibi bazı ondalık sayılar tam sığar, 0.1 gibi çoğu sığmaz ve en yakın değere yuvarlanır. Bu yüzden para hesabında BigDecimal kullanılır.Sözlükte gör → sayı denir. 0.5 gibi bazı sayılar tam sığar, ama 0.1 gibi çoğu ondalık sayı sığmaz ve en yakın değere yuvarlanır.

Küçük farklar birikir
System.out.println(0.1 + 0.2); // 0.30000000000000004
double toplam = 0;
for (int i = 0; i < 10; i++) {
toplam += 0.1;
}
System.out.println(toplam); // 0.9999999999999999

Tek bir hesapta fark çok küçüktür. Ama milyonlarca işlemde birikir, faizde çarpılır ve ekstrede görünür.

Kasa kuruşları sayıyor

Tohum 478141
Tutarların kuruşa çevrilmesi
tutardouble × 100kuruşdoğrusu

Oynat ya da adımla: her adımda dört tutar çevrilir.

Hız
Adım 0

Şu an ne oldu?

(long) (tutar * 100) · Satış fiyatları (2 hane)

Kasa her tutarı kuruşa çevirecek, gün sonunda toplamı beklenenle karşılaştıracak.

Görevler0/3

  • Bir günde en az 8 kuruş kaybetaçık

    İpucu

    Varsayılan ayarlar yeter.

  • Math.round ile bile yanlış yuvarlanan bir tutar bulaçık

    İpucu

    Üç haneli tutarlara bak.

  • Faiz tutarlarını hatasız çevir ve mutabakatı tutturaçık

    İpucu

    Sayıyı metinden kur, kuralı söyle.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. (long) (tutar * 100) on iki fiyattan sekizinde bir kuruş kesti; gün sonu toplamı tutmadı.
  2. “Math.round” seç. Fiyatlar düzeldi, ama double toplam yine 63.38’e eşit değil.
  3. “Faiz tutarları”na geç. Math.round bile 1.005’i 100’e yuvarladı; doğrusu 101.
  4. “BigDecimal + HALF_UP” seç. Her tutar doğru, mutabakat tuttu.
Kafam karıştı, daha basit anlat

double bir tartı gibidir: hızlıdır ama gramı gramına tartmaz. Para için hassas terazi gerekir; o da BigDecimal.

Hızlı kontrolBaşlangıç

`0.1 + 0.2` işlemi Java'da neden `0.30000000000000004` verir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

BigDecimal: her hane tam

`System.out.println(new BigDecimal(0.1));` ne yazdırır? Cevabı göster

0.1000000000000000055511151231257827021181583404541015625. double’a çevrilmiş 0.1 zaten yaklaşıktı; BigDecimal o yaklaşık değeri tam olarak kopyaladı.

BigDecimal yazdığın haneleri aynen saklar, ama ona tam haneleri vermen gerekir. Bu yüzden onu metinden kurarsın; bir double’dan kurarsan double’ın hatasını da kopyalarsın.

Doğru kurmak
new BigDecimal("0.10") // tam: 0.10
BigDecimal.valueOf(0.1) // 0.1 (double'ın kısa metin hâli üzerinden)
new BigDecimal(0.1) // 0.1000000000000000055… kaçın

BigDecimal de String gibi immutableOluşturulduktan sonra içi değişmeyen nesne. Anahtar olarak güvenlidir, çünkü hashCode'u hiç değişmez.Sözlükte gör →’dır. add, subtract, multiply eski sayıyı değiştirmez, yeni bir sonuç döndürür: toplam = toplam.add(tutar);

Kafam karıştı, daha basit anlat

BigDecimal’e sayıyı yazıyla ver: “0.10”. Böylece ne yazdıysan o saklanır. İşlem sonucunu da yine bir değişkene koymayı unutma.

Hızlı kontrolBaşlangıç

10 lira 10 kuruşu BigDecimal olarak tam doğru kurmanın yolu hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Program ne yazdırır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Toplam.java
1BigDecimal toplam = new BigDecimal("10.00");
2toplam.add(new BigDecimal("5.00"));
3System.out.println(toplam);
Java 21UTF-8LF

Satır satır: bölmek ve yuvarlamak

Toplamak ve çarpmak kolaydır. Asıl dikkat isteyen bölmedir: 100’ü 3’e bölmenin sonu yoktur.

100 lirayı üç kişiye bölmek

Bolusme.java
şu an çalışan satırBigDecimal hesap = new BigDecimal("100.00");
2BigDecimal kisi = new BigDecimal("3");
3
4BigDecimal pay = hesap.divide(kisi);
5BigDecimal pay2 = hesap.divide(kisi, 2, RoundingMode.HALF_EVEN);
6BigDecimal kalan = hesap.subtract(pay2.multiply(kisi));

Debug

Adım 1/4

hazırlık Tutarlar metinden kuruluyor; iki hane: 100.00.

hesap
= 100.00
kisi
= 3
Java 21UTF-8LF1:1

Sol/sağ ok tuşlarıyla da gezebilirsin.

Hızlı kontrolBaşlangıç

`new BigDecimal("100").divide(new BigDecimal("3"))` çalıştırılınca ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aynı değer, farklı ölçek

BigDecimal bir sayının yanında kaç ondalık hanesi olduğunu da (ölçekBir BigDecimal sayısının ondalık kısmında kaç hane olduğu. 2.50 sayısının ölçeği 2'dir.equals ölçeği de karşılaştırır: 2.0 ile 2.00 değerce eşit olsa da equals onlara farklı der. setScale ile ölçek sabitlenir.Sözlükte gör →) saklar. 2.0 ile 2.00 aynı değerdir ama ölçekleri farklıdır.

equals ölçeğe de bakar
BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");
a.equals(b); // false: ölçekler farklı
a.compareTo(b) == 0; // true: değerler aynı

İki tutarın aynı olup olmadığını sorarken compareTo kullan. Tutarları sakladığın yerde ölçeği sabitlemek de (setScale(2, RoundingMode.HALF_EVEN)) bu sürprizi baştan önler.

Kafam karıştı, daha basit anlat

2 lira ile 2 lira 00 kuruş aynı paradır, sadece farklı yazılmıştır. equals yazılışa da bakar, compareTo yalnızca miktara.

Hızlı kontrolOrta

Program ne yazdırır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Esit.java
1BigDecimal a = new BigDecimal("2.0");
2BigDecimal b = new BigDecimal("2.00");
3System.out.println(a.equals(b) + " " + (a.compareTo(b) == 0));
Java 21UTF-8LF

Bankada bunu en sık faiz hesabında görürsün: yıllık oran günlüğe bölünür, sonuç kuruşa yuvarlanır ve yuvarlama kuralı açıkça yazılır.

Derinleş · Mevduat faizi: tam hesap, açık yuvarlama 3 dosya · ~40 satır · ilk okumada atlayabilirsin
Proje dosyaları

src/main/java/com/bank/money/ Money.java Tutar: BigDecimal ve para birimi. Ölçek her zaman iki hane.

src/main/java/com/bank/money/Money.java
public record Money(BigDecimal amount, String currency) {
public Money {
// Every amount is kept to two decimals, so equals never trips over scale.
amount = amount.setScale(2, RoundingMode.HALF_EVEN);
}
public static Money of(String amount, String currency) {
return new Money(new BigDecimal(amount), currency);
}
public Money plus(Money other) {
return new Money(amount.add(other.amount), currency);
}
}

src/main/java/com/bank/deposit/ Interest.java Faiz: yıllık oran gün sayısına göre işletilir, en sonda bir kez yuvarlanır.

src/main/java/com/bank/deposit/Interest.java
public final class Interest {
private static final BigDecimal DAYS_IN_YEAR = new BigDecimal("365");
private Interest() {
}
// Simple interest for a term, rounded once at the end.
public static Money forTerm(Money principal, BigDecimal annualRate, long days) {
BigDecimal interest = principal.amount()
.multiply(annualRate)
.multiply(BigDecimal.valueOf(days))
.divide(DAYS_IN_YEAR, 2, RoundingMode.HALF_EVEN);
return new Money(interest, principal.currency());
}
}

src/main/java/com/bank/ Main.java Çıktı yorumlarda. Oranlar örnektir, gerçek bir bankanın tarifesi değildir.

src/main/java/com/bank/Main.java
public class Main {
public static void main(String[] args) {
Money principal = Money.of("10000.00", "TRY");
Money interest = Interest.forTerm(principal, new BigDecimal("0.40"), 32);
System.out.println(interest.amount()); // 350.68
System.out.println(principal.plus(interest).amount()); // 10350.68
}
}

Tuzaklar

new BigDecimal(double). double’ın yaklaşık değerini kopyalar. Metinden kur ya da BigDecimal.valueOf kullan.

Yuvarlama kuralını düşünmeden seçmek. HALF_UP okulda öğrendiğin yuvarlamadır; HALF_EVEN tam ortadaki sayıları en yakın çift haneye yuvarlar ve çok sayıda işlemde yukarı kaymayı dengeler. Hangisinin kullanılacağını genellikle iş kuralı ya da mevzuat belirler.

Yolda double’a dönmek. Tutarı JSON’da, veritabanında ya da bir ara hesapta double yaparsan kazandığın hassasiyeti orada kaybedersin. Tutar baştan sona BigDecimal kalmalı.

Hızlı kontrolBaşlangıç

Bir kampanyada her müşteriye 0.10 TL iade veriliyor. Gün sonu toplamı birkaç kuruş tutmuyor. Hatalı satır hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Hatalı satıra dokun, sonra kontrol et.

Iade.java
Java 21UTF-8LF

Kendini sına

Şimşek turu1/4

0.1 + 0.2 işlemi double ile tam olarak 0.3 verir.

Soru 1/3Orta

`RoundingMode.HALF_EVEN` ile 2.345 iki haneye yuvarlanırsa sonuç ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 double ondalık sayıları yaklaşık tutar; para hesabı her zaman BigDecimal ile yapılır ve BigDecimal metinden kurulur.
  2. 2 BigDecimal ile bölerken kaç hane ve hangi yuvarlama kuralı istediğini söylersin; söylemezsen bitmeyen bölümde hata alırsın.
  3. 3 2.0 ile 2.00'ın equals'ı false döner; iki tutarın aynı değerde olup olmadığını compareTo söyler.
Sonraki kapı New York'taki sunucu 16:30 yazdı. İstanbul'daki gün sonu raporu bu havaleyi hangi güne koyar? Zaman ve Saat Dilimleri — Havale Hangi Güne Yazılır? · 9 dk

4 kart sonraki derste seni bekliyor

0/3 kart bu dersten toplandı