Ternary Search
Finds the minimum or maximum of a unimodal function by dividing the search space into three parts and eliminating one third each iteration.
Syntax
ternarySearch(lo, hi, f, eps?) Parameters
| Name | Type | Required | Description |
|---|---|---|---|
lo | number | Yes | Lower bound of the search domain. |
hi | number | Yes | Upper bound of the search domain. |
f | (x: number) => number | Yes | A unimodal function — one that first decreases then increases (for minimum) or first increases then decreases (for maximum). |
eps | number | No | Precision threshold. Defaults to 1e-9. Iteration stops when hi - lo < eps. |
Returns
number — The x-value where f achieves its minimum (or maximum).
Examples
// Find x that minimises f(x) = (x - 3)^2 + 2
function ternarySearch(lo, hi, f, eps = 1e-9) {
while (hi - lo > eps) {
const m1 = lo + (hi - lo) / 3;
const m2 = hi - (hi - lo) / 3;
if (f(m1) < f(m2)) hi = m2;
else lo = m1;
}
return (lo + hi) / 2;
}
const f = x => (x - 3) ** 2 + 2;
const minX = ternarySearch(0, 10, f);
console.log(minX.toFixed(6));
console.log(f(minX).toFixed(6));
Output
3.000000
2.000000
// Integer ternary search on a discrete unimodal array
function ternarySearchInt(arr) {
let lo = 0, hi = arr.length - 1;
while (hi - lo > 2) {
const m1 = Math.floor(lo + (hi - lo) / 3);
const m2 = Math.ceil(hi - (hi - lo) / 3);
if (arr[m1] < arr[m2]) hi = m2;
else lo = m1;
}
let best = lo;
for (let i = lo + 1; i <= hi; i++) {
if (arr[i] < arr[best]) best = i;
}
return best;
}
// Unimodal: decreasing then increasing
const arr = [10, 7, 3, 1, 4, 8, 15];
console.log(ternarySearchInt(arr)); // minimum at index 3
Output
3
Notes
| Case | Time | Space |
|---------|----------|-------|
| Best | O(1) | O(1) |
| Average | O(log n) | O(1) |
| Worst | O(log n) | O(1) |
Ternary search eliminates 1/3 of the range each step, giving log_(3/2)(n)
iterations — slightly more than binary search's log_2(n) — so binary
search is preferred when the predicate is monotone. Ternary search is
the right tool when the objective is **unimodal** (single peak/valley).
For discrete integer arrays, handle the last 2–3 elements with a linear
scan to avoid off-by-one. Not applicable to multimodal functions.