Vibhanshu Sharma
active · powerplay
PORTFOLIO.SYS›content›blog›binary-search-derivation.mdx
Markdown · 8 min read · 2026-07-07

Binary Search: The Math Nobody Actually Derives (With a Live Race)

Not just how it works — why the math works. The integer overflow trap hiding in the naive formula, the full O(log n) derivation from first principles, and a live animation to see both searches race.


// tl;dr
  • The textbook midpoint formula (low+high)/2 can integer-overflow on large arrays — this exact bug lived in Java for 9 years.
  • The safe formula is low + (high-low)/2 — algebraically identical, but the intermediate sum can never overflow.
  • O(log n) isn't just intuition — it falls straight out of solving n / 2^k = 1 for k.
  • A billion-element array takes at most 30 comparisons; that asymptote is the whole point of algorithm design.

I learned binary search theory today. Not the "here's the code, now memorize it" version — the actual math underneath it.

Two things bothered me going in: why does the standard midpoint formula have a production bug, and how do you actually prove O(log⁡n)O(\log n) — not just assert it? Here's everything I worked through, with interactive demos so the intuition sticks.


What Binary Search Actually Does

You have a sorted array. You want to find a target value. Instead of scanning left to right, you:

  1. Check the middle element
  2. If it matches — done
  3. If the target is smaller — search the left half
  4. If the target is larger — search the right half
  5. Repeat until found or the search space is empty

Each step cuts the problem in half. The code is simple. The math is interesting.


Part 1: The Bug in the Formula You Were Taught

The "obvious" midpoint formula:

mid=low+high2mid = \frac{low + high}{2}

This is mathematically correct. It will also crash your program on large arrays.

The problem is integer overflow. If lowlow and highhigh are both close to the maximum value a 32-bit integer can hold (~2.1 billion), their sum exceeds what the variable can store. You get a negative number or garbage — not a crash with a clear error message, just silently wrong behavior.

This isn't hypothetical. This exact bug lived in Java's Arrays.binarySearch() for nine years before Joshua Bloch caught it in 2006.

The safe formula:

mid=low+high−low2mid = low + \frac{high - low}{2}

Subtract first, then add. (high−low)(high - low) is always smaller than either number alone, so it can't overflow.

But are these actually the same? Here's the algebraic proof:

// proof: safe formula = standard formula1/4 steps
low+high−low2low + \frac{high - low}{2}
01
Safe formula (starting point)This is what production code uses. We want to prove it equals the standard formula.

They compute the exact same midpoint. The safe version just sidesteps the intermediate sum that causes the overflow.


Part 2: Why O(log⁡n)O(\log n)? The Full Derivation

Most explanations just say "it halves the array each time, so it's logarithmic." That's the intuition — here's the actual proof.

Setup:

  • Let nn = number of elements in the sorted array
  • Let kk = number of iterations in the worst case

The halving pattern:

Each step reduces the search space by half:

IterationSearch space
00nn
11n/2n / 2
22n/22n / 2^2
33n/23n / 2^3
kkn/2kn / 2^k

The derivation:

Worst case: we keep halving until exactly 1 element remains. Set the search space at step kk equal to 1:

n2k=1\frac{n}{2^k} = 1

Multiply both sides by 2k2^k:

n=2kn = 2^k

Apply log⁡2\log_2 to both sides:

log⁡2(n)=log⁡2(2k)\log_2(n) = \log_2(2^k)

Use the logarithmic power rule — log⁡(ab)=b⋅log⁡(a)\log(a^b) = b \cdot \log(a):

log⁡2(n)=k⋅log⁡2(2)\log_2(n) = k \cdot \log_2(2)

Since log⁡2(2)=1\log_2(2) = 1:

k=log⁡2(n)k = \log_2(n)

The maximum steps to search nn elements is log⁡2(n)\log_2(n). Drop the base for Big-O notation: O(log⁡n)O(\log n).

What does this feel like in practice?

// O(log n) — steps to search n elements
Array size (n)Linear stepsBinary steps k = log₂(n)Ratio
8833×
6464611×
1,0241,02410102×
1,000,0001,000,0002050,000×
1,000,000,0001,000,000,0003033,333,333×
try any n:n = 1,024
Linear worst case
1,024 steps
Binary worst case
10 steps
Binary is faster by
102×

A billion-element array takes at most 30 comparisons. That's the real magic — not the code, but what the math guarantees.


Part 3: Watch It Race

Derivations are one thing. Here's the visual:

// search-race — sorted array [1…16]
target:speed:
LINEAR SEARCH
0 steps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
press ▶ RACE to start
BINARY SEARCH
0 steps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
waiting...
■ linear: current■ already checked■ binary: mid■ eliminated half■ found!

Try different targets. Target 14 (near the end) shows the gap most clearly — linear search grinds through 14 comparisons while binary search jumps to the answer in 3.

Target 4 (near the beginning) is linear search's best case — worth seeing how the algorithms compare when linear actually has a short path.


The Three Things Worth Internalizing

1. Sorted is the prerequisite. Binary search only works because you can eliminate half the search space based on a comparison. Unsorted data: you're back to linear.

2. The overflow bug isn't trivia. The naive formula low+high2\frac{low + high}{2} fails in production on large arrays. The safe formula low+high−low2low + \frac{high - low}{2} is what you should actually write — and now you can prove why it's equivalent.

3. Logarithms grow impossibly slowly. log⁡2(109)≈30\log_2(10^9) \approx 30. A problem 1000×1000\times larger takes only ∼ ⁣10\sim\!10 more steps. That asymptote is the whole game in algorithm design.

The code is five lines. The math behind it earns that simplicity.

Keep reading

We Shipped an AI Code Reviewer With Three Prompts. It Was Wrong Too Often and Quiet Too Long.

2026-07-28 · 9 min read

One Reviewer, Four Codebases, Four Different Definitions of Correct

2026-07-28 · 10 min read

Our Cross-File Pass Couldn't See Other Files. Tree-sitter Fixed That.

2026-07-28 · 10 min read

We Put a Cheap Model in Charge of the Expensive Ones

2026-07-28 · 10 min read
← all posts