Paper
Part IErrors, Information and Channels

Distance, Detection and Correction

November 14, 202650 min readbeginner

Minimum distance decides what a code can do. The chapter proves what a distance of d detects and corrects, with and without erasures, then works through single parity, ISBN and Luhn check digits, rectangular parity and Gray codes.

The previous chapter, Capacity and Shannon's Theorem, closed on a random code of 16 codewords of 12 bits in which two pairs of codewords differed in only 2 positions, so the code barely beat sending each message bit three times. The coding theorem proves that good codes exist but builds none, and a random draw leaves to chance the property that matters most, the distance between codewords. This chapter makes that distance the design target.

Channels, Signals and Likelihoods built the binary symmetric channel BSC(p)\text{BSC}(p), which flips each bit independently with probability pp, and the binary erasure channel, which loses a bit openly instead of flipping it, and Capacity and Shannon's Theorem measured how many bits per use such channels carry.

The chapter defines the distance between two words, pictures every word of nn bits as a corner of a cube, and proves from the smallest distance dd between codewords how many errors a code detects, how many it corrects, and how many errors and erasures it handles together. The same counting then prices the checks in daily use, single parity, the ISBN and Luhn check digits and rectangular parity, and the chapter ends with the Gray code, which uses a distance of one on purpose.

Every number in the chapter is recomputed by ch08_distance_detection_and_correction.py in the python/ folder of the companion repository ecc-book-lab, and the charts are drawn by ch08_charts.py in the same folder.

01.Distance and Weight

Take x=10110x = 10110 and y=11011y = 11011 and compare them position by position from the left. They disagree in positions 2, 3 and 5, so three single-bit flips turn one into the other, and no fewer will do, since each disagreeing position must be flipped at least once. XOR, written ⊕\oplus, gives 1 where two bits differ and 0 where they agree, so 10110⊕11011=0110110110 \oplus 11011 = 01101 marks the disagreements in one step, as Figure 1 shows.

Two 5-bit words, x = 10110 and y = 11011, written in boxes one above the other, with their bitwise XOR and AND below a rule. The XOR, 01101, has a 1 in exactly the three positions where x and y differ, positions 2, 3 and 5, and those boxes are shaded green. Its weight, 3, is the Hamming distance between x and y. The AND, 10010, marks the two positions where both words hold a 1, and the weights obey 3 + 4 − 2 times 2 = 3. position 1 2 3 4 5 x 1 0 1 1 0 weight 3 y 1 1 0 1 1 weight 4 x XOR y 0 1 1 0 1 weight 3, the distance x AND y 1 0 0 1 0 weight 2 A 1 in x XOR y marks a position where x and y differ. weight of x XOR y = 3 + 4 − 2 times 2 = 3
Figure 1. Distance as the weight of an XOR. The words 10110 and 11011 differ in three positions, which the XOR marks with 1s, and the weights of the two words and of their AND satisfy the identity of the weight lemma.

Distance is never negative, it is zero only for equal words, and it is symmetric. The fourth property of a distance, the triangle inequality, rests on a lemma that uses the bitwise AND, written a∧ba \wedge b, which is 1 only where both words hold a 1. For the example, 10110∧11011=1001010110 \wedge 11011 = 10010.

On the example the right side is 3+4−2×2=33 + 4 - 2 \times 2 = 3, the weight of 0110101101.

Proof. Let kk count the positions where both words hold a 1, and uu and vv the positions where only aa or only bb does. Then w(a)=k+uw(a) = k + u, w(b)=k+vw(b) = k + v and w(a∧b)=kw(a \wedge b) = k. The XOR is 1 exactly in the u+vu + v positions where one word holds a 1, so w(a⊕b)=u+v=w(a)+w(b)−2kw(a \oplus b) = u + v = w(a) + w(b) - 2k. ■\blacksquare

Proof. Let a=x⊕ya = x \oplus y and b=y⊕zb = y \oplus z. XOR can be regrouped freely, like addition, and a word XORed with itself is all zeros, so a⊕b=x⊕za \oplus b = x \oplus z. By Equation 1 and Equation 2,

d(x,z)=w(a⊕b)=w(a)+w(b)−2 w(a∧b)≤w(a)+w(b)=d(x,y)+d(y,z),d(x, z) = w(a \oplus b) = w(a) + w(b) - 2\,w(a \wedge b) \le w(a) + w(b) = d(x, y) + d(y, z),

since a weight is never negative. ■\blacksquare

Equality holds when a∧ba \wedge b is all zeros, so that no flip on the way from xx to yy is undone on the way to zz. With x=00000x = 00000, y=01101y = 01101 and z=11011z = 11011 the inequality reads 4≤3+34 \le 3 + 3, and the detour costs two extra flips.

Errors fit the same picture. Write what the channel does as an error pattern ee, a word with a 1 wherever a bit flipped. A sent codeword cc arrives as c⊕ec \oplus e, at distance w(c⊕e⊕c)=w(e)w(c \oplus e \oplus c) = w(e) from cc, so the received word lies exactly as far from what was sent as the number of errors.

02.Minimum Distance

The four words 0000000000, 0110101101, 1011010110 and 1101111011 form a small code, called C5C_5 in this chapter. Table 1 lists all six pairs of its codewords.

Table 1. Every pair of codewords of , with the XOR that marks their differences and its weight

First codewordSecond codewordXORDistance
0000001101011013
0000010110101103
0000011011110114
0110110110110114
0110111011101103
1011011011011013

Source: reproduced by ch08_distance_detection_and_correction.py.

No two codewords are fewer than 3 flips apart, and that single number turns out to decide what the code can detect and correct.

C5C_5 is a (5,4,3)(5, 4, 3) code of rate 2/52/5. For scale, the four 2-bit words have d=1d = 1, the even-weight 3-bit words 000000, 011011, 101101 and 110110 have d=2d = 2, and the repetition code R3R_3 of The Repetition Code, with codewords 000000 and 111111, has d=3d = 3. Checking every pair takes M(M−1)/2M(M - 1)/2 comparisons, but every XOR in the table is itself a codeword of C5C_5, and that gives a shortcut.

Proof. Such a code contains the all-zero word 00, since c⊕c=0c \oplus c = 0. For different codewords cc and c′c', the distance w(c⊕c′)w(c \oplus c') is the weight of a nonzero codeword. Conversely, every nonzero codeword cc has weight w(c)=d(0,c)w(c) = d(0, c), a distance between two codewords. The two lists hold the same numbers, so they have the same smallest value. ■\blacksquare

For C5C_5 the nonzero weights are 3, 3 and 4, so d=3d = 3 follows from three weights instead of six distances. Codes closed under XOR are the subject of the Part Linear Block Codes.

The random code of the previous chapter shows what happens without design. Figure 2 counts its 120 pairs by distance. The mean is 6.11, near the n/2=6n/2 = 6 expected for random words, but two pairs, 110000101100110000101100 with 110000111000110000111000 and 110010011110110010011110 with 110011010110110011010110, sit at distance 2. That is what chance predicts. A second random word lies within distance 2 of a first when it is one of the 1+12+66=791 + 12 + 66 = 79 such words, which happens with probability 79/4096=0.019379/4096 = 0.0193, so 120 pairs are expected to hold 2.31 close pairs. The dots give the same expectation, 120(12k)/4096120\binom{12}{k}/4096, at every distance kk.

Bar chart of the distances between all 120 pairs of codewords in a random code of 16 codewords of 12 bits. The counts are 2 at 2, 6 at 3, 15 at 4, 23 at 5, 17 at 6, 29 at 7, 22 at 8, 5 at 9, 1 at 10. Dots joined by a dashed line show the binomial expectation, 120 times C(12, k) over 4096, which peaks at 27.1 pairs at distance 6. The bar at distance 2 is marked, since two pairs of codewords differ in only 2 positions. distance between the two codewords of a pair number of pairs 0 5 10 15 20 25 30 0 1 2 3 4 5 6 7 8 9 10 11 12 two pairs at distance 2 pairs in the code binomial expectation
Figure 2. Distances between the 120 pairs of codewords in the random code of the previous chapter, against the binomial expectation for random words. Two pairs fall at distance 2, as chance predicts. Data: computed by ch08_charts.py in the companion repository.

Those two pairs dominate the failures. At p=0.01p = 0.01 the previous chapter's decoder fails on a block with probability 0.0032306, and the four codewords in the close pairs, a quarter of the code, account for 0.82 of that, because one flip in either position where a close pair differs leaves the received word halfway between them.

03.The Geometry of the Binary Cube

The Repetition Code drew the eight 3-bit words as the corners of a cube, with an edge between words that differ in one bit. The nn-cube does the same for all 2n2^n words of nn bits. Each word has nn neighbors and each edge joins two words, so the nn-cube has n 2n/2=n 2n−1n\,2^n/2 = n\,2^{n-1} edges, 12 for n=3n = 3 and 32 for n=4n = 4. Walking an edge flips one bit, so the shortest walk from xx to yy has exactly d(x,y)d(x, y) edges, since each differing position must be flipped once and flipping them one at a time suffices.

Table 2 lists the radius-1 balls of R3R_3 in the 3-cube, and those of the fourfold code R4R_4, with codewords 00000000 and 11111111, in the 4-cube.

Table 2. Balls of radius 1 around the codewords of and , and the words of the 4-cube that neither ball reaches

CodeCenterWords in the ballSize
R3R_3000000, 001, 010, 1004
R3R_3111111, 110, 101, 0114
R4R_400000000, 0001, 0010, 0100, 10005
R4R_411111111, 1110, 1101, 1011, 01115
R4R_4in neither ball0011, 0101, 0110, 1001, 1010, 11006

Source: reproduced by ch08_distance_detection_and_correction.py.

The two balls of R3R_3 share no word and hold all 8, as Figure 3 shows, so every received word is within one flip of exactly one codeword. The balls of R4R_4 hold 10 of the 16 words. The six words of weight 2 lie at distance 2 from both codewords and point to neither, and Figure 4 draws them in the middle column.

The 3-cube drawn in perspective, with its 8 vertices labeled by the 3-bit words and an edge joining every two words that differ in one bit. The codewords 000 and 111 of the threefold repetition code have thick boxes. The ball of radius 1 around 000, holding 000, 001, 010 and 100, is drawn in green, and the ball around 111, holding 111, 110, 101 and 011, in cyan. The two balls share no word and together hold all 8 words. Edges that run behind the front face are dashed. 000 001 010 011 100 101 110 111 within distance 1 of 000 000 001 010 100 within distance 1 of 111 111 110 101 011 Thick boxes are the codewords. The two balls hold all 8 words. Dashed edges run behind.
Figure 3. The radius-1 balls of the threefold repetition code in the 3-cube. They are disjoint and together hold every word, so each received word points back to one codeword.
The 16 words of 4 bits arranged in five columns by weight, 1, 4, 6, 4 and 1 words, with a line joining every two words that differ in one bit. The radius-1 ball around 0000 holds 0000 and the four words of weight 1, and the ball around 1111 holds 1111 and the four words of weight 3. The six words of weight 2 lie in neither ball, so the two balls cover 10 of the 16 words. 0000 0001 0010 0100 1000 0011 0101 0110 1001 1010 1100 0111 1011 1101 1110 1111 weight 0 weight 1 weight 2 weight 3 weight 4 within distance 1 of 0000 distance 2 from both within distance 1 of 1111
Figure 4. The 4-cube in layers of equal weight, with the radius-1 balls of the fourfold repetition code. The six words of weight 2 are equally far from both codewords and fall in neither ball. Data: computed by ch08_charts.py in the companion repository.

Proof. The words at distance exactly ii from cc are the words c⊕ec \oplus e with w(e)=iw(e) = i, and different patterns give different words. A pattern of weight ii is a choice of ii positions out of nn, and Counting Errors with the Binomial Distribution counted (ni)\binom{n}{i} such choices. Adding over ii from 0 to tt gives the ball. ■\blacksquare

For t=1t = 1 the sum is 1+n1 + n, the sizes 4 and 5 in the table. If the balls of radius tt around MM codewords share no word, they hold M V(n,t)M\,V(n, t) of the 2n2^n words, so

M V(n,t)≤2n.M\,V(n, t) \le 2^n .
(4)

This is the sphere-packing bound, also called the Hamming bound after Hamming's 1950 paper [1], and Correcting Errors shows that it applies to every code that corrects tt errors. For C5C_5 the four balls of size V(5,1)=6V(5, 1) = 6 hold 24 of the 32 words. Sixteen codewords of 6 bits cannot correct one error, since 16×7=11216 \times 7 = 112 exceeds 26=642^6 = 64, but at length 7 the count is 16×8=128=2716 \times 8 = 128 = 2^7, and the Hamming (7,4)(7, 4) code of the Part Linear Block Codes fills the 7-cube with no word to spare.

04.Detecting Errors

Send 0110101101 from C5C_5 and let the channel flip positions 3 and 4, the pattern 0011000110. The received word 0101101011 is at distances 3, 2, 4 and 1 from 0000000000, 0110101101, 1011010110 and 1101111011. It is not a codeword, so the receiver knows something went wrong, though its nearest codeword, 1101111011, was not the one sent. Flip positions 1, 3 and 4 instead, the pattern 1011010110, and the receiver gets 1101111011, a codeword, with no sign that anything happened.

Proof. Let cc be sent and 1≤w(e)≤d−11 \le w(e) \le d - 1. The received word is at distance w(e)>0w(e) > 0 from cc, so it differs from cc. If it were another codeword c′c', then d(c,c′)=w(e)<dd(c, c') = w(e) < d, contradicting the definition of dd, so it is flagged. For the second part, take codewords cc and c′c' at distance exactly dd. The pattern e=c⊕c′e = c \oplus c' has weight dd and turns cc into c′c', which the detector accepts. ■\blacksquare

For C5C_5 the guarantee covers one and two errors, and the pattern 1011010110 that escaped is the XOR of two codewords at distance 3. Most heavier patterns are caught as well, and for a code closed under XOR the escapes are easy to name. The word c⊕ec \oplus e is a codeword exactly when ee is, so the patterns that escape are the nonzero codewords, whichever codeword was sent. Write AiA_i for the number of codewords of weight ii. Each pattern of weight ii occurs on BSC(p)\text{BSC}(p) with probability pi(1−p)n−ip^i (1 - p)^{n - i}, so the probability of an undetected error is

Pud=∑i=1nAi pi(1−p)n−i.P_{ud} = \sum_{i=1}^{n} A_i\, p^i (1 - p)^{n - i} .
(5)

C5C_5 has A3=2A_3 = 2 and A4=1A_4 = 1, so Pud=2p3(1−p)2+p4(1−p)P_{ud} = 2p^3 (1 - p)^2 + p^4 (1 - p), which is 1.9701×10−61.9701 \times 10^{-6} at p=0.01p = 0.01, against 1−0.995=0.0490101 - 0.99^5 = 0.049010 for any error at all. Of the ten patterns of weight 3, only the two that are codewords escape.

05.Correcting Errors

Suppose C5C_5 delivers 1011110111. Its distances to the four codewords are 4, 3, 1 and 2, so the nearest is 1011010110, one flip away. Decisions by Bayes' Rule showed why nearest is right. On BSC(p)\text{BSC}(p) with p<1/2p < 1/2 and equally likely codewords, a codeword at distance kk from the received word has likelihood pk(1−p)n−kp^k (1 - p)^{n - k}, which shrinks as kk grows, so the nearest codeword is the most likely one.

Proof. If a word yy were within tt of two codewords cc and c′c', the triangle inequality would give d(c,c′)≤2t<dd(c, c') \le 2t < d, which is impossible, so the balls are disjoint. A pattern with w(e)≤tw(e) \le t leaves c⊕ec \oplus e in the ball of cc and no other, and the decoder returns cc. The condition d≥2t+1d \ge 2t + 1 means t≤(d−1)/2t \le (d - 1)/2, whose largest whole solution is the rounded-down value. For the last part, take codewords cc and c′c' at distance dd and flip t+1t + 1 of the positions where they differ, starting from cc. If d=2t+1d = 2t + 1, the word reached is within tt of c′c' and is miscorrected. If d=2t+2d = 2t + 2, it is t+1t + 1 from both and is flagged. ■\blacksquare

As dd runs from 1 to 7, tt runs through 0, 0, 1, 1, 2, 2 and 3, about half the detection guarantee d−1d - 1, because a corrected word must stay nearer its own codeword than any other. An even distance leaves a word exactly halfway, which Figure 5 shows being flagged.

Three rows of received words along a shortest path between two codewords, c on the left and c' on the right, each box labeled by its distance from c. In the first row the codewords are at distance 4 and the decoder corrects one error, so the word at distance 1 goes to c, the word at distance 3 goes to c', and the word at distance 2, equally far from both, is flagged. In the second row the distance is 5 and the decoder corrects two errors, so words at distances 1 and 2 go to c, words at 3 and 4 go to c', and nothing is flagged. In the third row the distance is again 5 but the decoder corrects only one error, so the words at distances 2 and 3 are flagged, and any pattern of up to three errors from c is detected. Each box is a received word, labeled by its distance from c. d = 4 correct 1, detect 2 c 1 2 3 c' d = 5 correct 2 c 1 2 3 4 c' d = 5 correct 1, detect 3 c 1 2 3 4 c' decoded to c decoded to c' flagged, not corrected
Figure 5. Decoding regions along a shortest path between two codewords. At distance 4 the halfway word is flagged, at distance 5 a decoder can correct two errors, or correct one and detect up to three.

Proof. Since t≤st \le s, the condition gives 2t≤d−12t \le d - 1, so the correction bound covers weights up to tt. Now let t<w(e)≤st < w(e) \le s. The received word is more than tt from cc, so the decoder cannot return cc. If it returned another codeword c′c', then c′c' would be within tt of the received word, and the triangle inequality would give d(c,c′)≤s+t≤d−1d(c, c') \le s + t \le d - 1, which is impossible. So the word is flagged. ■\blacksquare

R4R_4, with d=4d = 4, takes t=1t = 1 and s=2s = 2, correcting 00010001 to 00000000 and flagging 00110011. R5R_5, with d=5d = 5, can correct one error and flag two or three, or correct two and flag nothing beyond them, in which case three errors on 0000000000, such as 0011100111, are miscorrected to 1111111111. Which is better depends on whether a wrong answer costs more than a resend, the question of the next chapter.

06.Errors and Erasures Together

An erasure is a symbol marked as lost, the event of the binary erasure channel in Three Discrete Channels, and the receiver knows where it is. Take the code E6E_6 with codewords 000000000000, 001111001111, 110011110011 and 111100111100, whose minimum distance is 4. Send 110011110011, erase position 3 and flip position 6. The receiver gets 11?01011?010 and compares only the five positions it trusts, as Table 3 shows.

Table 3. Decoding the received word 11?010 from the code on the five positions that were not erased

CodewordOn positions 1, 2, 4, 5, 6Received on those positionsDistance
00000000000110103
00111100111110104
11001111011110101
11110011100110102

Source: reproduced by ch08_distance_detection_and_correction.py.

The nearest codeword on those positions is 110011110011, the one sent, recovered despite one error and one erasure.

Proof. Delete the ee erased positions from every codeword. Each deletion removes at most one difference between two codewords, so the shortened codewords still differ pairwise in at least d−ed - e positions, and since d−e>2t≥0d - e > 2t \ge 0, no two have become equal. On the kept positions the received word holds exactly tt errors. By the correction bound, nearest-codeword decoding recovers the sent codeword when d−e≥2t+1d - e \ge 2t + 1, which is 2t+e<d2t + e < d. ■\blacksquare

The bound is tight. The codewords 000000000000 and 001111001111 differ in positions 3 to 6, and erasing those four, so that e=de = d, leaves both reading 00????00????. An erasure costs half an error, so with no errors a code fills d−1d - 1 erasures, twice the errors it corrects. For d=4d = 4 that allows up to 3 erasures, or one error with one erasure. Even single parity, with d=2d = 2, fills one erasure, since the missing bit must make the count of 1s even, the idea behind Parity as a spare disk.

07.Single Parity

The even-weight code of nn bits, the single parity check of Detecting Instead of Correcting, holds every word with an even number of 1s. Flipping one bit makes the count odd, so d=2d = 2, and parity does better than the detection bound promises.

Proof. The checker computes the XOR of all received bits. For c⊕ec \oplus e this equals the XOR of the bits of cc, which is 0 because cc has even weight, combined with the XOR of the bits of ee, which is 1 exactly when w(e)w(e) is odd. ■\blacksquare

Detecting Instead of Correcting wrote EE and OO for the total probability of the even-weight and the odd-weight error patterns on BSC(p)\text{BSC}(p), and showed from the binomial theorem that E+O=1E + O = 1 and E−O=(1−2p)nE - O = (1 - 2p)^n. Subtracting the two gives 2O=1−(1−2p)n2O = 1 - (1 - 2p)^n, the chance that the checker raises its alarm.

For n=8n = 8 and p=0.01p = 0.01, 0.988=0.8507630.98^8 = 0.850763, so the alarm sounds with probability 0.074618. Some error occurs with probability 1−0.998=0.0772551 - 0.99^8 = 0.077255, so errors slip through with probability 0.0026368. The share of corrupted words the checker flags is its coverage,

coverage=1−(1−2p)n2(1−(1−p)n)≈1−(n−1)p2,\text{coverage} = \frac{1 - (1 - 2p)^n}{2\left(1 - (1 - p)^n\right)} \approx 1 - \frac{(n - 1)p}{2} ,
(9)

which here is 0.96587, or 96.6%. The approximation keeps terms up to p2p^2. By the binomial theorem (1−2p)n≈1−2np+2n(n−1)p2(1 - 2p)^n \approx 1 - 2np + 2n(n - 1)p^2 and (1−p)n≈1−np+12n(n−1)p2(1 - p)^n \approx 1 - np + \tfrac12 n(n - 1)p^2, so the alarm probability is about np−n(n−1)p2np - n(n - 1)p^2 and the chance of some error about np−12n(n−1)p2np - \tfrac12 n(n - 1)p^2. Dividing both by npnp and writing a=(n−1)pa = (n - 1)p, the coverage is about (1−a)/(1−a/2)≈(1−a)(1+a/2)≈1−a/2(1 - a)/(1 - a/2) \approx (1 - a)(1 + a/2) \approx 1 - a/2, which is 0.965 for n=8n = 8. Misses grow with length because they are mostly pairs of errors, and a longer word holds more pairs.

Figure 6 plots the coverage. At p=0.01p = 0.01 a 32-bit word covers 0.86561 and a 64-bit word 0.76469. At p=1/2p = 1/2 every received word is equally likely and half have even weight, so the coverage is 2n−1/(2n−1)2^{n-1}/(2^n - 1), which is 128/255=0.50196128/255 = 0.50196 for n=8n = 8.

Fraction of corrupted words that a single parity bit flags, plotted against the bit error probability p from 0.0001 to 0.5 on a log scale, for words of n = 8, 32 and 64 bits. Each curve starts near 1 and falls toward one half. At p = 0.01, marked by a dashed vertical line, the fractions are 0.966, 0.866 and 0.765. At p = 0.5 the fraction is 128/255, or 0.5020, for n = 8, and within a billionth of one half for the longer words. bit error probability p, log scale fraction of corrupted words flagged 0.4 0.5 0.6 0.7 0.8 0.9 1.0 0.0001 0.001 0.01 0.1 0.5 n = 8, 0.966 at p = 0.01 n = 32, 0.866 at p = 0.01 n = 64, 0.765 at p = 0.01
Figure 6. Coverage of a single parity bit, the share of corrupted words it flags, for words of 8, 32 and 64 bits. Longer words and noisier channels push the coverage toward one half. Data: computed by ch08_charts.py in the companion repository.

In hardware the XOR of all the bits is the parity tree of The parity tree, and a lab later in this Part checks the parity detection formula against simulated channels.

08.Check Digits

People who copy numbers make two common mistakes. A substitution replaces one digit with another, and an adjacent swap exchanges two neighbors, typing 72 for 27. A check digit is an extra digit chosen so that a weighted sum of all the digits meets a fixed rule, and Gallian surveys the schemes in use [2] [3]. Catching every substitution means that two valid numbers differ in at least two digits, a minimum distance of 2, which says nothing yet about swaps. The arithmetic uses congruence. For a modulus mm, a≡b(modm)a \equiv b \pmod{m} means that a−ba - b is a multiple of mm, so 116≡6(mod11)116 \equiv 6 \pmod{11} because 116=10×11+6116 = 10 \times 11 + 6.

ISBN-10

An ISBN-10 is ten digits x1,…,x10x_1, \dots, x_{10}, read from the left, of which the tenth is the check, chosen so that

∑i=110(11−i) xi≡0(mod11).\sum_{i=1}^{10} (11 - i)\,x_i \equiv 0 \pmod{11} .
(10)

The weights run from 10 down to 1, and a check value of 10 is written X. Table 4 finds the check digit for 0-13-042672, the start of the ISBN of Lin and Costello's textbook [4].

Table 4. The ISBN-10 check digit for 0-13-042672, with weights

Position iiDigit xix_iWeight 11−i11 - iProduct
10100
2199
33824
4070
54624
62510
76424
87321
9224
Sum116

Source: reproduced by ch08_distance_detection_and_correction.py.

The sum 116 leaves remainder 6 modulo 11, so the check digit, with weight 1, is 11−6=511 - 6 = 5, and 0-13-042672-5 has weighted sum 121=11×11121 = 11 \times 11.

Proof. Substituting bb for aa where the weight is ww changes the sum by w(b−a)w(b - a), with 1≤w≤101 \le w \le 10 and b−ab - a nonzero and between −10-10 and 10, so neither factor is a multiple of 11. Because 11 is prime, a product is a multiple of 11 only when a factor is, which is Euclid's lemma, so the change is not a multiple of 11. Swapping aa at weight wiw_i with bb at weight wjw_j changes the sum by wib+wja−wia−wjb=(wi−wj)(b−a)w_i b + w_j a - w_i a - w_j b = (w_i - w_j)(b - a). The weights differ, so wi−wjw_i - w_j is nonzero and between −9-9 and 9, and again neither factor is a multiple of 11. ■\blacksquare

The proof needs a prime modulus and distinct weights, and the price is the eleventh symbol X.

ISBN-13

Since 1 January 2007 ISBNs have 13 digits. An older book's ISBN-13 puts 978 in front of the first nine digits of its ISBN-10 and computes a new check digit by the rule of the 13-digit EAN barcode on retail goods, with weights alternating 1 and 3 from the left and modulus 10,

∑i=113wi xi≡0(mod10),wi={1i odd,3i even.\sum_{i=1}^{13} w_i\,x_i \equiv 0 \pmod{10}, \qquad w_i = \begin{cases} 1 & i \text{ odd}, \\ 3 & i \text{ even}. \end{cases}
(11)

Table 5. The ISBN-13 check digit for 978-0-13-042672, with weights alternating 1 and 3

Position iiDigit xix_iWeight wiw_iTerm
1919
27321
3818
4030
5111
6339
7010
84312
9212
106318
11717
12236
Sum93

Source: reproduced by ch08_distance_detection_and_correction.py.

Table 5 applies the rule to the same book. The terms add to 93, so the check digit 7 brings the sum to 100, and the number is 978-0-13-042672-7.

Proof. A substitution changes the sum by w(b−a)w(b - a) with ww equal to 1 or 3. For w=1w = 1 the change is nonzero and between −9-9 and 9. For w=3w = 3, if 3(b−a)3(b - a) were a multiple of 10, so would be 7×3(b−a)=20(b−a)+(b−a)7 \times 3(b - a) = 20(b - a) + (b - a), and hence b−ab - a, which is impossible. Neighbors carry the weights 1 and 3, so a swap changes the sum by ±2(b−a)\pm 2(b - a), a multiple of 10 exactly when b−ab - a is a multiple of 5, that is, when the digits differ by 5. Positions two apart carry equal weights, so a swap there changes nothing. ■\blacksquare

The pairs that differ by 5, such as 2 and 7, are 10 of the 90 ordered pairs of different digits, so ISBN-13 catches 80/9080/90, or 88.9%, of adjacent swaps. The worked example An ISBN-13 Swap That Slips Through follows one. The weights are not to blame. In any weighted sum modulo 10, an even weight ww makes 5w5w a multiple of 10 and a weight divisible by 5 makes 2w2w one, so some substitution in that position escapes. Catching every substitution therefore forces odd weights, the difference of two odd weights is even, and an even number times 5 is a multiple of 10. No weighted sum of decimal digits modulo 10 catches every substitution and every adjacent swap.

The Luhn formula

The Luhn formula, patented by Hans Peter Luhn of IBM in 1960 [5] and used on payment card numbers, escapes that limit by not being a weighted sum. Number the digits from the right, the check digit being digit 1. Every digit in an even position is doubled, and 9 is subtracted when the result exceeds 9. Writing yjy_j for the jj-th digit from the right and D(x)D(x) for the doubled value, a number is valid when

∑j oddyj+∑j evenD(yj)≡0(mod10),D(x)={2xx≤4,2x−9x≥5.\sum_{j \text{ odd}} y_j + \sum_{j \text{ even}} D(y_j) \equiv 0 \pmod{10}, \qquad D(x) = \begin{cases} 2x & x \le 4, \\ 2x - 9 & x \ge 5. \end{cases}
(12)

Doubling sends the digits 0,1,…,90, 1, \dots, 9 to 0,2,4,6,8,1,3,5,7,90, 2, 4, 6, 8, 1, 3, 5, 7, 9, each digit exactly once. For 314159265, the first nine digits of π\pi, the check digit is 3. Table 6 checks 3141592653 and two corrupted copies.

Table 6. The Luhn check on 3141592653 and on two corrupted copies, with the terms listed from the left

NumberChangeTermsSumVerdict
3141592653none6, 1, 8, 1, 1, 9, 4, 6, 1, 340valid
3141582653the 9 becomes 86, 1, 8, 1, 1, 8, 4, 6, 1, 339caught
31419526535 and 9 swapped6, 1, 8, 1, 9, 5, 4, 6, 1, 344caught

Source: reproduced by ch08_distance_detection_and_correction.py.

Proof. A substitution changes the sum by b−ab - a or by D(b)−D(a)D(b) - D(a). Both are nonzero, the second because DD sends different digits to different digits, and both lie between −9-9 and 9, so neither is a multiple of 10. Of two neighbors exactly one is doubled. If aa starts in the doubled position, the pair contributes D(a)+bD(a) + b before the swap and D(b)+aD(b) + a after, a change of f(b)−f(a)f(b) - f(a) with f(x)=D(x)−xf(x) = D(x) - x. For x=0,…,9x = 0, \dots, 9, ff takes the values 0,1,2,3,4,−4,−3,−2,−1,00, 1, 2, 3, 4, -4, -3, -2, -1, 0, so f(b)−f(a)f(b) - f(a) lies between −8-8 and 8 and is a multiple of 10 only when it is 0. The function ff repeats only the value 0, at x=0x = 0 and x=9x = 9, so only that swap escapes. Positions two apart are both doubled or both not, so a swap there leaves the sum unchanged. ■\blacksquare

The swap in the table changed the sum by f(9)−f(5)=4f(9) - f(5) = 4. Only 2 of the 90 ordered pairs escape, so Luhn catches 97.8% of adjacent swaps. The companion script confirms this on numbers of 10 and 16 digits and on all 10,000 valid five-digit strings, and shows that the weights 1, 3, 1, 3, 1 in place of doubling let 10 pairs through. Figure 7 compares the three schemes.

Grouped bar chart of the percentage of errors caught by the ISBN-10, ISBN-13 and Luhn check digits, in that order, for three kinds of error. For a single substitution they catch 100.0, 100.0, 100.0 percent. For an adjacent swap they catch 100.0, 88.9, 97.8 percent. For a swap two apart they catch 100.0, 0.0, 0.0 percent. kind of error, tested at every position and every pair of digits errors caught, percent 0 20 40 60 80 100 100 ISBN-10 100 ISBN-13 100 Luhn single substitution 100 ISBN-10 88.9 ISBN-13 97.8 Luhn adjacent swap 100 ISBN-10 0 ISBN-13 0 Luhn swap two apart
Figure 7. Share of single substitutions, adjacent swaps and swaps two apart caught by the ISBN-10, ISBN-13 and Luhn check digits. Only the prime modulus of ISBN-10 catches every swap. Data: computed by ch08_charts.py in the companion repository.

09.Rectangular Parity

One parity bit detects an error but cannot locate it. Arrange the data in a grid with a parity bit for each row and each column, and the crossing of a failed row and a failed column points at the error. Figure 8 sends 16 data bits as a 4 by 4 array with rows 1011, 0110, 1101 and 0010. The row parities are 1, 0, 1 and 1, the column parities 0, 0, 1 and 0, and a corner bit, 1, makes both the parity row and the parity column even. The channel flips the data bit in row 3, column 2.

Two 5 by 5 arrays of bits. The left one, sent, is a 4 by 4 block of data, rows 1011, 0110, 1101 and 0010, with a shaded parity bit at the end of each row, 1, 0, 1 and 1, a shaded parity bit under each column, 0, 0, 1 and 0, and a shaded corner bit 1. An arrow labeled channel leads to the right array, received, in which the data bit in row 3, column 2 has flipped from 1 to 0 and is drawn in red. Row 3 and column 2 now hold an odd number of 1s, so their cells are outlined in orange and marked odd, and the flipped bit is the one cell where they cross. sent received, one bit flipped 1 0 1 1 1 0 1 1 0 0 1 1 0 1 1 0 0 1 0 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0 0 1 0 0 1 1 0 0 1 0 1 0 0 1 0 1 odd odd channel parity bits in a row or column with odd parity flipped bit
Figure 8. Rectangular parity locating one error. The flipped bit is the only cell where a row with an odd count crosses a column with an odd count.

Table 7. The received array, with the data bit in row 3, column 2 flipped, and the check on each row and column

Column 1Column 2Column 3Column 4ParityCheck
Row 110111even
Row 201100even
Row 310011odd
Row 400101even
Parity00101even
Checkevenoddeveneveneven

Source: reproduced by ch08_distance_detection_and_correction.py.

In Table 7 only row 3 and column 2 fail, so the decoder flips the bit where they cross. The scheme spends 25 bits on 16, a rate of 16/25=0.6416/25 = 0.64, and its power follows from its minimum distance.

Proof. The XOR of two valid arrays is valid, since each parity bit is the XOR of the bits it covers, so it suffices to find the smallest weight of a nonzero valid array, in which every row and column holds an even number of 1s. A row holding a 1 holds at least two, in columns jj and j′j', and each of those columns holds a second 1 in another row, so the weight is at least 4. With exactly four, the second 1s of columns jj and j′j' share a row, or each of their rows would hold a single 1, so the array is a rectangle. Conversely every row and column of a rectangle is even, and an array whose rows and columns are all even is valid, because its data bits produce exactly the parity bits present. Two rows and two columns can be chosen in (52)2=100\binom{5}{2}^2 = 100 ways. ■\blacksquare

With d=4d = 4 the budget allows correcting one error and detecting two, the guarantee of R4R_4 at a rate of 0.64 instead of 0.25. The companion script confirms that all 25 single errors are corrected and all 300 double errors flagged. Three errors can deceive the decoder. With errors at (1,1)(1, 1), (1,3)(1, 3) and (3,1)(3, 1), written as (row, column), row 1 and column 1 hold two errors each and stay even, so only row 3 and column 3 fail, the signature of one error at (3,3)(3, 3). Flipping that bit completes a rectangle and delivers a valid array that was not sent. Grid codes like this, called product codes, go back to Elias [6], and later Parts build much stronger ones.

10.Gray Codes

A rotary sensor reports which of eight sectors a shaft points into, as a 3-bit word read from three tracks. In plain binary the boundary from sector 3, 011011, to sector 4, 100100, changes all three bits, and since the tracks never switch at exactly the same instant, a reading mid-change can catch any of the 23=82^3 = 8 combinations, such as 111111, sector 7. If neighboring sectors had words differing in one bit, a reading mid-change could only return one of the two sectors involved.

The reflected construction builds one for every nn. Start from the 1-bit list 0, 1. To go from nn bits to n+1n + 1, write the list with a 0 in front, then the same list reversed with a 1 in front. This gives 00, 01, 11, 10, and then 000, 001, 011, 010, 110, 111, 101, 100, the walk of Figure 9. Inside each half neighbors differ in one bit because the shorter list did, and at the middle and at the wrap the two words differ only in the front bit.

The 3-cube drawn in perspective, with its 8 vertices labeled by 3-bit words. Green arrows run along 8 of its 12 edges in the order 000, 001, 011, 010, 110, 111, 101, 100 and back to 000, the 3-bit reflected Gray code, so each step flips exactly one bit. A small number beside each vertex gives its position in the walk, from 0 to 7, and a table at the right lists the same order. 000 0 001 1 010 3 011 2 100 7 101 6 110 4 111 5 position Gray word 0 000 1 001 2 011 3 010 4 110 5 111 6 101 7 100 Each arrow flips one bit. The walk closes, 100 to 000.
Figure 9. The 3-bit reflected Gray code as a walk on the 3-cube. Each step follows one edge and so flips one bit, and the last step returns to the start.

A formula gives the word in position bb directly. Write bb in binary, with bits numbered from 0 at the right to n−1n - 1 at the left, and let b≫1b \gg 1 be bb shifted right one place, dropping its last bit and putting a 0 in front. Then

g=b⊕(b≫1),sogn−1=bn−1,gi=bi⊕bi+1 for i<n−1.g = b \oplus (b \gg 1), \qquad \text{so} \qquad g_{n-1} = b_{n-1}, \quad g_i = b_i \oplus b_{i+1} \text{ for } i < n - 1 .
(13)

Table 8 applies it to every 4-bit position and reproduces the reflected list, whose first eight entries without their leading 0 are the 3-bit list. The companion script confirms that the formula and the construction agree for every length up to 8.

Table 8. The 4-bit reflected Gray code from , with the 3-bit code beside its first eight entries

Position bbBinaryb≫1b \gg 14-bit Gray3-bit Gray
0000000000000000
1000100000001001
2001000010011011
3001100010010010
4010000100110110
5010100100111111
6011000110101101
7011100110100100
8100001001100
9100101001101
10101001011111
11101101011110
12110001101010
13110101101011
14111001111001
15111101111000

Source: reproduced by ch08_distance_detection_and_correction.py.

Proof. Since b<2n−1b < 2^n - 1, it ends in a 0 followed by kk 1s. Adding 1 turns those 1s into 0s and that 0 into a 1, so m=b⊕(b+1)m = b \oplus (b + 1) is k+1k + 1 1s at the right end. Shifting distributes over XOR, so g(b)⊕g(b+1)=m⊕(m≫1)g(b) \oplus g(b + 1) = m \oplus (m \gg 1), and since m≫1m \gg 1 is kk 1s at the right end, the XOR has a single 1, in bit kk. For the wrap, 2n−12^n - 1 is all 1s, and g(2n−1)=11…1⊕01…1=10…0g(2^n - 1) = 11\ldots1 \oplus 01\ldots1 = 10\ldots0, which differs from g(0)=0g(0) = 0 in the top bit only. ■\blacksquare

To convert back, run the formula from the top bit down. XORing gi=bi⊕bi+1g_i = b_i \oplus b_{i+1} with bi+1b_{i+1} gives

bn−1=gn−1,bi=bi+1⊕gi for i=n−2,…,0.b_{n-1} = g_{n-1}, \qquad b_i = b_{i+1} \oplus g_i \text{ for } i = n - 2, \dots, 0 .
(14)

For b=1011b = 1011 the shift is 01010101, and 1011⊕0101=11101011 \oplus 0101 = 1110, the entry for position 11. Going back from 11101110, b3=1b_3 = 1, b2=1⊕1=0b_2 = 1 \oplus 1 = 0, b1=0⊕1=1b_1 = 0 \oplus 1 = 1 and b0=1⊕0=1b_0 = 1 \oplus 0 = 1, which is 10111011 again.

In the Gray code sector 3 is 010010 and sector 4 is 110110, so the boundary changes one bit and a reading mid-change returns 3 or 4. Frank Gray's 1953 patent described this reflected binary code [7], and the same property makes Gray codes common in shaft encoders and in counters read by circuits on a different clock. As a code, a Gray code has minimum distance 1 and protects nothing against noise. It uses distance the other way, placing consecutive values as close as possible, so an uncertain reading costs one step and never a jump across the range.

11.Looking Ahead

A code of minimum distance dd detects d−1d - 1 errors, corrects ⌊(d−1)/2⌋\lfloor (d - 1)/2 \rfloor, and handles tt errors with ee erasures whenever 2t+e<d2t + e < d. The same counting priced single parity through the parity detection formula, the ISBN and Luhn check digits, and the rectangular array that locates one error.

A guarantee says what a code can do, not what a system should do with it. The next chapter, Error-Control Strategies and Performance, weighs forward error correction against retransmission, prices the retransmission schemes stop-and-wait, go-back-N and selective repeat, measures decoded error rates and coding gain, and defines the reliability measures of real systems, the failure rate in FIT, silent data corruption and the detected but unrecoverable error. The undetected-error probability of Detecting Errors and the parity detection formula are its raw inputs. Hamming's paper [1] introduced much of this chapter's geometry, and Lin and Costello [4] and MacKay [8] carry it further.

12.Worked Examples

13.Exercises

References

  1. [1]Hamming, Richard W. (1950). “Error Detecting and Error Correcting Codes.” Bell System Technical Journal, 29(2), pp. 147–160. doi:10.1002/j.1538-7305.1950.tb00463.x
  2. [2]Gallian, Joseph A. (1991). “The Mathematics of Identification Numbers.” The College Mathematics Journal, 22(3), pp. 194–202. doi:10.1080/07468342.1991.11973381
  3. [3]Gallian, Joseph A. (1996). “Error Detection Methods.” ACM Computing Surveys, 28(3), pp. 504–517. doi:10.1145/243439.243457
  4. [4]Lin, Shu and Costello, Jr., Daniel J. (2004). “Error Control Coding: Fundamentals and Applications.” 2nd edition. Pearson Prentice Hall.
  5. [5]Luhn, Hans Peter (1960). “Computer for Verifying Numbers.” U.S. Patent 2,950,048. https://patents.google.com/patent/US2950048A/en
  6. [6]Elias, Peter (1954). “Error-free Coding.” Transactions of the IRE Professional Group on Information Theory, 4(4), pp. 29–37. doi:10.1109/TIT.1954.1057464
  7. [7]Gray, Frank (1953). “Pulse Code Communication.” U.S. Patent 2,632,058. https://patents.google.com/patent/US2632058A/en
  8. [8]MacKay, David J. C. (2003). “Information Theory, Inference, and Learning Algorithms.” Cambridge University Press. The author's site offers the whole book free to read on screen. https://www.inference.org.uk/itila/book.html

— Anirban

Hardware–software at the seam where compilers meet microcode.

FeedbackBook modePaper
error-correction-codinginformation-and-channels