Skip to main content

Number Systems & Base Conversion

Digital hardware only has two stable states to work with per wire, so every number a digital circuit stores or computes has to ultimately be represented in base 2 — binary. Everything in this page is really in service of one skill: fluently moving between how humans prefer to read numbers (decimal, and its shorthand, hexadecimal) and how hardware actually stores them (binary).

Positional number systems​

Every number system covered here is positional — the value of a digit depends on where it sits, not just what it is. In decimal, 243 means 2×10² + 4×10¹ + 3×10⁰. The same idea generalizes to any base r: a digit d at position i (counting from 0 at the rightmost digit) contributes d × r^i to the total value.

BaseNameDigits usedCommon use in digital design
2Binary0, 1What hardware actually stores and computes
8Octal0–7Rare today; historically used to shorten binary (groups of 3 bits)
10Decimal0–9How humans naturally think about quantities
16Hexadecimal0–9, A–FHuman-readable shorthand for binary (groups of 4 bits)

Binary​

1011₂ = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 8 + 0 + 2 + 1 = 11₁₀

Hexadecimal​

Hex exists purely for human convenience — each hex digit maps exactly onto 4 binary bits (a nibble), with no rounding or remainder, which is what makes conversion between them trivial in a way conversion to/from decimal never is.

HexBinaryHexBinary
0000081000
1000191001
20010A1010
30011B1011
40100C1100
50101D1101
60110E1110
70111F1111

1011 1010₂ splits cleanly into two nibbles, 1011 and 1010, giving BA₁₆ directly — no arithmetic required. This is why register dumps, memory addresses, and waveform values in every simulator and debugger are shown in hex: it's binary, just written 4 bits at a time.

Verilog's own radix literals

This grouping is exactly why Verilog lets you write literals in any base directly — 8'hBA, 8'b10111010, 8'd186 all name the same 8-bit value. You'll meet this formally in Verilog; it's worth recognizing now that the hex form is just the binary form read four bits at a time.

Converting decimal to binary​

The standard method is repeated division by 2, reading remainders from bottom to top:

Convert 26 to binary:
26 ÷ 2 = 13 remainder 0
13 ÷ 2 = 6 remainder 1
6 ÷ 2 = 3 remainder 0
3 ÷ 2 = 1 remainder 1
1 ÷ 2 = 0 remainder 1

Reading remainders bottom-to-top: 11010₂
Check: 16 + 8 + 0 + 2 + 0 = 26 ✓

For fractional values, the equivalent technique is repeated multiplication by 2, reading the integer part of each result top to bottom, which converges (or terminates) as digits are generated — many decimal fractions, like 0.1, never terminate in binary at all, which is a real, recurring source of floating-point rounding surprises in software and is worth knowing about even at this level.

Signed and unsigned representation​

Everything above assumes an unsigned value — no negative numbers. An n-bit unsigned field represents 0 to 2ⁿ − 1. Representing negative numbers needs a deliberate encoding choice, and digital hardware has settled almost universally on one:

Two's complement​

To negate a value in two's complement: invert every bit, then add 1.

0001 0110 (22, unsigned)
Invert:
1110 1001
Add 1:
1110 1010 (-22, two's complement)

Two's complement wins over the alternatives (sign-magnitude, one's complement) for one decisive practical reason: addition hardware doesn't need to know or care whether its operands are signed. The same binary adder circuit produces the correct result whether you feed it two unsigned values or two two's-complement signed values — no separate "subtract" circuit, no special-casing the sign bit. That single property is why virtually every ALU in every processor uses it.

  • The most significant bit doubles as the sign bit: 0 for non-negative, 1 for negative — but it's still a normal place-value bit in the arithmetic, not a special flag bit off to the side.
  • An n-bit two's-complement field represents -2ⁿ⁻¹ to 2ⁿ⁻¹ − 1 — one more negative value than positive, because there's no redundant "negative zero" the way sign-magnitude has.
  • Sign extension — widening a signed value to more bits — just replicates the sign bit into the new upper positions. 1010₂ (-6, 4-bit) sign-extends to 1111 1010₂ (-6, 8-bit); the value is unchanged because you're just repeating the same-sign place values that were implicitly there at any width.
Overflow is a real hardware condition, not a software concern

Adding two large positive two's-complement numbers can produce a result that "wraps around" into negative territory — the classic case being an n-bit adder whose two positive inputs sum to more than 2ⁿ⁻¹ − 1. Real ALUs detect this (an overflow flag) rather than silently returning a wrong answer; when you design or verify an adder later in this topic and in Verification, overflow behavior is one of the first things worth explicitly testing, not an edge case to discover by accident.

What's next​

Representation is only half the picture — the next page covers how binary values are actually added, subtracted, and manipulated by hardware, building directly on the two's-complement representation introduced here.