Math and BigDecimal — Math Class, BigInteger, BigDecimal, and Rounding Modes
In this tutorial, you will learn about Math and BigDecimal. We cover key concepts, practical examples, and best practices to help you master this topic.
Java provides the Math class for basic mathematical operations, BigInteger for arbitrary-precision integers, and BigDecimal for precise decimal arithmetic essential in financial calculations. Using double for money is a common mistake that leads to rounding errors — 0.1 + 0.2 equals 0.30000000000000004 in floating-point arithmetic.
What You'll Learn
- The
Mathclass: min, max, abs, pow, sqrt, random BigInteger: operations on arbitrarily large integersBigDecimal: precise decimal arithmetic with rounding control- Rounding modes and common pitfalls
Why It Matters
Financial applications require exact decimal arithmetic. Scientific applications need arbitrary-precision integers for cryptography. Understanding these classes prevents silent data corruption from floating-point errors.
Real-World Use
BigDecimal is the standard for monetary values in e-commerce, banking, and accounting. BigInteger is used in cryptography (RSA), secure random number generation, and combinatorial calculations.
The Math Class
Math.abs(-5); // 5
Math.max(10, 20); // 20
Math.min(10, 20); // 10
Math.pow(2, 10); // 1024.0 (returns double)
Math.sqrt(25); // 5.0
Math.cbrt(27); // 3.0
Math.ceil(3.2); // 4.0
Math.floor(3.8); // 3.0
Math.round(3.5); // 4 (long)
Math.round(3.4); // 3
// Trigonometric
Math.sin(Math.PI / 2); // 1.0
Math.cos(0); // 1.0
Math.toRadians(180); // 3.14159...
// Random
double rand = Math.random(); // 0.0 <= rand < 1.0
Overflow-Safe Operations (Java 8+)
Math.addExact(a, b); // throws ArithmeticException on overflow
Math.subtractExact(a, b);
Math.multiplyExact(a, b);
Math.toIntExact(longVal); // safely converts long to int
BigInteger
For integers larger than Long.MAX_VALUE:
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = BigInteger.valueOf(1000); // from long
BigInteger sum = a.add(b);
BigInteger diff = a.subtract(b);
BigInteger prod = a.multiply(b);
BigInteger quot = a.divide(b);
BigInteger rem = a.remainder(b);
BigInteger[] divAndRem = a.divideAndRemainder(b);
// Comparison
int cmp = a.compareTo(b); // -1, 0, or 1
// Bit operations
BigInteger mask = BigInteger.ONE.shiftLeft(8);
boolean bitSet = a.testBit(3);
// Constants
BigInteger.ZERO
BigInteger.ONE
BigInteger.TEN
BigDecimal
For precise decimal arithmetic:
BigDecimal price = new BigDecimal("19.99");
BigDecimal taxRate = new BigDecimal("0.08");
BigDecimal tax = price.multiply(taxRate);
BigDecimal total = price.add(tax);
Why Not new BigDecimal(0.1)?
BigDecimal bad = new BigDecimal(0.1);
System.out.println(bad); // 0.1000000000000000055511151231257827021181583404541015625
The constructor using double reproduces the double's exact value. Always use new BigDecimal("0.1") or BigDecimal.valueOf(0.1).
Arithmetic with Scale and Rounding
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("3.00");
// Division requires rounding mode
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result); // 3.33
// Or use MathContext
BigDecimal result2 = a.divide(b, new MathContext(4, RoundingMode.HALF_UP));
Rounding Modes
| Mode | Description | Example: 2.5 with scale 0 |
|---|---|---|
HALF_UP |
Round up if fraction >= 0.5 | 3 |
HALF_DOWN |
Round down if fraction <= 0.5 | 2 |
HALF_EVEN |
Round to nearest even neighbor | 2 (banker's rounding) |
CEILING |
Round towards positive infinity | 3 |
FLOOR |
Round towards negative infinity | 2 |
UP |
Round away from zero | 3 |
DOWN |
Round towards zero | 2 |
Setting Scale
BigDecimal value = new BigDecimal("123.45678");
BigDecimal scaled = value.setScale(2, RoundingMode.HALF_UP);
System.out.println(scaled); // 123.46
Comparison
Always use compareTo(), not equals():
BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");
a.equals(b); // false! scales differ
a.compareTo(b); // 0 — correct (numerically equal)
Monetary Calculation Example
BigDecimal subtotal = new BigDecimal("49.99");
BigDecimal taxRate = new BigDecimal("0.08");
BigDecimal tax = subtotal.multiply(taxRate, new MathContext(4, RoundingMode.HALF_UP));
BigDecimal total = subtotal.add(tax).setScale(2, RoundingMode.HALF_UP);
System.out.println(total); // 53.99
Common Mistakes
- Using
doublefor money.0.1 + 0.2 != 0.3in floating-point. Always useBigDecimalfor monetary values. - Using
equals()instead ofcompareTo()forBigDecimal.equals()considers scale, so2.0 != 2.00. UsecompareTo()for value comparison. - Forgetting to specify scale/rounding in
divide().BigDecimal.valueOf(1).divide(BigDecimal.valueOf(3))throwsArithmeticException(non-terminating decimal). Always provide scale and rounding mode. - Using
new BigDecimal(double). This reproduces the floating-point imprecision. UseBigDecimal.valueOf(double)ornew BigDecimal(String). - Assuming
Math.random()is cryptographically secure.Math.random()usesRandom(LCG), notSecureRandom. UseSecureRandomfor security-sensitive applications.
Practice Questions
1. Why should you use BigDecimal for financial calculations instead of double?
Floating-point types cannot represent decimal fractions exactly (e.g., 0.1). Small rounding errors accumulate in financial calculations. BigDecimal provides exact decimal representation with configurable rounding.
2. What is the difference between BigDecimal.valueOf(0.1) and new BigDecimal(0.1)?
BigDecimal.valueOf(0.1) first converts the double to a string ("0.1") and then parses it, producing the exact value 0.1. new BigDecimal(0.1) reproduces the double's exact binary representation, which is imprecise.
3. What does Math.addExact(a, b) do differently from a + b?
addExact throws ArithmeticException if the result overflows. a + b silently wraps around (e.g., Integer.MAX_VALUE + 1 becomes Integer.MIN_VALUE).
4. What is RoundingMode.HALF_EVEN?
Banker's rounding: rounds to the nearest neighbor, but when the fraction is exactly 0.5, rounds to the nearest even digit. This reduces cumulative rounding bias.
5. How do you find the GCD of two large numbers using BigInteger?
a.gcd(b). BigInteger has a built-in gcd() method.
Challenge Question:
Write a method BigDecimal calculateCompoundInterest(BigDecimal principal, BigDecimal annualRate, int years, int compoundsPerYear) that calculates compound interest using the formula A = P(1 + r/n)^(nt). Use BigDecimal with appropriate scale and HALF_EVEN rounding. Test with principal=10000, rate=0.05, years=10, compounds=12.
FAQ
Mini Project
Write a program MathDemo.java that:
- Demonstrates
Mathclass functions:abs,max,min,pow,sqrt,random - Generates 10 random integers between 1 and 100 using
Math.random() - Creates a
BigIntegerfactorial method that calculates factorial of 1000 (correctly) - Builds an invoice calculator:
- Reads item prices from the user
- Calculates subtotal, 8% tax, and total using
BigDecimal - Rounds to 2 decimal places using
HALF_UP
- Shows the floating-point bug:
0.1 + 0.2withdoublevsBigDecimal - Demonstrates
addExactvs regular addition overflow
What's Next
With core APIs covered, we move to modern Java features. Lesson 33 introduces lambda expressions — the syntax, target typing, variable capture, and method references that enable Functional Programming in Java.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro