# Numbers & Number Systems

> Numbers come in expanding families - counting numbers, integers, fractions, the reals - each invented to fix something the last couldn't do. And the same number can be written in different bases, which is the whole reason computers think in binary and hex.


---

# Numbers & Number Systems

You've used numbers your whole life, so it's tempting to assume there's nothing left to understand about
them. But two things almost nobody is taught turn numbers from a blur into a clear map: *why* there are
different **families** of numbers (and what each one was invented to fix), and the fact that the same
number can be **written** in different ways - base 10, base 2, base 16 - which is the entire reason your
computer "thinks in binary."

This guide makes both concrete. You'll see why subtraction forced us to invent negative numbers and
division forced fractions, you'll convert between decimal, binary, and hex until it feels routine, and
you'll meet the "clock arithmetic" (modular arithmetic) that quietly powers hashing, parity checks, and
cryptography. It's the number sense that makes the rest of the Mathematics track - and a lot of code -
suddenly readable.

## How to read this
- **Here for binary and hex?** [Phase 2](02-bases-binary-decimal-hex.md) is the base-conversion phase.
- **Want the whole map?** Read in order - the families (Phase 1) give the rest its footing.

## The phases
1. **[The Families of Numbers](01-the-families-of-numbers.md)** - naturals, integers, rationals,
   irrationals, reals, and why each family had to be invented.
2. **[Bases: Binary, Decimal, Hex](02-bases-binary-decimal-hex.md)** - positional notation, converting
   between bases, and why computers use binary and hex.
3. **[Modular Arithmetic: Clock Math](03-modular-arithmetic-clock-math.md)** - remainders and
   wrap-around, and the everyday tech that runs on them.

> This builds on [Sets, Relations & Functions](/guides/sets-relations-and-functions) (the number
> families are nested sets). Next in the Mathematics track: counting, and probability.


---

# The Families of Numbers

You probably met "numbers" as one thing: symbols you count, add, and multiply
with. Mathematicians see something else - *families*. Each family was born for a
reason. Something broke. An operation refused to give an answer, so people
invented new numbers to fix it.

That's this whole phase. Not "memorize five definitions" but one thread:
**the number system kept growing because math kept needing it to.** Once you see
the thread, the names stop being trivia and become inevitable.

## The driving idea: numbers grew to keep math working

Here's the mental model to carry through everything below.

Every family starts as "the numbers we already have." Then someone asks a fair
question - a subtraction, a division, a length - and the plain answer is: *there
is no number here that works.* A math where reasonable questions have no answer
feels broken.

So people widened the system instead of accepting the gap. They invented new
numbers so the question *did* have an answer. Each widening keeps everything you
already had and adds what was missing. Nothing gets thrown away.

We'll do this four times. Watch the same move repeat.

## Naturals (ℕ): the counting numbers

Start with the most ancient numbers - the ones you'd use to count sheep:

```text
0, 1, 2, 3, 4, 5, ...
```

These are the **natural numbers**, written ℕ. (Some books start them at 1, some at
0. We'll include 0 here; it's a convention, not a deep truth.) They go up forever.

Addition is happy here: any two naturals add to another natural. Multiplication
too. So far the system holds together.

Then someone asks: what is `3 − 5`?

The answer should be "two below zero." But there is no natural number below zero.
Within ℕ, `3 − 5` has *no answer at all.* Subtraction - an ordinary operation - is
allowed to fail.

That gap is the reason for the next family.

## Integers (ℤ): add the negatives

To make subtraction always work, we add mirror-image numbers below zero:

```text
..., -3, -2, -1, 0, 1, 2, 3, ...
```

These are the **integers**, written ℤ (from the German *Zahlen*, "numbers"). Now
`3 − 5 = -2` has a real answer. In fact *any* subtraction of integers gives an
integer. The hole is patched.

We didn't lose the naturals. Every natural number is still here - `4` is both a
natural and an integer. We only *extended* the system downward.

Then someone asks the next fair question: what is `1 ÷ 2`?

No integer, doubled, gives 1. The nearest integers are 0 and 1, and neither works.
Within ℤ, `1 ÷ 2` has no answer. Division - again, an ordinary operation - fails.

Same move, one more time.

## Rationals (ℚ): ratios of integers

To make division work (almost always - we'll get to the catch), we allow one
integer divided by another:

```text
1/2,  -3/4,  7/1,  22/7,  0,  5
```

These are the **rationals**, written ℚ (for *quotient*). A rational is any number
you can write as a fraction `a/b` where `a` and `b` are integers and `b` is not
zero. That last rule matters: **division by zero stays undefined** even here.
`1 ÷ 2` is now `1/2`. The hole is patched again.

And once more, the old families survive. Every integer is a rational: `5` is
`5/1`. Every natural is too.

Rationals also have a decimal personality worth knowing. Write a rational as a
decimal and it always does one of two things:

- It **terminates**: `1/2 = 0.5`, `3/8 = 0.375`.
- Or it **repeats** forever in a pattern: `1/3 = 0.333...`, `1/7 = 0.142857142857...`

Terminating or repeating - those are the only options for a rational. Hold onto
that, because it's how we'll catch the numbers that *aren't* rational.

So have we got every number? It feels like fractions should cover everything.
They don't, and the reason comes not from arithmetic but from geometry.

## Irrationals: the numbers no fraction can reach

Draw a square one unit on each side. Its diagonal has a length. You can measure it,
point at it, build it - it's a real distance. By the Pythagorean relationship that
length is √2 (the number that, squared, gives 2).

Now the shock: **√2 cannot be written as any fraction `a/b`.** Not because we
haven't found the right one yet - it's been *proven* that no such fraction exists.
The ancient Greeks discovered this, and it genuinely unsettled them: fractions,
their whole notion of number, had a hole.

The circle constant π is the same story. The ratio of a circle's circumference to
its diameter is a perfectly real number, but it is provably not a fraction either.

Numbers like √2 and π are **irrational**: they cannot be written as a ratio of
integers. As decimals, they never terminate and never fall into a repeating
pattern - they run on forever without settling down:

```text
√2 = 1.41421356237...
π  = 3.14159265358...
```

That non-terminating, non-repeating decimal is the fingerprint of an irrational.
A rational always terminates or repeats; an irrational does neither.

## Reals (ℝ): the whole number line

Put the rationals and the irrationals together and you get the **real numbers**,
written ℝ. This is the number line you've always pictured - every point on it, no
gaps. The rationals are dense (there's one between any two you pick), but they
leave pinprick holes exactly where numbers like √2 and π live. The irrationals
fill those holes. Together they form one unbroken line.

Almost any quantity you measure in the physical world - a length, a temperature, a
weight - lives in ℝ.

Is *this* the end? For everyday math, yes. But the same pattern has one more
famous chapter: ask "what is √−1?" and no real number works, because any real
squared is zero or positive. To answer it, mathematicians invented the **complex
numbers** (ℂ), which extend ℝ the way ℤ once extended ℕ. We won't use them here -
notice the move never really stops.

## They nest like Russian dolls

Step back and look at what we built. Each family contained the last one whole:

```text
ℕ  ⊂  ℤ  ⊂  ℚ  ⊂  ℝ
naturals  integers  rationals  reals
```

That `⊂` means "is contained in." Read it as a chain of true statements:

- Every natural number is also an integer.
- Every integer is also a rational (`5 = 5/1`).
- Every rational is also a real.

The reverse is *not* true, and that's the interesting part: `-2` is an integer but
not a natural; `1/2` is rational but not an integer; `√2` is real but not rational.
Each family is strictly bigger than the one inside it.

This nesting is exactly the language of sets and subsets - each family is a set,
and the smaller ones are subsets of the larger. If that framing is new to you, see
[/guides/sets-relations-and-functions](/guides/sets-relations-and-functions). And
if the whole topic still feels intimidating rather than interesting, that's worth
addressing directly:
[/guides/why-math-isnt-your-enemy](/guides/why-math-isnt-your-enemy).

## For builders

If you write code, you've already been using two of these families, probably
without naming them.

- An `int` type is your machine's version of the **integers** ℤ - whole numbers,
  positive and negative. (With a catch: a real `int` has a maximum and minimum,
  while ℤ goes on forever. Overflow is what happens when a value walks off that
  edge.)
- A `float` (or `double`) is your machine's attempt at the **reals** ℝ - numbers
  with a fractional part.

Two things follow directly from the families above.

**Integer division throws away the fraction.** In many languages, `7 / 2` on two
integers gives `3`, not `3.5`. That's not a bug - the result is being kept inside ℤ,
where `3.5` doesn't exist, so it truncates. To get `3.5` you have to ask for real
(float) division.

**Floats are finite approximations, not the true reals.** This one bites people, so
it gets its own callout.

⚠️ **Gotcha: a float is not an exact real number.** ℝ is infinite in precision -
some reals (like √2) need infinitely many digits. Your computer has finite memory,
so it *cannot* store every real exactly; it stores the nearest value it can
represent. That's why, in almost every language:

```text
0.1 + 0.2  =  0.30000000000000004
```

The numbers `0.1` and `0.2` can't be held exactly in the machine's binary format,
so their stored versions are a hair off, and the error shows up in the sum. Nothing
is broken - it's the unavoidable cost of squeezing the infinite real line into a
fixed number of bits. The practical rule: don't test floats for exact equality;
check whether they're *close enough*.

## Recap

- Each family of numbers was invented to make an operation always have an answer.
- **ℕ (naturals):** counting numbers. Subtraction can fail (`3 − 5`).
- **ℤ (integers):** add negatives - subtraction always works. Division can fail (`1 ÷ 2`).
- **ℚ (rationals):** fractions `a/b` - division works (except by zero). Decimals
  terminate or repeat. But some real lengths (√2, π) are provably *not* fractions.
- **Irrationals:** can't be written as a ratio; decimals never terminate or repeat.
- **ℝ (reals):** rationals + irrationals = the full, gapless number line. (Next
  extension, ℂ, handles √−1.)
- They nest: ℕ ⊂ ℤ ⊂ ℚ ⊂ ℝ - every member of an inner family belongs to the outer
  ones too.
- For code: `int` ≈ integers, `float` ≈ a *finite approximation* of the reals, which
  is why `0.1 + 0.2` isn't exactly `0.3`.

Quick check before you move on:

```quiz
[
  {
    "q": "Subtraction like 3 − 5 has no answer among the natural numbers. Which family was invented to make subtraction always work?",
    "choices": ["The rationals (ℚ)", "The integers (ℤ)", "The irrationals", "The reals (ℝ)"],
    "answer": 1,
    "explain": "Adding the negative numbers gives the integers, where any subtraction of integers produces an integer. Rationals fix division, not subtraction."
  },
  {
    "q": "What makes a number irrational?",
    "choices": ["It is negative", "It is larger than every fraction", "It cannot be written as a ratio of two integers, and its decimal never terminates or repeats", "It has a decimal point in it"],
    "answer": 2,
    "explain": "An irrational like √2 or π provably can't be expressed as a/b for integers a and b; written out, its decimal goes on forever with no repeating pattern."
  },
  {
    "q": "Given the nesting ℕ ⊂ ℤ ⊂ ℚ ⊂ ℝ, which statement is true?",
    "choices": ["Every integer is also a rational number", "Every rational is also an integer", "Every real number is also a natural number", "Every rational is also an irrational"],
    "answer": 0,
    "explain": "Each family contains the one inside it: an integer like 5 is the rational 5/1, so every integer is rational. The reverse fails - 1/2 is rational but not an integer."
  }
]
```


---

# Bases: Binary, Decimal, Hex

You already count in base ten - you've done it your whole life without calling it
that. This phase shows you that base ten is one choice among many. Once you see the
pattern underneath it, binary and hex stop being cryptic computer trivia and become
the same idea in different clothes.

If numbers still feel like they're out to get you, the calmer framing in
[Why Math Isn't Your Enemy](/guides/why-math-isnt-your-enemy) pairs well with
this. Nothing here requires it, though.

## Positional notation: the idea under every number system

Look at the decimal number `234`. You read it instantly as "two hundred
thirty-four," but notice *how* the meaning is built. The same digit means different
amounts depending on **where** it sits:

```text
  234
  │││
  ││└─ 4 in the ones place    →  4 × 1   = 4
  │└── 3 in the tens place    →  3 × 10  = 30
  └─── 2 in the hundreds place →  2 × 100 = 200
                                 ─────────────
                                  total   = 234
```

Each place is a **power of ten**:

```text
234 = 2×10² + 3×10¹ + 4×10⁰
    = 2×100 + 3×10  + 4×1
```

That number ten is the **base**. Here's the cleanest definition you'll get: the
base is *how many digits you have before you run out and have to carry*. Decimal
has ten digits (0 through 9). Count past 9 and there's no single symbol left, so
you carry: `9` rolls over to `10`.

Why this matters: nothing about positional notation is special to ten. Pick any
base *b*, and the places become powers of *b*. Change the base, keep the
machinery. That one insight unlocks binary and hex.

## Binary (base 2): two digits, powers of two

Binary uses exactly two digits: `0` and `1`. With only two symbols, you carry much
sooner - after `1` you're already out, so `1 + 1 = 10` in binary (which is *two*,
not ten). The places are powers of two instead of powers of ten:

```text
place values:  ... 16   8   4   2   1
                   2⁴  2³  2²  2¹  2⁰
```

Let's convert `1011₂` to decimal. (The little `₂` means "this is base 2," so you
don't mistake it for one thousand eleven.) Read each digit against its place value
and add up the ones that are switched on:

```text
   1    0    1    1     ← binary digits
   8    4    2    1     ← place values
   ─    ─    ─    ─
   8 +  0 +  2 +  1  =  11
```

So `1011₂` equals `11` in decimal. A binary digit is called a **bit**, and a bit
is a yes/no: is this place value included or not?

### Going the other way: decimal to binary by repeated division

To turn a decimal number into binary, repeatedly divide by 2 and write down the
**remainder** each time. The remainders, read bottom-to-top, are the binary
digits. Let's convert `13`:

```text
13 ÷ 2 = 6  remainder 1   ← least significant bit (bottom)
 6 ÷ 2 = 3  remainder 0
 3 ÷ 2 = 1  remainder 1
 1 ÷ 2 = 0  remainder 1   ← most significant bit (top)
```

Read the remainders from bottom to top: `1101`. Check it: `8 + 4 + 0 + 1 = 13`.
It works because each division strips off the smallest place value and asks "is
it odd?" - and odd-or-even is exactly what the bottom bit records.

## Hex (base 16): a compact shorthand for binary

Hexadecimal - "hex" - is base 16. That's a problem at first glance: we only have
ten digit symbols (0–9), and base 16 needs sixteen. The fix is to borrow letters.
After `9`, hex keeps counting with `A` through `F`:

```text
hex:      0 1 2 3 4 5 6 7 8 9 A  B  C  D  E  F
decimal:  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
```

So `A` is ten, `F` is fifteen. The places are powers of sixteen. Convert `2F₁₆` to
decimal:

```text
   2          F
   ↓          ↓
   2×16¹  +  15×16⁰
   = 32   +  15
   = 47
```

So `2F₁₆ = 47`. Going back uses repeated division by 16, the same trick as binary -
but nobody does that by hand, because of the real reason hex exists, which is the
next section.

## Why these bases: hardware, and human eyes

Computers use **binary** because the physical hardware has two stable states. A
transistor is either conducting or not; a wire is either at high voltage or low.
Two clean states map perfectly onto `1` and `0` - no ambiguity, no in-between to
misread. Everything a machine "knows" is built from billions of these on/off
switches, combined by logic gates (the building blocks you'll meet properly in a
hardware guide). Binary isn't a stylistic choice; it's what the silicon can
physically hold.

Humans use **hex** because raw binary is exhausting to read. Eight bits look like
`11111111` - easy to miscount. But here's the magic: **one hex digit is exactly
four bits.** Four bits can represent 0 through 15, and so can one hex digit, so
they line up perfectly. Group a binary string into chunks of four and translate
each chunk to a single hex digit:

```text
1111 1111   ← eight bits, split into two groups of four
  F    F    ← each group → one hex digit
=  FF
```

`11111111₂` is `FF₁₆`. Hex is binary for human eyes: same information, four times
shorter, far harder to miscount.

## See it run

Python understands all three bases directly, which makes it a great place to check
your hand-conversions. Run this:

```python runnable
print(0b1011)        # binary literal -> 11
print(0xFF)          # hex literal    -> 255
print(int("1011", 2))  # parse binary string
print(bin(11))       # decimal -> binary string
print(hex(255))      # decimal -> hex string
```

*What just happened:* The prefix `0b` tells Python "the following digits are
binary," so `0b1011` is evaluated as `8 + 2 + 1 = 11` and prints `11`. The
prefix `0x` means hex, so `0xFF` is `15×16 + 15 = 255` and prints `255`.
`int("1011", 2)` takes the *string* `"1011"` and the base `2`, parsing it as
binary - again `11`. Going the other direction, `bin(11)` converts the decimal
`11` into a binary string and prints `0b1011`, and `hex(255)` converts `255`
into a hex string and prints `0xff` (Python writes hex letters in lowercase).
Notice the round trips: `0b1011` and `bin(11)` are the same number seen from
both sides, and so are `0xFF` and `hex(255)`.

## For builders

A few things you'll bump into constantly once you're writing code:

- **Literals.** Most languages let you write numbers in binary with a `0b`
  prefix and in hex with `0x`. So `0b1010`, `0xFF`, and `255` can all describe
  the same or related values - they're only different spellings.
- **A byte is 8 bits.** It's the standard chunk of memory. One byte holds 256
  distinct values, `0` through `255`.
- **`0xFF` = 255.** Two hex digits cover exactly one byte (4 bits + 4 bits), so
  hex is the natural way to write byte values. `0x00` is 0, `0xFF` is 255.
- **CSS colors are hex.** A color like `#FF8800` is three bytes - red `FF`
  (255), green `88` (136), blue `00` (0) - written as six hex digits. Now you
  can read them: `#FFFFFF` is all channels maxed (white), `#000000` is all off
  (black).

> ⚠️ **Gotcha:** One hex digit is *exactly* four bits - never three, never
> five. That's the whole reason hex is convenient. When you read a binary
> string, mentally chop it into groups of four *from the right*, and each group
> becomes one hex digit. Grouping from the left instead will give you the wrong
> answer if the length isn't a multiple of four.

## Recap

- **Positional notation** gives every digit a place value that's a power of the
  base; the base is how many digits you have before you carry.
- **Binary** is base 2 (digits `0`,`1`; place values are powers of two). Convert
  to decimal by adding the place values that are on; convert from decimal by
  repeated division by 2, reading remainders bottom-up.
- **Hex** is base 16 (digits `0`–`9` then `A`–`F` for 10–15). Its superpower:
  one hex digit equals exactly four bits, so it's a compact, readable shorthand
  for long binary strings.
- Computers store **binary** (two stable hardware states); humans read **hex**
  because it's binary that's four times shorter and easier on the eyes.

Quick check before you move on:

```quiz
[
  {
    "q": "What base is the binary number system?",
    "choices": ["Base 10", "Base 2", "Base 8", "Base 16"],
    "answer": 1,
    "explain": "Binary uses exactly two digits, 0 and 1, so it is base 2. Its place values are powers of two."
  },
  {
    "q": "What is the decimal value of the binary number 1010₂?",
    "choices": ["5", "8", "10", "12"],
    "answer": 2,
    "explain": "Place values from the right are 1, 2, 4, 8. The on bits are the 8 and the 2: 8 + 0 + 2 + 0 = 10."
  },
  {
    "q": "Why do people write binary values in hexadecimal?",
    "choices": [
      "Hex can store larger numbers than binary can",
      "Each hex digit is exactly 4 bits, so hex is a compact, readable shorthand for binary",
      "Computers can only understand hex, not binary",
      "Hex avoids the need for the digit zero"
    ],
    "answer": 1,
    "explain": "One hex digit maps to exactly four bits, so a long binary string becomes four times shorter and far easier to read without changing the underlying value."
  }
]
```

Watch it animated: [binary and number bases](/explainers/BinaryBits.dc.html)


---

# Modular Arithmetic: Clock Math

You already do modular arithmetic every day. You call it "telling time."

When someone says "I'll be there in 5 hours" and it's 10 o'clock, you don't answer "15 o'clock." You say "3 o'clock." Your brain wrapped the number around the clock face. That wrap-around - that fold back to the start - is the whole idea behind modular arithmetic. No new mental muscle required; you've done it since you learned to read a clock.

This phase gives that instinct a name, a precise definition, and a place in your toolbox. By the end you'll see it running underneath things that look nothing like clocks: hash tables, ring buffers, parity bits, even the math that keeps your messages private.

## The clock analogy

Picture a 12-hour clock face. The numbers run 1, 2, 3, all the way to 12, and then they don't keep going to 13 - they loop back to 1. The clock has no room for 13. Pass 12 and you start over.

So when it's 10 o'clock and you add 5 hours:

```
10 + 5 = 15
```

But 15 doesn't exist on the clock. You wrap it. You walk past 12, and the extra 3 hours land you on **3 o'clock**. The clock "forgot" the full lap and kept only what was left over.

That leftover is the key. Adding 5 hours to 10 didn't matter in its full size - what mattered was how far past 12 you ended up. Modular arithmetic is the math of *how far past the wrap point you land*. The clock is the friendliest example because you've held one your whole life, but the same wrapping happens with any cycle: days of the week, compass directions, seats around a table.

## Definition

Here's the precise version.

> `a mod n` is the **remainder** when you divide `a` by `n`.

We call `n` the **modulus** - the size of the cycle, the number you wrap around. The result of `a mod n` always lands in the range `0` to `n − 1`. It can never reach `n` itself: the moment the remainder would hit `n`, that's a full extra group, and it folds back to `0`.

Work through `17 mod 5`:

```
17 ÷ 5 = 3 remainder 2
```

Five goes into 17 three full times (that's 15), and 2 is left over. So `17 mod 5 = 2`. The "3 full times" is the part we throw away - like the full lap around the clock. The remainder, 2, is what we keep.

A few quick ones to feel the range:

```
0 mod 5 = 0      (nothing left over)
4 mod 5 = 4      (5 doesn't fit even once, so all 4 are "left over")
5 mod 5 = 0      (fits exactly once, nothing left - back to start)
6 mod 5 = 1      (one full group, 1 left over)
```

Notice the answers cycle 0, 1, 2, 3, 4, 0, 1, 2, 3, 4… forever. That repeating loop is the wrap-around made visible.

## Everyday patterns

Once you know to look for it, `mod` shows up everywhere a thing repeats.

**Even or odd.** A number is even when dividing by 2 leaves nothing over, odd when it leaves 1. So `n mod 2` is your even/odd test: `0` means even, `1` means odd. The whole concept of parity is one modulo away.

**Wrapping an index around a list.** Say you have a list of length `L` and you keep stepping forward, past the end, and want to loop back to the front (think of a playlist on repeat). Position `i mod L` always lands you on a real slot, `0` through `L − 1`, no matter how big `i` gets. Walk off the end and you reappear at the start.

**The day of the week.** Weeks cycle every 7 days. If today is day 0 and you ask "what day is it in 100 days?", you don't count 100 days - you compute `100 mod 7 = 2` and step forward 2 days. The mod did the wrapping for you.

Different surfaces, same move: take a number that grew too big for its cycle, and fold it back to where it belongs.

## Congruence (briefly)

You'll sometimes see this notation:

```
a ≡ b (mod n)
```

Read aloud: "a is congruent to b, modulo n." It means `a` and `b` leave the **same remainder** when divided by `n` - they land on the same spot in the cycle.

For example, `15 ≡ 3 (mod 12)`, because 15 and 3 both sit on "3 o'clock." They're not equal numbers, but on a 12-hour clock they're indistinguishable. That's all congruence says: *different numbers, same position once you wrap.* You don't need to do anything with this yet - recognize the `≡` symbol when it appears, so it doesn't look like a typo for `=`.

## Real uses

This is where the clock metaphor pays off in real systems.

**Hashing.** A hash table stores items in a fixed number of buckets. To decide which bucket an item goes in, you run it through a hash function (which spits out some large number) and then take `hash mod numBuckets`. The mod squashes any huge hash value down into a valid bucket index. Wrap-around is the right tool: you have more possible hashes than buckets, so you fold them into the range that fits.

**Ring buffers and round-robin.** A ring buffer is a fixed-size array you treat as a loop - reach the end, and you write back at the start. The write position is `i mod n`. The same math powers round-robin scheduling, where you hand work to server 0, then 1, then 2, then back to 0. The `mod` is what makes the line bend into a circle.

**Parity bits and checksums.** When data travels over a wire, a parity bit records whether the number of 1-bits is even or odd - a `mod 2` summary. If the parity doesn't match on arrival, something got corrupted. Larger checksums use bigger moduli but the same remainder idea to catch errors.

**Cryptography.** At a high level, much of modern cryptography is built on modular arithmetic - operations on huge numbers, all wrapped around a large modulus. The wrap-around makes certain calculations easy to do forward but very hard to reverse without the key. We won't go deeper here; the point is that the humble remainder you use to read a clock is the same machinery securing your bank login.

## See it run

Here's all of it in one place. Read the comments, then read the explanation below.

```python runnable
print(17 % 5)        # remainder -> 2
print(10 % 2)        # even -> 0
print((10 + 5) % 12) # clock wrap -> 3
i = 7
print(i % 3)         # wrap an index -> 1
```

*What just happened:* `%` is the modulo operator in Python (and most languages). `17 % 5` is `17 mod 5`, the remainder after 5 goes into 17 three times - that's **2**. `10 % 2` is **0**, which tells us 10 is even (no remainder). `(10 + 5) % 12` first adds to 15, then wraps it on a 12-clock to land on **3** o'clock. And `i % 3` with `i = 7` is **1**, because 3 fits into 7 twice (that's 6) with 1 left over - exactly how you'd wrap index 7 around a list of length 3.

## For builders

The practical kit, all in one spot:

- **The `%` operator.** In most languages - Python, JavaScript, Java, C, Go - `%` is modulo. `17 % 5` gives `2`. Reach for it any time you need "the remainder" or "wrap this around."
- **Hashing into buckets.** `bucket = hash(key) % numBuckets` is the line that turns an enormous hash value into a valid slot. It's in nearly every hash map you'll ever use.
- **Ring-buffer indices.** `nextIndex = (i + 1) % capacity` advances a position and loops it back to 0 at the end, no `if` statement needed. Clean, branch-free wrapping.
- **Alternating behavior.** `i % 2` flips between `0` and `1` as `i` counts up. Perfect for zebra-striping table rows, alternating colors, or splitting work between two workers.

These four show up constantly. Recognizing "oh, this is a modulo problem" is half the battle; the other half is typing `%`.

⚠️ **The negative-number trap.** Here's something that quietly bites people: the sign of `%` for negative numbers is **not** the same across languages. In Python, the result follows the sign of the *divisor*, so `-1 % 3` is `2` - a positive number, exactly what you want for wrapping an index. But in C, Java, and Go, `%` can return a *negative* remainder, so `-1 % 3` gives `-1`. Feed that straight into an array index and you'll read out of bounds or crash. When you might have negative inputs in those languages, force it positive with something like `((x % n) + n) % n`. Know which language you're in before you trust `%` with a negative.

## Recap

Modular arithmetic is wrap-around math, and you had the instinct before you had the word for it:

- `a mod n` is the **remainder** when you divide `a` by `n`, always landing in `0 … n − 1`.
- The clock is the perfect picture: pass the top, fold back to the start, keep only what's left over.
- `n mod 2` tests even (`0`) versus odd (`1`); `i mod L` wraps an index around a list.
- `a ≡ b (mod n)` means `a` and `b` share a remainder - same spot on the cycle.
- It powers hashing, ring buffers, round-robin, parity checks, and (at a high level) cryptography.
- Watch the sign of `%` for negative numbers - it differs by language.

Quick check before you move on:

```quiz
[
  {
    "q": "What does `a mod n` give you?",
    "choices": ["The quotient when a is divided by n", "The remainder when a is divided by n", "a multiplied by n", "n divided by a"],
    "answer": 1,
    "explain": "Modulo keeps only the remainder after dividing a by n - the leftover that didn't make a full group. The result always sits between 0 and n − 1."
  },
  {
    "q": "How do you test whether a number `n` is even using modulo?",
    "choices": ["n % 2 == 1", "n % 2 == 0", "n % 0 == 2", "n % 1 == 0"],
    "answer": 1,
    "explain": "An even number leaves no remainder when divided by 2, so `n % 2 == 0` means even. `n % 2 == 1` would mean odd."
  },
  {
    "q": "Which of these is a real-world use of modular arithmetic?",
    "choices": ["Picking a hash-table bucket with `hash % numBuckets`", "Measuring the length of a string", "Sorting a list alphabetically", "Reversing the characters in a word"],
    "answer": 0,
    "explain": "Hashing folds a huge hash value into a valid bucket index with modulo. Wrapping an index around a list and clock arithmetic are other everyday examples; the rest don't rely on remainders."
  }
]
```

That closes out **Numbers & Number Systems**. You started by seeing that numbers come in families that nest inside each other, you learned that the same value can be written in different bases - binary, decimal, hex - depending on what the machine or the human needs, and now you've got the math of wrap-around in hand. Numbers are no longer a flat list of digits; they're a structured, expressive system you can reason about.

From here, the rest of the Mathematics track builds on this footing. Counting comes next - the art of figuring out *how many* arrangements, choices, and combinations are possible without listing them all by hand. After that, probability, where counting meets uncertainty and you learn to put real numbers on "how likely is this?" If you ever feel a number-shaped knot of dread, revisit the mindset in [Why Math Isn't Your Enemy](/guides/why-math-isnt-your-enemy) - the same calm, build-it-up approach carries all the way through. And if you want to see how these number sets relate more formally, [Sets, Relations, and Functions](/guides/sets-relations-and-functions) is the natural next stop.
