Lecture 05 - Representing numbers

Published

February 18, 2026

Goals

  • Learn how to represent numbers at our current level of abstraction of wires and logic
  • Learn how to convert between bases

We now have the ability to create circuits that can carry out basic logic functions for us. But most of the work that we do with computers isn’t about logic prepositions. We all know that the proper use for a computer is sharing cat videos on the internet. Somehow we need videos, and images, and sound, and text, and numbers.

We will start with numbers because they are the easiest (and in truth everything else is built on top of them)

Base two (binary)

When I was writing out truth tables, I said that I was counting in binary – let’s get a little more formal

Binary is a base 2 number system, as opposed to our more common decimal, which is base ten.

What does it mean for a number system to be base-n?

There are a couple of ways that we can think about it - each digit in a number can have up to n different representations (e.g., base-2 (0,1), base-10 (0,1,2,3,4,5,6,7,8,9)) - more importantly, digits are positional and multiplied by powers of the base

so, for a number in base-b, we can convert to decimal using this formula \[(d_{3}d_{2}d_{1}d_{0})_{b} = (d_{3} * b^{3}) + (d_{2} * b^{2}) + (d_{1} * b^{1}) +(d_{0} * b^{0}) )\]

binary to decimal

In base-2 this is pretty straightforward since all of the multiplication is by 1s and 0s. So all you need to know is your powers of two.

decimal to binary

this is a little harder

We can start with a slightly different form of the equation above: Horner’s equation

We get here by just factoring out bs until we don’t have anything raised to a power

\[(d_{3}d_{2}d_{1}d_{0})_{b} = (((d_{3} * b) + d_{2}) * b + d_{1}) * b + d_{0}\] If we were to multiply the b s back in, we would get back to our original equation

If we take this expression and divide it by b, we will get

\[(((d_{3} * b) + d_{2}) * b + d_{1}), \text{remainder } d_{0}\]

\[(((d_{3} * b) + d_{2}) * b + d_{1}) / b = ((d_{3} * b) + d_{2}), \text{remainder } d_{1}\]

\[((d_{3} * b) + d_{2}) / b = d_{3}, \text{remainder } d_{2}\]

\[(d_{3} * b)/b = 0, \text{remainder } d_{3}\]

this provides our algorithm - reserve a spot to write the number in base b - while number is not equal to 0 - divide number by b getting a quotient and a remainder - add the remainder to the left of the new number - set number to the quotient - you should now have the number in base b representation

This will work in any base, but obviously the math is easier for binary

base 16 (hexadecimal)

A quick aside. Binary numbers get loooooong (and programmers are lazy), but bit patterns are important

So, we like bases other than base-10, like hex and octal (base-8)

The advantage to these bases is that 8 and 16 are powers of 2, which makes conversion between the bases easier

In base 16, there are 16 different values for each digit. In base-2, we can represent with all patterns of four bits

base-2 base-16
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

The big win here is that we only need to know how to convert between 1 digit of hex and 4 digits of binary and we can do any arbitrary conversion

\[A3_{16} = 10100011_2\]

We will typically write hex out as 0xA3

Doing math

Adding together numbers in binary works just like it does in decimal – we just have to carry out quicker

it is time to get back to our computer abstraction – how do we do this with circuits?

Let’s start with adding two 1 bit numbers together (one column of our addition)

We can make a truth table

A B sum1 sum0
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 0

Now, we can look at each output individually - sum0 is just an XOR - sum1 is just AND

We can build this pretty easily – we call it a half adder.

What if we want to add numbers with more bits? If we rename the outputs of the half adder to (carry_out, sum), we can use it for the first column of the addition.

What about the next column over? This one is a little different because it has a carry_in as well, so we can’t just add in a half adder

We need a new circuit, called a full adder that has three inputs (A, B, carry_in) and two outputs (sum, carry_out) - we could design this by starting with a new truth table - or you could think abstractly – the sum should come from A + B + carry_in, which we could rewrite as (A + B) + carry_in , and we know how to add two one bit numbers together (carry_out will still take some thought)

if we had a full adder and a half adder, we could chain them together to add any size number we like - e.g., to add two 8-bit numbers together we would need 7 full adders and one half adder

this would give us something called a ripple-carry adder > [!note] > > This is not actually how the adder in your computer works. This one is slow because you need to wait for the carrys to propagate. There are much faster adders that trade space for speed and precompute different variations of the answer simultaneously

Mechanical level

Skills - convert from binary to hex - convert from hex to binary