BCH encoder/decoder

advertisement
Forward Error Correction Coding
BCH encoding/decoding
Dr. M.A. Belkerdid
Spring 2008
TABLE OF CONTENTS
Section
Title
Page
1.0
ABSTRACT ........................................................................................................................ 1
2.0
FECC ................................................................................................................................... 1
2.1
Linear Block Codes ................................................................................................. 2
2.2
Convolutional Codes ............................................................................................... 2
2.3
Coding Gain ............................................................................................................. 3
3.0
GALOIS FIELDS ............................................................................................................... 5
4.0
INTRODUCTION TO BCH ENCODING/DECODING .................................................. 10
5.0
BCH ENCODING ............................................................................................................. 10
5.1
Galois field elements ............................................................................................. 12
5.2
(7,4) BCH Encoder ................................................................................................ 15
5.3
BCH codes in GF(24) ............................................................................................. 17
6.0
BCH DECODER ............................................................................................................... 18
6.1
Syndrome calculator .............................................................................................. 19
6.2
Berlkamp/Peterson Algorithm ............................................................................... 21
6.3
Chien Search Algorithm ........................................................................................ 24
7.0
APPENDIX A. C CODE .................................................................................................. 26
8.0
APPENDIX B C PROGRAM OUTPUT.......................................................................... 36
i
LIST OF FIGURES
Figure
Title
Page
Figure 1. Digital Communication system ................................................................................................ 1
Figure 2. K=7, R=1/2 convolutional encoder .......................................................................................... 2
Figure 3. BER for BPSK with and without FEC ..................................................................................... 3
Figure 4. Modulation efficiency improvement with FECC ..................................................................... 4
Figure 5. Primitive polynomial circuit architecture ................................................................................. 7
Figure 6. Polynomial division circuit ...................................................................................................... 7
Figure 7. 10th order primitive polynomial implementation ..................................................................... 9
Figure 8. 10th order primitive polynomial high speed implementation .................................................. 9
Figure 9. (7,4,1) BCH Encoder .............................................................................................................. 15
Figure 10. BCH Decoder Architecture .................................................................................................. 18
Figure 11. Syndrome Calculator for (7,4) BCH decoder ....................................................................... 20
ii
LIST OF TABLES
Table
Title
Page
Table 1. Table of Primitive polynomial ................................................................................................... 6
Table 2. primitive polynomials .............................................................................................................. 11
Table 3. BCH Code Table ...................................................................................................................... 12
Table 4. Elements of GF(23) .................................................................................................................. 13
Table 5. (7,4) BCH encoded codewords ................................................................................................ 16
Table 6. elements of GF(24).................................................................................................................... 17
iii
1.0
ABSTRACT
This document presents the theory and C code implementation of Bose-Chaudhuri-Hocquenghem
(BCH) codes. Galois Field theory is used extensively to simplify the understanding, design, and code
implementation of BCH codes. A C program is written to implement all the possible codes ranging
from GF(23) to GF(220). The main programs contains five (5) functions, read-p(), generate_gf(), genpoly(), encode_bch(), and decod_bch(). The read-p() function is used in the encoder to read in the user
define choice of BCH code. The generate_gf() function calculates the Galois Field elements of the
user chosen BCH code. The gen-poly() function calculates the polynomial generator of the user
chosen BCH code. The encode_bch() function calculates the redundant parity bits and appends them
to the input data bits to form the systematic codewords. The decod_bch() function includes the
syndrome calculator, the Berlkamp-Peterson algorithm, and a Chien search algorithm. The program
generates random data bits with different seeds and also allows the user to insert errors. A brief
introduction to Forward Error Correction coding (FECC), coding gain and Galois Field arithmetic is
first presented.
2.0
FECC
A digital communication system is depicted in Figure 1. Data is generated at a constant source symbol
rate Rs source symbols per second. The source output is encoded by a source encoder such as ASCII
code or Hoffman code. The output of the source encoder is fed to the channel encoder for forward
error correction coding. A linear block code such as Bose-Hockengham-Chadhuri (BCH), or Reed
Solomon (RS), or a convolutional encoder is normally used before the data is sent to the modulator,
and out to the antenna. The receiver performs the reverse of the transmitter.
Figure 1. Digital Communication system
1
The purpose of FECC is to reduce Pe for a given Eb/N0 .
How:
By introducing coding gain.
Mechanism: Redundancy
Cost:
Slows down throughput and cost of Hardware/Software
2.1
Linear Block Codes
In linear block codes, also referred to as algebraic coeds, data is blocked into k-bit blocks and r parity
bits are appended or post-pended the k-bits to form an k-bit block (n=k+r).
2.2
Convolutional Codes
The output bit stream of a convolutional encoder is generated by a digital convolution process where as
the present input bit will influence a number of encoded bits.
The continuous convolution integral of the bit stream with certain primitive polynomials is given by
t
x(t )   g ( )m(t   )d
L
is rewritten in the discrete domain as

x j   g i m j i
i 0
.
The xj output bits depend on the current bit and on the previous L+1 bits. K = L+1 is called the
constraint length. L is the number of shift registers need to implement the convolutional encoder.
There are only a handful of convolutional encoders. The most popular coeds are K=7, rate=1/2, K=9,
rate ½, and rate ¾. Figure 2 depicts the most widely used code K=7, rate=1/2. The Viterbi Algorithm
is used as the decoder of choice.
g1 ( x)  x 6 + x 4 + x 3 + x + 1
+
Input
6
5
4
3
1
2
0
Output
+
g 2 ( x)  x 6 + x 5 + x 4 + x 3 + 1
Figure 2. K=7, R=1/2 convolutional encoder
2
2.3
Coding Gain
The bit error rate for un-encoded BPSK, BPSK with (7,3) BCH encoder/decoder, and a BPSK with
K=7, R=1/2 Convolutional encoder/Viterbi decoder is depicted in Figure 1. Figure 2 depicts the
improvement in modulation efficiency in Shannon’s plane.
Figure 3. BER for BPSK with and without FEC
3
Figure 4. Modulation efficiency improvement with FECC
4
3.0 GALOIS FIELDS
Polynomial algebra and addition modulo 2 with no carry are used with the following basic operations:
1 +1 =0
1.1 = 1
1.0 = 0
A sequence of bits at a constant bit rate can be represented by a polynomial given by:
P(x) = C0x0 + C1x1 + C2x2 + C3x3 + C4x4 + C5x5 +….+ Cnxn
Where Cn is either 1 or o, and the power of x is the bit position (delay, shift register operation), C0 is
the first bit in the bit stream, while Cn is the last bit in the bit stream, and + is addition modulo 2 with
no carry (exclusive OR operation). Of course, x0 =1. For example, the bit stream:
1011101101
Is represented by the polynomial given by:
P(x) = 1 + x2 + x3 + x4 + x6 + x7 + x9
Pseudo-Random or Pseudo-Noise (PN) sequences can be represented by polynomials. Polynomials are
generated by delay elements (shift registers, Exclusive Or gates, and Tap feedback paths (Cn). If these
sequences are generated by PRIMITIVE POLYNOMIALs, then these sequences are periodic and offer
great properties such as very good autocorrelation properties, similar to the properties exhibited by
non-periodic BARKER or WILLARD sequences. If 2 PN sequences represented by 2 polynomials of
the same order, a ere modulo 2 added together may form another class of codes called GOLD codes.
Gold codes are special PN sequences with extremely good cross correlation property. Gold codes are
used as the spreading waveform for the GPS CDMA system. Let’s get back to the PN sequences
generated by a primitive polynomial. These sequences are referred to as maximal length sequences
(maximum period).
A polynomial p(x) of degree m is primitive if and only if the smallest integer n for which p(x) divides
xn +1 is given by:
n = 2m - 1
Example, find a primitive polynomial of order 3:
m=3, then n = 23 – 1= 7
We need to factor: (x7 +1) = (x+1)p(x)q(x) with p(x) being a polynomial of degree 3. Long
division is performed to find the factors of ( x7 +1).
5
x 6 + x5 + x 4 + x 3 + x 2 + x + 1
x+ 1 | x7 + 1
x 7 + x6
x6 + 1
x 6 + x5
…..
‘’’’’
x1 + 1
x1 + 1
0
(x7 +1) =(x +1)( x6 + x5 + x4 + x3 + x2 + x + 1)
Now factor out (x6 + x5 + x4 + x3 + x2 + x + 1) :
(x6 + x5 + x4 + x3 + x2 + x + 1) = (x3 + x + 1) (x3 + x2 + 1)
(x7 +1) =(x +1) (x3 + x + 1) (x3 + x2 + 1)
There are 2 primitive polynomials of order 3. Either polynomial will generate a maximum length
sequence of bits that are periodic with a period of 7. These 2 polynomials will generate a sequence of
7 bits that exhibit good randomness characteristics. The period is maxed out at 7 bits.
Let’s go to fourth order primitive polynomials (PN sequences that repeat every 15 bits):
m=4, then n = 24 – 1= 15
4
10
(x15 +1) =(x +1) (x + x + 1) (x + … + 1)
m
Primitive Polynomial
Period
3
P3(x) = 1 + x + x3
7
4
P4(x) = 1 + x + x4
15
5
P5(x) = 1 + x2 + x5
31
6
P6(x) = 1 + x + x6
63
7
P7(x) = 1 + x3 + x7
127
8
P8(x) = 1 + x2 + x3 + x4 + x8
255
9
P9(x) = 1 + x4 + x9
511
Table 1. Table of Primitive polynomial
6
A maximal sequence can be generated by shift registers (the number of shift registers is equal to the
degree of the primitive polynomial), exclusive OR gate and feed back paths governed by Cn, the
coefficients of the primitive polynomial. For example, a PN sequence with a period of 7 bits (chips),
with a primitive polynomial of order 10 given by:
P(x)= x3 + x + 1
is generated by
Figure 5. Primitive polynomial circuit architecture
The above circuit performs polynomial division of b(x) = m(x) / g(x) as shown below:
Let m(x) = 1 (loading the first register with a 1 initial condition), the output b(x) is given by:
b(x) = m(x) / g(x) = 1/g(x) = 1/(1 + x+ x3)
Figure 6. Polynomial division circuit
The output is easily obtained using long division as follows:
7
The output is
3
1 +x+ x
1 + x + x2 + x3 + x6 + x7 + x8 + x10 + x13 + x14 + x15 + x17 + x20 + x21
| 1
1 +x+ x3
x + x3
x+ x2 +x3
x2
x2 + x3 + x4
x3 + x4
x3 + x4 + x6
x6
x6 + x7 + x9
x7 + x9
x7 + x8 + x10
x8 + x9 + x10
x8 + x9 + x11
x10 + x11
x10 + x11 + x13
x13
x13 + x14 + x16
x14 + x16
x14 + x15 + x17
x15 + x16 + x17
x15 + x16 + x18
x17 + x18
x17 + x18 + x20
x20
x20 + x21 + x23
x21 + x23
+
b(x) = 1 + x + x2 + x3 + x6 + x7 + x8 + x10 + x13 + x14 + x15 + x17 + x20 + x21 +…..
The output is then:
bk = 111 1001110 1001110 1001110 …..
After the 3 bit initial conditions, the code repeats every 7 chips.
8
..
If m(x)= 1 + x3 (101), then b(x) = m(x) / g(x) = (1 + x3 )/g(x), and after the long division
operation:
bk = 111 1010011 1010011 1010011 …..
Note that the PN sequence is the same after the first 3 initial condition chips. Different initial
conditions just shifts the PN sequence.
Another example of a PN sequence with a period of 1023 bits (chips), with a primitive polynomial of
order 10 given by:
P(x) = 1 + x2 + x3 + x6 + x8 + x9 + x10
is generated by the following circuit:
Figure 7. 10th order primitive polynomial implementation
Figure 8. 10th order primitive polynomial high speed implementation
9
4.0 INTRODUCTION TO BCH ENCODING/DECODING
A BCH encoder is based on Galois Field theory and its implementation is rather simple. A
BCH decoder requires a syndrome calculator, an error location polynomial coefficients finder (x)
(Berlkemp/Massey algorithm), and a root finder for the error location polynomial (x) (Chien Search
algorithm).
5.0 BCH ENCODING
BCH codes are denoted by (n, k), where n is encoded block length and k is the input data block length.
BCH codes have the following parameters:
Block Length
n=2m – 1
Number of correctable errors
t
Number of parity check bits
n-k <= mt
The primitive element of the Galois Field of 2m elements, denoted by GF(2m ), is defined as . A
sequence of powers of , given by 2tis used to generate minimal polynomials.
The minimal polynomial of i is defined as mi(x), and the polynomial generator, g(x), for a t error
correcting BCH code is the least common multiple of m1(x), m2(x), … m2t(x), and is given by:
g(x) = LCM{ m1(x), m2(x), … m2t(x) }.
It is clear that 2t are roots of g(x), i.e. g(i ) = 0 for i= 0, 1, 2,...2t.
Furthermore if i is an even integer, then i = 2l i’, where i’ is an odd integer, and l >= 1. This then
implies that i and I’ , have the same minimal polynomial, m1(x)= m1’(x) and hence:
g(x) = LCM{ m1(x), m3(x), … m2t -1(x) }.
The minimal polynomials are not only necessary to generate the BCH polynomial generator for a given
code, but are instrumental for the syndrome calculations in the BCH decoder architecture.
The BCH code generator polynomials are generated in the following manner:
a) Select a primitive polynomial of degree m, and generate the elements of GF(2m)
b) Determine mi(x) for i= 0, 1, 2,...2t minimum polynomials
10
c) Get g(x) = LCM{ m1(x), m3(x), … m2t -1(x) }
d) The degree of g(x) is n-k.
The primitive polynomials for the GF ranging from 8 to 512 elements are listed in the table below.
These mth order primitive polynomial will generate (7, k) to (511, k) BCH codes.
m
Primitive Polynomial
3
P3(x) = 1 + x + x3
4
P4(x) = 1 + x + x4
5
P5(x) = 1 + x2 + x5
6
P6(x) = 1 + x + x6
7
P7(x) = 1 + x3 + x7
8
P8(x) = 1 + x2 + x3 + x4 + x8
9
P9(x) = 1 + x4 + x9
Table 2. primitive polynomials
All the possible (n,k,t) BCH codes from n=7 to n 511 are tabulated in table 2 below.
11
n
k
t
n
k
t
n
k
t
7
15
4
11
7
5
26
21
16
11
6
57
51
45
39
36
30
24
18
16
10
7
120
113
106
99
92
85
78
71
64
57
50
43
36
29
22
15
8
247
239
231
223
215
207
1
1
2
3
1
2
3
5
7
1
2
3
4
5
6
7
10
11
13
15
1
2
3
4
5
6
7
9
10
11
13
14
15
21
23
27
31
1
2
3
4
5
6
255
199
191
187
179
171
163
155
147
139
131
123
115
107
99
91
87
79
71
63
55
47
45
37
29
21
13
9
502
493
484
475
466
457
448
439
430
421
412
403
394
385
376
367
7
8
9
10
11
12
13
14
15
18
19
21
22
23
25
26
27
29
30
31
42
43
45
47
55
59
63
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
511
358
349
340
331
322
313
304
295
286
277
268
259
250
241
238
229
220
211
202
193
184
175
166
157
148
139
130
121
112
103
94
85
76
67
58
49
40
31
28
19
10
18
19
20
21
22
23
25
26
27
28
29
30
31
36
37
38
39
41
42
43
45
46
47
51
53
54
55
58
59
61
62
63
85
87
91
93
95
109
111
119
121
31
63
127
255
511
Table 3. BCH Code Table
5.1 Galois field elements
Galois field arithmetic is used to derive all the Galois field elements necessary for each BCH code.
Lets use GF(23) as in example to present the properties of Field theory. The primitive polynomial is
then:
P3(x) = 1 + x + x3
There are 8 field elements including 0. The rest of the elements are powers of . These elements
along with their conjugates, 3-tuples, and minimal polynomials are tabulated in Table 3 below.
12
Elements
Conjugates
3-tuples
0
0 = 1
Minimal polynomial
0
000
20 = 1
001
1 = 
24 
21 = 2
010
m1 ( x )  1 + x + x 2
2 = 2
48 = 2 6 =
22 = 4
100
m1 ( x )  1 + x + x 2
3 = 1+
6, 12 =
(001+010)
011
m3 ( x )  1 + x 2 + x 3
4 = +2
8 = , 16 =
(010+100)
110
m1 ( x )  1 + x + x 2
5 = 1++2
10 = , 20 =
(001+110)
111
m3 ( x )  1 + x 2 + x 3
6 = 1+2
12 = , 24 =
(001+100)
101
m3 ( x )  1 + x 2 + x 3
Table 4. Elements of GF(23)
Galois Field arithmetic is used to generate the entries of Table 3 above. In GF theory, multiplication of
two elements of the Galois Field is achieved by adding their exponents, for example in GF(2 3) 5 2 =
7 = 1, and 6 5 =7 4 = 4. Division is done similarly, 3/6 = 10/6 = 4. To add two elements
of the Galois Field, the other forms in the table are used in each case, hence
5+3=(1++2)+(1+)=1++2+1+=2; of course addition is modulo-2 with no carry (exclusive
Or-Gating).
Another operation needed for BCH decoding, is the root finding technique, or solving equations in the
Galois Field. This is illustrated in the example below.
f(x)=x2+(1+)x+1=0
In order to solve for x, the ordinary quadratic formula normally used will not work because division by
2 (which is equal to division by 0 in the GF) is not possible. The solution of the above equation, if it
exists, can be obtained by substituting all the elements of the GF given in the above table.
f (0)  0
f (1)  0
f ( )  0
f(2)=(2)2+(1+)2+1=4+2+3+1=+2+2+1++1=0
f ( 3 )  0
13
f ( 4 )  0
f(5)=(5)2+(1+)5+1=10+5+6+1=3+1++2+1+2+1=0
f ( 6 )  0
And hence f(x)=(x+2)(x+5), and 2 and 5 are the roots of f(x). Root finding in the GF is a must
operation in BCH, and RS decoders. It is also worth noting that f2(x)=f(x2) and for any positive integer
l, [f(x)]2l=f(x2l).
If  is an arbitrary element of the GF. The polynomial m(x) with the smallest degree in x(degree m or
less), and  is its root, i.e., m()=0, is called the minimum polynomial of element . The minimal
polynomials of all the elements of the GF (23) are obtained as follows:
1. Let =, then the following sequence is formed:
=, 2=2, (2)2=4, (2)3=8=, (2)4=16=2, ……
It is seen that repetition starts at (2)3. Hence the roots of the minimal polynomial of  are given by:
, 2, 4
and hence the minimal polynomial is given by
m1(x)=(x+)(x+2)(x+4)=(x2+2x+x+3)(x+4)=x3+[2++4]x2+[3+6+5]x+1=x3+x+1
2. Let =3 then the following sequence is formed:
=3, 2=6, (2)2=12=5, (2)3=24=3……
It is also seen that repetition starts at (2)3. Hence the roots of the minimal polynomial of 3 are given
by:
3, 5, 6
And hence the minimal polynomial is given by
m3(x)=(x+3)(x+5)(x+6)=x3+x2+1
From the above derivations the following is noted:
m1(x)=m2(x)=m4(x)
m3(x)=m5(x)=m6(x)
14
5.2
(7,4) BCH Encoder
In GF(23), there is only one possible BCH code, it is (7,4) with t=1, and its code polynomial generator
g(x) is given by:
g(x) = LCM{ m1(x), … m2t -1(x) }=LCM{ m1(x) }
g(x)= x3+x+1
The circuit consists of a shift register-Exclusive OR circuit with taps governed by g(x) in order to
generate the third order parity polynomial by diving the k bit polynomial by g(x), then appending the
parity bits to the end of the m bits. This is shown in Figure 9 below. The k bits proceed to the output
and to the input of the parity generator circuit. After 4 shifts the switch 1 is moved to position B, and
Switch 2 is opened, and the computed parity bits are sent to the output. The circuit is then ready for
the next input block.
Figure 9. (7,4,1) BCH Encoder
The 15 4-bit data blocks and their respective 15 7-bit BCH encoded blocks for the above single bit
error correcting (7,4) BCH encoder are given in Tabl2 4.
15
m(x)
C(x)
m0 m1 m2 m3
c0 c1 c2 c3 c4 c5 c6
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
1
1
0
0
1
0
0
0
1
0
1
1
0
0
0
1
1
0
0
1
1
1
0
1
0
1
0
0
0
1
0
0
1
1
1
0
1
0
1
0
1
0
1
1
0
0
0
1
1
0
0
1
1
0
0
0
1
0
1
1
1
0
1
1
1
0
1
0
1
0
0
0
1
0
0
0
1
0
1
1
0
0
1
1
0
0
1
1
1
0
1
0
1
0
1
0
1
0
0
1
1
1
0
1
1
1
0
1
1
0
0
0
1
1
0
0
1
1
0
0
0
1
0
1
1
0
1
1
1
0
1
0
0
1
1
1
1
0
1
1
1
0
1
0
0
1
1
1
1
1
1
1
1
1
1
1
Table 5. (7,4) BCH encoded codewords
16
5.3
BCH codes in GF(24)
The possible BCH codes in GF(24) are
(15,11) t=1, (15,7) t=2, (15,5) t=3
For example, the elements of (GF24), generated by a primitive polynomial given by:
P4(x) = 1 + x + x4
There are 16 field elements including 0. The rest of the elements are powers of . These elements
along with their conjugate, 4-tuples, and minimal polynomials are tabulated in Table 4 below.
Elements
Conjugates
0
0 = 1
3-tuples
Minimal polynomial
0
0000
20 = 1
0001
1 = 
24 8 
21 = 2
0010
m1 ( x )  1 + x + x 4
2
48,
22 = 4
0100
m1 ( x )  1 + x + x 4
3
6, 12 ,
23 = 8
1000
m3 ( x )  1 + x + x 2 + x 3 + x 4
4 = 1+
8 , , 
0011
m1 ( x )  1 + x + x 4
5 = +2
10
0110
m5 ( x )  1 + x + x 2
6 = 2+3
12 , 9 , 
1100
m3 ( x )  1 + x + x 2 + x 3 + x 4
7 = 1++3
14 ,, 
1011
m7 ( x )  1 + x 3 + x 4
8 = 1+2
 , , 
0101
m1 ( x )  1 + x + x 4
9 = +3
3 , , 
1010
m3 ( x )  1 + x + x 2 + x 3 + x 4
10 = 1++2

0111
m5 ( x )  1 + x + x 2
11 = +2+3
7, , 
1110
m7 ( x )  1 + x 3 + x 4
12= 1++2+3
, 6 ,
1111
m3 ( x )  1 + x + x 2 + x 3 + x 4
13 = 1++3
7, , 
1101
m7 ( x )  1 + x 3 + x 4
14 = 1+3
7 ,, 
1001
m7 ( x )  1 + x 3 + x 4
Table 6. elements of GF(24)
17
6.0
BCH DECODER
There three basic operations involved in the decoding of BCH codes.

Syndrome calculation

Determination of the error location polynomial (x)

Computation of the roots of (x) for the error location determination
The syndrome calculator involves polynomial division in GF, the error location polynomial is obtained
using the Berlkamp algorithm, ant the root location calculations are done using the Chien search
algorithm. The decoding process is depicted below.
+
Buffer registers
Input
output
Syndrome
Calculator
Brelkamp
Algorithm
Chien
Search
Algorithm
Figure 10. BCH Decoder Architecture
The decoding process will be described using (15,5,3) BCH example. This triple error correcting code
is generated by:
g ( x)  LMC{m1 (t ), m3 (t ), m5 (t )}  m1 (t )m3 (t )m5 (t )  (1 + x + x 4 )(1 + x + x 2 + x 3 + x 4 )(1 + x + x 2 )
 1 + x + x 2 + x 4 + x 5 + x 8 + x10
18
6.1
Syndrome calculator
The syndrome Si is the remainder of dividing the received code word with the corresponding minimal
polynomial mi. The syndromes are zero if there are no errors in the codes. So if the intent is to detect
error only a syndrome calculator is all that is needed in the decoder.
The transmitted codeword is obtained by appending the parity check bits to the message data bits. The
parity polynomial (parity bits) is the remainder of the division of the message polynomial by the BCH
code polynomial generator. The minimal polynomials are factors of the code polynomial generator. If
no error occurred then the receiver codeword divided by any of the minimal polynomials will result in
zero remainder. The remainder of the division of any received codeword by a minimal polynomial is
called the SYNDROME. The number of minimal polynomials (number of syndromes) per code is
equal to 2t. Where t is the number of error the code can correct. The syndrome calculator will generate
the syndrome polynomial given by:
S ( x )  S1 x + S 2 x 2 + S 3 x 3 + S 4 x 4 + S 5 x 5 + .. + S 2t x 2t
For the (7,4) BCH encoder above, n=7, k=4, and t=1, hence there are 2t =2 syndromes S1 and S2. This
(7,4) BCH code has 2 minimal polynomials m1(t) and m3(t). S1 is the remainder of the division of the
received codeword by m1 (x). S2 is the remainder of the division of the received codeword by m2 (x).
The syndrome circuit is shown below, and the register contents at the end of each code word are the
syndrome coefficient and are passed to the Berlkamp algorithm to start the error correction process if
they are not all zero.
The Berlkamp algorithm forms the error location polynomial given below and iteratively finds its
roots.
 ( x)  1 + S ( x)  1 + S1x + S2 x2 + S3x3 + S4 x4 + S5 x5 + .. + S2t x2t
The Chien search computes the error locations from the roots of the error location polynomial.
The example shown in Figure 11 is with a single error in the 3rd bit position.
19
Figure 11. Syndrome Calculator for (7,4) BCH decoder
20
6.2
Berlkamp/Peterson Algorithm
The error location polynomial is defined as;
 ( x)   0 +  1 x +  2 x 2 + ..... +   x
where   t . This polynomial can be rewritten as:
 ( x)  (1 + x 1)(1 + x 2 ) ...(1 + x  )
1
1
The roots of (x) are 1 ,  2 .....
1
and are the inverse of the error location numbers. From the
above equations the polynomial coefficients are related to their roots by:

 1    i   1+  2 + ... +  
i 1
 2    i  j   1  2 +  1  3 + ... +   2   +   1  
i j
3 

i j k
i
 j  k   1  2  3 + ... +   3   1   +   2   1  
 n   1  2  3...  2   1  
Newton's identities relate these coefficients to the syndromes by:
S1 +  1  0
S 2 +  1 S1 + 2 2  0
S 3 +  1 S 2 +  2 S1 + 3 3  0
S +  1 S 1 +  2 S  2 +   S1 +  S  0
BCH codes are binary codes and hence
21

n j   j
0
n odd
n even
S2 j  S j
and
with   t errors
2
Newton’s identities then become
S1 +  1  0
S 3 +  1 S 2 +  2 S1 +  3  0
S5 +  1S 4 +  2 S3 +  4 S5 +  5  0
S 2t 1 +  1 S 2t  2 +  2 S 2t 3 + ... +  t S t 1  0
This set of equations can be written in matrix form as
 1
 S
 2
 S4

 S6
 .
 .

 S 2t  4
 S 2t  2
0
0
0
0
0
...
0
S1
1
0
0
0
...
0
S3
S5
.
S2
S4
.
S1
S3
.
1
S2
.
0
S1
.
...
...
...
0
0
.
.
S 2 t 5
S 2 t 3
.
S 2t 6
S 2t  4
.
S 2t 7
S 2 t 5
.
S 2 t 8
S 2t 6
.
S 2 t 9
S 2t 7
...
.
... S t  2
... S t
0    1   S1 
0    2   S 3 
0   3   S5 


 
0   4    S7 
.  .   . 
.  .   . 


 
S t 3   t 1   S 2t 3 
S t 1    t   S 2t 1 
Matrix inversion is computation intensive. Berlkamp developed an iterative approach to solve the
system of equations and it has been referred to as the Berlkamp algorithm. Peterson and later Massey
further refined the algorithm. Lin, later derived a table driven iterative Berlkamp-Peterson algorithm
version. This table approach is based on t steps for Binary BCH decoding. This table is shown below.
-----------------------------------------------------------------------------------------
d
 ( x)
T
k
-----------------------------------------------------------------------------------------0
1
1
1
…
…
…
2
…
…
…
3
…
…
…
..
…
…
…
 (x)
t
…
…
(2k )
(2k )
(2k )
------------------------------------------------------------------------------------------
22
The algorithm is to fill out all the rows starting with the row with the index 1. Once the rows are all
filled out,  (x) corresponding to m=t is the desired error location polynomial. d(2k) is called the
discrepancy. The steps for filling out the rows are as fellows:
1. Set S ( x)  S1 x + S 2 x 2 + S 3 x 3 + ... + S 2t x 2t
2. Set the initial conditions: k=0,  ( 0) ( x)  1 , T ( 0)  1
3. Let d ( 2 k ) be the coefficient of x ( 2 k +1) in the product  ( 2 k ) ( x)1 + S ( x) 
4. Compute  ( 2 k + 2) ( x)   ( 2 k ) ( x) + d ( 2 k ) [ x  T ( 2 k ) ( x)]
 xT ( 2 k ) ( x)

5. Compute T ( 2 k + 2) ( x)   xT ( 2 k ) ( x)

 d ( 2k )
6. Set k=k+1. If k<t go to 3
if
d ( 2 k )  0 or deg[ ( 2 k )  k ]
if
d ( 2 k )  0 or deg[ ( 2 k )  k ]
7. Stop.  ( x)   2t ( x)
Step 3 brings in more and more syndromes as the iterative algorithm progresses.
Let’s run the algorithm on a (15, 5) triple error correcting BCH code. Let’s assume that an all zero
message (00000) is encoded and transmitted as a 15 zero code word. Let’s assume that 3 errors
occurred in the second, seventh, and thirteenth bit positions of the codeword. The received codeword
(010000100000100) is represented by
r ( x)  x + x 6 + x12
The syndromes, S1, S2, S3, S4, S5, and S6, are computed by dividing r(x) by the minimal polynomials.
These syndromes and are given by: S1=S2=S4=1, S3=6 S6=12 S5=5 .
The table is then filled out according to the algorithm and the steps are shown below:
1. S ( x)  x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6
2. k=0
 (0) ( x)  1 + S ( x)   1 + [ x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6 ]  1 + x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6
 d ( 0)  1
 ( 2) ( x)   (0) ( x) + d (0) [ x  T ( 0) ( x)]  1 + x
T ( 2 ) ( x) 
xT ( 2 k ) ( x)
x
d (2k )
23
3. k=1
 ( 2) ( x)1 + S ( x)   (1 + x)[ x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6 ]  1 + 1x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6
 1 + (1 +  6 ) x 3 + ......
 d ( 2)  (1 +  6 )   13
 ( 4) ( x)   ( 2) ( x) + d ( 2) [ x  T ( 2) ( x)]  1 + x +  13 x 2
T ( 4 ) ( x) 
x ( 2) ( x) x(1 + x)
1
1

 13 x + 13 x 2   2 x +  2 x 2
( 2)
13
d



4. k=2
 ( 4) ( x)1 + S ( x)   (1 + x +  13 x 2 )[ x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6 ]  1 + 1x + x 2 +  6 x 3 + x 4 +  5 x 5 +  12 x 6
 1 + .. + (1 +  5 +  19 ) x 5 + ......
 d ( 2)  (1 +  5 +  19 )   2
 ( 6) ( x)   ( 4) ( x) + d ( 4) [ x  T ( 4) ( x)]  1 + x +  11 x 2 +  4 x 3
The results are tabulated below
----------------------------------------------------------------------------------------d (2k )
k
 ( 2 k ) ( x)
T (2k )
-----------------------------------------------------------------------------------------0
1
1
1
1
1+x
x
13
2
1+x+13x2
2x+2x2
2
3
1+x+11x2+4x3
…
…
-----------------------------------------------------------------------------------------The error location polynomial is hence given by:
(x)=1+x+11x2+4x3
6.3
Chien Search Algorithm
The Chien search algorithm is used to find the roots of the error location polynomial given by: (x)=1+x+11x2+4x3.
The roots of (x) can be fond by plugging in all the elements of the GF and picking up the ones that set
(x) to zero, hence:
24
 ( x)  ( x +  3 )( x +  9 )( x +  14 )
 ( x)  (1 +  1 x)(1 +  2 x)(1 +  3 x)
The error locations are then given by:
 1
 2
 3
1
3
1
9
1
 14

 15
  12
3


 15
6
9


 15
 1
14

The 3 errors are in bit positions 13, 7, and 2.
25
7.0
APPENDIX A. C CODE
/*
BCH Encoder Decoder and Simulator
* m = order of the Galois field GF(2**m)
* n = 2**m - 1 = size of the multiplicative group of GF(2**m)
* length = length of the BCH code
* t = error correcting capability (max. no. of errors the code corrects)
* d = 2*t + 1 = designed min. distance = no. of consecutive roots of g(x) + 1
* k = n - deg(g(x)) = dimension (no. of information bits/codeword) of the code
* p[] = coefficients of a primitive polynomial used to generate GF(2**m)
* g[] = coefficients of the generator polynomial, g(x)
* alpha_to [] = log table of GF(2**m)
* index_of[] = antilog table of GF(2**m)
* data[] = information bits = coefficients of data polynomial, i(x)
* bb[] = coefficients of redundancy polynomial x^(length-k) i(x) modulo g(x)
* numerr = number of errors
* errpos[] = error positions
* recd[] = coefficients of the received polynomial
* decerror = number of decoding errors (in _message_ positions)
*
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int
int
int
int
int
int
m, n, length, k, t, d;
p[11];
alpha_to[512], index_of[512], g[15];
recd[511], data[510], bb[510];
seed;
numerr, errpos[512], decerror = 0;
void
read_p()
/*
*
Read m, the degree of a primitive polynomial p(x) used to compute the
*
Galois field GF(2**m). Get precomputed coefficients p[] of p(x). Read
*
the code length.
*/
{
int
i, ninf;
printf("bch3: An encoder/decoder for binary BCH codes\n");
printf("\nFirst, enter a value of m such that the code length is\n");
printf("2**(m-1) - 1 < length <= 2**m - 1\n\n");
do {
printf("Enter m (between 2 and 20): ");
scanf("%d", &m);
} while ( !(m>1) || !(m<21) );
for (i=1; i<m; i++)
p[i] = 0;
p[0] = p[m] = 1;
26
if (m == 2)
else if (m == 3)
else if (m == 4)
else if (m == 5)
else if (m == 6)
else if (m == 7)
else if (m == 8)
else if (m == 9)
else if (m == 10)
else if (m == 11)
else if (m == 12)
else if (m == 13)
else if (m == 14)
else if (m == 15)
else if (m == 16)
else if (m == 17)
else if (m == 18)
else if (m == 19)
else if (m == 20)
printf("p(x) = ");
p[1] = 1;
p[1] = 1;
p[1] = 1;
p[2] = 1;
p[1] = 1;
p[1] = 1;
p[4] = p[5] = p[6] = 1;
p[4] = 1;
p[3] = 1;
p[2] = 1;
p[3] = p[4] = p[7] = 1;
p[1] = p[3] = p[4] = 1;
p[1] = p[11] = p[12] = 1;
p[1] = 1;
p[2] = p[3] = p[5] = 1;
p[3] = 1;
p[7] = 1;
p[1] = p[5] = p[6] = 1;
p[3] = 1;
n = 1;
for (i = 0; i <= m; i++) {
n *= 2;
printf("%1d", p[i]);
}
printf("\n");
n = n / 2 - 1;
ninf = (n + 1) / 2 - 1;
do {
printf("Enter code length (%d < length <= %d): ", ninf, n);
scanf("%d", &length);
} while ( !((length <= n)&&(length>ninf)) );
}
void
generate_gf()
/*
* Generate field GF(2**m) from the irreducible polynomial p(X) with
* coefficients in p[0]..p[m].
*
* Lookup tables:
* index->polynomial form: alpha_to[] contains j=alpha^i;
* polynomial form -> index form: index_of[j=alpha^i] = i
*
* alpha=2 is the primitive element of GF(2**m)
*/
{
register int i, mask;
mask = 1;
alpha_to[m] = 0;
for (i = 0; i < m; i++) {
alpha_to[i] = mask;
index_of[alpha_to[i]] = i;
if (p[i] != 0)
alpha_to[m] ^= mask;
mask <<= 1;
27
}
index_of[alpha_to[m]] = m;
mask >>= 1;
for (i = m + 1; i < n; i++) {
if (alpha_to[i - 1] >= mask)
alpha_to[i] = alpha_to[m] ^ ((alpha_to[i - 1] ^ mask) << 1);
else
alpha_to[i] = alpha_to[i - 1] << 1;
index_of[alpha_to[i]] = i;
}
index_of[0] = -1;
}
void
gen_poly()
/*
* Compute the generator polynomial of a binary BCH code. Fist generate the
* cycle sets modulo 2**m - 1, cycle[][] = (i, 2*i, 4*i, ..., 2^l*i). Then
* determine those cycle sets that contain integers in the set of (d-1)
* consecutive integers {1..(d-1)}. The generator polynomial is calculated
* as the product of linear factors of the form (x+alpha^i), for every i in
* the above cycle sets.
*/
{
register int
ii, jj, ll, kaux;
register int
test, aux, nocycles, root, noterms, rdncy;
int
cycle[1024][21], size[1024], min[1024], zeros[1024];
/* Generate cycle sets modulo n, n = 2**m - 1 */
cycle[0][0] = 0;
size[0] = 1;
cycle[1][0] = 1;
size[1] = 1;
jj = 1;
/* cycle set index */
if (m > 9) {
printf("Computing cycle sets modulo %d\n", n);
printf("(This may take some time)...\n");
}
do {
/* Generate the jj-th cycle set */
ii = 0;
do {
ii++;
cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % n;
size[jj]++;
aux = (cycle[jj][ii] * 2) % n;
} while (aux != cycle[jj][0]);
/* Next cycle set representative */
ll = 0;
do {
ll++;
test = 0;
for (ii = 1; ((ii <= jj) && (!test)); ii++)
/* Examine previous cycle sets */
for (kaux = 0; ((kaux < size[ii]) && (!test)); kaux++)
if (ll == cycle[ii][kaux])
test = 1;
28
} while ((test) && (ll < (n - 1)));
if (!(test)) {
jj++;
/* next cycle set index */
cycle[jj][0] = ll;
size[jj] = 1;
}
} while (ll < (n - 1));
nocycles = jj;
/* number of cycle sets modulo n */
printf("Enter the error correcting capability, t: ");
scanf("%d", &t);
d = 2 * t + 1;
/* Search for roots 1, 2, ..., d-1 in cycle sets */
kaux = 0;
rdncy = 0;
for (ii = 1; ii <= nocycles; ii++) {
min[kaux] = 0;
test = 0;
for (jj = 0; ((jj < size[ii]) && (!test)); jj++)
for (root = 1; ((root < d) && (!test)); root++)
if (root == cycle[ii][jj]) {
test = 1;
min[kaux] = ii;
}
if (min[kaux]) {
rdncy += size[min[kaux]];
kaux++;
}
}
noterms = kaux;
kaux = 1;
for (ii = 0; ii < noterms; ii++)
for (jj = 0; jj < size[min[ii]]; jj++) {
zeros[kaux] = cycle[min[ii]][jj];
kaux++;
}
k = length - rdncy;
if (k<0)
{
printf("Parameters invalid!\n");
exit(0);
}
printf("This is a (%d, %d, %d) binary BCH code\n", length, k, d);
/* Compute the generator polynomial */
g[0] = alpha_to[zeros[1]];
g[1] = 1;
/* g(x) = (X + zeros[1]) initially */
for (ii = 2; ii <= rdncy; ii++) {
g[ii] = 1;
for (jj = ii - 1; jj > 0; jj--)
if (g[jj] != 0)
g[jj] = g[jj - 1] ^ alpha_to[(index_of[g[jj]] + zeros[ii]) % n];
else
29
g[jj] = g[jj - 1];
g[0] = alpha_to[(index_of[g[0]] + zeros[ii]) % n];
}
printf("Generator polynomial:\ng(x) = ");
for (ii = 0; ii <= rdncy; ii++) {
printf("%d", g[ii]);
if (ii && ((ii % 50) == 0))
printf("\n");
}
printf("\n");
}
void
encode_bch()
/*
* Compute redundacy bb[], the coefficients of b(x). The redundancy
* polynomial b(x) is the remainder after dividing x^(length-k)*data(x)
* by the generator polynomial g(x).
*/
{
register int i, j;
register int feedback;
for (i = 0; i < length - k; i++)
bb[i] = 0;
for (i = k - 1; i >= 0; i--) {
feedback = data[i] ^ bb[length - k - 1];
if (feedback != 0) {
for (j = length - k - 1; j > 0; j--)
if (g[j] != 0)
bb[j] = bb[j - 1] ^ feedback;
else
bb[j] = bb[j - 1];
bb[0] = g[0] && feedback;
} else {
for (j = length - k - 1; j > 0; j--)
bb[j] = bb[j - 1];
bb[0] = 0;
}
}
}
void
decode_bch()
/*
* Assume we have received bits in recd[i], i=0..(n-1).
*
* Compute the 2*t syndromes by substituting alpha^i into rec(X) and
* evaluating, storing the syndromes in s[i], i=1..2t (leave s[0] zero) .
* Then we use the Berlekamp algorithm to find the error location polynomial
* elp[i].
*
* If the degree of the elp is >t, then we cannot correct all the errors, and
* we have detected an uncorrectable error pattern. The received data is output uncorrected.
* If the degree of elp is <=t, we substitute alpha^i , i=1..n into the elp
* to get the roots, hence the inverse roots, the error location numbers.
30
* This step is usually called "Chien's search".
*
* If the number of errors located is not equal the degree of the elp, then
* the decoder assumes that there are more than t errors and cannot correct
* them, only detect them. The received data is output uncorrected.
*/
{
register int i, j, u, q, t2, count = 0, syn_error = 0;
int
elp[128][128], d[512], l[512], u_lu[512], s[512];
int
root[512], loc[20], err[512], reg[20];
t2 = 2 * t;
/* first form the syndromes */
printf("S(x) = ");
for (i = 1; i <= t2; i++) {
s[i] = 0;
for (j = 0; j < length; j++)
if (recd[j] != 0)
s[i] ^= alpha_to[(i * j) % n];
if (s[i] != 0)
syn_error = 1; /* set error flag if non-zero syndrome */
/*
* Note: If the code is used only for ERROR DETECTION, then
*
exit program here indicating the presence of errors.
*/
/* convert syndrome from polynomial form to index form */
s[i] = index_of[s[i]];
printf("%3d ", s[i]);
}
printf("\n");
if (syn_error) { /* if there are errors, try to correct them */
/*
* Compute the error location polynomial via the Berlekamp
* iterative algorithm. Following the terminology of Lin and
* Costello's book : d[u] is the 'mu'th discrepancy, where
* u='mu'+1 and 'mu' (the Greek letter!) is the step number
* ranging from -1 to 2*t (see L&C), l[u] is the degree of
* the elp at that step, and u_l[u] is the difference between
* the step number and the degree of the elp.
*/
/* initialise table entries */
d[0] = 0;
/* index form */
d[1] = s[1];
/* index form */
elp[0][0] = 0;
/* index form */
elp[1][0] = 1;
/* polynomial form */
for (i = 1; i < t2; i++) {
elp[0][i] = -1;
/* index form */
elp[1][i] = 0;
/* polynomial form */
}
l[0] = 0;
l[1] = 0;
u_lu[0] = -1;
u_lu[1] = 0;
u = 0;
do {
31
u++;
if (d[u] == -1) {
l[u + 1] = l[u];
for (i = 0; i <= l[u]; i++) {
elp[u + 1][i] = elp[u][i];
elp[u][i] = index_of[elp[u][i]];
}
} else
/*
* search for words with greatest u_lu[q] for
* which d[q]!=0
*/
{
q = u - 1;
while ((d[q] == -1) && (q > 0))
q--;
/* have found first non-zero d[q] */
if (q > 0) {
j = q;
do {
j--;
if ((d[j] != -1) && (u_lu[q] < u_lu[j]))
q = j;
} while (j > 0);
}
/*
* have now found q such that d[u]!=0 and
* u_lu[q] is maximum
*/
/* store degree of new elp polynomial */
if (l[u] > l[q] + u - q)
l[u + 1] = l[u];
else
l[u + 1] = l[q] + u - q;
/* form new elp(x) */
for (i = 0; i < t2; i++)
elp[u + 1][i] = 0;
for (i = 0; i <= l[q]; i++)
if (elp[q][i] != -1)
elp[u + 1][i + u - q] =
alpha_to[(d[u] + n - d[q] + elp[q][i]) % n];
for (i = 0; i <= l[u]; i++) {
elp[u + 1][i] ^= elp[u][i];
elp[u][i] = index_of[elp[u][i]];
}
}
u_lu[u + 1] = u - l[u + 1];
/* form (u+1)th discrepancy */
if (u < t2) {
/* no discrepancy computed on last iteration */
if (s[u + 1] != -1)
d[u + 1] = alpha_to[s[u + 1]];
else
d[u + 1] = 0;
for (i = 1; i <= l[u + 1]; i++)
32
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
d[u + 1] ^= alpha_to[(s[u + 1 - i]
+ index_of[elp[u + 1][i]]) % n];
/* put d[u+1] into index form */
d[u + 1] = index_of[d[u + 1]];
}
} while ((u < t2) && (l[u + 1] <= t));
u++;
if (l[u] <= t) {/* Can correct errors */
/* put elp into index form */
for (i = 0; i <= l[u]; i++)
elp[u][i] = index_of[elp[u][i]];
printf("sigma(x) = ");
for (i = 0; i <= l[u]; i++)
printf("%3d ", elp[u][i]);
printf("\n");
printf("Roots: ");
/* Chien search: find roots of the error location polynomial */
for (i = 1; i <= l[u]; i++)
reg[i] = elp[u][i];
count = 0;
for (i = 1; i <= n; i++) {
q = 1;
for (j = 1; j <= l[u]; j++)
if (reg[j] != -1) {
reg[j] = (reg[j] + j) % n;
q ^= alpha_to[reg[j]];
}
if (!q) { /* store root and error
* location number indices */
root[count] = i;
loc[count] = n - i;
count++;
printf("%3d ", n - i);
}
}
printf("\n");
if (count == l[u])
/* no. roots = degree of elp hence <= t errors */
for (i = 0; i < l[u]; i++)
recd[loc[i]] ^= 1;
else
/* elp has degree >t hence cannot solve */
printf("Incomplete decoding: errors detected\n");
}
}
}
main()
{
int
i;
read_p();
generate_gf();
gen_poly();
/* Read m */
/* Construct the Galois Field GF(2**m) */
/* Compute the generator polynomial of BCH code */
33
/* Randomly generate DATA */
seed = 131073;
srand(seed);
for (i = 0; i < k; i++)
data[i] = (rand() & 65536/16) >>12;
encode_bch();
/* encode data */
/*
* recd[] are the coefficients of c(x) = x**(length-k)*data(x) + b(x)
*/
for (i = 0; i < length - k; i++)
recd[i] = bb[i];
for (i = 0; i < k; i++)
recd[i + length - k] = data[i];
printf("Code polynomial:\nc(x) = ");
for (i = 0; i < length; i++) {
printf("%1d", recd[i]);
if (i && ((i % 50) == 0))
printf("\n");
}
printf("\n");
printf("Enter the number of errors:\n");
scanf("%d", &numerr); /* CHANNEL errors */
printf("Enter error locations (integers between");
printf(" 0 and %d): ", length-1);
/*
* recd[] are the coefficients of r(x) = c(x) + e(x)
*/
for (i = 0; i < numerr; i++)
scanf("%d", &errpos[i]);
if (numerr)
for (i = 0; i < numerr; i++)
recd[errpos[i]] ^= 1;
printf("r(x) = ");
for (i = 0; i < length; i++) {
printf("%1d", recd[i]);
if (i && ((i % 50) == 0))
printf("\n");
}
printf("\n");
decode_bch();
/* DECODE received codeword recv[] */
/*
* print out original and decoded data
*/
printf("Results:\n");
printf("original data = ");
for (i = 0; i < k; i++) {
printf("%1d", data[i]);
if (i && ((i % 50) == 0))
printf("\n");
}
printf("\nrecovered data = ");
34
for (i = length - k; i < length; i++) {
printf("%1d", recd[i]);
if ((i-length+k) && (((i-length+k) % 50) == 0))
printf("\n");
}
printf("\n");
/*
* DECODING ERRORS? we compare only the data portion
*/
for (i = length - k; i < length; i++)
if (data[i - length + k] != recd[i])
decerror++;
if (decerror)
printf("There were %d decoding errors in message positions\n", decerror);
else
printf("Succesful decoding\n");
}
35
8.0
APPENDIX B C PROGRAM OUTPUT
36
Download