What Is Integer Overflow and Underflow? The Bug Your Code Never Crashes On

- Integer overflow happens when arithmetic exceeds INT_MAX (or INT_MIN) and wraps to the opposite end of the range
- Python never overflows; Java and Go wrap silently; C++ signed overflow is undefined behavior; Rust panics in debug builds
- The most famous overflow bug:
(left + right) / 2in binary search — fix withleft + (right - left) / 2 - Floating-point underflow is separate: a positive value too small to represent rounds to 0.0 with no error raised
- Before coding, check constraints — multiplying two values up to 10^9 requires a long, not an int
- The danger: the bug never crashes, it silently produces wrong answers on large inputs
You add two numbers. The result is negative. No exception, no warning, no stack trace. Just a wrong number sitting quietly in your variable, waiting to corrupt everything downstream.
That is integer overflow. And it is one of the more dangerous bugs in programming precisely because it does not look like a bug. The code compiles. It runs. Small test cases pass. You feel good about yourself. Then the judge hands it an array with a billion elements and your binary search returns -1 for an index that exists, and you spend forty minutes convinced the test case is wrong before checking the midpoint calculation.
Why Numbers Have Limits
Every integer variable has a fixed number of bits. A 32-bit signed integer uses one bit for the sign and 31 bits for the magnitude, giving it exactly 2^32 possible values across the range -2,147,483,648 to 2,147,483,647.
That upper limit is INT_MAX. The lower limit is INT_MIN.
| Type | Bits | Min | Max |
|---|---|---|---|
| 32-bit signed int | 32 | -2,147,483,648 | 2,147,483,647 |
| 64-bit signed long | 64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
| 32-bit unsigned | 32 | 0 | 4,294,967,295 |
These limits come from the representation. The concept behind it is called two's complement, which is how every modern CPU stores negative integers. You did not choose these limits. They chose you.
When arithmetic produces a result outside the representable range, something has to give. The question is what.
Integer Overflow: The Wrap-Around
Think of integer storage as a circular odometer. A 3-bit unsigned integer counts 0, 1, 2, 3, 4, 5, 6, 7, then rolls back to 0. The moment you hit 7 and add 1, the carry bit falls off the end and you wrap to 0. The CPU does not apologize.
Overflow is when you go past the maximum value and wrap to the minimum, or vice versa. No error. No sound effect. Just a number that is confidently, silently wrong.
// Java - wraps silently int x = Integer.MAX_VALUE; // 2147483647 System.out.println(x + 1); // -2147483648
# Python - no overflow, ever x = 2**31 - 1 print(x + 1) # 2147483648 - just works
// C++ - undefined behavior for signed overflow int x = INT_MAX; printf("%d\n", x + 1); // could print anything; UB
Python is the exception. Its integers are arbitrary precision: they grow as large as your memory allows and never wrap. This is genuinely nice, but it can create a false sense of security before a Java or C++ interview. Python has been coddling you.
C++ has a sharper edge. Signed integer overflow is officially undefined behavior under the C++ standard. The compiler is allowed to assume it never happens and optimize accordingly. In practice the optimizer can delete branches, reorder instructions, or produce outputs that make no intuitive sense. Unsigned overflow in C++ is well-defined and always wraps.

Your code. Your math. Your consequences.
Underflow: The Other Direction
Subtract 1 from INT_MIN and you wrap to INT_MAX. The number line is a circle and you just went around the back.
int x = Integer.MIN_VALUE; // -2147483648 System.out.println(x - 1); // 2147483647
This trips people up on problems involving large subtractions, decrement loops near zero, or formulas that can go negative before being bounded. The fix is always the same: use a wider type before the operation, not after.
Floating-Point Underflow Is a Different Problem
When people say "underflow" in a floating-point context, they mean something different. Worth separating so you do not mix them up mid-interview.
IEEE 754 floating-point represents numbers as sign × mantissa × 2^exponent. The exponent has a limited range. The smallest positive normal double is approximately 2.225 × 10^-308. Go below that and you enter subnormal territory where the representation loses precision. Go smaller still and the number rounds to 0.0 with no error raised. You asked for a tiny positive number and got zero. Totally fine. Nothing wrong here.
import sys print(sys.float_info.min) # 2.2250738585072014e-308 x = 5e-324 # smallest representable subnormal print(x / 2) # 0.0 - underflowed to zero
Floating-point overflow also exists and produces infinity. A double overflows at around 1.8 × 10^308.
print(1e308 * 10) # inf
In coding interviews, floating-point underflow is less common. It shows up in probability calculations that multiply many small values together, and occasionally in hash function problems involving large exponents.
The Most Famous Overflow Bug in Programming
In 1986, Jon Bentley published "Programming Pearls," a collection of algorithms and their pitfalls. One section showed a binary search implementation with a subtle overflow bug sitting in plain sight. Not just any plain sight: this was a textbook. Read by millions of programmers. For decades.
The bug was the midpoint calculation:
// Wrong - overflows when left and right are near INT_MAX int mid = (left + right) / 2; // Correct int mid = left + (right - left) / 2;
If left and right are both large positive numbers, their sum can exceed INT_MAX and wrap negative. Dividing a negative number by 2 gives a negative midpoint. The binary search silently breaks. You get -1 for an element that is sitting right there.
This bug sat in Java's Arrays.binarySearch for nearly a decade after the language launched. It was found and fixed in 2006. Not by a crash. By someone reading the code and doing the math. If you code in Java or C++, always use the second form. See binary search off-by-one bugs for the full taxonomy of ways binary search goes wrong.
The broader lesson: integer overflow does not announce itself. It waits.

When the number looks right but the machine disagrees. Integer overflow has real-world consequences. The steak is also cold.
Where Overflow Actually Appears in Interviews
Running sums. Sum an array of 32-bit integers and the total can easily exceed INT_MAX if the values are large. Accumulate in a long instead.
long total = 0; for (int n : nums) { total += n; // widened automatically to long }
Multiplication before division. The expression a * b / c computes a * b first. If both are near INT_MAX, the intermediate product overflows before the division brings it back in range. Reorder to a / c * b when integer division is acceptable, or cast explicitly: (long) a * b / c.
Power and factorial calculations. 2^31 is 2,147,483,648, which exceeds INT_MAX by one. 13! exceeds INT_MAX. Problems that ask for large powers or factorials often expect answers mod 10^9+7 to avoid this. See why mod 10^9+7 is used for the reasoning.
Hash function accumulators. Rolling hash implementations multiply and add character codes in a loop. Without explicit modding, the accumulator overflows quickly. Take mod at each step.
Signed vs unsigned comparison. In C++, comparing a signed and unsigned integer can produce unexpected results because the signed value is implicitly converted to unsigned. This is a fun one to debug at midnight.
Every Language Has a Different Answer
| Language | Signed integer overflow |
|---|---|
| Python | No overflow (arbitrary precision) |
| Java | Silent two's complement wrapping |
| C++ | Undefined behavior (signed); wrapping (unsigned) |
| Go | Silent two's complement wrapping |
| JavaScript | Numbers are 64-bit floats; wraps only in bitwise ops |
| Rust | Panics in debug mode; wraps in release mode |
Rust's approach is the most transparent. In debug mode, you get an immediate panic at the exact line that overflowed. Like a fire alarm that goes off when there is actual fire, not three weeks later when your house is already ash. In release mode, you get wrapping behavior, but you were supposed to catch it in testing. Rust also offers explicit alternatives: checked_add returns None on overflow, saturating_add clamps to the max, and wrapping_add always wraps regardless of build mode.
Java and Go just wrap and say nothing. Python quietly upgrades your int to a bignum. C++ signed overflow lets the compiler interpret your future as it sees fit.
How to Catch It Before It Bites
The single best habit is reading the constraint block before you write any code.
If a problem says values go up to 10^9 and you are multiplying two of them, the product can reach 10^18. INT_MAX is about 2.1 × 10^9. The product overflows. You need a long (max about 9.2 × 10^18).
Rough mental thresholds:
- INT_MAX is about 2.1 × 10^9
- LONG_MAX is about 9.2 × 10^18
- A product of two large ints can overflow. A product of two longs almost certainly does.
When in doubt in Java, declare your accumulator as long from the start. The cast is essentially free.
In C++ with very large intermediates, __int128 gives you 128-bit signed arithmetic without external libraries.
__int128 result = (__int128) a * b;
For Python interviews: you do not need to worry about integer overflow at all. But you might be asked to solve a problem as if you were coding in Java, at which point Python has trained you to never think about this, which is its own problem.
Why Integer Overflow Shows Up in Interviews
Overflow is a calibration question. Interviewers use it to see whether you read constraints carefully and reason about the magnitude of your values before reaching for a type. Getting the arithmetic right on small inputs and then silently producing a wrong answer on large ones is exactly the mistake that costs a hire recommendation.
The signal interviewers want is proactive: you notice that intermediate values might overflow, say so out loud, and make the fix before writing the line. Reactively fixing it after the interviewer points out a failing test case is a weaker signal. Saying nothing is the worst, because from the interviewer's perspective, you just shipped a bug.
Practicing this out loud, on real timing, in a voice interview environment, is how the habit gets built. SpaceComplexity runs AI-powered mock interviews that catch overflow mistakes in your live reasoning and walk you through the fix before the habit solidifies wrong.
Key Takeaways
- Integer overflow happens when arithmetic exceeds the max (or min) representable value and wraps around
- Python never overflows; Java and Go wrap silently; C++ signed overflow is undefined behavior; Rust panics in debug builds
- Floating-point underflow is distinct: a positive value too small to represent rounds to 0.0
- The classic overflow:
(left + right) / 2in binary search with large indices; fix isleft + (right - left) / 2 - Before coding, check constraints. Values up to 10^9 multiplied together need a
long - The bug does not crash. That is what makes it dangerous.