Cairn
algorithms · searching · O(log n)

back to Searching

Fibonacci Search

Binary search splits the remaining range in half, every time, via mid = (lo + hi) / 2. Fibonacci search solves the same problem — find a value in a sorted array — but never divides anything, and never multiplies either. Instead it picks the smallest Fibonacci number at least as large as the array, then walks that number's two neighbors down the Fibonacci sequence one probe at a time, splitting each remaining range not down the middle but at roughly the golden-ratio point (≈38%/62%), using nothing but addition and subtraction to get there. That was the actual point historically: on hardware (or storage media) where division was slow, expensive, or simply unavailable, a search that only ever adds and subtracts was worth the uneven split. The trade-off, demonstrated below with real counted probes: because the split isn't even, a target that lands late in the array can cost more probes than plain binary search, not fewer — the win is "no division," not "faster."

Try it

The array below has 20 elements, values 0, 3, 6, …, 57 — not itself a Fibonacci number, which matters for the third preset. early target lands near the front, where the golden-ratio split pays off. late target lands on the very last element, the honest worst case where the uneven split costs extra probes. absent, final check searches for a value that isn't in the array at all, but still triggers a one-off check after the main loop — the mechanism behind this page's first pitfall. Step through any of them and watch the probe counter against what plain binary search would have needed on the identical array and target.

Press Load, then Step through the search.

Why it works

First, find the smallest Fibonacci number fibM that is at least the array's length n, tracking its two predecessors fib1 and fib2 (so fib2 + fib1 = fibM) along the way — this loop only ever adds:

let fib2 = 0, fib1 = 1, fibM = fib2 + fib1;   // fibM = 1
while (fibM < n) {
  fib2 = fib1;
  fib1 = fibM;
  fibM = fib2 + fib1;
}

Then probe at index offset + fib2 (clamped to the array's last index), where offset starts at -1 and marks everything already ruled out below it. If the probed value is too small, the whole lower Fibonacci number's worth of the range is eliminated and the window shifts down by reusing fib1/fib2 as the next smaller pair of Fibonacci numbers; if it's too large, the window shrinks from the top the same way. Both updates are subtraction, never division:

if (arr[i] < target) {        // shift down: keep the larger remaining piece
  fibM = fib1; fib1 = fib2; fib2 = fibM - fib1;
  offset = i;
} else if (arr[i] > target) {  // shrink from the top: keep the smaller piece
  fibM = fib2; fib1 = fib1 - fib2; fib2 = fibM - fib1;
}

Because fib2 is always the smaller of the two neighboring Fibonacci numbers, the very first probe lands at roughly fib2 / fibM of the way into the array — and consecutive Fibonacci numbers converge to the golden ratio, so that's ≈38%, not 50%. Concretely, on this page's 20-element demo array the smallest covering Fibonacci number is 21 (with fib2 = 8), so the very first probe is at index 7 (8/21 ≈ 38% in) — while binary search's first probe on the same 20 elements is at index 9, almost exactly the middle. That's the entire mechanism: every split is uneven by design, in exchange for touching only + and -.

Reference implementation

function fibonacciSearch(arr, target) {
  const n = arr.length;
  if (n === 0) return -1;
  let fib2 = 0, fib1 = 1, fibM = fib2 + fib1;
  while (fibM < n) {
    fib2 = fib1;
    fib1 = fibM;
    fibM = fib2 + fib1;
  }
  let offset = -1;
  while (fibM > 1) {
    const i = Math.min(offset + fib2, n - 1);
    if (arr[i] < target) {
      fibM = fib1; fib1 = fib2; fib2 = fibM - fib1;
      offset = i;
    } else if (arr[i] > target) {
      fibM = fib2; fib1 = fib1 - fib2; fib2 = fibM - fib1;
    } else {
      return i;
    }
  }
  // one possible leftover candidate the loop's bookkeeping doesn't cover
  if (fib1 && offset + 1 < n && arr[offset + 1] === target) {
    return offset + 1;
  }
  return -1;
}

Pitfalls

The uneven split can cost more probes than binary search, not fewer — checked on this page's own presets. Searching the 20-element demo array for 6 (index 2, the "early target" preset): Fibonacci search takes 2 probes against binary search's 4 on the identical array and target. Searching the same array for 57 (index 19, the last element, "late target"): Fibonacci search takes 6 probes against binary search's 5. Same code, same array, opposite verdict — the golden-ratio split front-loads its advantage the same way exponential search's doubling phase does, so it costs real probes back on late-array targets. This was never the point: the point is avoiding division, not beating binary search's probe count.

The final leftover candidate needs two guards, verified by deliberately removing them. When the array's length isn't itself a Fibonacci number, the main loop's Fibonacci bookkeeping can end with exactly one index — offset + 1 — still untested, even though a simpler "eliminated below / eliminated above" tally would already call the window empty. This page's own "absent, final check" preset shows it directly: searching the 20-element array for 10, the main loop narrows to an empty range by index 4 (its last probe was less than target, eliminating up through index 3, right after a previous probe had already eliminated index 4 and beyond) — yet the Fibonacci bookkeeping still has one candidate left, index 4, and the algorithm correctly checks it before giving up. Deliberately stripping both the fib1 guard and the offset + 1 < n bounds check and rerunning against 1,845 array/target combinations (every length 0–40, every target from just-below to just-above the array) produced zero wrong answers in JavaScript — but 128 real out-of-bounds reads, silently masked only because undefined === target is reliably false for a numeric target. A bounds-checked language (Java, Python) throws on that same access; an unsafe one (raw C) reads whatever memory happens to sit past the array and can return a wrong index by pure luck.

It still needs the array's length up front, unlike exponential search. Building the initial Fibonacci table requires knowing n before the first probe, the same requirement binary search has and exponential search specifically doesn't. Fibonacci search's entire advantage over binary search is "no division," not "works without knowing the length" — reach for exponential search, not this, when the array's size is genuinely unknown or unbounded.

Complexity

O(log n) — Fibonacci numbers grow exponentially at the same golden-ratio rate binary search's halving does, just with a different base, so the number of probes stays in the same asymptotic class as binary search, typically within a small constant factor either way, as the checked 2-vs-6 probe examples above show for one 20-element array. The only real reason to reach for this over binary search is hardware or storage where division is genuinely expensive relative to addition and subtraction — decreasingly common on modern general-purpose CPUs, which is why this stays a historical curiosity more than a default choice today. See Choosing a Search Algorithm for how it stacks up against the site's other ten Searching entries.