← Back to all articles

Number Bases Made Intuitive: Binary, Hex and Color Codes

Number basesBeginner

The core idea: positional notation

A number in any base = the sum of each digit × the base's positional weight. Binary 1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11. Hex uses A–F for 10–15, so 0xFF = 15×16 + 15 = 255. Once this clicks, conversion is just arithmetic.

Why programmers love hex

One hex digit maps exactly to 4 binary digits, so a byte (8 bits) is always 2 hex characters. Memory addresses, byte sequences and colors all use it for this reason: #FF5733 = R:255, G:87, B:51, three hex pairs are three channel intensities.

Common pitfalls

  1. Lost leading zeros: "007" parses to the number 7 and changes when converted back;
  2. Big-number precision: beyond JavaScript's safe integer (2^53) results are unreliable, treat as strings or use BigInt;
  3. Floats are never exact: 0.1 is an infinitely repeating binary fraction; base conversion is exact for integers only, mind rounding for fractions.

Handy conversions

DecimalBinaryOctalHex
10101012A
2551111 1111377FF
1024100 0000 00002000400
655351111 1111 1111 1111177777FFFF

Code examples

// Parsing: the second argument is the radix
parseInt('FF', 16);         // 255
Number.parseInt('1010', 2); // 10

// Formatting: toString(radix)
(255).toString(16);         // "ff"
(10).toString(2);           // "1010"

// Colour channels to hex (pad each channel to two digits)
'#' + [255, 87, 51].map(v => v.toString(16).padStart(2, '0')).join('');
// => "#ff5733"

Three limitations to know

  1. Leading zeros vanish: "007" parses to 7 and never comes back, treat IDs and codes as strings;
  2. Big integers lose precision: beyond Number.MAX_SAFE_INTEGER (2^53−1) use BigInt or strings;
  3. Fractions are approximations: 0.1 is an infinite binary fraction; only the integer part converts exactly.

Where it shows up in practice

Base conversion looks basic but goes wrong in specific contexts; what matters is knowing what each context needs.

  1. Permission bits and masks: file modes, netmasks and feature flags appear as octal or binary. Read them bit by bit rather than treating the whole as one decimal number.
  2. Colours and identifiers: hex is common for colours and hashes; case is irrelevant but length must match exactly, a wrong length usually means truncation or padding.
  3. Protocol fields: network protocols and hardware registers use fixed widths, so pad with leading zeros or the parser reads the wrong field.
  4. Short links and encodings: converting an incrementing number to a higher base shortens display length, but choose the alphabet carefully and avoid case ambiguity.
  5. Large integers: values beyond the safe integer range must be handled as strings and never pass through floating point, or trailing digits are silently rewritten.

Verification habit

Convert the result back and compare with the input. For critical data, also check length and range, eyeballing is exactly how a single differing digit goes unnoticed.

Tools and human error

Conversion mistakes almost always come from manual work: a mistyped digit, missing leading zeros, a confused prefix. Do the conversion in tooling or code and verify automatically, leaving humans to judge whether the result matches expectations rather than to compute it.

Try them: Base converter, Color converter