↑ ↓ to move · enter to open

C00 · Computers · Binary, two's complement, units, UTF-8, floats

bits & bytes

Everything a computer stores is a row of switches, each one off or on. A bit is one switch. A byte is eight. Numbers, file sizes, letters and decimals are all agreements about what a pattern of switches means. Flip them here and watch each agreement read the same bits in its own way.

LAB 1

one byte, eight switches

Each switch has a place value, doubling from right to left: 1, 2, 4, up to 128. The number is the sum of the lit place values, so eight switches can count from 0 to 255. Read as signed, the leftmost switch is worth −128 instead of +128, which gives −128 to 127 from the same 256 patterns.

unsigned · 0 to 255
Read as
Presets

How to read this: click a switch to flip it. Each lit switch adds the number printed above it, and the total shows below. The next line splits the 8 switches into two groups of 4. Each group is one hex digit.

  • switch on (1)
  • red outline: the answer didn't fit
  • amber −128: the top switch in signed mode

Try this: press 255, then +1. The switches flash red because 256 needs a ninth switch.

—
Decimal (unsigned)
—
Hex
—
Binary
—
ASCII character

CodePython

Place values

value = Σ biti · 2i signed: bit 7 is worth −27

Hex is a shorthand for binary. Each hex digit stands for exactly four bits, so one byte is always two hex digits, 00 to FF.

Two's complement makes −1 the pattern that becomes 0 when you add 1: 11111111. That is why the same adder circuit works for signed and unsigned numbers. Only the reading changes.

Why it wraps

A byte has no ninth switch. When 255 + 1 carries out of the top bit, the carry is lost and the byte reads 0. Real programs use 32 or 64 bits, which pushes the edge far away but does not remove it. 014 · Missing number shows a sum overflowing and an XOR trick that never carries.

LAB 2

from bits to gigabytes

Eight bits make a byte. After that two ladders run side by side. The SI ladder multiplies by 1000 (kB, MB, GB, TB). The binary ladder multiplies by 1024 (KiB, MiB, GiB, TiB). The two start 2.4% apart and drift further with every rung.

size ladder
—

How to read this: each small tick on the ruler is 10 times bigger than the one before. That is what "log scale" means, and it lets one bit and a terabyte fit on one line. The bars below show how far apart the two kinds of unit are at each step.

  • above the ruler: 1000-based units (kB, MB)
  • below: 1024-based units (KiB, MiB)
  • the size you picked
  • one 1024-based unit
  • the matching 1000-based unit
  • the difference

Try this: click 1 TB, then 1 TiB, and watch the red sliver on the TB row.

—
Bytes
—
Bits
—
SI units (×1000)
—
Binary units (×1024)

CodePython

Now

Why a 1 TB drive shows 931 GB

Drive makers count in SI units: 1 TB is 1012 bytes. Windows File Explorer divides by 10243 and still writes "GB", so the same drive shows up as about 931 of them. macOS divides by 1000 and shows 1 TB. No bytes go missing. The two numbers use different units.

Exactly: 1012 / 230 = 931.322574615478515625 GiB. The division ends because 230 has no factor other than 2.

LAB 3

text is numbers

Unicode gives every character a number, its code point, written U+ and hex. UTF-8 stores that number in 1 to 4 bytes. Plain English letters take one byte, so old ASCII files are already valid UTF-8. Accents take two, most other scripts and symbols take two or three, and emoji take four.

utf-8 bytes
filled = 1, empty = 0 amber: marker bits that say how many bytes this character uses green: the character's own numbergold hex = first byte of the character

Try this: click 😀 and count its four rows. The first row starts with four amber 1s.

Try
—
Code points (Python len)
—
UTF-8 bytes
—
UTF-16 units (JS .length)
—
Characters you see

Selected character

CodePython

Why it is built this way

The first bits of each byte say what it is. 0 starts a one-byte character, 110, 1110 and 11110 start 2, 3 and 4-byte characters, and 10 marks a continuation byte. A program dropped into the middle of a file can find the next character start by skipping bytes that begin with 10.

Counting depends on what you count. JavaScript's .length counts UTF-16 units, so 😀 has length 2. A thumbs-up with a skin tone is two code points that display as one symbol.

LAB 4

why 0.1 + 0.2 isn't 0.3

A JavaScript number, or a Python float, is an IEEE 754 double: 64 bits split into a sign, an 11-bit exponent and a 52-bit fraction. It stores a binary fraction. Most decimals, including 0.1, have no exact binary form, so the computer stores the nearest double instead. Type a number, or click any bit to flip it.

64-bit double
Prints as
0.1
Exact value stored
Number
a + b

How to read this: the 64 squares are the number's bits. Filled = 1. One sign bit says plus or minus, 11 bits say how big, and 52 bits hold the detail.

  • sign bit
  • size bits (exponent)
  • bit set to 1

Try this: flip the leftmost fraction bit of 0.1 and see how far the value moves. Then click 0.5 to see a number stored exactly.

—
Sign bit
—
Exponent bits − 1023
—
Fraction (52 bits, hex)
—
Gap to next storable number

The format

CodePython

Why 0.1 can't be exact

0.1 is 1/10, and 10 = 2 × 5. A binary fraction can only have a power of 2 below the line, so the factor 5 makes 0.1 repeat forever in binary: 0.000110011001100…. The double keeps 53 significant bits and rounds the rest.

0.1 and 0.2 are each stored a little high. Their sum lands one step above the double nearest 0.3, so it prints as 0.30000000000000004. Every result is rounded to the nearest double, and printing shows the shortest decimal that reads back to the same bits.

Next: C01 · The CPU does this arithmetic, and C02 · Memory & RAM holds the bytes.