Integer Overflow and Floating-Point Precision
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:
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);
}
}max: 2147483647
max + 1: -2147483648
as long: 2147483648How it works
- Line 4 adds 1 to the largest
int. There's no room for the answer, so the value wraps around toInteger.MIN_VALUE. No exception, no warning. - Line 8 writes
1L, so the addition is done inlong, 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:
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());
}
}
}Stopped: integer overflowA 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:
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));
}
}0.1 + 0.2 = 0.30000000000000004
equal to 0.3? false
1.0 / 0 = Infinity
0.0 / 0 = NaNHow it works
- Line 3 adds two values that are each slightly off, and the result shows the error.
- Line 5 compares with
==and getsfalse. Never compare decimals with==; check that they're close instead:Math.abs(sum - 0.3) < 1e-9. - Lines 6 and 7 show that dividing a
doubleby zero doesn't crash: you getInfinityorNaN(not a number). Dividing anintby zero throwsArithmeticException: / by zero.
Money the Right Way
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);
}
}BigDecimal: 0.30
In paise: 30Create 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
- Easy: Predict, then run:
Integer.MAX_VALUE * 2,Long.MAX_VALUE + 1,0.1 * 3. - Harder: Add Rs. 0.10 to a total ten times using
double, then usingBigDecimal. Print both totals.
Key Takeaways
Was this tutorial helpful?