Kotlin Integer Overflow for Coding Interviews: The Complete Guide

June 19, 20269 min read
dsaalgorithmsinterview-prepkotlin
Kotlin Integer Overflow for Coding Interviews: The Complete Guide
TL;DR
  • Kotlin integer overflow is silent: Int.MAX_VALUE + 1 wraps to Int.MIN_VALUE with no exception and no compile warning.
  • Int is 32-bit (~2.1 × 10^9 max) and Kotlin's default numeric type; the compiler will not widen it for you.
  • Binary search midpoint is the most common interview bug: use left + (right - left) / 2, never (left + right) / 2.
  • .toLong() on one operand before any large multiply widens the entire expression automatically; you only need to call it once.
  • Declare loop accumulators as 0L so the sum stays Long from the first iteration, not just after it overflows.
  • Modular arithmetic trap: even with Long, a * b % MOD can overflow when both factors approach 10^9; reduce each factor before multiplying.
  • Math.addExact throws ArithmeticException on overflow and is the correct tool when the problem asks you to detect it.

You're solving a LeetCode medium. Constraints say n can reach 10^9. You sum two indices, run your algorithm, and submit. Wrong answer. The kind that makes you stare at your code like it personally offended you. You add a debug print and the output is a negative number. That's Kotlin integer overflow, and it happens with no warning, no exception, and no stack trace. Just vibes and a wrong answer.

This guide covers every number type Kotlin gives you for interview work, where overflow silently strikes, and the patterns that prevent it.


Every Number Type You'll Actually Use

Kotlin has six built-in numeric types. In practice, three do the work:

TypeWidthRangeWhen to use
Int32-bit-2,147,483,648 to 2,147,483,647 (~2.1 × 10^9)Default: indices, small counts
Long64-bit~-9.2 × 10^18 to ~9.2 × 10^18Sums, products, anything that could exceed 2 × 10^9
BigIntegerArbitraryNo limitExact factorial, large combinations, modular exponentiation

Short (16-bit) and Byte (8-bit) exist but almost never appear in interview code. Double handles floating-point geometry but introduces its own precision trap.

Int is what Kotlin infers by default. Long is what you reach for when constraints touch 10^9.

A literal like 2147483647 infers as Int. The moment you need more room, you have to say so explicitly, because the compiler will not widen for you.


Overflow Is Silent. That's the Whole Problem.

Add 1 to Int.MAX_VALUE in Kotlin:

println(Int.MAX_VALUE + 1) // -2147483648

No exception. No compile warning. The result wraps to Int.MIN_VALUE: Kotlin inherits two's complement arithmetic from the JVM, and the bit pattern rolls over like a car odometer hitting 999,999.

This is the same behavior as Java. If you've been burned by Java's silent overflow, Kotlin gives you no extra protection. If you're coming from Python, where integers are arbitrarily large and you've never had to think about this, congratulations: this is your welcoming committee.

The silence is what makes this dangerous. Your code runs, produces a wrong answer, and the failure mode looks exactly like a logic bug rather than a type issue. You'll spend 10 minutes re-checking your algorithm before you notice the number in your debug output is somehow negative.

You can verify the boundary yourself:

println(Int.MAX_VALUE) // 2147483647 println(Int.MAX_VALUE + 1) // -2147483648 ← wraps println(Long.MAX_VALUE) // 9223372036854775807 println(Long.MAX_VALUE + 1) // -9223372036854775808 ← Long wraps too, much later

HeckOverflow parody of Stack Overflow showing a circular unhelpful Q&A exchange about how to do A

Debugging a wrong answer when the bug is a type mismatch, not your algorithm.


Three Places Overflow Kills Your Interview Code

1. Summing two large values

The constraint says 1 ≤ nums[i] ≤ 10^9. You add two elements:

val total = nums[i] + nums[j] // both are Int, could reach 2 × 10^9 → overflow

Int.MAX_VALUE is ~2.1 × 10^9. Two elements each at 10^9 already push 2 × 10^9, right at the limit. Accumulate across more values and you're over.

The fix is to widen before you add, not after:

val total = nums[i].toLong() + nums[j] // one toLong() widens the whole expression

Once one operand is Long, Kotlin promotes the other automatically. You don't need to call .toLong() on both.

2. The binary search midpoint

This is the most famous interview overflow. You have a binary search with left and right as Int:

val mid = (left + right) / 2 // wrong: sum can overflow before the division

If both bounds are large, left + right wraps negative before dividing. The safe form avoids the large intermediate:

val mid = left + (right - left) / 2 // subtraction stays small

right - left is always a valid non-negative difference. Some engineers prefer the explicit cast:

val mid = ((left.toLong() + right) / 2).toInt()

Either form is correct. The wrong form (left + right) / 2 is a documented bug in older Java standard library code, and interviewers know it. They will spot it even on problems where the test inputs don't trigger it, because demonstrating awareness of the boundary is part of the rubric.

For more on binary search correctness, see Your Binary Search Has an Off-by-One Bug. Prove Me Wrong..

3. Multiplying indices or counts

Triangular numbers, area calculations, and combinatorics all multiply values that individually fit in Int but whose product does not:

val n = 100_000 val pairs = n * (n - 1) / 2 // n * (n - 1) ≈ 10^10 → overflows Int silently

The fix: promote before you multiply.

val pairs = n.toLong() * (n - 1) / 2

Multiplication overflow is sneakier than addition overflow because the gap between "looks fine" and "explodes" is larger. The last Int-safe value for n * n is n = 46_340 (46,340² = 2,147,395,600). One higher: 46,341² wraps.


Four Patterns for Safe Arithmetic

Pattern 1: L suffix on literals

Force a Long computation by making the first constant a Long literal:

val result = 1_000_000_000L * n // literal is Long; n is promoted automatically

Useful for constants. Less useful when values come from function parameters inferred as Int.

Pattern 2: .toLong() on one operand

The most common interview pattern:

val result = a.toLong() + b // b promoted automatically val result = a.toLong() * b * c // all three multiplied as Long

Put .toLong() on the first operand. Everything downstream in the expression widens automatically. This is the pattern to drill until it's reflex.

Pattern 3: Declare accumulator as Long from the start

When accumulating in a loop, set the type upfront:

var sum = 0L // Long from the start for (x in nums) { sum += x // x (Int) is promoted automatically }

Declaring var sum = 0 and then doing sum += x keeps everything in Int until something overflows. Declaring 0L sidesteps the problem entirely.

Pattern 4: Math.addExact when overflow should be an error

If a problem asks you to detect overflow (several LeetCode problems do), Kotlin has access to Java's exact arithmetic:

import java.lang.Math try { val result = Math.addExact(a, b) // throws ArithmeticException on overflow val product = Math.multiplyExact(a, b) // same } catch (e: ArithmeticException) { // overflow detected, handle accordingly }

subtractExact and toIntExact (throws if a Long doesn't fit in Int) round out the family. These are niche in interviews but are the right answer when the problem is specifically about detecting overflow. For the Java-side context on this, see Java Integer Overflow: Patterns, Pitfalls, and Safe Code.


When Long Still Isn't Enough: BigInteger

Long handles values up to ~9.2 × 10^18. That covers almost every interview constraint. When a problem asks for exact factorial, exact Catalan numbers, or large modular exponentiation without a modulus, Long runs out.

Kotlin exposes java.math.BigInteger directly:

import java.math.BigInteger fun factorial(n: Int): BigInteger { var result = BigInteger.ONE for (i in 2..n) { result = result.multiply(BigInteger.valueOf(i.toLong())) } return result } println(factorial(20)) // 2432902008176640000 println(factorial(50)) // 30414093201713378043612608166979581188299763898377856000000000000

There's also a convenience extension:

val big = 12345.toBigInteger() val product = big * 67890.toBigInteger() // operator overloading works

BigInteger arithmetic is slower than primitive arithmetic. For interview problems this rarely matters: numbers that require BigInteger are too large to store any other way. The slowdown only bites if you're running millions of BigInteger operations in a hot loop, which is not a typical interview pattern.


The Modular Arithmetic Trap Inside Long

One more Kotlin-specific detail deserves its own callout. Counting problems often reduce results mod 10^9+7. Even when you're working modulo a prime, intermediate products can overflow Long if both factors are close to 10^9:

val MOD = 1_000_000_007L val a = 999_999_999L val b = 999_999_999L println(a * b % MOD) // wrong: a * b overflows Long before the mod println(a % MOD * (b % MOD) % MOD) // correct: products stay below 10^18

Long.MAX_VALUE is ~9.2 × 10^18. Two values each near 10^9 multiply to ~10^18, right at the edge. The safe pattern reduces each factor to [0, MOD) before multiplying. This trips up a surprising number of otherwise-correct DP solutions. See Kotlin Coding Interview Gotchas for related footguns.

The conceptual background on two's complement wrapping is covered in What Is Integer Overflow and Underflow? if you want to understand the bit-level mechanism.


When to Use What

SituationWhat to do
Index arithmetic, arrays ≤ 10^6 elementsInt is fine
n ≤ 10^9 and you multiply two inputs.toLong() before the multiply
Binary search midpointleft + (right - left) / 2
Accumulating sum of Int valuesDeclare accumulator as 0L
Exact factorial or large combinationsBigInteger
Detecting overflow as a conditionMath.addExact with try-catch
Modular arithmetic with large factorsReduce each factor mod MOD before multiplying
Checking if a Long fits back in IntMath.toIntExact(longValue)

Build the Muscle Now, Not During the Interview

You won't have time to reason through type widening when you're 20 minutes into a hard problem. The patterns above need to be automatic: .toLong() before the first multiply, 0L for any accumulator, left + (right - left) / 2 in every binary search. That kind of precision under pressure is exactly what voice-based mock interviews at SpaceComplexity train you to hold. The rubric scores implementation correctness, not just whether your high-level approach was right.


Further Reading