Integer Overflow and Floating-Point Precision

Naveen AnamaneniUpdated · 5 min read

An old car's odometer shows six digits. Drive past 999,999 km and it doesn't stop; it rolls over to 000,000. Java's whole-number types behave exactly like that, and Java's decimal types have a different surprise: some simple decimals, such as 0.1, can't be stored exactly. Neither problem gives an error. Both have caused real bugs in banking and billing systems, so it's worth seeing them once.

Integer Overflow: Rolling Over

An int can hold values up to 2,147,483,647. Add 1 more and it wraps around to the most negative value:

Past the maximum, an int rolls over to the minimum
Overflow.java▶ Try it
public class Overflow {
    public static void main(String[] args) {
        int max = Integer.MAX_VALUE;
        int next = max + 1;
        System.out.println("max:      " + max);
        System.out.println("max + 1:  " + next);
 
        long fixed = max + 1L;
        System.out.println("as long:  " + fixed);
    }
}
Output
max:      2147483647
max + 1:  -2147483648
as long:  2147483648

How it works

  1. Line 4 adds 1 to the largest int. There's no room for the answer, so the value wraps around to Integer.MIN_VALUE. No exception, no warning.
  2. Line 8 writes 1L, so the addition is done in long, which has room. The answer is correct.

Try it yourself: subtract 1 from Integer.MIN_VALUE. What do you get?

Catch Overflow Instead

Math.addExact, Math.subtractExact and Math.multiplyExact do the same arithmetic but throw an exception when the result doesn't fit:

Exact.java▶ Try it
public class Exact {
    public static void main(String[] args) {
        try {
            int total = Math.addExact(Integer.MAX_VALUE, 1);
            System.out.println(total);
        } catch (ArithmeticException e) {
            System.out.println("Stopped: " + e.getMessage());
        }
    }
}
Output
Stopped: integer overflow

A crash with a clear message is much easier to find than a wrong number in a report. Exceptions are covered properly later in the course.

Floating-Point Precision: 0.1 + 0.2

double and float store numbers in binary. Just as 1/3 can't be written exactly in decimal (0.3333...), 0.1 can't be written exactly in binary. The stored value is extremely close, but not exact, and the tiny differences show up in results:

Precision.java▶ Try it
public class Precision {
    public static void main(String[] args) {
        double sum = 0.1 + 0.2;
        System.out.println("0.1 + 0.2 = " + sum);
        System.out.println("equal to 0.3? " + (sum == 0.3));
        System.out.println("1.0 / 0 = " + (1.0 / 0));
        System.out.println("0.0 / 0 = " + (0.0 / 0));
    }
}
Output
0.1 + 0.2 = 0.30000000000000004
equal to 0.3? false
1.0 / 0 = Infinity
0.0 / 0 = NaN

How it works

  1. Line 3 adds two values that are each slightly off, and the result shows the error.
  2. Line 5 compares with == and gets false. Never compare decimals with ==; check that they're close instead: Math.abs(sum - 0.3) < 1e-9.
  3. Lines 6 and 7 show that dividing a double by zero doesn't crash: you get Infinity or NaN (not a number). Dividing an int by zero throws ArithmeticException: / by zero.

Money the Right Way

Money.java▶ Try it
import java.math.BigDecimal;
 
public class Money {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.10");
        BigDecimal b = new BigDecimal("0.20");
        System.out.println("BigDecimal: " + a.add(b));
 
        long paise = 10 + 20;
        System.out.println("In paise:   " + paise);
    }
}
Output
BigDecimal: 0.30
In paise:   30

Create BigDecimal values from strings like "0.10". Writing new BigDecimal(0.1) copies the inexact double and brings the problem back.

Common Mistakes

Calculating with int and storing in long. long ms = 30 * 24 * 60 * 60 * 1000; overflows before the assignment, because the arithmetic is done in int. Write 30L * 24 * ....

Comparing decimals with ==. Compare the difference with a small tolerance, or use BigDecimal.compareTo.

Checking for overflow after it has happened. if (a + b > Integer.MAX_VALUE) can never be true for two ints. Use Math.addExact, or do the sum in long.

Interview Corner

What is Integer.MAX_VALUE + 1?

Integer.MIN_VALUE, which is -2,147,483,648. Integer arithmetic in Java wraps around silently on overflow. Use long, Math.addExact or BigInteger when values can exceed the range.

Why does 0.1 + 0.2 not equal 0.3 in Java?

double stores numbers in binary floating point (IEEE 754), where 0.1 and 0.2 can't be represented exactly. The small errors add up to 0.30000000000000004. Compare with a tolerance, and use BigDecimal or whole paise for money.

Practice

  1. Easy: Predict, then run: Integer.MAX_VALUE * 2, Long.MAX_VALUE + 1, 0.1 * 3.
  2. Harder: Add Rs. 0.10 to a total ten times using double, then using BigDecimal. Print both totals.

Quick check: Overflow and precision

4 questions
1What is Integer.MAX_VALUE + 1?
2Which method throws an exception on overflow?
3What does 0.1 + 0.2 == 0.3 evaluate to?
4Which is the safest way to store Rs. 249.50?

Key Takeaways

Was this tutorial helpful?

Lesson 40 of 482