skip to content

What is the difference between BigInteger and BigDecimal, and how do you convert between them?

level: middleimportance: should knowfreq 44%

answer

  1. BigInteger = whole; BigDecimal = decimal with scale
  2. BigDecimal = unscaled BigInteger + scale → exact money
  3. new BigDecimal(bi) lossless; toBigInteger() truncates
  4. toBigIntegerExact() throws on a fraction
  5. BigDecimal equals respects scale; use compareTo for value

basics

~10 s

BigInteger holds arbitrarily large whole numbers; BigDecimal holds arbitrary-precision decimals (with a fraction part and a scale). You convert with new BigDecimal(bigInteger) and, going back, BigDecimal.toBigInteger() (which drops the fraction).

solid answer

~50 s

Both live in java.math and both are immutable, arbitrary-precision, and arithmetic-safe, but they model different things. BigInteger is a whole number of unlimited size — no fractional part. BigDecimal is an exact decimal: internally an unscaled BigInteger plus a scale (number of digits after the decimal point), so it represents values like 19.99 exactly, which double cannot. Use BigInteger for integer/number-theory/crypto work; use BigDecimal for money and any exact decimal arithmetic. Converting: BigDecimal has a constructor new BigDecimal(BigInteger) and new BigDecimal(BigInteger unscaled, int scale); a BigInteger has no fraction so it converts losslessly. Going the other way, BigDecimal.toBigInteger() truncates the fractional part (toBigIntegerExact() throws if there is one). A subtle gotcha: a BigDecimal carries scale, so new BigDecimal('2.0') is not equal() to new BigDecimal('2.00') even though compareTo() reports them equal — use compareTo for numeric equality.

go deeper

for a junior

Knows BigInteger is for whole numbers and BigDecimal is for decimals/money.

for a middle

Explains the unscaled-value+scale model, why double is wrong for money, and converts both directions knowing toBigInteger truncates.

for a senior

Adds the equals-vs-compareTo scale pitfall and chooses *Exact conversions to surface unexpected fractions.

for a principal

Frames precision/rounding policy (RoundingMode, MathContext) and where to enforce the BigDecimal boundary in monetary domains and APIs.

## Two arbitrary-precision types, two jobs Both `BigInteger` and `BigDecimal` are in `java.math`, both are **immutable**, both grow to whatever size memory allows, and both give **exact** results (no overflow, no floating-point rounding error). The difference is what they represent: - **`BigInteger`** = an arbitrarily large **whole number** (an integer). No fractional part at all. - **`BigDecimal`** = an arbitrarily precise **decimal number**, including a fractional part. ## How BigDecimal stores a decimal A `BigDecimal` is really two parts: 1. an **unscaled value**, which is itself a `BigInteger` (all the significant digits as one integer), and 2. a **scale**, an `int` saying how many of those digits sit after the decimal point. So `19.99` is stored as unscaled value `1999` with scale `2` (meaning 1999 × 10^-2). This lets it represent decimal fractions **exactly** — unlike `double`, where `0.1` is not exactly representable in binary and accumulates rounding errors. That exactness is why money should use `BigDecimal`, never `double`. ## Which to use when - **`BigInteger`**: counting/IDs beyond `long`, factorials, combinatorics, hashing, cryptography (`modPow`, `gcd`, primes). - **`BigDecimal`**: currency, tax, interest, invoices — anything where 0.01 must mean exactly one cent and rounding must be controlled. ## Converting between them **BigInteger → BigDecimal** (always lossless, since a whole number has no fraction): ```java BigInteger bi = new BigInteger("123456789012345678901234567890"); BigDecimal bd = new BigDecimal(bi); // scale 0 BigDecimal scaled = new BigDecimal(bi, 2); // treats bi as the unscaled value → bi × 10^-2 ``` **BigDecimal → BigInteger** (drops the fractional part): ```java BigDecimal price = new BigDecimal("19.99"); BigInteger whole = price.toBigInteger(); // 19 — truncates toward zero BigInteger exact = price.toBigIntegerExact(); // throws ArithmeticException (has a fraction) ``` Use `toBigIntegerExact()` when a non-zero fraction would be a bug you want surfaced. ## The equals-vs-compareTo gotcha (BigDecimal) Because `BigDecimal` carries a **scale**, two values that are numerically equal but written with different scales are **not** `equals()`: ```java new BigDecimal("2.0").equals(new BigDecimal("2.00")); // false! different scale new BigDecimal("2.0").compareTo(new BigDecimal("2.00")); // 0 → numerically equal ``` For numeric comparison always use `compareTo() == 0`, not `equals()`. (`BigInteger` has no scale, so its `equals` and `compareTo` agree.) ## Shared traits to remember Both are immutable (every operation returns a new object — capture the result), both are reference types so compare with `equals`/`compareTo` not `==`, and both trade speed for correctness versus primitives.

  • Why is new BigDecimal("2.0").equals(new BigDecimal("2.00")) false?
    BigDecimal's equals considers scale, and the two have scales 1 and 2. They are numerically equal, which compareTo reports as 0, but not equals-equal.
  • Is converting a BigInteger to a BigDecimal ever lossy?
    No. A BigInteger is a whole number with no fractional part, so new BigDecimal(bigInteger) preserves the exact value (at scale 0).

saying these in an interview costs you the question

  • Using double for money instead of BigDecimal
  • Assuming new BigDecimal('2.0').equals('2.00') is true
  • Thinking BigInteger can hold fractions
  • Forgetting toBigInteger drops the fractional part silently

context