Skip to content

Math and BigDecimal — Math Class, BigInteger, BigDecimal, and Rounding Modes

DodaTech Updated 2026-06-28 5 min read

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 Math class: min, max, abs, pow, sqrt, random
  • BigInteger: operations on arbitrarily large integers
  • BigDecimal: 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

  1. Using double for money. 0.1 + 0.2 != 0.3 in floating-point. Always use BigDecimal for monetary values.
  2. Using equals() instead of compareTo() for BigDecimal. equals() considers scale, so 2.0 != 2.00. Use compareTo() for value comparison.
  3. Forgetting to specify scale/rounding in divide(). BigDecimal.valueOf(1).divide(BigDecimal.valueOf(3)) throws ArithmeticException (non-terminating decimal). Always provide scale and rounding mode.
  4. Using new BigDecimal(double). This reproduces the floating-point imprecision. Use BigDecimal.valueOf(double) or new BigDecimal(String).
  5. Assuming Math.random() is cryptographically secure. Math.random() uses Random (LCG), not SecureRandom. Use SecureRandom for 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

What is the maximum value Math.random() can return?

Just under 1.0. It returns a double between 0.0 (inclusive) and 1.0 (exclusive).

Can BigInteger be used with primitive operators like + and *?

No. BigInteger is an object, not a primitive. Use methods like add(), subtract(), multiply(), divide().

What is the range of BigInteger?

Unbounded (limited by available memory). BigInteger grows dynamically as needed.

What is the difference between `setScale()` and `round()`?

setScale() sets the scale and applies rounding if needed. round() uses a MathContext to specify both precision and rounding mode. Both achieve similar results.

When should I use `MathContext`?

When you want to control both precision (total significant digits) and rounding mode in a single object. Useful when the same context applies to multiple operations.

Mini Project

Write a program MathDemo.java that:

  1. Demonstrates Math class functions: abs, max, min, pow, sqrt, random
  2. Generates 10 random integers between 1 and 100 using Math.random()
  3. Creates a BigInteger factorial method that calculates factorial of 1000 (correctly)
  4. 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
  5. Shows the floating-point bug: 0.1 + 0.2 with double vs BigDecimal
  6. Demonstrates addExact vs 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