Counting Steps, Not Seconds
A stopwatch measures one machine on one input. Counting the operations a piece of work performs measures the work itself, and that number is the one that predicts next year.
Two procedures are measured on the same thousand rows. One takes 40
milliseconds and the other 90. Which should be used on a million rows?
Nothing in those two numbers answers that. The slower one may be four times
slower at every size, or it may be the only one of the two still running
tomorrow.
| ms on a laptop, 1000 row | ms on a server, 1000 row | ms on a laptop, 100000 r | operations, as a count | |
|---|---|---|---|---|
| procedure A, scanning on | 90 | 30 | 9000 | 1 |
| procedure B, comparing e | 40 | 13 | 400000 | 2 |
Naming the size
Before anything can be counted, it has to be counted against something. Call
it , and say what it is: the number of rows, the length of the list, the
count of nodes.
The choice is usually obvious and occasionally not. A procedure on a graph has
two sizes, the nodes and the edges, and its cost generally depends on both. An
image has a width and a height, and a procedure that visits every pixel is
linear in their product and quadratic in the side length, which are the same
statement about the same code.
The trap is a number given as input. A loop that counts up to a number
runs times, which sounds linear and is not: the input is the number
itself, written in about digits, so the loop runs exponentially
many times in the size of what was actually supplied. That distinction is
behind a surprising amount of confusion, and naming the size out loud avoids
all of it.
| step | stage | what happens | comparisons so far |
|---|---|---|---|
| 1 | setup | take the first item as the current best | 0 |
| 2 | second item | compare it with the current best | 1 |
| 3 | third item | compare it with the current best | 2 |
| 4 | fourth item | compare it with the current best | 3 |
| 5 | the nth item | compare it with the current best | n - 1 |
| 6 | finished | return the current best | n - 1 in total |
- the count of operations performed on an input of size n
- the input size, named explicitly before any counting began
- the operations done per item in the scanning procedure
- the operations done per pair in the comparing procedure
- the fixed setup cost, the same for both and soon irrelevant
def largest(xs):
best, steps = xs[0], 0
for x in xs[1:]:
steps += 1 # one comparison per item after the first
if x > best:
best = x
return best, steps
def closest_pair_gap(xs):
gap, steps = float('inf'), 0
for i in range(len(xs)):
for j in range(i + 1, len(xs)):
steps += 1 # one comparison per pair
gap = min(gap, abs(xs[i] - xs[j]))
return gap, steps
xs = list(range(1_000))
print(largest(xs)[1], closest_pair_gap(xs)[1]) # 999 and 499500What the count is for
It is not a prediction of seconds, and it should not be used as one. It is a
prediction of how the seconds change when the input changes, which is a
different and more durable thing.
That is enough to answer the question this lesson opened with. Procedure B is
the right choice at a thousand rows and the wrong one at a million, and the
count says so without anybody running it at a million.
What comes next
There is a small number of growth shapes that nearly all real work falls into,
and knowing them in order is most of the value of this subject. That is the
next lesson.
Recap
- A timing measures the machine, the input and the code together, so it answers a question about today. Counting operations as a function of the input size answers the question about tomorrow.
- The count is written as a function of one number, the size of the input, which has to be chosen and named before anything can be counted. Different choices of size give different and equally correct answers.
- Only the operations that grow with the input matter. The rest form a fixed cost that becomes invisible as the input grows, which is what makes the count short enough to be useful.
This is the reading half
Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.
The contents