7b break, Square Roots, and What an Algorithm Is

This lesson introduces the break statement and the while True idiom, builds Newton's method as a loop that improves an estimate until it stops changing, explains why floats must not be tested for equality, and defines what an algorithm is.

Subject: Python · 65 slides · code lesson

Open the interactive version of this deck

What this lesson covers

The lesson, slide by slide

1. Lesson 7b break, Square Roots, and What an Algorithm Is

Title

Python · Chapter 7 — Iteration

§7.4-7.7, pp. 66-68

2. By the end of this lesson you can

Objectives

Five things, each one you can check yourself at an interpreter prompt.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 66-68 — the pages these objectives are drawn from

3. Before we start: when do you know to stop?

Warm-up

Every loop so far knew its stopping condition before it began. Find a case that does not.

Discussion prompt

Think of a task where you cannot know in advance how many repetitions it will take — only that you will recognise the end when you reach it. Describe one, and say what tells you to stop.

Hint: Searching for something, or improving something until it is good enough.

Answer:

Searching a list until you find what you want, kneading dough until it is smooth, or refining an estimate until it stops changing.

In every case the stopping condition is about what you have found, not about how many times you have gone round.

That is exactly what a while loop is for, and this lesson's main example — computing a square root by successive improvement — is the clearest case in the book: nobody knows in advance how many steps it takes.

4. The one idea behind this lesson: stop when you get there, not after a fixed count

Concept

Loops are often used in programs that compute numerical results by starting with an approximate answer and iteratively improving it. In such a loop the number of passes is not known in advance — and the loop's whole job is to recognise when it has arrived.

algorithm — A mechanical process for solving a category of problems, in which each step follows from the last according to a simple set of rules.

Newton's method is an example of an algorithm: a mechanical process for solving a category of problems, in this case computing square roots. This lesson builds it, and then asks what makes it an algorithm at all.

Figure (svg): A diagram showing an estimate being improved repeatedly until it stops changing

The number of passes depends on the guess and the target, and is not known in advance.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 66-67

5. break: leaving a loop from the middle

Section

Section 1

6. When you do not know it is time to stop until you are halfway through

Concept

Sometimes you do not know it is time to end a loop until you get half way through the body. In that case you can use the break statement to jump out of the loop.

while True:
    line = input('> ')
    if line == 'done':
        break
    print(line)
print('Done!')
LineIts roleNote
while True:the condition is always truethe loop runs until break
line = input('> ')read one linethe work happens first
if line == 'done': breakthe real stopping conditionin the middle of the body
print(line)only reached if we did not breakechoes the input

The loop condition is True, which is always true, so the loop runs until it hits the break statement. Each time through, it prompts the user with an angle bracket; if the user types done, the break statement exits the loop.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 66-66

7. Picture it: the exit is in the middle

Picture it

The loop cannot decide whether to stop until it has read a line, and reading is inside the body.

Figure (svg): A flow chart showing a loop that reads input, tests it, and either breaks out or prints and loops back

A while condition at the top could not do this: it would have to test a line before any line had been read.

8. Worked example: why the condition cannot go at the top

Worked example

Try to write this loop without break and see what goes wrong.

# attempted, without break:
line = ''
while line != 'done':
    line = input('> ')
    print(line)
AspectWhat happensVerdict
the initializationline must be set before the first testan artificial value
the last passprints 'done' before testing itunwanted output
the break versiontests before printingno unwanted output

Notice the initialization problem.

Why: The condition tests line before any line exists, so line has to be given a fake starting value that means not done yet.

Notice the ordering problem.

Why: The body reads a line and then prints it, so on the final pass the word done is printed before the condition gets a chance to stop the loop.

Compare with the break version.

Why: Reading, testing and printing happen in the order the problem requires, with no artificial initialization and no unwanted output.

Figure (svg): Two columns comparing a loop with a top condition against the same loop written with while True and break

Same loop, and the right-hand column can put the test where it belongs.

The top-tested version needs a fake initial value and prints the sentinel before stopping. The break version puts the test exactly where the decision is actually made.

Verify: Run both and compare the last two lines of output.

Why: The break version's session ends with Done!, and the other prints done first. That one extra line is the whole difference, and it is caused entirely by where the test can be placed.

9. Predict: what does this print?

Prediction

The break is in the middle of the body.

n = 0
while True:
    n = n + 1
    if n > 3:
        break
    print(n)
PassThe testOutput
n becomes 11 > 3 is falseprint 1
n becomes 2falseprint 2
n becomes 3falseprint 3
n becomes 44 > 3 is truebreak, before printing

Predict first

What does this print?

  • 1, 2, 3
  • 1, 2, 3, 4
  • 0, 1, 2, 3
  • Nothing

Correct: 1, 2, 3 — the fourth pass breaks before reaching the print statement.

Why: The break jumps out of the loop immediately, so anything after it in the body is skipped for that pass. That is exactly why the break idiom is useful: the decision to stop is made in the middle, and the work after it does not happen on the final pass. Compare this with the input example, where the same placement is what stops the word done from being echoed.

10. Worked example: affirmative stop conditions

Worked example

The book gives a second reason for this idiom, and it is about reading.

# negative: keep going until that happens
while line != 'done':

# affirmative: stop when this happens
while True:
    ...
    if line == 'done':
        break
FormHow it readsNote
the negated formkeep going while NOT donea double negative to read
the affirmative formstop when donereads directly
with several conditionsthe negation compoundsmuch worse

Read the negated condition aloud.

Why: While line is not done — you are stating the continuation condition, which is the opposite of the thing you actually care about.

Read the affirmative version.

Why: If the line is done, stop. You are stating the stopping condition directly.

Consider several stopping conditions.

Why: Written as a while condition they combine with and and negations; written as breaks they are simply separate if statements, each saying stop when this happens.

Figure (svg): The state of the program after each line of Worked example affirmative stop conditions, drawn as a ladder with one rung per traced line

The whole run at once: each drop is one line of the program.

The break form lets you express the stop condition affirmatively — stop when this happens — rather than negatively, which is the book's second reason for the idiom and the one that matters most as loops get more complicated.

Verify: Write a loop with two stopping conditions each way.

Why: As a while condition it becomes while line != 'done' and count < 100, which is two negations joined. As breaks it is two independent if statements, each reading as a sentence. The gap widens with every extra condition.

11. Trap: a while True with no break

Trap

The trap

A student adopts the while True idiom and then writes the stopping logic without a break statement in it.

Treat while True as the standard way to start a loop

Why: The idiom is common, so it starts to feel like boilerplate rather than a decision.

Now the condition really is always true and nothing ever leaves. This is a genuine infinite loop, and unlike a forgotten update it looks deliberate.

The fix

while True is a promise that a break exists somewhere in the body.

Write the break before you write anything else in the body

Why: Then the exit exists from the start and cannot be forgotten.

Check that every path through the body can reach it

Why: A break inside a condition that is never true is the same as no break at all.

This is lesson 7a's requirement in a different form: the body must be able to end the loop. With a top condition that means updating a variable; with while True it means reaching a break.

12. Discriminate: top condition or break?

Discrimination

Ask whether the stopping decision can be made before the work.

Sort into buckets

For each loop, is a top condition enough, or is a break needed?

a top condition is enough
count from 1 to 10; halve a number until it is below 1; repeat 5 times
a break is cleaner
read lines until the user types done; search a list until you find a match; keep asking until the answer is valid
top
In each case the stopping condition can be tested before the body runs, because it depends on a value that already exists — a counter, or the number being halved.
brk
In each case the thing being tested is produced by the body itself: the line the user typed, the item just examined, the answer just given. Testing before the body would mean testing something that does not exist yet.

13. Complete it: leave the loop when the input is empty

Faded example

The test goes after the read and before the work.

Fill in the blanks

while True:
line = input('> ')
if line == '':
break
print('you typed:', line)

Why: break exits the loop immediately, so the print statement below it is skipped on the final pass — which is the point, since an empty line should not be echoed. Note the shape: read, test, work. That ordering is what the while True idiom exists to allow, and it is impossible with a condition at the top.

14. Think it through: is while True an infinite loop?

Socratic

The condition is literally always true. Decide whether the name applies.

Discussion prompt

An infinite loop is one whose condition never becomes false. while True has a condition that can never become false. Is every while True loop therefore infinite?

Hint: What ends a loop, besides the condition?

Answer:

No, because a break ends a loop without the condition ever being tested again. The loop has an exit; it simply is not the condition.

So the definition needs widening: an infinite loop is one that has no way to end, not one whose condition stays true. A while True with a reachable break is finite.

What makes the idiom safe is the promise it implies. Writing while True is a commitment to putting a break in the body, and a while True without one is an infinite loop in the fullest sense.

15. Newton's method: improving an estimate

Section

Section 2

16. A loop whose length nobody knows in advance

Concept

One way of computing square roots is Newton's method. Suppose you want to know the square root of a. If you start with almost any estimate x, you can compute a better estimate with a single formula — and repeating it converges on the answer.

>>> a = 4
>>> x = 3
>>> y = (x + a/x) / 2
>>> y
2.1666666666666665
StepWhat happensValue
x = 3a deliberately poor first guessthe true answer is 2
(x + a/x) / 2the improvement formula2.1666...
repeatusing the new estimate as xcloser each time

The result is closer to the correct answer, and if you repeat the process with the new estimate it gets closer still. In general we do not know ahead of time how many steps it takes to get to the right answer, but we know when we get there, because the estimate stops changing.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 66-67

17. Picture it: the estimates closing in

Picture it

Five improvements from a poor starting guess.

Figure (svg): A ladder showing successive Newton estimates for the square root of four, from three down through two point one six seven to two

Each step roughly doubles the number of correct digits. Five steps from a bad guess.

Notice how fast it converges: after three steps the answer is right to four decimal places, and after five it has stopped changing altogether.

18. Worked example: the loop that stops when the estimate settles

Worked example

The book's version. Notice where the test is.

while True:
    print(x)
    y = (x + a/x) / 2
    if y == x:
        break
    x = y
LineIts roleNote
print(x)show the current estimatethe work
y = (x + a/x) / 2compute a better onethe improvement
if y == x: breakhas it stopped changing?the stopping test
x = yadopt the new estimatethe update

Notice why the test cannot be at the top.

Why: The stopping condition compares the new estimate with the old one, and the new estimate is computed inside the body. There is nothing to compare before the first pass.

Notice the order of the last two lines.

Why: The test comes before the update, so that x still holds the previous estimate when the comparison is made.

Notice what the loop is watching.

Why: Not the number of passes and not the accuracy directly, but whether the estimate has stopped changing — which is a signal the loop can actually detect.

Figure (svg): The state of the program after each line of Worked example the loop that stops when the estimate settles, drawn as a ladder with one rung per traced line

The whole run at once: each drop is one line of the program.

A while True loop with the test in the middle: improve, compare, and either break or adopt the new estimate. The number of passes depends on the starting guess and is not known in advance.

Verify: Try a different starting guess and count the passes.

Why: Starting from 100 rather than 3 takes several more passes for the same answer. That the count varies with the input is exactly why a while loop is the right construct — a for loop would need a number nobody can supply.

19. Predict: the next estimate

Prediction

Apply the formula once by hand.

a = 9
x = 4
y = (x + a/x) / 2
StepCalculationValue
a/x9 / 42.25
x + a/x4 + 2.256.25
divided by 26.25 / 23.125

Predict first

What is the new estimate y?

  • 3.125
  • 2.25
  • 6.5
  • 3.0

Correct: 3.125 — the average of 4 and 2.25.

Why: The true square root of 9 is 3, and the estimate has moved from 4 to 3.125 in one step. Notice the bracketing: 4 is above the answer and 9/4 is below it, so their average lands between them. One more pass gives 3.00125, and a third gives 3.0000002 — the doubling of correct digits at each step.

20. Worked example: why the formula improves the estimate

Worked example

It is not magic. Look at what the average is averaging.

# if x is too small, then a/x is too big
# if x is too big,   then a/x is too small
# so the true root lies between x and a/x
# and their average is closer than either

# a = 4, x = 3:  a/x = 1.333,  average = 2.167
QuantityRelative to the true rootValue
x = 3too big3 > 2
a/x = 1.333too small1.333 < 2
their averagebetween them, so closer2.167

Notice the relationship between x and a/x.

Why: If x is bigger than the square root of a, then a/x is smaller than it, and the other way round. They bracket the answer.

Take the average.

Why: A value between two numbers that bracket the target must be closer to the target than at least one of them — and in this case closer than both.

See why it converges quickly.

Why: Each step roughly halves the error and then some, which is why five steps take you from a guess of 3 to an exact 2.

Figure (svg): A number line style diagram showing x above the true root and a over x below it, with their average between them

a/x on the left, x on the right, the true root at 2.0, and the new estimate between them.

The two quantities x and a/x always bracket the true square root, so their average is closer than either. Repeating that squeeze converges very fast.

Verify: Check the bracketing claim on the second pass.

Why: With x = 2.1667, a/x is 1.8462 — one above 2 and one below, exactly as predicted. That the bracketing survives every pass is what guarantees the method converges rather than wandering.

21. Trap: guessing the number of passes

Trap

The trap

A student replaces the while loop with a for loop of ten passes, reasoning that ten improvements will surely be enough.

Turn an unknown count into a generous fixed one

Why: Ten looks safe, and a for loop is simpler to write.

For an easy case it wastes passes after the answer has settled; for a hard one — a huge value, or a terrible starting guess — ten may not be enough, and the loop returns a wrong answer with no indication.

The fix

Let the loop decide, by watching for the thing that actually signals completion.

Stop when the estimate stops changing

Why: That is a condition the loop can test, and it is true exactly when there is no more work to do.

Use while, not for, when the count is data-dependent

Why: In general we do not know ahead of time how many steps it takes, but we know when we get there.

This is the defining case for the while statement. A for loop needs a count in advance; a while loop needs only a way to recognise the end.

22. Watch the estimates converge

Invariant

Step through Newton's method for the square root of 4, starting from 3.

Step through it

Roughly what happens to the error at each pass, and why does that mean the loop is short?

  1. The starting guess, deliberately poor. The true answer is 2.
  2. One pass: the error has dropped from 1 to about 0.17.
  3. Two passes: the error is about 0.006. Roughly the square of the previous error.
  4. Three passes: correct to four decimal places. The error keeps squaring.
  5. Four passes: the estimate has stopped changing, so the loop breaks.

The error is roughly squared each time — 1, then 0.17, then 0.006, then 0.00001. That is why five passes suffice from a bad guess, and why doubling the starting error costs only one extra pass rather than doubling the work.

23. Push the boundary: what if the guess is zero?

Edge cases

The book says almost any estimate. Find the one that is not allowed.

Discussion prompt

The formula is (x + a/x) / 2. Which starting value of x would break it immediately, and what would you do about it?

Hint: Look at the division.

Answer:

Zero. The formula divides by x, so a starting estimate of zero raises a ZeroDivisionError on the first pass.

The fix is a guardian, from lesson 6c: reject a starting estimate of zero, or simply choose the starting estimate inside the function rather than accepting it — a is often a reasonable first guess, and it is never zero unless a is.

This is why the book says almost any estimate. The word is doing real work, and finding the exception is exactly the boundary-checking habit that turns a working function into a reliable one.

24. Where iterative improvement is used

Real world

This shape of loop is everywhere in computing.

Discussion prompt

Newton's method starts with a guess and improves it until it settles. Name another situation — in computing or outside it — with the same shape, and say what plays the role of the improvement formula.

Hint: Anything that converges on an answer rather than calculating it directly.

Answer:

Machine learning training is the large modern example: start with random parameters, improve them a little using the error, repeat until the error stops falling.

Outside computing, adjusting a recipe by tasting, or tuning an instrument by comparing and correcting, have the same shape: measure the error, apply a correction, repeat.

What they share is that no direct formula exists, or the direct formula is harder than the iteration. That is the situation iterative improvement is for, and recognising it is worth more than the specific square-root formula.

25. Why you must not test floats for equality

Section

Section 3

26. Approximately right is not exactly equal

Concept

For most values of a the equality test works fine, but in general it is dangerous to test float equality. Floating-point values are only approximately right: most rational numbers, like one third, and irrational numbers, like the square root of two, cannot be represented exactly with a float.

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
ExpressionWhat happensResult
0.1 + 0.2neither can be represented exactlya tiny error accumulates
the result0.30000000000000004not equal to 0.3
the comparisonFalseand no error is raised

Rather than checking whether two values are exactly equal, it is safer to use the built-in function abs to compute the magnitude of the difference between them, and to compare that with a small number.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 67-67

27. Picture it: two numbers that should be equal and are not

Picture it

The difference is about one part in a hundred thousand billion — and equality does not care how small it is.

Figure (svg): Two columns contrasting an exact equality test on floats with a tolerance test using abs

Where epsilon has a value like 0.0000001 that determines how close is close enough.

The tolerance is not a fudge. It is a statement of what accuracy the answer needs, which is information the exact test never had a way to express.

28. Worked example: the tolerance version of the loop

Worked example

One line changes, and the loop becomes safe for every input.

epsilon = 0.0000001
while True:
    y = (x + a/x) / 2
    if abs(y - x) < epsilon:
        break
    x = y
PartWhat it meansNote
abs(y - x)the magnitude of the changealways non-negative
< epsilonis the change small enough?close enough to stop
epsilonchosen by youhow close is close enough

Compute the difference and take its magnitude.

Why: abs computes the absolute value, so the test works whether the estimate overshot or undershot.

Compare with a small number.

Why: Where epsilon has a value like 0.0000001 that determines how close is close enough.

Notice what this makes explicit.

Why: The exact test silently demanded infinite precision. The tolerance version states the required accuracy, which is a decision somebody should be making anyway.

Figure (svg): A flow chart showing the improvement loop with a tolerance test deciding whether to break

A loop that terminates for every input, with an explicit statement of how accurate the answer needs to be. The change is one line and it converts a risky loop into a reliable one.

Verify: Ask what happens if epsilon is set far too small, say 1e-300.

Why: The loop may again fail to terminate, because no achievable difference is that small. The tolerance does not remove the requirement to choose a sensible value — it makes the choice visible, which is the improvement.

29. Predict: is 0.1 + 0.2 equal to 0.3?

Prediction

Both look like ordinary decimals.

Predict first

What does 0.1 + 0.2 == 0.3 give in Python?

  • True
  • False
  • An error
  • It depends on the machine

Correct: False — neither 0.1 nor 0.2 can be represented exactly, so their sum is very slightly off.

Why: The sum is 0.30000000000000004, which is not 0.3. Note that no error is raised: the comparison quietly answers no, which is what makes this dangerous rather than merely surprising. This is the same shape of silent failure as comparing a string with a number in lesson 5a — a condition that is always false and nothing to tell you why.

30. Worked example: why the exact test usually works

Worked example

It worked for the square root of 4. Understand why that is misleading.

# a = 4: the estimates reach exactly 2.0 and stop
# a = 2: the true root is irrational
#        the estimates may oscillate between two adjacent floats
#        and y == x may never be true
CaseWhyOutcome
a = 4the answer is exactly representabley == x eventually holds
a = 2the answer is irrationalmay oscillate forever
the lessonit works when the answer happens to be exactwhich you cannot rely on

Notice what made the first case work.

Why: Two is exactly representable as a float, so the sequence of estimates can land on it exactly and then stop changing.

Notice what is different about an irrational root.

Why: Most irrational numbers cannot be represented exactly with a float, so the estimates approach a value the machine cannot hold and may bounce between the two nearest representable numbers forever.

Draw the general conclusion.

Why: For most values of a this works fine — which is precisely what makes it dangerous. It fails on inputs you did not test.

Figure (svg): The state of the program after each line of Worked example why the exact test usually works, drawn as a ladder with one rung per traced line

The whole run at once: each drop is one line of the program.

The exact test works when the answer happens to be exactly representable, which is a property of the input rather than of the program. A test that depends on the data in that way is not a test you can rely on.

Verify: Connect this to lesson 7a's termination discussion.

Why: This is a loop whose termination depends on properties of the input that are hard to reason about — exactly the situation lesson 7a warned about. The tolerance test restores provable termination, because the difference shrinks and must eventually fall below any fixed positive epsilon.

31. Trap: comparing computed floats for equality

Trap

The trap

A program checks whether a computed total equals an expected value with a plain equality test on floats.

Treat floats as though they were exact

Why: They print as though they were, and for whole-number values they behave as though they were.

0.1 + 0.2 is not 0.3, so the check fails, and the failure is invisible — the numbers look identical when printed.

The fix

Compare floats with a tolerance, and say what tolerance you mean.

Use abs of the difference against a small number

Why: abs(a - b) < epsilon asks whether they are close enough, which is the question you actually have.

Choose epsilon from the problem, not from habit

Why: How accurate does the answer need to be? A currency calculation and a physics simulation want very different values.

Integers are exempt: they are exact, and testing them for equality is fine. It is specifically floats — computed ones especially — where equality is the wrong question.

32. Discriminate: is equality safe here?

Discrimination

Exact values may be compared exactly; computed floats may not.

Sort into buckets

For each comparison, is a plain equality test safe?

equality is safe
count == 10, where count is an integer counter; name == 'done', comparing two strings; n % 2 == 0, testing evenness
use a tolerance instead
total == 0.3, where total is 0.1 + 0.2; y == x, comparing two Newton estimates; average == 1/3, where average was computed
safe
Integers and strings are exact. A counter really does become exactly 10, a remainder really is exactly 0, and two strings really are character-for-character equal or not.
risky
Each compares floats that were computed rather than written down. One third cannot be represented exactly, the sum of two inexact decimals is inexact, and two successive estimates may differ by an amount too small to represent.

33. Complete it: replace the equality test

Faded example

One built-in function and one small number.

Fill in the blanks

epsilon = 0.0000001
if abs(y - x) < epsilon:
break

Why: abs computes the absolute value, or magnitude, of the difference — so the test works whether the new estimate is above or below the old one. Without it, a negative difference would always be less than epsilon and the loop would break on the first pass in which the estimate decreased, which is worse than the original bug.

34. Explain it yourself: what does epsilon actually decide?

Explain it to yourself

It is not a magic constant. Say what it means.

Discussion prompt

Explain what the value of epsilon controls, and what would go wrong if it were set much larger — say 1.0 — or much smaller than the machine can achieve.

Hint: It is a statement about accuracy.

Answer:

It determines how close is close enough — the accuracy the answer needs to have before the loop is willing to stop.

Too large, and the loop stops early with a poor answer: with epsilon of 1.0, the square root of 4 might come back as 2.17.

Too small, and the loop may never terminate, because no achievable difference is that tiny. So epsilon is a real decision with failure modes on both sides, and choosing it means knowing what the answer is for — which is exactly the kind of thing the exact-equality test hid.

35. What an algorithm is

Section

Section 4

36. Defined by contrast with something that is not one

Concept

Newton's method is an example of an algorithm: a mechanical process for solving a category of problems. To understand what an algorithm is, it helps to start with something that is not one.

# not an algorithm: the multiplication table
#   100 memorized specific solutions

# an algorithm: multiplying by 9
#   write n-1 as the first digit
#   write 10-n as the second digit
#   e.g. 7 * 9 -> first digit 6, second digit 3 -> 63
KnowledgeWhat it isVerdict
the tablespecific answers, memorisedno general method
the tricka rule that works for any single digita general solution
the differencea category of problems, not a list of answersthat is an algorithm

When you learned to multiply single-digit numbers you probably memorised the multiplication table — in effect, one hundred specific solutions. That kind of knowledge is not algorithmic. But the trick for multiplying by 9 is a general solution for any single-digit number, and that is an algorithm.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 67-68

37. Picture it: a hundred answers versus one rule

Picture it

Both let you multiply by 9. Only one of them is a method.

Figure (svg): Two columns contrasting a memorised multiplication table with the general rule for multiplying by nine

The right-hand column is shorter and covers more.

One of the characteristics of algorithms is that they do not require any intelligence to carry out. They are mechanical processes where each step follows from the last according to a simple set of rules.

38. Worked example: checking the multiply-by-9 trick

Worked example

Apply the rule and verify it against something you know.

# n = 7
# first digit  = n - 1  = 6
# second digit = 10 - n = 3
# answer = 63

# n = 4
# first digit  = 3, second digit = 6, answer = 36
InputThe two digitsCheck
n = 76 and 363, and 7 * 9 is 63
n = 43 and 636, and 4 * 9 is 36
n = 98 and 181, and 9 * 9 is 81

Apply the rule mechanically.

Why: Subtract one for the first digit, subtract from ten for the second. No judgement is required, which is one of the defining characteristics.

Check it against known answers.

Why: Three cases, three correct results. That is evidence rather than proof, but it is the right first step.

Notice why it works.

Why: Nine times n is ten times n minus n, which is why the digits come out as n-1 and 10-n. The trick is arithmetic, not coincidence — though you can use it without knowing that, which is itself an algorithmic property.

Figure (svg): The state of the program after each line of Worked example checking the multiply-by-9 trick, drawn as a ladder with one rung per traced line

The whole run at once: each drop is one line of the program.

The rule produces 63, 36 and 81, all correct. It is a general solution for multiplying any single-digit number by 9, which is what makes it an algorithm rather than a memorised fact.

Verify: Test it on the one case where it needs care.

Why: For n = 1 the digits are 0 and 9, giving 09, which is 9 — correct if you allow a leading zero. Finding the edge case is what tells you whether a rule is really general, and this one survives with a small caveat about notation.

39. Sort: algorithm or not?

Sorting

Apply the three properties: mechanical, general, rule-following.

Sort into buckets

Sort each piece of knowledge or procedure.

an algorithm
long division; the trick for multiplying by 9; Newton's method for square roots
not an algorithm
the multiplication table, memorised; season the soup to taste; recognising a friend's face
alg
Each is a mechanical, general, rule-following process: a fixed set of steps that solves any instance of its category, requiring no judgement to carry out.
not
One is a set of memorised specific answers rather than a method. One requires a judgement that has not been specified. And one is something people do effortlessly that nobody has been able to express as a set of rules — the book's own example of the hardest kind.

40. Worked example: what makes something algorithmic

Worked example

Three properties, and each excludes something.

# an algorithm is:
#   1. mechanical -- no intelligence required to carry out
#   2. general   -- solves a category of problems, not one
#   3. finite    -- each step follows from the last by simple rules
PropertyWhat it excludesExample
mechanicalexcludes anything needing judgementseason to taste is not one
generalexcludes memorised answersthe multiplication table is not one
rule-followingexcludes vague instructionshandle it appropriately is not one

Take the mechanical requirement seriously.

Why: They are mechanical processes where each step follows from the last according to a simple set of rules — so anything requiring taste or interpretation is not one.

Take the generality requirement seriously.

Why: It solves a category of problems. A single answer, however correct, is not an algorithm.

Notice the connection to lesson 1a.

Why: This is the decomposition test again: break a task down until each piece is one of the five basic instructions. A piece that still needs judgement has not been decomposed far enough.

Figure (svg): A three-stage diagram showing the three properties that make a process an algorithm

All three are needed. Dropping any one lets something in that is not an algorithm.

Mechanical, general, and rule-following. Between them these exclude memorised answers, tasks needing judgement, and instructions that leave a decision to the reader.

Verify: Test the definition on long division.

Why: It is mechanical, it solves any division rather than one, and each step follows by simple rules — so it qualifies, exactly as the book says. Similarly the techniques for addition with carrying and subtraction with borrowing are all algorithms.

41. Trap: calling any procedure an algorithm

Trap

The trap

A student writes a list of steps for a task and calls it an algorithm, even though two of the steps require a judgement call.

Treat a list of steps as the definition

Why: It is most of the definition, and the list really is a procedure.

A step like choose a reasonable value cannot be carried out mechanically, so the list cannot be followed by something with no intelligence — which is the property the book singles out.

The fix

Check that every step could be carried out by something that understands nothing.

Look for words that hide a judgement

Why: Reasonable, appropriate, suitable, enough. Each conceals a decision that has not been specified.

Replace each with a rule

Why: Choose a reasonable epsilon becomes use 0.0000001, or a rule for computing one.

This is exactly the decomposition test from lesson 1a, and the connection is not accidental: a program IS an algorithm written in a formal language, so a step Python cannot carry out is a step that has not been decomposed far enough.

42. Predict: what does the trick give for 6?

Prediction

Apply the rule mechanically. No multiplication allowed.

Predict first

Using the multiply-by-9 trick, what is 6 times 9?

  • 54
  • 45
  • 63
  • 56

Correct: 54 — the first digit is 6 minus 1, which is 5, and the second is 10 minus 6, which is 4.

Why: The rule was applied without doing any multiplication, which is the point: it is a mechanical process that produces the right answer for a whole category of problems. Note that the two digits always add to 9, which is a nice check on the rule and a consequence of it being n-1 and 10-n.

43. Find the counterexample: is every program an algorithm?

Counterexample

Programs are mechanical and rule-following. Test the third property.

Discussion prompt

A program is certainly mechanical and rule-following. Give an example of a program that is nonetheless not an algorithm, and say which property it fails.

Hint: Consider a program that never finishes.

Answer:

A program with an infinite loop. It is mechanical and rule-following and it never produces an answer, so it does not solve anything.

A program that only handles one specific input also fails, on generality: print(63) computes 7 times 9 and is not a method for multiplying by nine.

So the properties are independent, and being written in a formal language is not enough on its own. That is worth noticing because it means I wrote a program and I have an algorithm are different claims.

44. Explain it: what is an algorithm?

Explain it

The book's definition is best given with its contrast.

Discussion prompt

Explain to somebody what an algorithm is, using the multiplication table and the multiply-by-9 trick as your example. Then give them one everyday thing that is definitely not an algorithm and say why.

Hint: The contrast is what makes the definition land.

Answer:

Say: memorising the times table is a hundred specific answers, and knowing the trick for nines is one rule that handles them all. The rule is an algorithm; the memorised answers are not.

The defining feature is that carrying it out requires no intelligence — each step follows from the last by a simple rule, which is why a machine can do it.

For the counterexample, the book's own is the best: understanding natural language. We all do it without conscious thought, and nobody has been able to explain how, at least not in the form of an algorithm. The things people find easiest are often the hardest to express algorithmically.

45. Debugging by bisection

Section

Section 5

46. Halving the search instead of walking it

Concept

As you start writing bigger programs you might find yourself spending more time debugging. One way to cut that time is debugging by bisection: rather than checking a hundred lines one at a time, check the middle and eliminate half.

# 100 lines, checked one at a time:   100 steps
# 100 lines, halved each time:
#   100 -> 50 -> 25 -> 13 -> 7 -> 4 -> 2
#   about 7 steps
MethodWhat each check buysTotal checks
one at a timeeliminate one line per check100 checks
bisectioneliminate half per checkabout 7 checks
the differencelinear versus halvinggrows with program size

Look at the middle of the program, or near it, for an intermediate value you can check. Add a print statement and run the program. If the mid-point check is incorrect, there must be a problem in the first half; if it is correct, the problem is in the second half. Every time you perform a check like this, you halve the number of lines you have to search.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 68-68

47. Picture it: seven checks instead of a hundred

Picture it

Each check eliminates half of what is left.

Figure (svg): A graph comparing a linear search of n lines against a bisection search taking about log n steps

For a hundred lines it is seven checks against a hundred. For a thousand it is ten against a thousand, which is why the technique matters more the bigger the program.

48. Worked example: bisecting a program

Worked example

One print statement, placed deliberately, halves the search.

# a program of about 40 lines produces a wrong final answer
# step 1: find an intermediate value about halfway through
# step 2: print it and compare with what you expect
# step 3a: if it is wrong, the bug is above
# step 3b: if it is right, the bug is below
StageLines remainingNote
before any check40 lines to search-
after one check20 lineshalf eliminated
after two10 linesand so on
after five1 or 2 linesfound

Find a checkable intermediate value near the middle.

Why: Not literally the middle line: it does not make sense to count lines and find the exact midpoint. You need a value you can predict independently.

Print it and compare.

Why: Add a print statement, or something else that has a verifiable effect, and run the program.

Eliminate half.

Why: If the mid-point check is incorrect there must be a problem in the first half; if it is correct, the problem is in the second half.

Figure (svg): The state of the program after each line of Worked example bisecting a program, drawn as a ladder with one rung per traced line

The whole run at once: each drop is one line of the program.

Five or six checks for a forty-line program, instead of forty. Each check must be placed where you can say in advance what the value should be.

Verify: Notice what makes a check useful.

Why: A value you cannot predict tells you nothing, whichever half it is in. That is why the technique needs the same thing incremental development needed in lesson 6a: a test case whose intermediate values you know.

49. Predict: how many checks?

Prediction

Each check halves what is left.

Predict first

Roughly how many bisection checks does it take to narrow 1000 lines down to one?

  • About 10
  • About 30
  • About 100
  • About 500

Correct: About 10 — each check halves the range, and ten halvings take 1000 down to one.

Why: A thousand halves to five hundred, then 250, 125, 63, 32, 16, 8, 4, 2, 1 — ten steps. Compare that with a thousand checks one at a time. The saving grows as programs get bigger, which is why the book introduces the technique in the chapter that warns you your programs are getting longer.

50. Worked example: choosing where to check

Worked example

The book adds a practical caveat. Take it seriously.

# the ideal: the exact midpoint
# the practical rule:
#   choose a spot where you think the chances are about the same
#   that the bug is before or after the check
CriterionProblem or benefitVerdict
exact midpointnot always meaningfullines are not equal
easy to checksome places have no checkable valueprefer where you can check
equal chancesthe real criterionhalve the PROBABILITY, not the lines

Drop the arithmetic version.

Why: In practice it is not always clear what the middle of the program is, and not always possible to check it. It does not make sense to count lines and find the exact midpoint.

Use the practical rule.

Why: Think about places in the program where there might be errors and places where it is easy to put a check.

State the real criterion.

Why: Then choose a spot where you think the chances are about the same that the bug is before or after the check.

Figure (svg): A flow chart showing a bisection check dividing the search space in half and repeating

Halve the probability rather than the line count. A check placed where you can actually verify a value, and where the bug is equally likely on either side, is worth more than one at the arithmetic midpoint.

Verify: Consider what happens with a badly placed check.

Why: A check at line 3 of 40 eliminates three lines if it fails and thirty-seven if it passes — so on average it eliminates far less than half. The value of a check is highest when the two outcomes are equally likely, which is why the criterion is about probability.

51. Trap: bisecting with a value you cannot predict

Trap

The trap

A developer adds a print statement halfway through, runs the program, and looks at the number it produces.

Assume any intermediate value is a check

Why: It is information, and it came from the middle of the program.

Without knowing what the value SHOULD be, seeing it eliminates nothing. The search space is exactly as large as it was, and one more line of output has been added.

The fix

A check needs an expectation, not just a value.

Predict what the value should be before running

Why: If you cannot, choose a different place to check.

Prefer places where a hand calculation is possible

Why: Which is why the test case matters: a 3-4-5 triangle makes every intermediate value predictable.

This is the same requirement as lesson 6a's incremental development, arriving from the other direction. There you predicted values as you built; here you predict them as you search — and both fail without a test case you understand.

52. Rank: the steps of a bisection

Ranking

Put one round of the technique in order.

Put in order

  1. find a place near the middle where you can check an intermediate value
  2. work out what that value should be
  3. run the program and compare the printed value with the expectation
  4. decide which half the bug must be in, and repeat on that half

Why: Choosing the place comes first, then forming the expectation, then running, then eliminating half. The order matters because forming the expectation AFTER seeing the value is not a check at all — whatever appeared will look plausible. Predicting first is what makes the observation informative.

53. Estimate: when is bisection worth the trouble?

Estimation

For a very short program it is not. Estimate the crossover.

Predict first

Below roughly how many lines is checking one at a time as fast as bisecting?

  • About 5
  • About 50
  • About 500
  • It is never as fast

Correct: About 5 — below that, the setup cost of choosing a check point and forming an expectation outweighs the saving.

Why: For four or five lines you can read them all faster than you can place a check, and bisecting would take two or three checks anyway. The technique earns its keep from about ten lines upward and becomes overwhelming above a hundred. Knowing where a technique stops paying is part of knowing the technique.

54. Where bisection appears elsewhere

Real world

The same idea has many names.

Discussion prompt

Halving a search space at every step appears in several places you may already know. Name one from outside programming, and say what plays the role of the check.

Hint: Guessing a number, or finding a word.

Answer:

Guessing a number between 1 and 100 with higher-or-lower answers: seven guesses suffice, and the answer is the check.

Finding a word in a dictionary: you open it in the middle and eliminate half, which is why a dictionary of a hundred thousand words takes about seventeen openings rather than a hundred thousand.

The programming version has an extra requirement the others do not: you must be able to say what the correct value is at the point you check. In a dictionary the ordering supplies that for free, which is why the technique is easier there.

55. Compare: two ways to end a loop

Comparison

Fill the blanks. Both are legitimate; they suit different problems.

Comparison matrix

QuestionCondition at the topwhile True with break
Where is the test?before the bodyanywhere in the body
How is the condition phrased?negatively: keep going untilaffirmatively: stop when this happens
Can the body run zero times?yesno — the body always runs at least once
Best whenthe stopping condition is known before the body runsthe body produces the thing being tested

The bottom row is the criterion. If the thing you test is created inside the body, the test has to be inside the body too.

56. The procedure: writing an iterative improvement loop

Pattern

Six steps, and two of them are about knowing when to stop.

  1. Choose a starting estimate, and check that it cannot break the improvement formula.
  2. Write the formula that turns an estimate into a better one.
  3. Decide what good enough means, and give it a name — epsilon.
  4. Write a while True loop that improves the estimate, then tests whether the change is smaller than epsilon.
  5. Compare with abs of the difference, never with exact equality, because the values are floats.
  6. Test on a case whose answer you know, and on one whose answer is irrational, since those fail differently.

Step 5 is the one that gets skipped, and it is the one that turns an occasionally-infinite loop into a reliably terminating one. Step 6's second case is what reveals whether you skipped it.

Python documentation — More Control Flow Tools More Control Flow Tools

57. Check yourself 1 of 3: break

Check

The break is before the print.

n = 0
while True:
    n = n + 1
    if n == 3:
        break
    print(n)
PassThe testOutput
n = 1not 3print 1
n = 2not 3print 2
n = 3equals 3break, before printing

Check your understanding

What does this print?

  • A. 1, 2, 3
  • B. 1, 2 (correct)
  • C. 0, 1, 2
  • D. Nothing

Answer: B

Why: break leaves the loop immediately, so the print statement after it is skipped on the pass where the break happens. Two passes print, and the third breaks before reaching the print. This placement is the whole point of break: the decision to stop is made partway through the body, and the work after it does not happen on the final pass.

Why A tempts people
This would require the print to run on the third pass, but the break happens before it is reached.
Why C tempts people
n is incremented before the test, so its first printed value is 1 rather than 0.
Why D tempts people
Two passes complete normally and print. Nothing would print only if the break happened on the first pass.

58. Check yourself 2 of 3: float equality

Check

Both operands are computed floats.

>>> 0.1 + 0.2 == 0.3
False
StepWhat happensResult
0.1 and 0.2neither is exactly representablesmall errors
their sum0.30000000000000004not 0.3
the comparisonFalse, with no errorsilent

Check your understanding

What should you write instead, to test whether two computed floats are effectively equal?

  • A. if a == b:
  • B. if abs(a - b) < epsilon: (correct)
  • C. if int(a) == int(b):
  • D. if str(a) == str(b):

Answer: B

Why: Comparing the magnitude of the difference with a small tolerance asks the question you actually have — are these close enough — rather than demanding exact representability. The value of epsilon states how close is close enough, which is a decision the exact test had no way to express.

Why A tempts people
This is the test being replaced. It fails whenever either value carries a representation error, which for computed floats is most of the time.
Why C tempts people
Converting to int chops the fraction, so 2.9 and 2.1 would compare equal. It answers a completely different question.
Why D tempts people
Comparing the printed forms is comparing floats by another route, and it is worse: it depends on how many digits Python chooses to display.

59. Check yourself 3 of 3: algorithms

Check

Apply the three properties.

Check your understanding

Which of these is an algorithm?

  • A. the memorised multiplication table
  • B. the rule for multiplying any single digit by 9 (correct)
  • C. seasoning a dish to taste
  • D. recognising a friend's voice

Answer: B

Why: It is a general solution for a whole category of problems, carried out by mechanical rules that require no judgement — which is exactly the book's definition. The digits are n-1 and 10-n, and applying that needs no understanding of why it works.

Why A tempts people
A hundred memorised specific solutions is not a method. The book uses it precisely as the example of knowledge that is not algorithmic.
Why C tempts people
To taste requires a judgement that has not been specified, so it cannot be carried out mechanically.
Why D tempts people
This is the book's own example of the hardest case: something people do without conscious thought that nobody has managed to express as an algorithm.

60. Where this shows up outside this course

Real world

Stopping conditions and tolerances are decisions everybody makes, usually without noticing.

Discussion prompt

Find a real process that stops when something is close enough rather than exactly right. What is its epsilon, who chose it, and what would happen if it were much tighter or much looser?

Hint: Manufacturing tolerances, or how precisely you measure when cooking.

Answer:

Manufacturing is the clearest: a part is made to within a stated tolerance, and that number is chosen by somebody who knows what the part is for.

Too tight and production becomes impossible or unaffordable; too loose and the parts do not fit. Exactly the two failure modes of an epsilon that is too small or too large.

The transferable point is that close enough is always a decision, and writing it as an explicit number is better than leaving it implicit. An exact-equality test in code is the equivalent of a specification demanding perfection, which is not achievable and therefore not a specification at all.

61. Confidence wager: commit before you check

Commit first

Answer, then rate your confidence. This is the most practically important fact in the lesson.

Predict first

A loop improving a floating-point estimate uses if y == x: break. For which inputs might it fail to terminate?

  • None — the estimates always converge
  • Inputs whose answer cannot be represented exactly as a float
  • Only negative inputs
  • Only very large inputs

Correct: Inputs whose answer cannot be represented exactly as a float — the estimates may oscillate between the two nearest representable values and never be exactly equal.

Why: Floating-point values are only approximately right, and most rational numbers like one third and irrational numbers like the square root of two cannot be represented exactly. When the target is unrepresentable, successive estimates may bounce between neighbouring floats forever, so an exact-equality test never becomes true. The book's warning is unambiguous: for most values of a this works fine, but in general it is dangerous to test float equality. The fix is one line — compare the magnitude of the difference against a small tolerance.

62. Explain it to someone else

Explain it

The float-equality warning is the thing most worth passing on.

Discussion prompt

A classmate's loop hangs on some inputs and works on others, and it ends with if y == x: break. Explain what is happening and what to change, and give them a one-line demonstration they can type at the prompt.

Hint: The demonstration involves two very ordinary decimals.

Answer:

Say: floats are approximate, so two values that ought to be equal often differ in the last few digits, and an exact test can never become true.

Give them the demonstration: 0.1 + 0.2 == 0.3 gives False. That single line convinces people faster than any explanation, because both numbers look completely ordinary.

Then the fix: compare abs of the difference with a small number, and choose that number from how accurate the answer needs to be. The tolerance is not a workaround — it is the accuracy requirement written down, which the exact test never had a way to state.

63. Exit ticket

Exit ticket

One honest answer. It decides what the next lesson opens with.

Predict first

Which of these is still least solid for you?

  • break, and why while True is not an infinite loop
  • Newton's method, and loops whose length is not known in advance
  • Why floats must not be compared for equality
  • What makes a process an algorithm

Correct: Whichever you picked is the right answer — this one is for you, not for a mark.

Why: break is a small piece of syntax with a good justification, and it settles quickly. Newton's method is one instance of a shape you will meet repeatedly, so the shape matters more than the formula. The float-equality warning is the highest-value item here by a distance — it is a bug people write for years, it is silent, and one line at the prompt is enough to make it stick. And the definition of an algorithm is worth revisiting whenever you write a step that quietly requires a judgement.

64. Synthesis: draw the map of this lesson

Connect it up

One page, from memory.

Draw it

Draw the Newton's-method loop as a flow chart, marking where the break is and why it cannot be a condition at the top. Beside it, write the exact-equality test and the tolerance test, and under each say for which inputs it terminates. Then, at the bottom, write the three properties of an algorithm and give one example that fails each property in turn.

65. What you can do now

Recap

Three pages, and chapter 7 is finished: a loop that stops when it has arrived rather than after a fixed count.

If you remember one thingIt is this
From breakwhile True promises a break. Without one it really is infinite.
From Newton's methodA while loop is for when you cannot know the number of passes in advance.
From floats0.1 + 0.2 is not 0.3. Use abs of the difference against an epsilon.
From algorithmsIt must be carryable-out by something that understands nothing.
From bisectionA check is only worth making if you know what the value should be.

Chapter 8 goes back to a data type you have used since the first lesson and takes it apart: a string is a sequence, with a position for every character, and that single idea brings indexing, slicing, traversal, and the first encounter with something that cannot be changed.

Think Python, 2nd edition — Allen B. Downey §7.4-7.7, pp. 66-68 — everything on these slides traces back here

Sources

  1. Think Python, 2nd edition — Allen B. Downey — Allen B. Downey, Think Python: How to Think Like a Computer Scientist, 2nd edition (Green Tea Press, 2015), §7.4-7.7, pp. 66-68
  2. Python documentation — More Control Flow Tools
  3. Python documentation — Built-in Functions

Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108