Skip to content

← Computing Further 6–8

How Does a Barcode Catch a Typing Mistake?

Topic 18 · Grades 6–8 · Check digits

Blocks, from Grade 7 (Variables and Choices); the Python parts from Grade 8 (loops and functions).

What this builds on from class
In this unit 9 sections
  1. Try it
  2. How it works
  3. Program it
  4. What your program shows
  5. Four ways to check a number
  6. Going further still
  7. Challenges
  8. Questions
  9. Where to go next

At the shop, the shopkeeper holds a packet of biscuits under the scanner. Beep: the price comes up. But sometimes the barcode is crumpled or wet, and the scanner can’t read it. Then the shopkeeper types the number printed under the bars, 13 digits, by hand.

People make mistakes when they type. A 3 becomes an 8. Two digits get swapped. If the till took the wrong number, you might pay for washing powder instead of biscuits. So the number has a guard built in: its last digit. It isn’t part of the product’s number at all. It is worked out from the other 12, and it lets the till spot almost every typing mistake.

4006381333931check digit
Figure 18.1 The barcode on a Stabilo Point 88 pen, drawn from its 13 digits. The bars and the digits say the same thing; the last digit is the check digit.

Here is that pen’s number. Tap a digit to change it, and see if the till would notice.

Try it

Make a mistake

Each tap changes the digit by one (9 goes back to 0). Press “Back to the real number” to start again.

Multiply the digits by 1, 3, 1, 3… and add. The total must end in 0.

Tap to:
Total
90, ends in 0
Check
passes ✓

This is the barcode on a Stabilo Point 88 pen. It passes the check. Tap a digit to make a mistake.

Wrong digits caught
—
Neighbor swaps caught
—
Swaps missed
—

Change any one digit, any way you like. How often do you think the check catches it?

Pick an answer to see why.

You need: for the blocks, nothing new (variables and repeat, from Grades 6 and 7). For the Python, loops and functions, from Grade 8.

Try it

Play with the number above.

  • a.Change one digit at a time. Is a mistake ever missed?
  • b.Now press Swap with next and tap a digit: it swaps places with the digit to its right. Swap a few pairs. Are they all caught?

Why 3 and 8? Keep that question in mind. The answer is in how the check digit is worked out.

How it works

Each digit is multiplied by a weight: 1, 3, 1, 3, and so on along the number. Then the answers are added up. For a correct barcode, the total always ends in 0: it is a multiple of 10. The last digit, the check digit, is chosen to make that happen.

Here is the pen’s number, worked out:

Digit 4 0 0 6 3 8 1 3 3 3 9 3 1
Weight 1 3 1 3 1 3 1 3 1 3 1 3 1
Digit × weight 4 0 0 18 3 24 1 9 3 9 9 9 1

The total is 4 + 0 + 0 + 18 + 3 + 24 + 1 + 9 + 3 + 9 + 9 + 9 + 1 = 90. It ends in 0, so the number passes.

Why one wrong digit is always caught

Suppose one digit is typed wrong: it is too big or too small by some amount, say by 4. If that digit has weight 1, the total changes by 4. If it has weight 3, the total changes by 3 × 4 = 12. Either way the total no longer ends in 0, so the mistake is caught.

Could the change ever be a whole 10, so that the total still ends in 0? A digit can only be wrong by 1 to 9. Times 1, that is 1 to 9: never 10. Times 3, that is 3, 6, 9, 12, 15, 18, 21, 24 or 27: never a multiple of 10 either. So every single wrong digit is caught.

Why some swaps slip through

Now swap two neighbors. One of them had weight 1 and the other weight 3, and after the swap each gets the other’s weight. If the two digits are 3 and 8:

  • before: 3 × 1 + 8 × 3 = 3 + 24 = 27
  • after: 8 × 1 + 3 × 3 = 8 + 9 = 17

The total drops by exactly 10, so it still ends in 0, and the swap is missed. A swap always changes the total by twice the difference between the two digits. 8 − 3 = 5, and 2 × 5 = 10. So the shop barcode misses a swap exactly when the two digits differ by 5: 0 and 5, 1 and 6, 2 and 7, 3 and 8, 4 and 9.

Which of these typing mistakes would the shop barcode miss?

Pick an answer to see why.

Program it

With blocks

Here is the till’s check as a block program. It asks for the 13 digits one at a time, adds up each digit times its weight, and at the end looks at the remainder when the total is divided by 10, which is its last digit. (The weight starts at 1. set weight to 4 − weight turns 1 into 3 and 3 back into 1.)

Try it

The till’s check

Press Run and type the pen’s digits, 4 0 0 6 3 8 1 3 3 3 9 3 1, one at a time, and watch the trace table. Then press Test: it runs four numbers, the last with 3 and 8 swapped.

What the program says and asks appears here.

total – no value
weight – no value
digit – no value
StepBlocktotalweightdigit
TestShould sayIt said
The penLooks right
One wrongMistake!
0↔6Mistake!
3↔8Looks right

Press Run to start the program, or Step to do one block at a time.

Loading the blocks…

In Python (from Grade 8)

The same check in Python is a short function. A barcode is a string of 13 digits; code[i] is one digit, and int() turns it into a number.

def ean_valid(code):    total = 0    for i in range(13):        if i % 2 == 0:            weight = 1        else:            weight = 3        total = total + int(code[i]) * weight    return total % 10 == 0 print(ean_valid('4006381333931'))   # the penprint(ean_valid('4076381333931'))   # one digit wrongprint(ean_valid('4006831333931'))   # 3 and 8 swapped

Output

TrueFalseTrue

i % 2 == 0 is true for places 0, 2, 4…, which get weight 1 (Python counts places from 0).

Try every mistake

Typing mistakes one at a time is slow. A program can make every possible mistake in a number and count how many are caught. This one tries every single wrong digit (each of the 13 places, each of the 9 other digits) and every swap of two different neighbors.

The second method in it is the one books used before 2007, the ISBN-10: ten digits, weights 10, 9, 8… down to 1, and the total must divide exactly by 11. Its check digit can come out as 10, which is written X.

def ean_valid(code):    total = 0    for i in range(13):        if i % 2 == 0:            weight = 1        else:            weight = 3        total = total + int(code[i]) * weight    return total % 10 == 0 def isbn_valid(code):    total = 0    for i in range(10):        if code[i] == 'X':            value = 10        else:            value = int(code[i])        total = total + value * (10 - i)    return total % 11 == 0 def try_mistakes(code, valid):    wrong = 0    wrong_caught = 0    for i in range(len(code)):        for d in '0123456789':            if d != code[i]:                mistake = code[:i] + d + code[i + 1:]                wrong = wrong + 1                if not valid(mistake):                    wrong_caught = wrong_caught + 1    swaps = 0    swaps_caught = 0    missed = []    for i in range(len(code) - 1):        if code[i] != code[i + 1]:            mistake = code[:i] + code[i + 1] + code[i] + code[i + 2:]            swaps = swaps + 1            if not valid(mistake):                swaps_caught = swaps_caught + 1            else:                missed.append(code[i] + code[i + 1])    print(code, ': wrong digits caught', wrong_caught, 'of', wrong)    print('   swaps caught', swaps_caught, 'of', swaps, ', missed:', missed) try_mistakes('4006381333931', ean_valid)try_mistakes('9780306406157', ean_valid)try_mistakes('0306406152', isbn_valid)

Output

4006381333931 : wrong digits caught 117 of 117   swaps caught 8 of 9 , missed: ['38']9780306406157 : wrong digits caught 117 of 117   swaps caught 11 of 12 , missed: ['61']0306406152 : wrong digits caught 90 of 90   swaps caught 9 of 9 , missed: []

(code[:i] is the part of the string before place i, and code[i + 1:] the part after it.)

What your program shows

  • Every single wrong digit was caught, in every number: 117 of 117, and 90 of 90. (The widget below also tries an X in the book number’s last place, so it counts 91 of 91.)
  • The shop barcode missed a swap in both of its numbers: 3 and 8 in the pen’s number, 6 and 1 in the barcode on a book. Both pairs differ by 5.
  • The old book number, the ISBN-10, caught every swap.

Why does ISBN-10 do better? A swap of two neighbors changes its total by exactly the difference between the two digits (their weights differ by 1). The difference is 1 to 9 (or 10 with an X), and none of those divides by 11. Dividing by 11 instead of 10 is what makes it work, but it costs something: the check “digit” can be 10, which needs the letter X.

This little program checks every pair of digits at once, in any barcode:

missed = []for a in range(10):    for b in range(10):        if a != b:            before = a * 1 + b * 3    # a has weight 1, b has weight 3            after = b * 1 + a * 3     # swapped            if (after - before) % 10 == 0:                missed.append(str(a) + str(b))print(len(missed), 'of 90 swaps are missed:', missed)

Output

10 of 90 swaps are missed: ['05', '16', '27', '38', '49', '50', '61', '72', '83', '94']

So the shop barcode catches 80 of the 90 kinds of swap, about 9 in 10, and every wrong digit. For a till, where the shopkeeper can see the product’s name on the screen, that is good enough.

Four ways to check a number

Many numbers in your life end in a check digit. Try the same mistakes on each kind.

Try it

Four checks

Choose a kind of number. Make mistakes, then press Try every mistake for each.

Multiply the digits by 10, 9, 8… 1 and add. The total must divide by 11 (X stands for 10).

Tap to:
Total
132 = 12 × 11
Check
passes ✓

This is the ISBN-10 that Wikipedia uses as its example. It passes the check. Tap a digit to make a mistake.

Wrong digits caught
—
Neighbor swaps caught
—
Swaps missed
—
  • Shop barcodes (EAN-13): weights 1 and 3, total ends in 0. Since 1 January 2007 every new book’s number, its ISBN, is a 13-digit barcode number starting with 978 or 979, checked the same way.
  • Old book numbers (ISBN-10): weights 10 down to 1, total divides by 11.
  • Bank cards: the long number on a debit or credit card ends in a check digit worked out by the Luhn method, invented by Hans Peter Luhn at IBM (patented in 1960). It doubles every second digit. It catches every wrong digit and almost every swap of neighbors; the one swap it misses is 09 and 90.
  • Verhoeff’s method: in 1969 the Dutch mathematician Jacobus Verhoeff published the first check for ordinary digits that catches every wrong digit and every swap of neighbors. Instead of weights, it mixes the digits with a table built from the ways a regular pentagon can be turned and flipped. India’s Aadhaar numbers use it.

In the widget, which methods catch every swap of two neighbors?

Pick an answer to see why.

Going further still

A check digit says that, not where. If a barcode fails the check, can the till work out which digit is wrong and fix it? Try it in the first widget: make one mistake, then think about every way to change one digit of the wrong number so that it passes. How many are there? (Challenge ★★★ asks a program to find them all.)

Other kinds of mistakes. People also type “twin” mistakes (22 for 55) and jumps (swapping two digits with one between them, 123 → 321). Change the try_mistakes program to try these. Which methods catch them?

Challenges

★ Make the check digit (blocks)

Finish the program so that, after the 12 digits are typed, it says the check digit and nothing else (for 400638133393 it says 1). Then press Test.

Try it

★ Make the check digit

What the program says and asks appears here.

total – no value
weight – no value
digit – no value
TestShould sayIt said
A pen1
A book7
Sample7
Ends in 00

Press Run to start the program, or Step to do one block at a time.

Loading the blocks…

Hint
Another hint
Answer

★★ The smudged book number (Python, from Grade 8)

One digit of an ISBN-10 is smudged and shows as ?. Write missing_isbn(isbn) that gives back the digit that must have been there, as a string ('0' to '9', or 'X' if it is the last place and must be 10). Every test has exactly one answer.

def missing_isbn(isbn):    # isbn is 10 characters, one of them '?'    return '0' print(missing_isbn('?306406152'))

Try it

★★ The smudged book number

  1. The first digit is smudged missing_isbn('?306406152') Should give '0' Yours —
  2. A digit in the middle missing_isbn('03064?6152') Should give '0' Yours —
  3. The last digit is smudged missing_isbn('526018159?') Should give 'X' Yours —
Tests passed
— / 10
Challenge
★★ solved

Write your missing_isbn in the program above (Edit), then check it.

A test your function gets wrong, anything it prints, and any error appear here.

Hint
Answer

★★★ Every possible fix (Python, from Grade 8)

A barcode has failed the check. Write fixes(code) that gives back a list of every valid barcode that differs from code in exactly one digit. Any order is fine. What do you notice about how many there are?

def fixes(code):    # code is 13 digits; give back every valid barcode one digit away    return [] print(len(fixes('4006381333932')))

Try it

★★★ Every possible fix

  1. The pen’s barcode, last digit wrong fixes('4006381333932') Should give ['3006381333932', '4306381333932', '4096381333932', '4009381333932', '4006281333932', '4006311333932', '4006380333932', '4006381633932', '4006381323932', '4006381336932', '4006381333832', '4006381333962', '4006381333931'] Yours —
  2. One digit typed wrong fixes('4076381333931') Should give ['7076381333931', '4176381333931', '4006381333931', '4077381333931', '4076681333931', '4076391333931', '4076384333931', '4076381433931', '4076381363931', '4076381334931', '4076381333231', '4076381333941', '4076381333934'] Yours —
  3. A barcode that is already right fixes('4006381333931') Should give [] Yours —
Tests passed
— / 6
Challenge
★★★ solved

Write your fixes in the program above (Edit), then check it.

A test your function gets wrong, anything it prints, and any error appear here.

Hint
Answer

Questions

What is a check digit for?

Pick an answer to see why.

A barcode’s total of digits times weights comes to 117 when it is typed. What does the till decide?

Pick an answer to see why.

a.

Work out the check digit for the 12 digits 590123412345.

Answer
b.

Explain why the shop barcode can’t catch the mistake of typing 16 for 61 (in two neighboring places).

Answer
c.

A friend says: “If one extra digit catches mistakes, the till should also be able to put them right.” Is your friend right? Explain.

Answer
d.

Why do you think bank cards and identity numbers use a check digit that catches (almost) every swap, while a till can manage with one that misses some?

Answer

Where to go next

  • Grade 6, Zeros and Ones: how a computer stores numbers and text as bits.
  • Grade 8, Functions: writing functions like ean_valid that answer a question.
  • Grade 9, Data in Depth: more on how data is stored and checked.
  • Which card was flipped? Add one row and one column of cards, and you can find and fix a mistake, not just spot it.