Compute lower bound using arithmetic or conditional moves instead of branches.
Branchless lower bound computes the first position where a value is greater than or equal to a target, without using unpredictable branches. It follows the same logical structure as binary search but replaces control flow with arithmetic updates or conditional moves.
The result is the same as standard lower bound. The benefit is improved performance on modern CPUs when branch misprediction is expensive.
Problem
Given a sorted array of length and a target , find the smallest index such that
If all elements are smaller than , return .
Idea
Maintain a base index that always points to the largest known position where the value is less than .
At each step, test whether a candidate position also satisfies the condition. Update the base using a conditional assignment that can compile to a branchless instruction.
The search proceeds by testing powers of two, from large to small.
Algorithm
branchless_lower_bound(A, x):
n = length(A)
base = -1
step = 1
while step * 2 <= n:
step = step * 2
while step > 0:
next = base + step
cond = (next < n) and (A[next] < x)
if cond:
base = next
step = step // 2
return base + 1In optimized implementations, the if cond update becomes:
base = cond ? next : basewhich compiles to a conditional move.
Example
Let
and
Trace:
| step | candidate | value | value < x | base |
|---|---|---|---|---|
| 4 | 3 | 20 | yes | 3 |
| 2 | 5 | 30 | no | 3 |
| 1 | 4 | 25 | no | 3 |
Return:
So index is the first position where .
Correctness
The invariant maintains that base is the largest index such that .
Each step tests whether a larger candidate also satisfies the condition. If so, the invariant extends forward. Otherwise, the invariant remains unchanged.
When all step sizes have been tested, no larger valid index exists. Therefore the next position, base + 1, is the smallest index such that .
Complexity
| case | time |
|---|---|
| all cases |
Space:
The number of comparisons matches binary search. The difference lies in execution behavior, not asymptotic complexity.
When to Use
Use branchless lower bound when:
- arrays are large
- queries are frequent
- branch misprediction affects performance
- predictable execution matters more than code simplicity
For small inputs, a standard lower bound is often simpler and sufficient.
Implementation
def branchless_lower_bound(a, x):
n = len(a)
base = -1
step = 1
while step * 2 <= n:
step *= 2
while step > 0:
nxt = base + step
if nxt < n and a[nxt] < x:
base = nxt
step //= 2
return base + 1func BranchlessLowerBound(a []int, x int) int {
n := len(a)
base := -1
step := 1
for step*2 <= n {
step *= 2
}
for step > 0 {
next := base + step
if next < n && a[next] < x {
base = next
}
step /= 2
}
return base + 1
}