- 1 1. Úvod
- 2 2. Co je BigDecimal?
- 3 3. Základní použití BigDecimal
- 4 4. Pokročilé Použití BigDecimal
- 5 5. Běžné Chyby a Jak Je Opravit
- 6 6. Praktické příklady použití
- 7 7. Summary
- 8 8. FAQ: Frequently Asked Questions About BigDecimal
- 8.1 Q1. Why should I use BigDecimal instead of float or double?
- 8.2 Q2. What is the safest way to construct BigDecimal instances?
- 8.3 Q3. Why does divide() throw an exception?
- 8.4 Q4. What’s the difference between compareTo() and equals()?
- 8.5 Q5. How do I perform rounding?
- 8.6 Q6. Can I check decimal digits (scale)?
- 8.7 Q7. How should I handle null/empty input safely?
1. Úvod
Problémy s přesností v numerických výpočtech v Javě
V programování v Javě se numerické výpočty provádějí denně. Například výpočet cen produktů, určení daní nebo úroků — tyto operace jsou vyžadovány v mnoha aplikacích. Nicméně, když se takové výpočty provádějí pomocí typů s plovoucí desetinnou čárkou jako float nebo double, mohou nastat neočekávané chyby.
To se děje proto, že float a double reprezentují hodnoty jako binární aproximace. Hodnoty jako „0.1“ nebo „0.2“, které lze vyjádřit přesně v desetinné soustavě, nelze reprezentovat přesně v binární soustavě — a v důsledku toho se hromadí malé chyby.
BigDecimal je nezbytný pro měnové nebo přesné výpočty
Takové chyby mohou být kritické v oblastech jako měnové výpočty a přesné vědecké/inženýrské výpočty. Například při výpočtech faktur může i 1-jenová nesrovnalost vést k problémům s důvěryhodností.
Zde vyniká třída BigDecimal v Javě. BigDecimal dokáže zpracovávat desetinná čísla s libovolnou přesností a použitím místo float nebo double lze provádět numerické výpočty bez chyb.
Co získáte z tohoto článku
V tomto článku vysvětlíme základy použití BigDecimal v Javě, pokročilé techniky, stejně jako běžné chyby a upozornění systematickým způsobem.
To je užitečné pro ty, kteří chtějí v Javě zpracovávat měnové výpočty přesně nebo zvažují přijetí BigDecimal ve svých projektech.
2. Co je BigDecimal?
Přehled BigDecimal
BigDecimal je třída v Javě, která umožňuje výpočty s desetinnými čísly s vysokou přesností. Patří do balíčku java.math a je navržena speciálně pro výpočty netolerantní k chybám, jako jsou finanční/účetní/daní výpočty.
S float a double v Javě se číselné hodnoty ukládají jako binární aproximace — což znamená, že desetiny jako „0.1“ nebo „0.2“ nelze reprezentovat přesně, což je zdroj chyby. Naopak BigDecimal ukládá hodnoty jako desetinnou reprezentaci založenou na řetězci, čímž potlačuje chyby zaokrouhlování a aproximace.
Zpracování čísel s libovolnou přesností
Největší charakteristikou BigDecimal je „libovolná přesnost“. Jak celá část, tak desetinná část mohou teoreticky zpracovávat prakticky neomezený počet číslic, čímž se vyhýbají zaokrouhlování nebo ztrátě číslic kvůli omezením počtu číslic.
Například následující velké číslo lze zpracovat přesně:
BigDecimal bigValue = new BigDecimal("12345678901234567890.12345678901234567890");
Schopnost provádět aritmetiku při zachování přesnosti tímto způsobem je hlavní silnou stránkou BigDecimal.
Hlavní použití
BigDecimal se doporučuje v situacích jako:
- Měnové výpočty — výpočty úroků, daňových sazeb ve finančních aplikacích
- Zpracování částek faktur / nabídek
- Vědecké/inženýrské výpočty vyžadující vysokou přesnost
- Procesy, kde dlouhodobé hromadění způsobuje nahromadění chyb
Například v účetních systémech a výpočtech mezd — kde může 1-jenový rozdíl vést k velkým ztrátám nebo sporům — je přesnost BigDecimal nezbytná.
3. Základní použití BigDecimal
Jak vytvářet instance BigDecimal
Na rozdíl od běžných numerických literálů by BigDecimal měl být obecně vytvářen z řetězce. To proto, že hodnoty vytvořené z double nebo float mohou již obsahovat chyby binární aproximace.
Doporučeno (vytvoření z String):
BigDecimal value = new BigDecimal("0.1");
Vyhnout se (vytvoření z double):
BigDecimal value = new BigDecimal(0.1); // may contain error
Jak provádět aritmetiku
BigDecimal nelze používat s běžnými aritmetickými operátory (+, -, *, /). Místo toho je nutné použít dedikované metody.
Sčítání (add)
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2.3");
BigDecimal result = a.add(b); // 12.8
Odečítání (subtract)
BigDecimal result = a.subtract(b); // 8.2
Násobení (multiply)
BigDecimal result = a.multiply(b); // 24.15
Dělení (divide) a Režim Zaokrouhlení
Dělení vyžaduje opatrnost. Pokud není rovnoměrně dělitelné, dojde k ArithmeticException, pokud není specifikován režim zaokrouhlení.
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // 3.33
Zde specifikujeme „2 desetinná místa“ a „zaokrouhlení nahoru při půlce“.
Nastavení Měřítka a Režimu Zaokrouhlení pomocí setScale
setScale lze použít k zaokrouhlení na zadaný počet číslic.
BigDecimal value = new Big BigDecimal("123.456789");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // 123.46
Běžné hodnoty RoundingMode:
| Mode Name | Description |
|---|---|
HALF_UP | Round half up (standard rounding) |
HALF_DOWN | Round half down |
HALF_EVEN | Banker’s rounding |
UP | Always round up |
DOWN | Always round down |
BigDecimal Je Neměnný
BigDecimal je neměnný. To znamená — aritmetické metody (add, subtract, atd.) nemění původní hodnotu — vracejí novou instanci.
BigDecimal original = new BigDecimal("5.0");
BigDecimal result = original.add(new BigDecimal("1.0"));
System.out.println(original); // still 5.0
System.out.println(result); // 6.0
4. Pokročilé Použití BigDecimal
Porovnávání Hodnot: Rozdíl Mezi compareTo a equals
V BigDecimal existují dva způsoby porovnávání hodnot: compareTo() a equals() a tyto se chovají odlišně.
compareTo()porovnává pouze číselnou hodnotu (ignoruje měřítko).equals()porovnává včetně měřítka (počet desetinných míst).BigDecimal a = new BigDecimal("10.0"); BigDecimal b = new BigDecimal("10.00"); System.out.println(a.compareTo(b)); // 0 (values are equal) System.out.println(a.equals(b)); // false (scale differs)
Poznámka: Pro kontroly numerické rovnosti — například rovnosti peněz — je compareTo() obecně doporučeno.
Konverze Do/Z Ze Stringu
Při vstupu od uživatele a importu z externích souborů je běžná konverze s typy String.
String → BigDecimal
BigDecimal value = new Big BigDecimal("1234.56");
BigDecimal → String
String str = value.toString(); // "1234.56"
Použití valueOf
Java má také BigDecimal.valueOf(double val), ale toto také interně obsahuje chybu double, takže konstrukce ze stringu je stále bezpečnější.
BigDecimal unsafe = BigDecimal.valueOf(0.1); // contains internal error
Přesnost a Pravidla Zaokrouhlení Přes MathContext
MathContext umožňuje ovládat přesnost a režim zaokrouhlení najednou — užitečné při aplikaci společných pravidel napříč mnoha operacemi.
MathContext mc = new MathContext(4, RoundingMode.HALF_UP);
BigDecimal result = new BigDecimal("123.4567").round(mc); // 123.5
Lze použít také v aritmetice:
BigDecimal a = new BigDecimal("10.456");
BigDecimal b = new BigDecimal("2.1");
BigDecimal result = a.multiply(b, mc); // 4-digit precision
Kontroly null a Bezpečné Inicializace
Formuláře mohou předat null nebo prázdné hodnoty — ochranný kód je standardní.
String input = ""; // empty
BigDecimal value = (input == null || input.isEmpty()) ? BigDecimal.ZERO : new BigDecimal(input);
Kontrola Měřítka BigDecimal
K zjištění počtu desetinných míst použijte scale():
BigDecimal value = new BigDecimal("123.45");
System.out.println(value.scale()); // 3
5. Běžné Chyby a Jak Je Opravit
ArithmeticException: Nekonečné Desetinné Rozvoje
Příklad Chyby:
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b); // exception
Jedná se o „1 ÷ 3“ — protože se stává nekonečným desetinným rozvojem, pokud není zadáno zaokrouhlení/měřítko, dojde k výjimce.
Oprava: specifikujte měřítko + režim zaokrouhlení
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // OK (3.33)
Chyby Při Konstrukci Přímo Z double
Přímé předání double může již obsahovat binární chybu — vytvářející neočekávané hodnoty.
Špatný příklad:
BigDecimal val = new BigDecimal(0.1);
System.out.println(val); // 0.100000000000000005551115123...
Správně: Použijte řetězec
BigDecimal val = new BigDecimal("0.1"); // exact 0.1
Poznámka: BigDecimal.valueOf(0.1) interně používá Double.toString(), takže je to „téměř stejné“ jako new BigDecimal("0.1") — ale řetězec je 100% nejbezpečnější.

Nesprávné chápání equals kvůli nesouladu škály
Protože equals() porovnává škálu, může vrátit false i když jsou hodnoty numericky rovny.
BigDecimal a = new BigDecimal("10.0");
BigDecimal b = new BigDecimal("10.00");
System.out.println(a.equals(b)); // false
Řešení: použijte compareTo() pro numerickou rovnost
System.out.println(a.compareTo(b)); // 0
Neočekávané výsledky způsobené nedostatečnou přesností
Pokud používáte setScale bez specifikace režimu zaokrouhlování — mohou nastat výjimky.
Špatný příklad:
BigDecimal value = new BigDecimal("1.2567");
BigDecimal rounded = value.setScale(2); // exception
Řešení:
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // OK
NumberFormatException při neplatné vstupní hodnotě
Pokud je předán neplatný text, který nelze parsovat jako číslo (např. uživatelský vstup / pole CSV), dojde k NumberFormatException.
Řešení: použijte zpracování výjimek
try {
BigDecimal value = new BigDecimal(userInput);
} catch (NumberFormatException e) {
// show error message or fallback logic
}
6. Praktické příklady použití
Zde představujeme scénáře ze skutečného světa demonstrující, jak lze BigDecimal použít v praxi. Zejména ve finančních/účetních/daněných výpočtech se stává důležitost přesného zpracování čísel zjevnou.
Zpracování desetinných míst ve výpočtech cen (zaokrouhlování zlomků)
Příklad: Výpočet ceny včetně 10% spotřební daně
BigDecimal price = new BigDecimal("980"); // price w/o tax
BigDecimal taxRate = new BigDecimal("0.10");
BigDecimal tax = price.multiply(taxRate).setScale(0, RoundingMode.HALF_UP);
BigDecimal total = price.add(tax);
System.out.println("Tax: " + tax); // Tax: 98
System.out.println("Total: " + total); // Total: 1078
Body:
- Výsledky výpočtu daně jsou často zpracovávány jako celá čísla, pomocí
setScale(0, RoundingMode.HALF_UP)k zaokrouhlení. doublemá tendenci produkovat chyby —BigDecimalje doporučen.
Výpočty slev (% OFF)
Příklad: 20% sleva
BigDecimal originalPrice = new BigDecimal("3500");
BigDecimal discountRate = new BigDecimal("0.20");
BigDecimal discount = originalPrice.multiply(discountRate).setScale(0, RoundingMode.HALF_UP);
BigDecimal discountedPrice = originalPrice.subtract(discount);
System.out.println("Discount: " + discount); // Discount: 700
System.out.println("After discount: " + discountedPrice); // 2800
Bod: Výpočty slev cen nesmí ztratit přesnost.
Výpočet Jednotkové ceny × Množství (Typický scénář obchodní aplikace)
Příklad: 298.5 jen × 7 kusů
BigDecimal unitPrice = new BigDecimal("298.5");
BigDecimal quantity = new BigDecimal("7");
BigDecimal total = unitPrice.multiply(quantity).setScale(2, RoundingMode.HALF_UP);
System.out.println("Total: " + total); // 2089.50
Body:
- Upravte zaokrouhlování pro násobení zlomky.
- Důležité pro účetní / objednávkové systémy.
Výpočet složeného úroku (Finanční příklad)
Příklad: 3% roční úrok × 5 let
BigDecimal principal = new BigDecimal("1000000"); // base: 1,000,000
BigDecimal rate = new BigDecimal("0.03");
int years = 5;
BigDecimal finalAmount = principal;
for (int i = 0; i < years; i++) {
finalAmount = finalAmount.multiply(rate.add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_UP);
}
System.out.println("Po 5 letech: " + finalAmount); // přibližně 1 159 274,41
Point:
- Repeated calculations accumulate errors — BigDecimal avoids this.
Validation & Conversion of User Input
public static BigDecimal parseAmount(String input) {
try {
return new BigDecimal(input).setScale(2, RoundingMode.HALF_UP);
} catch (NumberFormatException e) {
return BigDecimal.ZERO; // považovat neplatný vstup za 0
}
}
Points:
- Safely convert user-provided numeric strings.
- Validation + error fallback improves robustness.
7. Summary
The Role of BigDecimal
In Java’s numeric processing — especially monetary or precision-required logic — the BigDecimal class is indispensable. Errors inherent in float / double can be dramatically avoided by using BigDecimal.
This article covered fundamentals, arithmetic, comparisons, rounding, error handling, and real-world examples.
Key Review Points
BigDecimalhandles arbitrary-precision decimal — ideal for money and precision math- Initialization should be via string literal , e.g.
new BigDecimal("0.1") - Use
add(),subtract(),multiply(),divide(), and always specify rounding mode when dividing - Use
compareTo()for equality — understand difference vsequals() setScale()/MathContextlet you finely control scale + rounding- Real business logic cases include money, tax, quantity × unit price etc.
For Those About to Use BigDecimal
Although “handling numbers in Java” looks simple — precision / rounding / numeric error problems always exist behind it. BigDecimal is a tool that directly addresses those problems — mastering it lets you write more reliable code.
At first you may struggle with rounding modes — but with real project usage, it becomes natural.
Next chapter is an FAQ section summarizing common questions about BigDecimal — useful for review and specific semantic searches.
8. FAQ: Frequently Asked Questions About BigDecimal
Q1. Why should I use BigDecimal instead of float or double?
A1.
Because float/double represent numbers as binary approximations — decimal fractions cannot be represented exactly. This causes results such as “0.1 + 0.2 ≠ 0.3.”
BigDecimal preserves decimal values exactly — ideal for money or precision-critical logic.
Q2. What is the safest way to construct BigDecimal instances?
A2.
Always construct from string.
Bad (error):
new BigDecimal(0.1)
Correct:
new BigDecimal("0.1")
BigDecimal.valueOf(0.1) uses Double.toString() internally, so it’s almost same — but string is the safest.
Q3. Why does divide() throw an exception?
A3.
Because BigDecimal.divide() throws ArithmeticException when result is a non-terminating decimal.
Solution: specify scale + rounding mode
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
Q4. What’s the difference between compareTo() and equals()?
A4.
compareTo()checks numeric equality (scale ignored)equals()checks exact equality including scalenew BigDecimal("10.0").compareTo(new BigDecimal("10.00")); // → 0 new BigDecimal("10.0").equals(new BigDecimal("10.00")); // → false
Q5. How do I perform rounding?
A5.
Use setScale() with explicit rounding mode.
BigDecimal value = new BigDecimal("123.4567");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // 123.46
Main rounding modes:
RoundingMode.HALF_UP(round half up)RoundingMode.DOWN(round down)RoundingMode.UP(round up)
Q6. Can I check decimal digits (scale)?
A6.
Yes — use scale().
BigDecimal val = new BigDecimal("123.45");
System.out.println(val.scale()); // → 3
Q7. How should I handle null/empty input safely?
A7.
Vždy zahrňte kontroly null + zpracování výjimek.
public static BigDecimal parseSafe(String input) {
if (input == null || input.trim().isEmpty()) return BigDecimal.ZERO;
try {
return new BigDecimal(input.trim());
} catch (NumberFormatException e) {
return BigDecimal.ZERO;
}
}

