Binary search
The same program in MIPS, RISC-V, Z80, x86.
Binary search finds a value by checking the middle of a sorted array, then keeping only the half
where the value could still be. This program looks for 91 among twelve words sorted from smallest
to largest. It leaves the matching index in d3, or -1 if the value is absent. The order matters:
without it, a comparison cannot tell us which half is safe to discard.
count equ 12
lea numbers, a0 ; the array
move.l #91, d0 ; the value we are looking for
clr.l d1 ; low = 0
move.l #count-1, d2 ; high = count - 1
moveq #-1, d3 ; found = -1, meaning not there
search:
cmp.l d2, d1 ; low - high
bgt search_done ; stop if low > high
move.l d1, d4
add.l d2, d4
lsr.l #1, d4 ; mid = (low + high) / 2, rounded down
move.l d4, d5
add.l d5, d5 ; mid * 2, the size of a word
move.w (a0, d5), d6 ; numbers[mid]
cmp.w d0, d6 ; numbers[mid] - target
beq found
bgt too_big ; numbers[mid] > target
move.l d4, d1
addq.l #1, d1 ; low = mid + 1
bra search
too_big:
move.l d4, d2
subq.l #1, d2 ; high = mid - 1
bra search
found:
move.l d4, d3 ; found = mid
search_done:
org $2000
numbers: dc.w 2, 5, 8, 12, 16, 23, 38, 56, 72, 91, 100, 127
d1 and d2 mark the first and last indices still worth searching. cmp.l d2, d1 calculates
low - high for the condition flags. The signed bgt ends the search when low > high, because
no indices remain. This signed check also works if high reaches -1 after ruling out the first
element.
For a range that remains, d4 becomes its middle index. lsr.l #1, d4 divides the sum of
low and high by two, rounding down. The indices here are never negative. Each array element
is a word of two bytes, so add.l d5, d5 converts the middle index into a byte offset. For
example, when mid is 9, d5 becomes 18 and (a0, d5) reads numbers + 18: the tenth word, 91. The first word has index 0 and offset 0.
The second comparison, cmp.w d0, d6, calculates numbers[mid] - target using words. beq
finds an equal value. If the signed bgt branches to too_big, the middle value is larger than
the target, so high moves to mid - 1. Otherwise the middle value is smaller, and low moves
to mid + 1. The values in this array and the target fit in signed words, and the array is in
signed ascending order.
Select Build, then Run. The registers panel shows d3 = 00000009: 91 is at index 9.
Select Build again to reset the program, then use Step to watch each middle value. The
first probe reads 23 at index 5, so low becomes 6. The next reads 72 at index 8, so low
becomes 9. The third reads 100 at index 10, so high becomes 9. The fourth reads 91 at index
9 and sets d3 to 9. This search reads four array elements; scanning from the start would read
ten to reach index 9. Halving gives roughly logarithmic growth in array reads: around ten
reads can search a thousand sorted elements, and around twenty can search a million. The loop
also does arithmetic and comparisons between reads.
Try another target
Change #91 to #2, the first value in the array. Predict the index in d3, then select
Build and Run to check. Next change the target to #90, which is absent, and predict
d3 again. Keep the array sorted while trying other values: the search relies on that order.
Show answer
For 2, d3 is 00000000, a valid index. For 90, d3 stays FFFFFFFF, which represents -1.
The search for 90 eventually has low = 9 and high = 8, so the first bgt ends the loop.
The program starts d3 at -1 and changes it only after a match. It cannot use 0 to mean
"absent" because the first array element has index 0.