The number 255 and the notations 0xFF, 0o377 and 0b11111111 are four different outfits worn by the same value. Nothing about that number "is" decimal — base ten is a habit we inherited from the anatomy of our hands, not a property of the number itself. A computer has no such habit: its world ends at two voltage states. Every notation a programmer meets on screen grows out of that mismatch — the machine counts differently than a human thinks, and somebody has to compromise.
Value is not notation
In a positional system, every digit carries a weight determined by where it sits. A number in base r decomposes into a sum of powers:
N = aₙ·rⁿ + aₙ₋₁·rⁿ⁻¹ + … + a₁·r¹ + a₀·r⁰, where the digits aᵢ range from 0 to r−1.
The base is a convention. So are the glyphs: we write the values ten through fifteen as A–F purely because the alphabet was lying around. What is not a convention is the arithmetic — converting between bases rounds nothing and loses nothing, because it does not change the value, only its clothing.
Hence the classic beginner's stumble: the notation 10 means nothing on its own. In binary it is two, in octal eight, in hexadecimal sixteen. Without a declared base, a string of digits is just a graphic pattern.
For any of this to work, you need zero — not as "nothing", but as a marker for an empty column, the thing that tells 205 apart from 25. The Babylonians, who built an impressive sexagesimal system (we tell that story in why an hour has 60 minutes), never had a consistent zero, so the value had to be read from context. Indian mathematicians closed the gap: the bindu dot in the Bakhshali manuscript (Oxford's radiocarbon dating points to the 3rd–4th century CE, though it is disputed) was the seed of today's symbol, and in 628 CE Brahmagupta was the first to write down the rules of arithmetic for zero — treating it as a number in its own right, not a hole in the notation.
Why the machine picked two
The computer's choice of base two has nothing to do with mathematical elegance. It has everything to do with the physics of semiconductors. In a digital circuit, a transistor works as a voltage-driven switch with two extreme regimes: cut-off (no current flows — a logical 0) and saturation (current flows freely — a logical 1).
The decisive property is noise immunity. Voltage in a real circuit wobbles: silicon heats up, a neighbouring trace radiates, materials age. With two states the margin is enormous — a signal can drift by more than ten percent and still be classified, without error, as "high" or "low". If a processor counted in decimal, it would have to distinguish ten voltage bands inside the same range; each would be ten times narrower, and the circuit ten times easier for noise to fool. On top of that, dissipated power grows with the square of voltage (P = V²/R), so pushing the levels further apart to make room costs heat.
Binary won not because it is the best, but because it is the hardest to break.
On paper, base three was winning
Engineering has a name for this trade-off: radix economy. The cost of representing numbers in a given base is estimated as the base B times the number of digit positions needed — roughly B·log_B(N). The assumption comes from the classic 1950 study High-Speed Computing Devices, where one digit in base B cost exactly B physical components.
Treat the base as a continuous variable, minimise the function, and the answer is startling: the optimum lands precisely on e ≈ 2.718. Since a physical machine needs a whole-number base, the nearest sensible candidate is three, not two.
And somebody built it. In 1958, at Moscow State University, Nikolai Brusentsov's team switched on Setun — a ternary computer running balanced ternary, on states −1, 0 and +1. The benefit was real: if the digit carries its own sign, the machine needs no separate sign bit, and subtraction is simply adding the negative. Dozens of units were produced, the machine worked, and its users liked it.
It lost anyway — not to mathematics, but to economies of scale. Mass production of two-state silicon transistors drove their price down so hard that base three's theoretical savings stopped meaning anything. It is the classic technology story: the winner is never the optimum, it is whatever can be stamped out a billion times cheaply.
Leibniz, hexagrams and a medal for the creation of the world
Binary itself predates silicon by three centuries. Thomas Harriot worked on it, and Gottfried Wilhelm Leibniz developed it — in the March 1679 manuscript De Progressione Dyadica he laid out an arithmetic using nothing but 0 and 1.
For Leibniz, though, this was first of all theology. He identified 1 with God and 0 with nothingness, and argued that if every number can be generated from those two marks, then we are looking at a mathematical image of creation out of nothing. He took the idea seriously enough to design, with Duke Rudolph August, a commemorative medal — Imago Creationis — with a binary table illustrating the act of creation.
The punchline came from China. The Jesuit Joachim Bouvet, a missionary at the court of the Kangxi Emperor, sent Leibniz a letter dated 4 November 1701 (it only reached him in the spring of 1703) containing the diagram of the 64 Fu Xi hexagrams from the I Ching. Each hexagram is six lines in two states: broken yin and solid yang. Arranged in the right order, they form a perfect sequence of the numbers 0 to 63 — a six-bit counter in Chinese dress, read in the opposite direction. Later that same year, Leibniz published Explication de l'arithmétique binaire.
Hexadecimal is a human interface
The machine reads bits flawlessly. People do not. A string like 11111111 is still manageable, but a memory address or a debugger dump loses the eye within seconds. What was needed was a compact notation that nevertheless keeps its link to the bits.
The solution follows straight from arithmetic: 8 = 2³ and 16 = 2⁴. Conversion therefore requires no calculation at all — you just slice the bit string into chunks:
- Hexadecimal groups bits by four (that quartet is a nibble, half a byte). Each quartet maps to exactly one character from 0–9 and A–F, so a byte is always two characters:
11111111→FF. - Octal groups bits by three. Its heyday came on machines whose word length divided by three — the 12-bit PDP-8, the 36-bit PDP-10. Curiously, octal also stuck on the 16-bit PDP-11, even though 16 is not divisible by 3: there the unit that mattered was not the word but the instruction field, which was laid out precisely in three-bit groups.
Hex, then, is not a "prettier" notation. It is a notation you can unpack back into bits in your head — and that is the whole of its value.
How to do it on paper
Converting from decimal to any other base comes down to division with remainder: divide the number by the target base, note the remainder, repeat with the quotient, until you reach zero. Reading the remainders from last to first gives you the finished notation.
Take 255. In base 16: 255 ÷ 16 = 15 remainder 15, then 15 ÷ 16 = 0 remainder 15. Both remainders are fifteen, the digit F — hence FF. In base 8: 255 ÷ 8 = 31 remainder 7, 31 ÷ 8 = 3 remainder 7, 3 ÷ 8 = 0 remainder 3, giving 377. In base 2 you get eight ones in a row. All four notations describe exactly the same value:
255₁₀ = 0b11111111 = 0o377 = 0xFF
If you would rather not do it by hand, our number systems converter shows all four bases at once and accepts numbers of any size — it runs on arbitrary-precision arithmetic, so nothing gets rounded along the way.
Where you actually meet this
Hex and octal are not decorations for theorists. They sit inside tools you use every day.
Colours. In the RGB model each of the three channels fits in a single byte, the range 0–255 — which is exactly two hex characters. That is why #RRGGBB has six of them: #FFFFFF is white (255, 255, 255), #000000 is black, and #00FF00 is pure green with the G channel pushed to maximum.
Addresses. Memory addresses (0x002F7C1A) and network MAC addresses are written in hex because one character corresponds to four address lines. A MAC is 48 bits, so six pairs of characters: 00:1A:2B:3C:4D:5E.
Unix permissions. Here octal rules — and not by accident. File permissions split into three groups (owner, group, others), and each group holds three independent bits: read, write, execute. Three bits are exactly one octal digit.
| Digit | Bits | Symbolic | What it grants |
|---|---|---|---|
| 7 | 111 | rwx | read, write and execute — full rights |
| 6 | 110 | rw- | read and write, no execution |
| 5 | 101 | r-x | read and execute, no modification |
| 4 | 100 | r-- | read only |
| 0 | 000 | --- | no rights at all |
So when you type chmod 755 script.sh, you are not reciting a magic formula: you give the owner 7 (4+2+1 = rwx), and the group and the rest of the world 5 (4+1 = r-x). Three digits, nine bits, zero ambiguity.
The leading-zero trap
Since the same digits mean different things in different bases, a compiler has to tell binary 10 from decimal 10 somehow. The history of those markers is a small museum of design decisions — and the source of one of the most insidious bugs in programming.
| Language | Octal | Hexadecimal | Why it was done that way |
|---|---|---|---|
| BCPL (1960s) | # | #x | The first attempt at unambiguous syntax. |
| B (Thompson) | 0 | none | A leading zero told the parser: this is a number, not a name. |
| C (Ritchie) | 0 (e.g. 010) | 0x (e.g. 0x1A) | The leading zero carried over from B; 0x came from BCPL. |
| Modern (ES6) | 0o | 0x, 0b | An explicit prefix, to end the leading-zero ambiguity. |
That single decision of Ritchie's — keeping the leading zero as an octal marker — still takes its revenge. In C, C++, Java, Ruby and Python 2, the notation 010 is not ten; it is eight (1·8¹ + 0·8⁰ = 8). The conversion happens during tokenisation, before the program even runs, so the compiler does not so much as blink.
It sounds harmless until you align a column of numbers with leading zeros, or paste in a postcode, a bank account number or a product ID that starts with a zero. At that point one of your values quietly stops being the one you can see on screen.
Languages have since armoured themselves. Python 3 requires an explicit 0o and rejects a bare 010 as a syntax error. Modern JavaScript in strict mode ('use strict') treats a legacy octal literal as a SyntaxError rather than silently swapping the value, and since ES6 it has the safe 0o and 0b prefixes. While we are here, let us defuse a popular myth: parseInt('010') returns 10 in today's engines, not 8 — automatic octal detection was cut from the language years ago. Writing parseInt('010', 10) is still a good habit, just not because the engine is still guessing.
Equivalence table
| Dec | Bin | Oct | Hex | Why this value matters |
|---|---|---|---|---|
| 0 | 0b0 | 0o0 | 0x0 | A transistor in cut-off |
| 1 | 0b1 | 0o1 | 0x1 | The high state — a single bit |
| 7 | 0b111 | 0o7 | 0x7 | The largest octal digit; rwx |
| 8 | 0b1000 | 0o10 | 0x8 | The number of bits in a byte |
| 10 | 0b1010 | 0o12 | 0xA | The first "letter" in hex |
| 15 | 0b1111 | 0o17 | 0xF | The maximum of a nibble |
| 16 | 0b10000 | 0o20 | 0x10 | The hex base — where the notation rolls over |
| 64 | 0b1000000 | 0o100 | 0x40 | The number of I Ching hexagrams (2⁶) |
| 127 | 0b1111111 | 0o177 | 0x7F | The edge of 7-bit ASCII |
| 128 | 0b10000000 | 0o200 | 0x80 | The first value with the top bit set |
| 255 | 0b11111111 | 0o377 | 0xFF | The maximum of a single byte |
| 256 | 0b100000000 | 0o400 | 0x100 | The number of states in a byte (2⁸) |
Four notations, one number
Number systems are the cleanest example of technology negotiating between physics and biology. Silicon imposed base two, because two states are the one thing a transistor cannot confuse. Humans answered with base sixteen, because four bits at a time still fit in a head. Octal survived in Unix permissions, where triplets of bits line up into access rights. Decimal stayed where it always was — on our hands.
None of these systems is truer than the others. 0xFF, 0o377, 0b11111111 and 255 are four ways of pointing at the same number — and the only thing you really need to know is which one you are currently speaking.
Further reading
- Brian Hayes, Third Base, American Scientist — radix economy and the Soviet ternary computers.
- University of Oxford, carbon dating of the Bakhshali manuscript — the oldest known recorded origin of the zero symbol.
- G. W. Leibniz, Explication de l'arithmétique binaire (1703) — the source text on binary and the I Ching hexagrams.
- MDN, SyntaxError: "0"-prefixed octal literals are deprecated — how modern JavaScript defuses the leading-zero trap.
