Course outline · 0% complete

0/28 lessons0%

Course overview →

Binary and bytes

lesson 2-1 · ~11 min · 4/28

From lesson 1-2, the CPU simulator stored its program as a list called memory and read memory[pc] each cycle. In a real computer that program lives in RAM while it runs.

The program file starts on disk, and to run it the OS copies it into RAM. The CPU then fetches each instruction from RAM, exactly as the simulator read memory[pc].

Disk is far too slow to fetch from every cycle. At roughly 100,000 nanoseconds per read, from lesson 1-1, a CPU running billions of cycles per second would spend essentially all of its time waiting.

Everything is bits

This unit exists because file sizes, network payloads, corrupted text, and the famous 0.1 + 0.2 surprise in the next lesson are all consequences of one fact engineers hit weekly. The machine stores nothing but bits, and every meaning is a rule layered on top.

RAM, disk, and the CPU all store exactly one kind of thing: bits. A bit is a single 0 or 1, physically a tiny switch that is off or on. A byte is a group of 8 bits.

Numbers, text, images, and code are all patterns of bits, and a pattern only means something because we agree on a rule for reading it. The rule for whole numbers is binary, which is ordinary place-value counting with 2 instead of 10.

Place1286432168421
bits of 500000101
bits of 1300001101

In decimal, 203 means 2×100 + 0×10 + 3×1. In binary, 101 means 1×4 + 0×2 + 1×1, which is 5. Each place is worth double the one to its right, so the eight places of a byte run 1, 2, 4, 8, 16, 32, 64, 128.

12864321684210010101032 + 8 + 2 = 42one byte = 8 bits
The byte 00101010. Adding the place values of the 1-bits (gold) gives 42.

Converting in both directions

bin shows a number's binary form and int(text, 2) reads binary text back.

print(bin(5))
print(bin(13))
print(int("1101", 2))
print(2 ** 8)

Output

0b101
0b1101
13
256

The 0b prefix only marks the text as binary and is not part of the value. int("1101", 2) says to read those digits in base 2, giving 8 + 4 + 0 + 1.

The last line is the size of a byte's vocabulary. Two to the eighth power is 256, which is the number of different patterns one byte can hold, conventionally used for the numbers 0 through 255.

One number, both directions

42 into binary, then the same digits back into a number.

print(bin(42))
print(int("101010", 2))

Output

0b101010
42

Reading the places from the left, 101010 is 32 + 0 + 8 + 0 + 2 + 0, which is 42.

The two calls are exact inverses, and they exist because binary is a notation rather than a different kind of number. The value 42 is already binary inside the machine, so bin only chooses how to print it.

Hexadecimal, the shorthand for bytes

Binary is what the machine stores, but eight 0s and 1s per byte is miserable to read, so programmers write bytes in hexadecimal, which is place-value counting in base 16 using the digits 0 to 9 and then a to f, where a is 10 and f is 15.

Hex won because it fits exactly. One hex digit represents exactly 4 bits, so one byte is always exactly two hex digits, and ff is 255, the largest byte value.

NotationValue 195 written as
binary11000011
hexc3
decimal195

You will meet hex everywhere bytes are shown: 0xff in code, #d4af37 in web colors as three bytes for red, green, and blue, memory addresses in crash reports, and byte dumps such as \xc3\xa9 in the next lesson.

Python marks hex numbers with the 0x prefix, the same way 0b marks binary.

Hex in both directions

hex prints the hexadecimal form, int(text, 16) reads it back, and 0xc3 is a literal you can compute with.

print(hex(255))
print(hex(195))
print(int("c3", 16))
print(bin(0xc3))

Output

0xff
0xc3
195
0b11000011

The digit c is 12, so c3 in hex is 12×16 + 3, which is 195.

The last line shows why hex is the convenient notation. The binary form 11000011 is 8 bits, and each hex digit maps to exactly 4 of them, with c as 1100 and 3 as 0011, so converting between the two is done digit by digit with no arithmetic at all.

The vocabulary of one byte

One byte is 8 bits and can represent 256 different values.

Each bit doubles the possibilities, so eight bits give 2×2×2×2×2×2×2×2, which is 2⁸ and therefore 256 patterns. Those are usually read as the numbers 0 through 255.

BitsPatterns
12
416, exactly one hex digit
8256, one byte
1665,536

The doubling is worth internalizing, because it explains limits that look arbitrary otherwise. A single byte cannot hold a code point for an emoji, which is the constraint the encoding lesson has to work around.