Java Academy · Lekcja

BigDecimal w obliczeniach finansowych

Używaj BigDecimal, aby uniknąć błędów precyzji zmiennoprzecinkowej w obliczeniach kwot i podatków.

Lekcja 3 z 413 kroki

BigDecimal w obliczeniach finansowych to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

BigDecimal w obliczeniach finansowych

Typy zmiennoprzecinkowe (double, float) nie mogą dokładnie reprezentować wszystkich wartości dziesiętnych ze względu na reprezentację binarną. Do kwot i podatków używaj BigDecimal.

Problem z liczbami zmiennoprzecinkowymi

Binarna arytmetyka zmiennoprzecinkowa wprowadza niewielkie błędy zaokrągleń. W aplikacjach finansowych błędy te się kumulują i prowadzą do rzeczywistych usterek.

double price = 0.1 + 0.2;
System.out.println(price);          // 0.30000000000000004 (WRONG!)
System.out.println(price == 0.3);   // false

// Real bug: total never equals expected
double total = 0;
for (int i = 0; i < 10; i++) total += 0.1;
System.out.println(total); // 0.9999999999999999

Bezpieczne tworzenie BigDecimal

Zawsze twórz BigDecimal na podstawie String, a nie double. Użycie konstruktora przyjmującego double dziedziczy niedokładność arytmetyki zmiennoprzecinkowej.

import java.math.BigDecimal;

// WRONG: double constructor
BigDecimal wrong = new BigDecimal(0.1);
System.out.println(wrong); // 0.1000000000000000055511...

// CORRECT: String constructor
BigDecimal correct = new BigDecimal("0.1");
System.out.println(correct); // 0.1

// Or use valueOf (also safe)
BigDecimal safe = BigDecimal.valueOf(0.1);
System.out.println(safe); // 0.1

Podstawowe działania arytmetyczne z BigDecimal

BigDecimal używa wywołań metod do wykonywania działań arytmetycznych: add(), subtract(), multiply(), divide(). Metody te zwracają nowe instancje BigDecimal (jest to typ niezmienny).

import java.math.BigDecimal;

BigDecimal price = new BigDecimal("19.99");
BigDecimal tax   = new BigDecimal("0.08");
BigDecimal qty   = new BigDecimal("3");

BigDecimal subtotal = price.multiply(qty);
BigDecimal taxAmount = subtotal.multiply(tax);
BigDecimal total = subtotal.add(taxAmount);

System.out.println(subtotal);  // 59.97
System.out.println(taxAmount); // 4.7976
System.out.println(total);     // 64.7676

Tryby zaokrąglania

RoundingMode określa sposób zaokrąglania wartości BigDecimal. Najważniejsze tryby:

  • HALF_UP — standardowe zaokrąglanie (0.5 zaokrągla w górę)
  • HALF_EVEN — zaokrąglanie bankierskie (0.5 zaokrągla do najbliższej liczby parzystej)
  • DOWN — obcinanie w kierunku zera
  • CEILING — zaokrąglanie w kierunku dodatniej nieskończoności
import java.math.*;

BigDecimal val = new BigDecimal("2.565");

System.out.println(val.setScale(2, RoundingMode.HALF_UP));   // 2.57
System.out.println(val.setScale(2, RoundingMode.HALF_EVEN)); // 2.56 (banker's)
System.out.println(val.setScale(2, RoundingMode.DOWN));      // 2.56
System.out.println(val.setScale(2, RoundingMode.CEILING));   // 2.57

Dzielenie i skala

Dzielenie za pomocą BigDecimal wymaga określenia skali i trybu zaokrąglania, aby uniknąć ArithmeticException w przypadku nieskończonych rozwinięć dziesiętnych.

import java.math.*;

BigDecimal revenue = new BigDecimal("1000.00");
BigDecimal months  = new BigDecimal("3");

// Without scale → ArithmeticException (non-terminating decimal)
try {
    revenue.divide(months);
} catch (ArithmeticException e) {
    System.out.println("Need to specify scale!");
}

// Correct: specify scale and rounding
BigDecimal monthly = revenue.divide(months, 2, RoundingMode.HALF_UP);
System.out.println(monthly); // 333.33

Porównywanie wartości BigDecimal

Do porównywania wartości używaj compareTo(), a nie equals(). equals() uwzględnia skalę — 2.0 i 2.00 NIE są równe według equals(), ale SĄ równe według compareTo().

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");

System.out.println(a.equals(b));        // false (different scale)
System.out.println(a.compareTo(b));     // 0 (same value)
System.out.println(a.compareTo(b) == 0); // true

// For sorting in collections
import java.util.*;
List<BigDecimal> prices = Arrays.asList(
    new BigDecimal("3.50"), new BigDecimal("1.00"), new BigDecimal("2.75")
);
Collections.sort(prices);
System.out.println(prices); // [1.00, 2.75, 3.50]

MathContext a cyfry znaczące

MathContext określa precyzję (liczbę cyfr znaczących) i tryb zaokrąglania. Używaj go, gdy potrzebujesz spójnej precyzji określonej liczbą cyfr znaczących, a nie liczbą miejsc dziesiętnych.

import java.math.*;

MathContext mc = new MathContext(4, RoundingMode.HALF_UP);

BigDecimal a = new BigDecimal("1234567");
BigDecimal b = new BigDecimal("3");

BigDecimal result = a.divide(b, mc);
System.out.println(result); // 4.115E+5 (4 significant digits)

// DECIMAL32, DECIMAL64, DECIMAL128 are standard MathContexts
BigDecimal precise = new BigDecimal("355").divide(
    new BigDecimal("113"), MathContext.DECIMAL64);
System.out.println(precise); // 3.141592920353982...

Przykład koszyka zakupowego

Kompletne obliczenie dla koszyka zakupowego z użyciem BigDecimal: pozycje, podatek, rabat i końcowa suma.

import java.math.*;

record LineItem(String name, BigDecimal price, int qty) {
    BigDecimal subtotal() {
        return price.multiply(new BigDecimal(qty));
    }
}

var items = List.of(
    new LineItem("Laptop",  new BigDecimal("999.00"), 1),
    new LineItem("Case",    new BigDecimal("29.99"),  2),
    new LineItem("Charger", new BigDecimal("49.99"),  1)
);

BigDecimal subtotal = items.stream()
    .map(LineItem::subtotal)
    .reduce(BigDecimal.ZERO, BigDecimal::add);

BigDecimal taxRate = new BigDecimal("0.09");
BigDecimal tax = subtotal.multiply(taxRate).setScale(2, RoundingMode.HALF_UP);
BigDecimal total = subtotal.add(tax);

System.out.println("Subtotal: " + subtotal);
System.out.println("Tax:      " + tax);
System.out.println("Total:    " + total);

Stripe: waluta w centach

Procesory płatności, takie jak Stripe, przechowują kwoty jako całkowite wartości w centach, aby całkowicie uniknąć problemów z wartościami dziesiętnymi. Przeliczanie między centami a kwotami wyświetlanymi jest często stosowanym wzorcem.

import java.math.*;

// Store as cents (long) for database / API
long amountCents = 999_99L; // $999.99

// Convert to BigDecimal for display
BigDecimal amount = BigDecimal
    .valueOf(amountCents)
    .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);

System.out.println("Amount: $" + amount); // Amount: $999.99

// Convert user input back to cents
BigDecimal input = new BigDecimal("49.95");
long cents = input.multiply(new BigDecimal("100"))
    .setScale(0, RoundingMode.HALF_UP).longValueExact();
System.out.println("Cents: " + cents); // Cents: 4995

Kiedy używać BigDecimal, a kiedy double

Wybierz odpowiedni typ do danego zastosowania:

  • BigDecimal: kwoty finansowe, podatki, faktury — wszędzie tam, gdzie ważna jest dokładna reprezentacja dziesiętna
  • double: obliczenia naukowe, grafika, ML — gdy liczy się szybkość, a niewielkie błędy są dopuszczalne
  • int/long cents: interfejsy API płatności, przechowywanie kwot w bazie danych

Szybkie sprawdzenie

Jakiej metody porównywania BigDecimal należy użyć, aby sprawdzić, czy dwie wartości BigDecimal są równe liczbowo, niezależnie od skali?

Podsumowanie: BigDecimal w obliczeniach finansowych

Najważniejsze informacje:

  • double/float powodują błędy zaokrągleń — nigdy nie używaj ich do kwot pieniężnych
  • Twórz BigDecimal na podstawie String lub BigDecimal.valueOf(), a nie double
  • Do działań arytmetycznych używaj add(), subtract(), multiply(), divide()
  • Podczas dzielenia zawsze określaj skalę i RoundingMode
  • Do sprawdzania równości używaj compareTo(), a nie equals()
  • W przypadku baz danych i API rozważ przechowywanie kwot jako całkowitych centów
Bezpłatny start

Ucz się Java dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
104
Lekcje
374

Często zadawane pytania

Czy lekcja „BigDecimal w obliczeniach finansowych” jest bezpłatna?

Tak — pełny tekst „BigDecimal w obliczeniach finansowych” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „BigDecimal w obliczeniach finansowych”?

Używaj BigDecimal, aby uniknąć błędów precyzji zmiennoprzecinkowej w obliczeniach kwot i podatków. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „BigDecimal w obliczeniach finansowych”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Najważniejsze elementy klasy Math
  2. Arytmetyka liczb całkowitych i przepełnienie
  3. BigDecimal w obliczeniach finansowych
  4. NumberFormat i printf
← Powrót do Java Academy