BCD Explained: How Binary Coded Decimal Keeps Clocks and Displays Honest
A plain guide to binary coded decimal (BCD): how each digit gets its own 4-bit nibble, why hardware prefers it over pure binary, and the size cost.
BCD Explained: How Binary Coded Decimal Keeps Clocks and Displays Honest
The first time I wired a four-digit LED display to a microcontroller, I had a number sitting in a variable and four little glowing digits that refused to show it. The data sheet kept saying "BCD input," and I had no idea why the chip wanted decimal dressed up as binary instead of the binary the rest of my code already spoke. That confusion is the whole story of binary coded decimal, so let me lay it out the way I wish someone had laid it out for me.
One digit, one nibble
Pure binary takes a whole number and converts it in one shot. The value 25 becomes 11001 — five bits, no respect for where one decimal digit ends and the next begins. BCD does something different and almost stubborn: it encodes each decimal digit separately, in its own group of four bits.
So in BCD, the number 25 is two nibbles. The digit 2 becomes 0010, the digit 5 becomes 0101, and you write them side by side: 0010 0101. The exact same value, 25, is 11001 in pure binary but 0010 0101 in BCD. Those are not two ways of writing the same bits — they are genuinely different bit patterns that happen to mean the same quantity.
The four bits use the standard 8421 weighting, which just means the positions carry the values 8, 4, 2 and 1, left to right. Add up the positions that hold a 1 and you get the digit. The digit 7 is 0111, because 4 + 2 + 1 = 7. The digit 9 is 1001, because 8 + 1 = 9. Nothing past 9 ever appears, which becomes important in a moment.
Why the wasted bits buy you something
Here is the catch that bothers everyone at first. Four bits can count from 0 to 15, but a single decimal digit only goes up to 9. That means BCD throws away six of the sixteen possible patterns for every nibble. The codes 1010, 1011, 1100, 1101, 1110 and 1111 are simply illegal — they never stand for a valid decimal digit. A good converter treats them as an error rather than guessing, which is exactly what the BCD Converter does when you feed it a stray nibble.
That waste is real, and it scales. But it buys two things that pure binary cannot give you cheaply.
The first is trivial display logic. A seven segment display, the kind in clocks and microwaves, shows one digit at a time. If your number is already chopped into per-digit nibbles, each nibble maps straight to a display digit with no division, no modulo, no remainder math. The hardware reads four bits and lights up the right segments. Pure binary would force the chip to repeatedly divide by ten to peel off decimal digits, and division in cheap silicon is expensive.
The second is exactness. BCD never inherits binary's fractional rounding. A value like 0.1 has no clean binary representation — it repeats forever, the same way 1/3 does in decimal — so floating point quietly rounds it. Store cents as BCD digits instead and 10 cents is always exactly 0001 0000, with no drift to chase down three months later in an accounting report.
A worked example: 1990 in BCD
Take 1990 and walk it through by hand. Split it into its four digits: 1, 9, 9, 0.
- 1 becomes 0001
- 9 becomes 1001 (8 + 1)
- 9 becomes 1001 (8 + 1)
- 0 becomes 0000
Line them up and the grouped BCD is 0001 1001 1001 0000. Strip the spaces and the packed form is 0001100110010000. That is 16 bits to hold a number that pure binary fits into 11 bits (1990 is 11111000110). The cost of BCD is right there in those extra five bits.
Now the neat trick. Read each nibble as a hexadecimal digit — 0001 is 1, 1001 is 9, 1001 is 9, 0000 is 0 — and the packed BCD literally spells out 1990 in hex. This is why register dumps of packed BCD look like the decimal value staring back at you. An old calculator or a real time clock chip storing the year as packed BCD shows 0x1990 in a debugger, and you read the year without converting anything.
Where BCD actually shows up
It is tempting to file BCD under "historical curiosity," but it is still load-bearing in a few places:
- Real time clock chips. RTC modules store hours, minutes and seconds in packed BCD. A reading of 0010 0011 is not 35 — it is 23, two nibbles, 2 and 3. Misread it as plain binary and your clock jumps an hour.
- Seven segment and LED displays. Decoder chips that drive multiplexed digits expect one BCD nibble per digit, for the no-division reason above.
- Financial and legacy code. Anywhere cents must stay exact, packed BCD sidesteps floating point entirely. Some database decimal types and older COBOL fixed-point routines lean on the same idea.
When you do need to cross over into raw binary — say you grabbed a value that turned out not to be BCD at all — that is a job for a base converter instead, which reads the bits as a single binary integer rather than per-digit nibbles.
Reading BCD without tripping over it
Two mistakes catch people, and both come from forgetting that BCD is grouped, not continuous.
First, never parse a BCD string as one binary number. The bits 0001100110010000 mean 1990 in BCD but a completely different, much larger value if you treat them as a single binary integer. The grouping is the whole point; ignore it and the number is gibberish.
Second, BCD lengths must be a multiple of four. A string like 000110011001000 — fifteen bits, not sixteen — has no clean nibble boundary, so there is no honest way to split it into digits. Pad each group to a full four bits before you decode, and if a nibble lands on 1010 or higher, the data is corrupt, misaligned, or was actually plain binary the whole time.
That is the entire shape of binary coded decimal: one decimal digit per nibble, six forbidden patterns, more bits than binary, and in exchange, base ten that stays exact and prints itself. Once the per-digit grouping clicks, the LED display that ignored me all those years ago suddenly makes perfect sense — it was never being difficult, it just wanted its digits handed over one nibble at a time.
Made by Toolora · Updated 2026-06-13