Theory: Character Codes: BCD, EBCDIC, ASCII & Unicode
A computer only stores bit patterns, but people type letters, digits and punctuation. A character code is simply an agreed table that maps each human-readable character to a fixed bit pattern, so that the keyboard, the memory, the printer and every other computer that uses the same table agree on what 01000001 means. This lesson follows the historical path of the main codes (Null & Lobur, Ch. 2): BCD → EBCDIC → ASCII → Unicode. Each step exists because the previous code ran out of room.
| Code | Bits per character | Characters possible | Where it is used |
|---|
| BCD (6-bit) | 6 | 26=64 | IBM mainframes, 1950s–60s |
| EBCDIC | 8 | 28=256 | IBM mainframes (still today) |
| ASCII | 7 (+1 parity) | 27=128 | Almost everything outside IBM mainframes |
| Unicode | 21-bit code space (stored as 8/16/32-bit units) | 1,114,112 code points | Modern OSes, Java, the web |
Binary-Coded Decimal (BCD)
Intuition: business computers mostly handled decimal amounts (money, quantities). Instead of converting a whole number to binary, BCD encodes each decimal digit separately in 4 bits. That makes conversion to and from printed decimal trivial and avoids binary-fraction rounding of amounts like 0.10.
The rule: each digit 0–9 becomes its 4-bit binary value. The six patterns 1010–1111 are never used for digits.
| Digit | BCD | Digit | BCD |
|---|
| 0 | 0000 | 5 | 0101 |
| 1 | 0001 | 6 | 0110 |
| 2 | 0010 | 7 | 0111 |
| 3 | 0011 | 8 | 1000 |
| 4 | 0100 | 9 | 1001 |
Mini-example
30510 in BCD is 0011 0000 0101 (3 → 0011, 0 → 0000, 5 → 0101). Compare with pure binary: 30510=1001100012. The BCD form is longer (12 bits vs 9) but every nibble can be read off as a decimal digit.
Zone and digit
When BCD is stored one digit per byte, the byte is split into two nibbles: the high nibble is the zone and the low nibble is the digit. The zone tells us how to interpret the digit:
| Zone (high nibble) | Meaning |
|---|
| 1111 | unsigned digit |
| 1100 | positive (+) |
| 1101 | negative (−) |
So +4 is stored as zone 1100, digit 0100: 1100 0100. In a multi-digit zoned decimal number, every digit gets zone 1111 except the last (rightmost) digit, whose zone carries the sign.
Packed BCD and the sign nibble
Storing a whole byte per digit wastes half the bits, so packed BCD puts two digits per byte and places the sign in a final sign nibble at the right-hand end: 1100 = +, 1101 = −, 1111 = unsigned. If the digits plus the sign nibble make an odd number of nibbles, a leading 0000 is added so the number fills whole bytes.
Mini-example
−26 in packed BCD: digits 0010 0110, sign 1101 → three nibbles, so pad on the left with 0000:
0000 0010 | 0110 1101 = 02 6D (hex)
pad 2 6 sign(−)
EBCDIC
In 1964 IBM extended 6-bit BCD to the 8-bit Extended Binary-Coded Decimal Interchange Code (EBCDIC). It was one of the first widely used codes with both upper- and lowercase letters plus punctuation and control characters, and it is still used on IBM mainframes.
EBCDIC keeps the zone | digit idea: the high nibble (zone) picks a row of the code table and the low nibble (digit) picks a column. Some landmarks worth remembering:
| Character(s) | Zone | Digits | Hex |
|---|
| space | 0100 | 0000 | 40 |
| a – i | 1000 | 0001–1001 | 81–89 |
| j – r | 1001 | 0001–1001 | 91–99 |
| s – z | 1010 | 0010–1001 | A2–A9 |
| A – I | 1100 | 0001–1001 | C1–C9 |
| J – R | 1101 | 0001–1001 | D1–D9 |
| S – Z | 1110 | 0010–1001 | E2–E9 |
| 0 – 9 | 1111 | 0000–1001 | F0–F9 |
Notice the digits: zone 1111 + the BCD digit, exactly the “unsigned” zone from BCD. The letters are not contiguous (there are gaps after I and R), a leftover of punched-card codes.
Mini-example
“A” in EBCDIC: row 1100, column 0001 → 1100 0001 = C1. The digit “7”: 1111 0111 = F7.
ASCII
Other manufacturers adopted the 7-bit American Standard Code for Information Interchange (ASCII). BCD/EBCDIC came from punched-card codes; ASCII came from telecommunications (Telex) codes. It became the dominant code outside the IBM world.
With 7 bits there are 27=128 codes, hex 00–7F:
| Range (hex) | Contents |
|---|
| 00–1F, 7F | control characters (NUL, LF = 0A, CR = 0D, ESC = 1B, DEL = 7F …) |
| 20 | space |
| 30–39 | digits “0”–“9” |
| 41–5A | “A”–“Z” |
| 61–7A | “a”–“z” |
Three anchors let you derive almost any ASCII code: “0” = 30 hex (48), “A” = 41 hex (65), “a” = 61 hex (97). Count forward from the anchor. Upper and lower case differ by exactly 20 hex (32), i.e. a single bit (bit 5). In Excel, =CODE("A") gives 65 and =CHAR(65) gives “A”; =DEC2BIN(65) gives 1000001.
Mini-example
“K” is the 11th letter, so its code is 4116+10=4B16=7510. In 7 bits: 4B16=100 10112.
Parity bits (even and odd)
A 7-bit code fits in an 8-bit byte with one bit to spare. Early systems used that spare bit as a parity bit, the simplest error-detecting code. It is placed in the leftmost (8th) position.
- Even parity: choose the parity bit so the total number of 1s in all 8 bits is even.
- Odd parity: choose it so the total number of 1s is odd.
Procedure:
- Write the 7-bit code and count its 1s.
- Even parity: parity bit = 1 if the count is odd, else 0. Odd parity: parity bit = 1 if the count is even, else 0.
- Prepend the parity bit.
To check a received byte, count all eight 1s: if the count does not have the agreed parity, an error has occurred.
Mini-example (as in the lecture)
- ASCII “C” = 100 0011 has three 1s. Odd parity needs an odd total, which it already has, so parity bit = 0 →
0100 0011.
- ASCII “A” = 100 0001 has two 1s. Odd parity → parity bit = 1 →
1100 0001.
- Under even parity, is
1000 0011 correct? It contains three 1s, an odd count, so an error is detected.
A single parity bit detects any odd number of flipped bits but misses an even number: if two bits flip, the count of 1s keeps its parity and the error goes unnoticed. Parity can also only detect: it cannot tell you which bit is wrong. As hardware became more reliable, the parity bit was often dropped and the 8th bit used instead for an extended character set (128 more characters: accented letters, line-drawing and math symbols, Thai characters in TIS-620, etc.).
Unicode
Most of today’s systems use Unicode, which aims to give every character of every writing system a unique number. Java and many operating systems use it as their default character code. The original Unicode was a 16-bit code, and Null & Lobur describe its 16-bit code space in broad blocks:
| Character types | Language | Number of characters | Hex values |
|---|
| Alphabets | Latin, Greek, Cyrillic, etc. | 8192 | 0000–1FFF |
| Symbols | Dingbats, mathematical, etc. | 4096 | 2000–2FFF |
| CJK | Chinese, Japanese, Korean phonetic symbols and punctuation | 4096 | 3000–3FFF |
| Han | Unified Chinese, Japanese and Korean | 40,960 | 4000–DFFF |
| Han expansion | | 4096 | E000–EFFF |
| User defined | | 4095 | F000–FFFE |
Code points and planes. Each character is identified by a code point, written U+ followed by hex digits (e.g. U+0041). Modern Unicode (version 15) uses a 21-bit code space from U+0000 to U+10FFFF, divided into 17 planes of 216=65,536 code points each:
| Plane | Range | Contents |
|---|
| 0 — Basic Multilingual Plane (BMP) | U+0000 – U+FFFF | almost all commonly used characters |
| 1 – 16 — supplementary planes | U+10000 – U+10FFFF | ancient scripts, rare CJK, symbols, emoji, private use |
- The plane number of a code point is everything above its low 16 bits: plane = code point ÷65536 (integer part), i.e. the hex digits in front of the last four.
- The lowest 128 code points, U+0000 to U+007F, are exactly ASCII, so ASCII text is already valid Unicode.
- Total code points: 17×65,536=1,114,112; the largest, 10FFFF16, needs 21 bits.
Mini-example
“A” = U+0041 (plane 0, same value as ASCII 41). ”€” = U+20AC (plane 0, in the symbols block 2000–2FFF). ”😀” = U+1F600: the digits in front of the last four are “1”, so it lies in plane 1, outside the BMP.
A code point is a number; an encoding form says how that number is stored. UTF-16 stores every BMP character in one 16-bit unit and a supplementary character in two units (a surrogate pair); UTF-8 uses 1 to 4 bytes and stores ASCII characters in a single byte unchanged.
Converting text to codes: the general procedure
- Look up each character’s code (ASCII/EBCDIC table or Unicode code point), usually as hex.
- Convert each hex digit to 4 bits (ASCII: drop the leading 0 to get 7 bits).
- If a parity scheme is used, count the 1s and prepend the parity bit.
- Write the bytes in order, left to right as the text is read.
Decoding runs the same steps backwards: check parity, strip the parity bit, look up the 7-bit value.
Worked Examples
Exercise 1
Encode the word CAT in 7-bit ASCII. Give each character in decimal, hex and binary, then give the 8-bit bytes with (a) even parity and (b) odd parity.
Show solution ↓Hide solution ↑
Solution
Step 1: look up the codes. Using the anchor “A” = 4116: C is 2 letters after A, T is 19 letters after A.
| Char | Decimal | Hex | 7-bit binary | Number of 1s |
|---|
| C | 67 | 43 | 100 0011 | 3 |
| A | 65 | 41 | 100 0001 | 2 |
| T | 84 | 54 | 101 0100 | 3 |
(Check T: 4116+19=4116+1316=5416=8410 ✓.)
Step 2: (a) even parity. The parity bit makes the total number of 1s even, so it is 1 when the 7-bit count is odd.
| Char | Count | Parity bit | Byte | Hex |
|---|
| C | 3 (odd) | 1 | 1100 0011 | C3 |
| A | 2 (even) | 0 | 0100 0001 | 41 |
| T | 3 (odd) | 1 | 1101 0100 | D4 |
Step 3: (b) odd parity. The parity bit is the complement of the even-parity bit.
| Char | Parity bit | Byte | Hex |
|---|
| C | 0 | 0100 0011 | 43 |
| A | 1 | 1100 0001 | C1 |
| T | 0 | 0101 0100 | 54 |
Check: even-parity C = 1100 0011 has four 1s (even) ✓; odd-parity A = 1100 0001 has three 1s (odd) ✓.
Exercise 2
Encode the message “OK” in ASCII with even parity. (This is the message used for all the recording codes in the next section.)
Show solution ↓Hide solution ↑
Solution
“O”: O is the 15th letter, so 4116+14=4116+E16=4F16=7910.
4F16=100 11112⇒five 1s (odd)⇒parity bit=1
O = 1100 1111.
“K”: 4116+10=4B16=7510.
4B16=100 10112⇒four 1s (even)⇒parity bit=0
K = 0100 1011.
Message: 11001111 01001011 (16 bits). Check: O has six 1s, K has four 1s, both even ✓.
In Excel: =CODE("O") → 79 and =DEC2BIN(79) → 1001111; then add the parity bit by hand.
Exercise 3
A receiver uses 7-bit ASCII with even parity. Which of these received bytes contain a detectable error? For the good ones, give the character.
(a) 1000 0011 (b) 0100 0001 (c) 1100 1001 (d) 0111 0001 (e) 1101 0111
Show solution ↓Hide solution ↑
Solution
Count all eight bits. Even parity requires an even count.
| Byte | Number of 1s | Parity OK? | 7-bit code | Character |
|---|
| (a) 1000 0011 | 3 | ✗ error | — | — |
| (b) 0100 0001 | 2 | ✓ | 100 0001 = 41 | A |
| (c) 1100 1001 | 4 | ✓ | 100 1001 = 49 | I |
| (d) 0111 0001 | 4 | ✓ | 111 0001 = 71 | q |
| (e) 1101 0111 | 6 | ✓ | 101 0111 = 57 | W |
Only (a) is detected as an error (it is the lecture’s example: “C” would be 1100 0011 under even parity, and the leading parity bit has been flipped).
“Parity OK” does not prove the byte is correct. If (e) had been sent as “U” = 0101 0101 (four 1s) and two bits flipped to give 1101 0111, the count would still be even and the error would pass unnoticed.
Exercise 4
Write each signed decimal number in (i) zoned decimal (one digit per byte) and (ii) packed BCD, giving binary and hex.
(a) +4 (b) +305 (c) −1265
Show solution ↓Hide solution ↑
Solution
Rules: zoned decimal puts zone 1111 on every digit except the last, whose zone is the sign (1100 = +, 1101 = −). Packed BCD writes the digits two per byte and ends with a sign nibble, padding with a leading 0000 if needed.
(a) +4
- Zoned: one digit, zone = + →
1100 0100 = C4.
- Packed: digit 0100, sign 1100 →
0100 1100 = 4C.
(b) +305 (digits 0011, 0000, 0101)
- Zoned:
1111 0011 | 1111 0000 | 1100 0101 = F3 F0 C5.
- Packed: 3 digits + sign = 4 nibbles (even, no padding):
0011 0000 | 0101 1100 = 30 5C.
(c) −1265 (digits 0001, 0010, 0110, 0101)
- Zoned:
1111 0001 | 1111 0010 | 1111 0110 | 1101 0101 = F1 F2 F6 D5.
- Packed: 4 digits + sign = 5 nibbles (odd) → pad with 0000:
0000 0001 | 0010 0110 | 0101 1101 = 01 26 5D
pad 1 2 6 5 sign(−)
Check (c) by decoding the packed form: nibbles 0,1,2,6,5 → 01265, sign nibble 1101 → negative → −1265 ✓.
Exercise 5
Encode the text IBM 7 (five characters including the space) in EBCDIC and in ASCII. Give hex and binary.
Show solution ↓Hide solution ↑
Solution
EBCDIC (zone | digit from the code table):
- I: letters A–I use zone 1100 and digits 0001–1001; I is the 9th →
1100 1001 = C9.
- B: 2nd letter →
1100 0010 = C2.
- M: J–R use zone 1101; M is the 4th of that group (J, K, L, M) →
1101 0100 = D4.
- space:
0100 0000 = 40.
- 7: zone 1111, digit 0111 →
1111 0111 = F7.
ASCII (7-bit, shown with a leading 0 in 8 bits):
- I: 4116+8=4916 →
0100 1001
- B: 4216 →
0100 0010
- M: 4116+12=4D16 →
0100 1101
- space: 2016 →
0010 0000
- 7: 3016+7=3716 →
0011 0111
| Char | EBCDIC | ASCII |
|---|
| I | C9 | 49 |
| B | C2 | 42 |
| M | D4 | 4D |
| space | 40 | 20 |
| 7 | F7 | 37 |
The same text gives completely different bytes, which is why a file must be converted when moved between an IBM mainframe and an ASCII system.
Exercise 6
For each character give its Unicode code point, its plane, and whether it is in the BMP: (a) “A” (b) Thai “ก” (U+0E01) (c) ”€” (U+20AC) (d) ”😀” (U+1F600). Then (e) how many code points does Unicode have and how many bits are needed for the largest one?
Show solution ↓Hide solution ↑
Solution
The plane is the part of the code point in front of the last four hex digits (code point ÷216).
| Char | Code point | Plane | In BMP? | Block (Null & Lobur layout) |
|---|
| (a) A | U+0041 | 0 | yes | alphabets; equals ASCII 41 |
| (b) ก | U+0E01 | 0 | yes | alphabets (0000–1FFF) |
| (c) € | U+20AC | 0 | yes | symbols (2000–2FFF) |
| (d) 😀 | U+1F600 | 1 | no | supplementary plane |
For (d): 1F60016÷1000016=1 remainder F60016, so plane 1.
(e) 17 planes × 65,536=1,114,112 code points (U+0000 to U+10FFFF). The largest, 10FFFF16=1000011111111111111112, has 21 bits, so Unicode is a 21-bit code space.
Exercise 7
A terminal receives the hex bytes 53 C9 D4 using 7-bit ASCII with even parity. Check the parity of each byte and decode the message.
Show solution ↓Hide solution ↑
Solution
| Hex | Binary | Number of 1s | Parity | Strip parity bit | 7-bit hex | Char |
|---|
| 53 | 0101 0011 | 4 | ✓ even | 101 0011 | 53 | S |
| C9 | 1100 1001 | 4 | ✓ even | 100 1001 | 49 | I |
| D4 | 1101 0100 | 4 | ✓ even | 101 0100 | 54 | T |
All three bytes pass, and the message is “SIT”.
Check by re-encoding: S = 101 0011 has four 1s → parity 0 → 53 ✓; I = 100 1001 has three 1s → parity 1 → C9 ✓; T = 101 0100 has three 1s → parity 1 → D4 ✓.