DEV Community

Snappy Tools
Snappy Tools

Posted on

Number Systems Demystified: Binary, Octal, Decimal, and Hex

Most people grow up with one number system (base 10). Programmers regularly work with three more: binary (base 2), octal (base 8), and hexadecimal (base 16). Here's why each exists and how to convert between them.

Why multiple number systems?

Computers store everything as bits — ones and zeros. Every higher number system is ultimately just a more compact way to represent sequences of bits.

Binary (base 2): How hardware actually works. Each bit is a binary digit (0 or 1). Understanding binary is essential for bitwise operations, understanding memory, and debugging at the hardware level.

Hexadecimal (base 16): A compact shorthand for binary. One hex digit maps exactly to 4 bits (a nibble). Two hex digits = one byte. This makes hex ideal for memory addresses, color codes, byte sequences, and hash values.

Octal (base 8): Historically common on older systems (DEC PDP and VAX computers). Still used for Unix file permissions. Each octal digit maps to 3 bits.

How each system works

In base 10, each digit position represents a power of 10: the number 547 means 5×10² + 4×10¹ + 7×10⁰.

In binary, each position is a power of 2: 1101₂ = 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 8+4+0+1 = 13.

In hex, positions are powers of 16, using digits 0–9 and A–F (A=10, B=11, C=12, D=13, E=14, F=15): 1F₁₆ = 1×16¹ + 15×16⁰ = 16+15 = 31.

Binary → Hex: the quick trick

Since 16 = 2⁴, each hex digit maps exactly to 4 binary digits:

Binary:  1111 0110 1010 0001
         F    6    A    1
Hex:     F6A1
Enter fullscreen mode Exit fullscreen mode

Group binary digits from right to left in groups of 4, then convert each group:

  • 0000 = 0, 0001 = 1, 0010 = 2, 0011 = 3
  • 0100 = 4, 0101 = 5, 0110 = 6, 0111 = 7
  • 1000 = 8, 1001 = 9, 1010 = A, 1011 = B
  • 1100 = C, 1101 = D, 1110 = E, 1111 = F

This is why hex is used in error codes, memory dumps, and network packets — it's the human-readable form of binary.

Where you encounter each system

Binary:

  • Bitwise operations: flags & 0b0001, permissions | 0b0100
  • Floating point representation
  • Bitfields and protocol headers
  • Understanding integer overflow and two's complement

Hexadecimal:

  • Color codes: #2F855A = R:47 G:133 B:90
  • Memory addresses: 0x00007fff5fbff8e8
  • Byte values in network packets and binary files
  • SHA-256 hash: 2cf24dba5fb0a30e26e83b2ac5b9e29e...
  • CSS hex colors, Unicode code points (U+1F600)

Octal:

  • Unix file permissions: chmod 755 (= 111 101 101₂)
  • Escape sequences in strings: \177 (DEL character in octal)
  • Legacy protocols

Converting in code

For quick manual conversions between binary, octal, decimal, and hex, a number base converter handles all four simultaneously — type in any field and the others update instantly.

JavaScript:

// Decimal → other bases
(255).toString(2)   // "11111111" (binary)
(255).toString(8)   // "377" (octal)
(255).toString(16)  // "ff" (hex)

// Any base → decimal
parseInt("11111111", 2)  // 255
parseInt("377", 8)       // 255
parseInt("ff", 16)       // 255
parseInt("ff", 16)       // 255

// Literals in code
const binary = 0b11111111;  // = 255
const octal = 0o377;         // = 255
const hex = 0xff;            // = 255
const bigHex = 0xDEADBEEF;  // = 3735928559

// Formatting with prefix
"0x" + (255).toString(16).toUpperCase()  // "0xFF"
"0b" + (255).toString(2)                 // "0b11111111"
Enter fullscreen mode Exit fullscreen mode

Python:

# Decimal → other bases
bin(255)    # '0b11111111'
oct(255)    # '0o377'
hex(255)    # '0xff'

# Without prefix
format(255, 'b')   # '11111111'
format(255, 'o')   # '377'
format(255, 'x')   # 'ff'
format(255, 'X')   # 'FF'
format(255, '08b') # '11111111' (zero-padded to 8 digits)
format(255, '04x') # '00ff' (zero-padded to 4 hex digits)

# Any base → decimal
int("11111111", 2)  # 255
int("377", 8)       # 255
int("ff", 16)       # 255

# Literals in code
binary = 0b11111111   # 255
octal = 0o377         # 255
hex_val = 0xff        # 255
Enter fullscreen mode Exit fullscreen mode

Bitwise operations

Binary thinking is essential for bitwise operations:

// AND: both bits must be 1
5 & 3   // 0b101 & 0b011 = 0b001 = 1

// OR: at least one bit is 1
5 | 3   // 0b101 | 0b011 = 0b111 = 7

// XOR: exactly one bit is 1
5 ^ 3   // 0b101 ^ 0b011 = 0b110 = 6

// NOT: flip all bits (with 32-bit interpretation)
~5      // -(5+1) = -6

// Left shift: multiply by 2^n
5 << 2  // 0b101 << 2 = 0b10100 = 20

// Right shift: divide by 2^n (integer division)
20 >> 2  // 0b10100 >> 2 = 0b101 = 5
Enter fullscreen mode Exit fullscreen mode

Common bitwise patterns:

// Check if a bit is set
const hasFlag = (value, flag) => (value & flag) !== 0;

// Set a bit
const setFlag = (value, flag) => value | flag;

// Clear a bit  
const clearFlag = (value, flag) => value & ~flag;

// Toggle a bit
const toggleFlag = (value, flag) => value ^ flag;

// Check if a number is even
const isEven = n => (n & 1) === 0;

// Fast multiply/divide by powers of 2
const double = n => n << 1;
const halve = n => n >> 1;
Enter fullscreen mode Exit fullscreen mode

Unix file permissions: octal in practice

Unix permissions use a 9-bit system: owner (3 bits), group (3 bits), others (3 bits). Each bit is read (4), write (2), execute (1).

chmod 755  →  7=111  5=101  5=101
             rwx    r-x    r-x
owner: read+write+execute (rwx = 7)
group: read+execute (r-x = 5)
others: read+execute (r-x = 5)
Enter fullscreen mode Exit fullscreen mode

Expressed in binary: 111 101 101 = all permissions encoded as three 3-bit groups.

Two's complement: how negative numbers work

In binary, negative integers use two's complement representation. To negate a number in n-bit two's complement:

  1. Flip all bits (bitwise NOT)
  2. Add 1

For 8-bit: 5 = 00000101

  • Flip: 11111010
  • Add 1: 11111011 = -5

This is why ~5 in JavaScript gives -6 — it's the bitwise NOT, which is one step short of the full negation.

The maximum positive value in n bits is 2^(n-1) - 1. For a 32-bit integer: 2,147,483,647. Overflow wraps to the minimum value.


Binary, octal, and hex aren't different languages — they're different views of the same bit patterns. Hex is the most practically useful because it maps cleanly to bytes and is compact enough to read. Understanding the relationship between these bases is what makes memory addresses, color codes, and bitwise operations fully transparent.

Top comments (0)