Exponential search Created 2026-10-20 Updated 2026-11-05
Exponential search locates a target's possible range in a sorted sequence by probing indices until the target is bounded above or the sequence ends, then uses binary search inside the final bracket. If the target lies near index , this takes probes under random-access and constant-comparison assumptions. For an unbounded monotone predicate, the same method brackets the first true index. It is useful when the relevant prefix is much shorter than the whole sequence or its length is not initially known. Finite sequences still require bounds checks at each probe.
First find a sign bracket by exponential search, then bisect that bracket without evaluating its endpoints again:
def floorRoot(): Int = {
require(eval(0.0) < 0.0)
var lo = 0
var hi = 1
while (eval(hi.toDouble) <= 0.0) {
lo = hi
require(hi <= Int.MaxValue / 2, "doubling bound exceeds Int range")
hi *= 2
}
while (hi - lo > 1) {
val mid = lo + (hi - lo) / 2
if (eval(mid.toDouble) <= 0.0) lo = mid
else hi = mid
}
lo
}For the first while loop the loop invariant is , with
hi a positive power of two, and either or . Every previously tested power of two has nonpositive value. Let be the least nonnegative integer for which . It exists by the positive leading coefficient. If the current upper endpoint is , a mathematical loop variant is while the guard holds; the next doubling decreases it by one. The first while loop's postcondition is . The second while loop has exactly the invariant, variant and adjacent-integer postcondition established in part c.There are evaluations at powers of two. If , the final bracket has width and takes exactly midpoint evaluations. Including the initial sign check, the total is evaluations for , and two for . Thus evaluation cost is for the first positive dyadic bound ; it is not a claim about the first positive root of a polynomial when the polynomial is nonmonotone.
The mathematical argument uses unbounded integer endpoints and reliable signs. The guarded
Int implementation requires the successful dyadic bound to fit in Int; otherwise it explicitly fails rather than wrapping to a negative bound. The coefficient assumptions alone cannot guarantee that a requested integer result fits a fixed-width type. Floating-point overflow or unreliable signs likewise need a wider or certified evaluator for a fully general implementation.