Binary, Octal, Decimal, Hex: A Developer's Guide to Number Base Conversion
2026-08-12
0xFF, 0b1010, 0755, 255 — four ways to write numbers that show up constantly in code, config files, permissions, colors, and network addresses. Every programmer develops a rough fluency with binary and hex over time, but it’s often pattern-matching rather than understanding: you know 0xFF is 255 because you’ve seen it a thousand times, not because the conversion is obvious. This guide builds the actual understanding — what a “base” is, how to convert between any two of them, and the mental shortcuts that make hex and binary feel as natural as decimal.
What a “Base” Actually Is
All the number systems above are the same idea with a different width: positional notation. The number 255 in decimal means 2×100 + 5×10 + 5×1 — each digit’s value is its face value times a power of 10, and the power is determined by position. Change the multiplier from powers of 10 to powers of some other number b, and you get base b. You need exactly b distinct digit symbols:
- Binary (base 2): digits 0–1. Powers of 2.
- Octal (base 8): digits 0–7. Powers of 8.
- Decimal (base 10): digits 0–9. Powers of 10.
- Hexadecimal (base 16): digits 0–9 plus A–F for values 10–15. Powers of 16.
So 1010 in binary means 1×8 + 0×4 + 1×2 + 0×1 = 10, and FF in hex means 15×16 + 15×1 = 255. That single expansion — digit times base-to-the-position, summed — is every conversion formula in disguise. Any base → decimal is literally just writing out this sum.
Why Programmers Live in Binary and Hex
Computers store everything as bits, so binary is the ground truth — but raw binary is unreadable at any length: 11111111 strains the eye, and 32-bit values are hopeless. Hex solves this because of one beautiful coincidence: 16 is 2⁴, so exactly one hex digit maps to exactly four binary digits (a nibble). Converting hex ↔ binary requires no arithmetic at all, just a 16-row lookup table:
0=0000 1=0001 2=0010 3=0011 4=0100 5=0101 6=0110 7=0111
8=1000 9=1001 A=1010 B=1011 C=1100 D=1101 E=1110 F=1111
0xF5 → F=1111, 5=0101 → 11110101. Going the other way, group binary into fours from the right and translate each group. This is why hex appears anywhere humans must read raw bytes: memory addresses, MAC addresses, color codes (#FF5733 is three bytes), file signatures, hashes. One byte = two hex digits, always.
Octal survives for the same reason with groups of three (8 = 2³): one octal digit = three bits. Its main modern habitat is Unix file permissions — chmod 755 is three groups of three bits (read/write/execute). Decimal, meanwhile, remains what humans think in, which is why conversion back to decimal is the other everyday need.
Converting TO Decimal: Expand and Sum
The universal method for any base → decimal is the positional expansion:
0x2F = 2×16 + 15 = 47
0b1010 = 1×8 + 1×2 = 10
0o755 = 7×64 + 5×8 + 5 = 493
For hex specifically, a useful reflex is knowing the “landmark” values: 0x10=16, 0x20=32, 0x40=64, 0x80=128, 0xFF=255, 0x100=256. Most hex you encounter is near one of these, so 0xF5 is “a bit less than 0xFF” ≈ 245 (it’s 245; check: 15×16+5). When you need an exact conversion fast, the Number Base Converter handles binary, octal, decimal, and hex in both directions.
Converting FROM Decimal: Divide and Collect Remainders
Decimal → any base uses repeated division by the target base; the remainders, read in reverse, are the digits:
247 ÷ 16 = 15 remainder 7 → 7
15 ÷ 16 = 0 remainder 15 → F
read bottom-up: 0xF7
For decimal → binary there’s a shortcut most developers prefer: subtract powers of two. Know the sequence 1, 2, 4, 8, 16, 32, 64, 128 cold. For 247: take 128 (119 left), take 64 (55), take 32 (23), take 16 (7), skip 8, take 4 (3), take 2 (1), take 1. Bits set at positions 7,6,5,4,2,1,0 → 11110111. Verify via hex: 11110111 = F7. ✓
Prefixes and Notation Across Languages
The same values wear different prefixes depending on context:
0xor#prefix = hex (0xFFin C/Java/JS/Python,#FF5733in CSS,FF5733bare in many tools)0b= binary in most modern languages;0Bin some- Leading
0= octal in C and JavaScript strict-mode-era legacy (0755);0oin Python and modern JS (0o755) \xin string escapes is hex ("\x41"is “A”), while\uintroduces a Unicode code point in hex
Two traps: a bare leading zero makes 0755 octal in several languages, silently changing values (010 = 8); and octal-looking literals like 08 or 09 are flat-out invalid in strict mode. When in doubt, use explicit prefixes and verify with a converter.
Where This Shows Up in Real Work
- Colors:
#FF5733is three bytes — converting color channels is hex↔decimal. - Permissions:
chmod 755is octal for bit groups; the chmod Calculator shows the bit mapping directly. - Character codes: ASCII
Ais 65 decimal =0x41=0b01000001; the ASCII Table lists all three columns side by side. - Sizes and memory: file sizes mix decimal marketing units with binary hardware units — KB vs KiB — which is its own base-confusion story the Byte Converter untangles.
- Bitwise flags: APIs that pack options as
FLAG_A | FLAG_Bare binary in disguise; readingflags & 0b0100fluently means reading binary positions.
Quick Reference
- Any base → decimal: expand
digit × base^positionand sum. - Decimal → any base: divide repeatedly, collect remainders bottom-up.
- Hex ↔ binary: one hex digit = 4 bits, pure table lookup, no math.
- Octal ↔ binary: one octal digit = 3 bits.
- Landmarks:
0xFF=255,0x100=256,0b1000=8,0755(octal)=493. - Prefixes:
0xhex,0bbinary,0o/leading-0octal (leading-zero form is a legacy trap).