01 — Real Numbers
Topic 1 of the syllabus (Review). This is our starting point. Everything later in mathematics — equations, functions, graphs, calculus, and the mathematics used in AI — is built on top of the real numbers. So we go slowly and carefully here.
1. Intuition first: numbers are points on a line
Forget formulas for a minute. Picture a straight line that goes on forever in both directions. Pick one point and call it 0. Pick a step size and call the point one step to the right 1.
Now the big idea:
Every real number is exactly one point on that line, and every point on the line is exactly one real number.
That line is called the real number line. “Real number” is just the name for “a point on this line”. Nothing more mysterious than that.
Why we needed to invent more and more numbers
Humans did not get all these numbers at once. Each new kind of number was invented because the old ones could not answer a question:
| Question people asked | Number they had to invent | Name |
|---|---|---|
| How many sheep do I have? | $1, 2, 3, \dots$ | natural numbers |
| I have no sheep. | $0$ | zero |
| I owe you 5 sheep. | $-5$ | negative integers |
| Share 3 pizzas between 4 people. | $\tfrac{3}{4}$ | fractions / rationals |
| How long is the diagonal of a square of side 1? | $\sqrt{2}$ | irrational numbers |
The last one is the surprise of this notebook. The diagonal of a unit square has a length that cannot be written as a fraction of two whole numbers. We will prove that later — not just believe it.
All of these numbers together are the real numbers, written $\mathbb{R}$.
2. The tools we will use (read this before the first code cell)
We will draw pictures and check calculations with Python. Three libraries do the work. A library is just a collection of ready-made Python code that someone else wrote.
- matplotlib — a drawing library. It makes plots: number lines, graphs, shapes.
We always import it as
matplotlib.pyplot as plt. Rule of this course: every picture is drawn by code, never with keyboard characters. - numpy — a fast numbers library. Its main object is the array: a list of many
numbers that you can add, multiply, or feed to a function all at once.
np.linspace(0, 1, 5)means “give me 5 numbers evenly spaced from 0 to 1”. - sympy — a symbolic mathematics library. Normal Python computes
2**0.5 = 1.4142135623730951(an approximation). SymPy keeps $\sqrt{2}$ as the exact symbol $\sqrt{2}$ and can tell us true facts about it, such as “this is not rational”.
Every line that touches one of these libraries gets a comment in plain English.
# --- our very first picture: the real number line ---
import matplotlib.pyplot as plt # plt = the drawing tool (matplotlib's plotting part)
import numpy as np # np = the fast-numbers tool (we use it for pi and sqrt)
# Colour code used in the WHOLE notebook, so pictures stay consistent:
C_INT = "#1f77b4" # blue -> integers
C_RAT = "#2ca02c" # green -> rational numbers that are not integers
C_IRR = "#d62728" # red -> irrational numbers
fig, ax = plt.subplots(figsize=(11, 2.6)) # make one empty drawing area, 11 wide, 2.6 tall
ax.axhline(0, color="white", lw=1.5) # axhline = draw a horizontal line at height 0
# tick marks at every whole number from -4 to 4
for t in range(-4, 5): # range(-4, 5) gives -4, -3, ..., 4
ax.plot([t, t], [-0.09, 0.09], color="white", lw=1) # a short vertical stroke
ax.text(t, -0.42, str(t), ha="center", fontsize=10) # text = write the label below
# the numbers we want to show off: (label, value, colour, height of the label)
# the heights alternate so that neighbouring labels do not touch each other
marks = [
(r"$-3$", -3.0, C_INT, 0.30),
(r"$-\frac{5}{2}$", -2.5, C_RAT, 0.58),
(r"$\frac{3}{4}$", 0.75, C_RAT, 0.30),
(r"$\sqrt{2}\approx1.414$", np.sqrt(2), C_IRR, 0.58), # np.sqrt = square root
(r"$\pi\approx3.1416$", np.pi, C_IRR, 0.30), # np.pi = the number pi
]
for label, value, colour, height in marks:
ax.plot(value, 0, "o", color=colour, markersize=9) # "o" = a filled dot
ax.text(value, height, label, ha="center", color=colour, fontsize=12)
ax.set_xlim(-4.6, 4.6) # how much of the line we look at, left to right
ax.set_ylim(-0.8, 1.0) # vertical window (the line itself is flat)
ax.axis("off") # hide the default box and axes: we drew our own line
ax.set_title("The real number line: every real number is one point", fontsize=13)
plt.show() # show the finished picture

Look at the picture. Blue dots are whole numbers, green dots are fractions, red dots are the strange ones. They all live on the same line. There is no gap and no special shelf for $\pi$. That is the whole point of the real numbers: the line is complete, with no holes in it.
3. Formal definitions
Now we say the same things precisely. New symbols are defined the first time they appear.
3.1 Sets
A set is a collection of objects. The objects are called elements. We write a set with curly braces: $A = {1, 2, 3}$.
| Symbol | Read as | Meaning |
|---|---|---|
| $x \in A$ | “$x$ belongs to $A$” | $x$ is an element of the set $A$ |
| $x \notin A$ | “$x$ does not belong to $A$” | $x$ is not an element of $A$ |
| $A \subseteq B$ | “$A$ is a subset of $B$” | every element of $A$ is also an element of $B$ |
| $A \cup B$ | “$A$ union $B$” | everything that is in $A$, or in $B$, or in both |
| $A \cap B$ | “$A$ intersect $B$” | everything that is in $A$ and in $B$ |
| $\varnothing$ | “the empty set” | the set with no elements at all |
We also use set-builder notation: \(\{\, x \mid x \text{ has some property} \,\}\) read as “the set of all $x$ such that $x$ has that property”. The bar $\mid$ means “such that”.
3.2 The five families of numbers
Definition 1 (natural numbers). \(\mathbb{N} = \{1, 2, 3, 4, \dots\}\) the counting numbers. (Some books put $0$ inside $\mathbb{N}$; we will not. The numbers $0,1,2,3,\dots$ are called the whole numbers.)
Definition 2 (integers). \(\mathbb{Z} = \{\dots, -3, -2, -1, 0, 1, 2, 3, \dots\}\) the natural numbers, their negatives, and zero. (The letter $Z$ comes from the German word Zahlen, “numbers”.)
Definition 3 (rational numbers). \(\mathbb{Q} = \left\{\, \frac{a}{b} \;\middle|\; a \in \mathbb{Z},\; b \in \mathbb{Z},\; b \neq 0 \,\right\}\) a rational number is a ratio of two integers, with a non-zero bottom. ($Q$ is for quotient.) In the fraction $\frac{a}{b}$, the top number $a$ is the numerator and the bottom number $b$ is the denominator.
Definition 4 (irrational numbers). A real number that is not rational is called irrational. We write this set $\mathbb{I}$. Examples: $\sqrt{2}$, $\sqrt{3}$, $\pi$, $e$.
Definition 5 (real numbers). \(\mathbb{R} = \mathbb{Q} \cup \mathbb{I}\) every point of the number line. Every rational is real; every irrational is real; nothing else is real.
These families sit inside one another: \(\mathbb{N} \subseteq \mathbb{Z} \subseteq \mathbb{Q} \subseteq \mathbb{R}\)
Why is $\mathbb{Z} \subseteq \mathbb{Q}$? Because any integer $n$ can be written as the fraction $\frac{n}{1}$. So every integer is a rational number, even though we do not usually write it as a fraction.
# --- picture of the families sitting inside one another ---
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse # Ellipse = an oval shape we can draw and fill
fig, ax = plt.subplots(figsize=(9, 6))
# Each Ellipse((cx, cy), width, height, ...) is one oval centred at (cx, cy).
# facecolor = fill colour, edgecolor = border colour, lw = border thickness.
ovals = [
(Ellipse((0.0, 0.0), 10.0, 7.0, facecolor="#f2f2f2", edgecolor="black", lw=2), r"$\mathbb{R}$ real", (0.0, 3.05)),
(Ellipse((-1.6, 0.0), 6.0, 5.4, facecolor="#dff0d8", edgecolor="#2ca02c", lw=2), r"$\mathbb{Q}$ rational",
(-1.6, 2.35)),
(Ellipse((-1.9, -0.4), 4.0, 3.4, facecolor="#d6e9f8", edgecolor="#1f77b4", lw=2), r"$\mathbb{Z}$ integers",
(-1.9, 0.75)),
(Ellipse((-2.0, -0.9), 2.4, 1.7, facecolor="#ffffff", edgecolor="#7f4fa0", lw=2), r"$\mathbb{N}$ natural",
(-2.0, -0.55)),
]
for oval, label, (lx, ly) in ovals:
ax.add_patch(oval) # add_patch = put the shape on the drawing
ax.text(lx, ly, label, ha="center", fontsize=13) # its name
# a few example numbers written where they belong
samples = [
("7", -2.0, -1.05, "#7f4fa0"), # natural
("-4", -3.2, 0.10, "#1f77b4"), # integer, not natural
(r"$\frac{3}{4}$", -2.6, 1.75, "#2ca02c"), # rational, not integer
("= 0.75", -1.6, 1.75, "#2ca02c"), # the same number in decimal form
(r"$\sqrt{2}$", 3.0, 0.90, "#d62728"), # irrational
(r"$\pi$", 3.2, -0.40, "#d62728"), # irrational
]
for txt, x, y, colour in samples:
ax.text(x, y, txt, ha="center", fontsize=13, color=colour)
# the part of R that is OUTSIDE Q is exactly the set of irrational numbers
ax.text(2.9, 2.0, r"$\mathbb{I}$ irrational", ha="center", fontsize=13, color="#d62728")
ax.set_xlim(-5.5, 5.5)
ax.set_ylim(-4.0, 3.6)
ax.set_aspect("equal") # equal = one unit across looks the same as one unit up, so ovals are not squashed
ax.axis("off")
ax.set_title("The number families are nested boxes", fontsize=14)
plt.show()

3.3 Decimal form
Every real number can be written as a decimal: an integer part, a dot, and then a list of digits, possibly infinite.
- Terminating decimal — the digits stop: $\;\frac{5}{8} = 0.625$
- Repeating decimal — a block of digits repeats for ever. We put a bar over the block: $\;\frac{1}{3} = 0.\overline{3} = 0.3333\dots$ and $\;\frac{23}{55} = 0.4\overline{18} = 0.4181818\dots$
- Non-terminating and non-repeating — the digits never stop and never fall into a repeating pattern: $\;\sqrt{2} = 1.41421356\dots$ and $\;\pi = 3.14159265\dots$
Theorem D below proves the key fact: the first two cases are exactly the rational numbers, and the third case is exactly the irrational numbers.
3.4 Order
Definition 6 (order). For real numbers $a$ and $b$, we write $a < b$ (“$a$ is less than $b$”) when $a$ lies to the left of $b$ on the number line. $a > b$ means $b < a$, and $a \le b$ means “$a < b$ or $a = b$”.
3.5 Absolute value and distance
Definition 7 (absolute value). For a real number $a$, \(|a| = \begin{cases} a, & \text{if } a \ge 0,\\[2pt] -a, & \text{if } a < 0.\end{cases}\)
| In words: $ | a | $ is the number without its sign. It is the distance from $a$ to $0$ on | ||
| the number line, so it is never negative. Example: $ | 5 | = 5$ and $ | -5 | = -(-5) = 5$. |
Definition 8 (distance). The distance between two real numbers $a$ and $b$ is \(d(a, b) = |a - b|.\) Example: the distance between $-4$ and $7$ is $|-4 - 7| = |-11| = 11$.
3.6 Intervals
An interval is a piece of the number line with no holes in it. Let $a < b$.
| Notation | Meaning as a set | Ends |
|---|---|---|
| $(a, b)$ | ${x \mid a < x < b}$ | both ends excluded (open) |
| $[a, b]$ | ${x \mid a \le x \le b}$ | both ends included (closed) |
| $[a, b)$ | ${x \mid a \le x < b}$ | left included, right excluded |
| $(a, \infty)$ | ${x \mid x > a}$ | goes right for ever |
| $(-\infty, b]$ | ${x \mid x \le b}$ | goes left for ever |
The symbol $\infty$ (“infinity”) is not a number. It is a shorthand for “this side never stops”, so it always gets a round bracket, never a square one.
In pictures: a filled dot means the endpoint is included, an open (hollow) dot means it is excluded.
# --- picture: what the interval notations look like ---
import matplotlib.pyplot as plt
# each row is: (name, left end, right end, is the left end included?, is the right end included?)
# True = included (filled dot), False = excluded (hollow dot), None = goes on for ever (arrow)
rows = [
(r"$(-1,\,3)$", -1, 3, False, False),
(r"$[-1,\,3]$", -1, 3, True, True),
(r"$[-1,\,3)$", -1, 3, True, False),
(r"$(1,\,\infty)$", 1, 5, False, None),
(r"$(-\infty,\,0]$", -5, 0, None, True),
]
fig, ax = plt.subplots(figsize=(10, 5))
for i, (name, lo, hi, lclosed, rclosed) in enumerate(rows):
y = -i # each interval on its own row, going downwards
ax.axhline(y, color="0.85", lw=1) # a faint grey guide line across the row
ax.plot([lo, hi], [y, y], color="#1f77b4", lw=4) # the thick blue bar = the interval itself
for end, closed, direction in [(lo, lclosed, -1), (hi, rclosed, +1)]:
if closed is True: # filled dot = endpoint belongs to the set
ax.plot(end, y, "o", color="#1f77b4", markersize=11)
elif closed is False: # hollow dot = endpoint does NOT belong
ax.plot(end, y, "o", markerfacecolor="white", markeredgecolor="#1f77b4",
markeredgewidth=2, markersize=11)
else: # arrow = the interval never ends on this side
ax.annotate("", xy=(end + 0.55 * direction, y), xytext=(end, y),
arrowprops=dict(arrowstyle="-|>", color="#1f77b4", lw=3))
ax.text(-6.8, y, name, ha="left", va="center", fontsize=13) # the name in the left margin
for t in range(-5, 6): # one shared scale of tick labels at the bottom
ax.text(t, -len(rows) + 0.45, str(t), ha="center", fontsize=9, color="0.4")
ax.set_xlim(-7.2, 6.0)
ax.set_ylim(-len(rows) + 0.2, 0.8)
ax.axis("off")
ax.set_title("Interval notation: filled dot = included, hollow dot = excluded", fontsize=13)
plt.show()

3.7 The rules the real numbers obey (the axioms)
An axiom is a rule we accept as a starting point, without proof. Everything else must be proved from the axioms. Here are the axioms of $\mathbb{R}$. Let $a, b, c$ be any real numbers.
Algebra axioms
| Name | Addition | Multiplication |
|---|---|---|
| Closure | $a + b$ is a real number | $ab$ is a real number |
| Commutative | $a + b = b + a$ | $ab = ba$ |
| Associative | $(a+b)+c = a+(b+c)$ | $(ab)c = a(bc)$ |
| Identity | $a + 0 = a$ | $a \cdot 1 = a$, and $1 \neq 0$ |
| Inverse | there is $-a$ with $a + (-a) = 0$ | if $a \neq 0$ there is $\tfrac{1}{a}$ with $a \cdot \tfrac1a = 1$ |
| Distributive | $a(b + c) = ab + ac$ |
(The distributive law is the only axiom that links $+$ and $\times$. It does most of the work in algebra.)
Order axioms
- Trichotomy: exactly one of $a < b$, $a = b$, $a > b$ is true.
- Transitivity: if $a < b$ and $b < c$, then $a < c$.
- If $a < b$, then $a + c < b + c$.
- If $a < b$ and $c > 0$, then $ac < bc$.
Completeness axiom — the one that makes $\mathbb{R}$ different from $\mathbb{Q}$. First two new words:
- $M$ is an upper bound of a set $S$ if $x \le M$ for every $x \in S$.
- $M$ is the least upper bound (or supremum) of $S$ if it is an upper bound and no smaller number is an upper bound.
Completeness. Every non-empty set of real numbers that has an upper bound has a least upper bound, and that least upper bound is itself a real number.
In plain language: the real line has no holes. The rational numbers fail this test. Look at $S = {x \in \mathbb{Q} \mid x^2 < 2}$. Inside $\mathbb{Q}$ this set has upper bounds ($1.5$, $1.42$, $1.415$, …) but no least one, because the number that ought to be the least upper bound is $\sqrt{2}$ — and $\sqrt{2}$ is not rational. There is a hole in $\mathbb{Q}$ exactly where $\sqrt{2}$ should be. The completeness axiom says $\mathbb{R}$ has no such holes, and that is also what guarantees the symbol $\sqrt{2}$ names a real number at all.
4. Theorems, with full proofs
A theorem is a statement we can prove. A proof is a chain of steps where every step is an axiom, a definition, or something already proved. A lemma is a small helper theorem, proved only so we can use it inside a bigger proof.
Read every proof line by line and ask yourself: which rule allows this step? That habit is the whole skill.
Lemma 1 — the additive inverse is unique
Statement. If $x + y = 0$ and $x + y’ = 0$, then $y = y’$.
(In words: a number has only one “opposite”. So writing $-x$ is not ambiguous.)
Proof. \(\begin{aligned} y &= y + 0 && \text{(identity axiom)}\\ &= y + (x + y') && \text{(because } x + y' = 0)\\ &= (y + x) + y' && \text{(associative axiom)}\\ &= (x + y) + y' && \text{(commutative axiom)}\\ &= 0 + y' && \text{(because } x + y = 0)\\ &= y' && \text{(identity axiom)} \end{aligned}\) $\blacksquare$
(The black square $\blacksquare$ marks the end of a proof.)
Theorem A — multiplying by zero
Statement. For every real number $a$: $\;a \cdot 0 = 0$.
Why this needs a proof. Look at the axiom list again. Nothing there says $a \cdot 0 = 0$. The axioms only say $a + 0 = a$ and $a \cdot 1 = a$. So this “obvious” fact is a theorem, and we must derive it.
Proof. Start from $0 + 0 = 0$ (identity axiom, with $a = 0$). Multiply both sides by $a$: \(a \cdot 0 = a \cdot (0 + 0) = a \cdot 0 + a \cdot 0 \qquad \text{(distributive axiom)}\) Write $t = a\cdot 0$ to keep it short. We have shown $t = t + t$. By the inverse axiom there is a number $-t$ with $t + (-t) = 0$. Add it to both sides: \(\begin{aligned} t + (-t) &= (t + t) + (-t)\\ 0 &= t + \bigl(t + (-t)\bigr) && \text{(associative)}\\ 0 &= t + 0 && \text{(inverse)}\\ 0 &= t && \text{(identity)} \end{aligned}\) So $a \cdot 0 = t = 0$. $\blacksquare$
Theorem B — the zero-product property
Statement. If $ab = 0$, then $a = 0$ or $b = 0$.
Why we care. This is the reason “factor, then set each factor equal to zero” solves equations. Without it, solving $x^2 - 5x + 6 = 0$ by writing $(x-2)(x-3) = 0$ would prove nothing.
Proof. Suppose $ab = 0$. There are two cases.
Case 1: $a = 0$. Then the conclusion “$a = 0$ or $b = 0$” is already true. Done.
Case 2: $a \neq 0$. Then by the inverse axiom the number $\frac1a$ exists, and \(\begin{aligned} b &= 1 \cdot b && \text{(identity)}\\ &= \left(\tfrac1a \cdot a\right) b && \text{(inverse axiom)}\\ &= \tfrac1a \,(a b) && \text{(associative)}\\ &= \tfrac1a \cdot 0 && \text{(our assumption } ab = 0)\\ &= 0 && \text{(Theorem A)} \end{aligned}\) So $b = 0$. In both cases at least one of the two numbers is $0$. $\blacksquare$
Theorem C — the sign rules
Statement. For all real $a, b$: (i) $(-a)b = -(ab)$; (ii) $-(-a) = a$; (iii) $(-a)(-b) = ab$.
Proof of (i). By definition, $-(ab)$ is the number you add to $ab$ to get $0$. So it is enough to show that $(-a)b$ does that job; Lemma 1 then says it must be $-(ab)$. \(ab + (-a)b = \bigl(a + (-a)\bigr) b = 0 \cdot b = 0\) using the distributive axiom (read backwards), then the inverse axiom, then Theorem A together with commutativity, since $0 \cdot b = b \cdot 0 = 0$. $\blacksquare$
Proof of (ii). The inverse axiom gives $a + (-a) = 0$, so by commutativity $(-a) + a = 0$. That equation says: $a$ is a number which, added to $-a$, gives $0$. But $-(-a)$ is also such a number. By Lemma 1 (uniqueness) they must be equal: $-(-a) = a$. $\blacksquare$
Proof of (iii). \((-a)(-b) \overset{\text{(i)}}{=} -\bigl(a(-b)\bigr) = -\bigl((-b)a\bigr) \overset{\text{(i)}}{=} -\bigl(-(ba)\bigr) \overset{\text{(ii)}}{=} ba = ab\) Each step is marked with the rule used; the unmarked steps are commutativity. $\blacksquare$
So now we know why “minus times minus is plus”. It is not a convention that someone invented. It is forced by the distributive law.
Theorem D — the rationals are exactly the terminating or repeating decimals
Statement. Let $x$ be a real number written as a decimal. Then \(x \in \mathbb{Q} \iff \text{the decimal of } x \text{ terminates or eventually repeats.}\)
The symbol $\iff$ means “if and only if”: both directions are claimed, so we must prove two things.
Part 1: rational $\Rightarrow$ terminating or repeating.
The tool is the pigeonhole principle: if you put $n+1$ pigeons into $n$ holes, then some hole gets two pigeons. Obvious, but powerful.
Proof. Let $x = \frac{p}{q}$ with $p, q$ integers and $q > 0$ (if $q$ were negative, multiply top and bottom by $-1$). Do long division of $p$ by $q$. At every step you have a remainder $r$, and by the definition of a remainder \(0 \le r < q .\) So the remainder is always one of the $q$ numbers $0, 1, 2, \dots, q-1$. Those are our “holes”, and there are only $q$ of them.
Two cases:
- If some remainder is $0$, the division stops. The decimal terminates.
-
If no remainder is ever $0$, then every remainder is one of the $q-1$ values $1, 2, \dots, q-1$. Look at the first $q$ remainders: that is $q$ pigeons in $q-1$ holes, so two of them must be equal.
Now the key observation. In long division, the next digit and the next remainder are computed only from the current remainder: you bring down a zero, divide $10r$ by $q$, the quotient is the next digit and the leftover $10r \bmod q$ is the next remainder. So if the remainder at step $i$ equals the remainder at step $j$ (with $i < j$), then steps $i+1$ and $j+1$ produce the same digit and the same remainder, then $i+2$ and $j+2$ do too, and so on for ever. The digits from step $i$ up to step $j-1$ repeat for ever, with period $j - i$.
So the decimal repeats, and the repeating block has length at most $q - 1$. $\blacksquare$
A free bonus from this proof: the repeating block of $\frac{p}{q}$ is never longer than $q-1$ digits. For $q = 7$ that promises at most 6 digits — and indeed $\frac17 = 0.\overline{142857}$, exactly 6.
Part 2: terminating or repeating $\Rightarrow$ rational.
Proof. A terminating decimal with $k$ digits after the point equals $\frac{\text{(all the digits read as one integer)}}{10^{k}}$ — an integer over an integer, so it is rational. For example $0.625 = \frac{625}{1000}$.
Now the repeating case. Say $x$ has $k$ digits before the repeating block starts, and the repeating block has length $m$. Consider the two numbers $10^{k}x$ and $10^{k+m}x$. Multiplying by a power of ten only shifts the decimal point, so:
- in $10^{k}x$ the repeating block starts immediately after the point;
- in $10^{k+m}x$ the repeating block also starts immediately after the point, because we shifted by exactly one whole block more.
Their fractional parts (the digits after the point) are therefore identical, and subtracting kills them completely: \(10^{k+m}x - 10^{k}x = N, \qquad N \in \mathbb{Z}.\) Factor the left side: $x\left(10^{k+m} - 10^{k}\right) = N$, and $10^{k+m} - 10^{k}$ is a non-zero integer, so \(x = \frac{N}{10^{k+m} - 10^{k}} \in \mathbb{Q}. \qquad \blacksquare\)
The same proof on a concrete number. Let $x = 0.4\overline{18} = 0.4181818\dots$ Here $k = 1$ (one digit “4” before the block) and $m = 2$ (the block is “18”). \(\begin{aligned} 10^{3}x &= 418.181818\dots\\ 10^{1}x &= \phantom{41}4.181818\dots\\ \hline 990x &= 414 \end{aligned} \qquad\Longrightarrow\qquad x = \frac{414}{990} = \frac{23}{55}.\)
# --- long division by hand, in pure Python, so we can SEE the pigeonhole argument ---
# This cell uses no library at all: only the core Python you already know.
def long_division(p, q, max_digits=40):
# Returns (integer part, list of decimal digits, index where the repetition starts).
# The last item is None if the decimal terminates.
# We copy exactly what you do on paper: keep a remainder, multiply it by 10,
# divide by q, write down the digit, keep the new remainder.
whole, r = divmod(p, q) # divmod(p, q) gives (p // q, p % q) in one step
digits = [] # the decimal digits we produce, in order
seen = {} # remembers: remainder -> the digit position where we saw it
while r != 0 and len(digits) < max_digits:
if r in seen: # this remainder appeared before -> the cycle starts there
return whole, digits, seen[r]
seen[r] = len(digits) # record the position of this remainder
digit, r = divmod(r * 10, q) # bring down a zero: divide 10*r by q
digits.append(digit)
return whole, digits, None # None = the division terminated
for p, q in [(5, 8), (1, 3), (1, 7), (23, 55), (1, 13)]:
whole, digits, start = long_division(p, q)
if start is None:
text = f"{whole}." + "".join(map(str, digits)) # a terminating decimal
kind = "TERMINATES"
else:
before = "".join(map(str, digits[:start])) # the digits before the repeating block
block = "".join(map(str, digits[start:])) # the repeating block itself
text = f"{whole}.{before}({block})" # ( ) marks the repeating block
kind = f"REPEATS, block length {len(block)} (must be <= q-1 = {q - 1})"
print(f"{p:>2}/{q:<3} = {text:<26} {kind}")
5/8 = 0.625 TERMINATES
1/3 = 0.(3) REPEATS, block length 1 (must be <= q-1 = 2)
1/7 = 0.(142857) REPEATS, block length 6 (must be <= q-1 = 6)
23/55 = 0.4(18) REPEATS, block length 2 (must be <= q-1 = 54)
1/13 = 0.(076923) REPEATS, block length 6 (must be <= q-1 = 12)
# --- the same idea as a picture: the remainders of 1/7 walk around a closed loop ---
import matplotlib.pyplot as plt
q = 7
r = 1 # long division of 1 by 7 starts with remainder 1
steps, rems, digs = [], [], []
for step in range(14): # 14 steps = twice around the cycle
steps.append(step)
rems.append(r)
digit, r = divmod(r * 10, q) # exactly one step of long division
digs.append(digit)
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(steps, rems, "-o", color="#1f77b4", lw=2, markersize=8) # the remainder after each step
for s, rr, d in zip(steps, rems, digs):
ax.text(s, rr + 0.28, str(d), ha="center", color="#d62728", fontsize=11) # the digit produced
ax.axhspan(0.5, q - 0.5, color="#dff0d8", alpha=0.5, zorder=0) # axhspan = shade a horizontal band
ax.text(-0.3, 7.1, "the green band holds the only 6 possible non-zero remainders",
ha="left", fontsize=10, color="#2ca02c")
ax.set_ylim(0, 7.8) # leave empty space at the top for that sentence
ax.set_yticks(range(0, q)) # show every whole-number remainder on the vertical axis
ax.set_xticks(steps)
ax.set_xlabel("step of the long division")
ax.set_ylabel("remainder")
ax.set_title(r"$1/7$: the remainders must repeat (pigeonhole). Red numbers are the decimal digits.",
fontsize=12)
ax.grid(alpha=0.3) # a faint grid, so values are easy to read
plt.show()
print("digits of 1/7:", "".join(map(str, digs)))

digits of 1/7: 14285714285714
Theorem E — $\sqrt{2}$ is irrational
This is the theorem that forced humans to accept irrational numbers. The Greeks found it about 2500 years ago, and the story says it upset them badly.
First the definition: $\sqrt{2}$ is the positive real number whose square is $2$. (That such a number exists on the real line is guaranteed by the completeness axiom.)
We also need one fact about fractions: every rational number can be written in lowest terms, that is as $\frac{a}{b}$ where $a$ and $b$ have no common factor except $1$. Why? Because if they had a common factor $d > 1$, we could cancel it, and the denominator would become strictly smaller. A positive whole number cannot get smaller for ever, so the cancelling must stop.
Lemma 2. For an integer $n$: if $n^{2}$ is even, then $n$ is even.
Proof (by contrapositive). The statement “if $P$ then $Q$” says exactly the same thing as “if not $Q$ then not $P$”. So instead we prove: if $n$ is odd, then $n^2$ is odd.
Let $n$ be odd. By the definition of odd, $n = 2k + 1$ for some integer $k$. Then \(n^{2} = (2k+1)^{2} = 4k^{2} + 4k + 1 = 2\underbrace{(2k^{2} + 2k)}_{\text{an integer}} + 1,\) which is $2 \times (\text{integer}) + 1$, so $n^2$ is odd. $\blacksquare$
Theorem E. $\sqrt{2} \notin \mathbb{Q}$.
Proof (by contradiction). In a proof by contradiction we assume the opposite of what we want, and then derive something impossible. That forces the assumption to be false.
Assume $\sqrt{2}$ is rational. Then we may write \(\sqrt{2} = \frac{a}{b}, \qquad a, b \in \mathbb{Z},\; b \neq 0,\; \gcd(a,b) = 1\) (in lowest terms, as explained above; $\gcd$ means “greatest common divisor”).
Square both sides: \(2 = \frac{a^{2}}{b^{2}} \quad\Longrightarrow\quad a^{2} = 2b^{2}. \tag{$\ast$}\)
- From $(\ast)$, $a^{2}$ equals $2 \times (\text{integer})$, so $a^{2}$ is even.
- By Lemma 2, $a$ is even. So $a = 2k$ for some integer $k$.
- Put $a = 2k$ back into $(\ast)$: \((2k)^{2} = 2b^{2} \;\Longrightarrow\; 4k^{2} = 2b^{2} \;\Longrightarrow\; b^{2} = 2k^{2}.\)
- So $b^{2}$ is even, and by Lemma 2 again, $b$ is even.
Now $a$ and $b$ are both even, so both are divisible by $2$ — but we chose them with $\gcd(a,b) = 1$, meaning they share no factor bigger than $1$. Contradiction.
Therefore the assumption was false: $\sqrt{2}$ cannot be written as a ratio of integers. $\sqrt{2}$ is irrational. $\blacksquare$
Notice how little the proof used about the number $2$: only “even/odd”, which really means only that $2$ is prime. The same argument works for $\sqrt{3}, \sqrt{5}, \sqrt{7}, \dots$ (Exercise 18 asks you to do $\sqrt{3}$.)
# --- SymPy: exact mathematics instead of approximations ---
# sympy keeps symbols such as sqrt(2) exactly, so it can answer "is this rational?" truthfully.
import sympy as sp
r2 = sp.sqrt(2) # the EXACT object "square root of 2", not a decimal
print("sympy object :", r2)
print("its square :", sp.simplify(r2 ** 2)) # simplify = tidy an expression -> 2
print("is it rational? :", r2.is_rational) # sympy answers False: it knows Theorem E
print("is pi rational? :", sp.pi.is_rational)
print("is 23/55 rational? :", sp.Rational(23, 55).is_rational) # Rational(a, b) = the exact fraction a/b
print()
print("50 exact digits of sqrt(2):", sp.N(r2, 50)) # N(x, d) = the numeric value of x with d digits
print("plain Python float :", 2 ** 0.5, " <- only about 17 digits, and rounded")
print()
# our repeating-decimal example, done exactly
x = sp.Rational(414, 990) # the fraction the proof produced
print("414/990 in lowest terms :", x) # sympy cancels automatically -> 23/55
print("back to a decimal :", sp.N(x, 15))
# nsimplify guesses the exact fraction hiding behind a decimal
print("nsimplify(0.625) :", sp.nsimplify(0.625, rational=True))
sympy object : sqrt(2)
its square : 2
is it rational? : False
is pi rational? : False
is 23/55 rational? : True
50 exact digits of sqrt(2): 1.4142135623730950488016887242096980785696718753769
plain Python float : 1.4142135623730951 <- only about 17 digits, and rounded
414/990 in lowest terms : 23/55
back to a decimal : 0.418181818181818
nsimplify(0.625) : 5/8
# --- no fraction can hit sqrt(2) exactly, however large we let the denominator grow ---
# For each denominator b we take the BEST possible numerator a, then look at the error.
import numpy as np
import matplotlib.pyplot as plt
target = np.sqrt(2) # the decimal value we are chasing
bs = np.arange(1, 201) # denominators b = 1, 2, ..., 200 (an array of integers)
a_best = np.round(target * bs) # np.round = closest integer numerator for each b
errors = np.abs(a_best / bs - target) # np.abs = absolute value, applied to the whole array at once
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(bs, errors, "o", markersize=4, color="#d62728")
ax.set_yscale("log") # a log scale can show very small numbers clearly
ax.set_xlabel("denominator b")
ax.set_ylabel(r"error $\left|\frac{a}{b}-\sqrt{2}\right|$ (log scale)")
ax.set_title(r"Best fractions get close to $\sqrt{2}$ — but the error is never exactly 0", fontsize=12)
ax.grid(alpha=0.3, which="both")
plt.show()
i = errors.argmin() # argmin = the position of the smallest value
print("smallest error found:", errors[i], " at b =", bs[i], " (fraction", int(a_best[i]), "/", bs[i], ")")
print("...small, but NOT zero. Theorem E says it can never be zero.")

smallest error found: 1.2378941142587863e-05 at b = 169 (fraction 239 / 169 )
...small, but NOT zero. Theorem E says it can never be zero.
Theorem F — the triangle inequality
| Statement. For all real $a, b$: $\; | a + b | \le | a | + | b | $. |
Intuition. Walk $a$ steps, then $b$ steps. If both walks go the same way, you end as far from home as possible: $|a+b| = |a|+|b|$. If they fight each other, they cancel a little and you end up closer. So the final distance is never more than the sum of the two.
| Lemma 3. For every real $a$: $\;- | a | \le a \le | a | $. |
Proof. Two cases, straight from Definition 7.
-
If $a \ge 0$: then $ a = a$, so “$a \le a $” reads $a \le a$ — true. And $- a = -a \le 0 \le a$ — true. - If $a < 0$: then $|a| = -a > 0$, so $a < 0 < |a|$ — true. And $-|a| = -(-a) = a$ (Theorem C(ii)), so “$-|a| \le a$” reads $a \le a$ — true. $\blacksquare$
| Lemma 4. Let $c \ge 0$. If $-c \le x \le c$, then $ | x | \le c$. |
Proof. Two cases.
-
If $x \ge 0$: then $ x = x \le c$ by assumption. Done. - If $x < 0$: then $|x| = -x$. From $-c \le x$, adding $c - x$ to both sides gives $-x \le c$, that is $|x| \le c$. Done. $\blacksquare$
Proof of Theorem F. Apply Lemma 3 to $a$ and to $b$: \(-|a| \le a \le |a|, \qquad -|b| \le b \le |b|.\) Adding two inequalities that point the same way is allowed (order axiom 3, used twice), so \(-\bigl(|a| + |b|\bigr) \le a + b \le |a| + |b|.\) Now put $x = a+b$ and $c = |a| + |b|$. Note $c \ge 0$, because absolute values are never negative. Lemma 4 gives exactly \(|a + b| \le |a| + |b|. \qquad \blacksquare\)
When is it an equality? Exactly when $a$ and $b$ have the same sign, or one of them is $0$. In the picture below, that is where the two curves touch.
# --- picture: |a+b| never rises above |a|+|b| ---
import numpy as np
import matplotlib.pyplot as plt
a = 2.0 # keep a fixed and let b vary
b = np.linspace(-6, 6, 601) # linspace(start, stop, n) = n evenly spaced values
left = np.abs(a + b) # the left-hand side |a+b|, computed for every b at once
right = np.abs(a) + np.abs(b) # the right-hand side |a|+|b|
fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(b, right, color="#1f77b4", lw=2.5, label=r"$|a|+|b|$")
ax.plot(b, left, color="#d62728", lw=2.5, label=r"$|a+b|$")
ax.fill_between(b, left, right, color="#d62728", alpha=0.12) # fill_between = shade between two curves
ax.axvline(0, color="0.7", lw=1) # axvline = a vertical line, here at b = 0
ax.set_xlabel("b")
ax.set_ylabel("value")
ax.set_title(r"Triangle inequality with $a=2$: the red curve is never above the blue one", fontsize=12)
ax.legend(fontsize=12) # legend = the little box that names each curve
ax.grid(alpha=0.3)
plt.show()
print("largest value of |a+b| - (|a|+|b|):", (left - right).max(), " (it is never positive)")

largest value of |a+b| - (|a|+|b|): 0.0 (it is never positive)
Theorem G — between any two real numbers there is a rational number
This is called the density of $\mathbb{Q}$ in $\mathbb{R}$. It says the fractions are spread everywhere, leaving no empty stretch of the line, however tiny.
We first need one consequence of completeness.
Archimedean property. For every real number $x$ there is a natural number $n$ with $n > x$. (In words: the natural numbers have no ceiling — you can always count past any number.)
Proof. Suppose not. Then $\mathbb{N}$ has an upper bound, and $\mathbb{N}$ is not empty, so by the completeness axiom it has a least upper bound $s$. Since $s$ is the least upper bound, the smaller number $s - 1$ is not an upper bound, which means some $n \in \mathbb{N}$ satisfies $n > s - 1$. Add $1$ to both sides: $n + 1 > s$. But $n+1$ is also a natural number, and $s$ was supposed to be an upper bound of $\mathbb{N}$, so we need $n + 1 \le s$. Contradiction. $\blacksquare$
Theorem G. If $x < y$ are real numbers, then there exists $r \in \mathbb{Q}$ with $x < r < y$.
The idea before the symbols. Take a ruler whose marks are $\frac1n$ apart, and choose $n$ so large that the spacing is smaller than the gap $y - x$. A ruler mark cannot jump over a gap that is wider than its own step, so some mark $\frac{m}{n}$ has to land inside $(x, y)$.
Proof.
- Since $x < y$, we have $y - x > 0$. By the Archimedean property choose $n \in \mathbb{N}$ with $n > \dfrac{1}{y-x}$. Multiplying both sides by the positive number $\frac{y-x}{n}$ gives \(\frac{1}{n} < y - x. \tag{1}\)
- Again by the Archimedean property, integers larger than $nx$ exist. Among all integers greater than $nx$, let $m$ be the smallest one. (A non-empty set of integers that is bounded below has a smallest element — this is the well-ordering fact about integers.)
- “$m$ is the smallest integer greater than $nx$” means precisely \(m - 1 \le nx < m. \tag{2}\)
- From the right half of (2), $nx < m$; dividing by $n > 0$, \(x < \frac{m}{n}.\)
- From the left half of (2), $m \le nx + 1$. Using (1) in the form $1 < n(y-x)$, \(m \le nx + 1 < nx + n(y - x) = ny,\) and dividing by $n > 0$ gives $\dfrac{m}{n} < y$.
Putting steps 4 and 5 together: \(x < \frac{m}{n} < y,\) and $\frac{m}{n}$ is a ratio of integers, hence rational. $\blacksquare$
A consequence worth noticing. This works for every pair $x<y$, no matter how close. So there are infinitely many rationals between any two different reals: find one, then apply the theorem again to the smaller gap, for ever.
# --- density in action: squeeze a fraction into a tiny gap next to sqrt(2) ---
import numpy as np
import matplotlib.pyplot as plt
from fractions import Fraction # Fraction is CORE Python: an exact fraction a/b
x = np.sqrt(2) # the left end of our tiny interval
y = x + 1e-6 # the right end: only 0.000001 further right
# the recipe from the proof, done literally:
n = int(1 / (y - x)) + 1 # step 1: n bigger than 1/(y-x)
m = int(np.floor(n * x)) + 1 # step 2: m = the smallest integer strictly greater than n*x
r = Fraction(m, n) # the rational number the proof promises us
print(f"gap : ({x:.15f}, {y:.15f})")
print(f"n : {n}")
print(f"rational : {m}/{n} = {float(r):.15f}")
print(f"is x < r < y ? {x < float(r) < y}")
# --- and the same idea as a picture, at a zoom level we can actually see ---
x2, y2 = 0.6180, 0.6185 # a gap wide enough to draw
n2 = 20000 # a ruler with marks 1/20000 apart
ms = np.arange(int(np.ceil(x2 * n2)), int(np.floor(y2 * n2)) + 1) # every ruler mark inside the gap
marks = ms / n2
fig, ax = plt.subplots(figsize=(10, 2.8))
ax.plot([x2, y2], [0, 0], color="#dff0d8", lw=14, zorder=0) # the gap, as a thick green band
ax.axhline(0, color="black", lw=1.2)
ax.plot(marks, np.zeros_like(marks), "|", color="#2ca02c", markersize=22, markeredgewidth=2)
ax.plot([x2, y2], [0, 0], "o", color="#d62728", markersize=9) # the two ends x and y
ax.text(x2, 0.22, r"$x$", ha="center", color="#d62728", fontsize=13)
ax.text(y2, 0.22, r"$y$", ha="center", color="#d62728", fontsize=13)
ax.text((x2 + y2) / 2, -0.38, f"{len(marks)} rationals with denominator {n2} already fit inside",
ha="center", fontsize=11, color="#2ca02c")
ax.set_xlim(x2 - 0.00008, y2 + 0.00008)
ax.set_ylim(-0.6, 0.6)
ax.axis("off")
ax.set_title("Density: however small the gap, fractions are already inside it", fontsize=12)
plt.show()
gap : (1.414213562373095, 1.414214562373095)
n : 1000001
rational : 1414215/1000001 = 1.414213585786414
is x < r < y ? True

5. Worked examples
Each example is done end to end. Cover the solution with your hand and try it first.
Example 1 — classify each number. \(-3,\quad 0,\quad \frac{5}{8},\quad \sqrt{9},\quad \sqrt{2},\quad 0.\overline{3},\quad \frac{22}{7},\quad \pi\)
| Number | Natural? | Integer? | Rational? | Irrational? | Real? |
|---|---|---|---|---|---|
| $-3$ | no | yes | yes | no | yes |
| $0$ | no (we start $\mathbb{N}$ at 1) | yes | yes | no | yes |
| $\frac58$ | no | no | yes | no | yes |
| $\sqrt 9$ | yes (it is $3$) | yes | yes | no | yes |
| $\sqrt 2$ | no | no | no | yes | yes |
| $0.\overline{3}$ | no | no | yes (it is $\frac13$) | no | yes |
| $\frac{22}{7}$ | no | no | yes | no | yes |
| $\pi$ | no | no | no | yes | yes |
Two traps to remember:
- $\sqrt{9}$ looks irrational but it is just $3$. A square root is irrational only when the number under it is not a perfect square.
- $\frac{22}{7} = 3.142857\dots$ is a famous approximation of $\pi$, but it is a fraction, so it is rational — and it is not equal to $\pi$.
Example 2 — turn $0.\overline{7}$ into a fraction.
Let $x = 0.7777\dots$ Here there are $k=0$ digits before the block and the block has length $m=1$, so multiply by $10^{0+1}=10$ and by $10^{0}=1$: \(\begin{aligned} 10x &= 7.7777\dots\\ 1x &= 0.7777\dots\\ \hline 9x &= 7 \end{aligned} \qquad\Longrightarrow\qquad x = \frac{7}{9}.\) Check: $7 \div 9 = 0.777\dots$ ✓
Example 3 — order of operations.
Evaluate $\;8 - 2\bigl[4 - (2 + 5)\bigr] \div 3 + 1$.
Work from the inside out (brackets → multiply/divide, left to right → add/subtract, left to right): \(\begin{aligned} 8 - 2[4 - (2+5)] \div 3 + 1 &= 8 - 2[4 - 7] \div 3 + 1 && \text{innermost bracket}\\ &= 8 - 2(-3) \div 3 + 1 && \text{square bracket}\\ &= 8 - (-6) \div 3 + 1 && \text{multiply first (left to right)}\\ &= 8 - (-2) + 1 && \text{then divide}\\ &= 8 + 2 + 1 = 11 && \text{Theorem C(ii): } -(-2) = 2 \end{aligned}\)
Example 4 — absolute value and distance.
| (a) Compute $ | 3 - 9 | - | {-2} | $. | ||
| $$ | 3-9 | - | -2 | = | -6 | - 2 = 6 - 2 = 4.$$ |
(b) Solve $|x - 3| = 5$. The equation says “the distance from $x$ to $3$ is $5$”. On the number line you can go $5$ to the left or $5$ to the right: \(x - 3 = 5 \;\Rightarrow\; x = 8, \qquad x - 3 = -5 \;\Rightarrow\; x = -2.\) So $x \in {-2, 8}$.
(c) Solve $|x + 2| < 4$ and write the answer as an interval. $|x+2| = |x - (-2)|$ is the distance from $x$ to $-2$, and we want it smaller than $4$: \(-4 < x + 2 < 4 \;\Longrightarrow\; -6 < x < 2,\) (subtracting $2$ from all three parts, which order axiom 3 allows). As an interval: $(-6, 2)$.
Example 5 — where is an expression undefined?
For which real $x$ does $\dfrac{x+1}{x^{2}-4}$ make sense?
Division by $0$ is not defined, so we need $x^{2} - 4 \neq 0$. Factor: $x^{2}-4 = (x-2)(x+2)$. By Theorem B, this product is $0$ exactly when $x - 2 = 0$ or $x + 2 = 0$, that is $x = 2$ or $x = -2$. So the expression is defined for \(x \in (-\infty, -2) \cup (-2, 2) \cup (2, \infty).\)
# --- check the worked examples with Python ---
import sympy as sp
from fractions import Fraction
# Example 2: does 7/9 really give 0.7777... ?
print("Example 2: 7/9 =", sp.N(sp.Rational(7, 9), 12))
# Example 3: Python obeys the same order of operations
print("Example 3: 8 - 2*(4 - (2+5))/3 + 1 =", 8 - 2 * (4 - (2 + 5)) / 3 + 1)
# Example 4a
print("Example 4a: |3-9| - |-2| =", abs(3 - 9) - abs(-2)) # abs = core Python absolute value
# Example 4b: solve |x-3| = 5 exactly with sympy
x = sp.symbols("x", real=True) # symbols(...) = create the unknown x (a real number)
print("Example 4b: solutions of |x-3| = 5 :", sp.solve(sp.Abs(x - 3) - 5, x)) # solve( expr = 0 )
# Example 4c: solve the inequality |x+2| < 4
print("Example 4c: |x+2| < 4 means :", sp.solve_univariate_inequality(sp.Abs(x + 2) < 4, x))
# Example 5: where is the denominator zero?
print("Example 5: x^2 - 4 = 0 at x =", sp.solve(x ** 2 - 4, x))
Example 2: 7/9 = 0.777777777778
Example 3: 8 - 2*(4 - (2+5))/3 + 1 = 11.0
Example 4a: |3-9| - |-2| = 4
Example 4b: solutions of |x-3| = 5 : [-2, 8]
Example 4c: |x+2| < 4 means : (-6 < x) & (x < 2)
Example 5: x^2 - 4 = 0 at x = [-2, 2]
6. More Python demonstrations
These cells are here for you to change the numbers and re-run. Experimenting is how the ideas become yours.
# --- WHICH fractions terminate? A small experiment ---
# Try to spot the pattern yourself before reading the sentence under the output.
# We reuse the long_division function defined earlier in this notebook.
import sympy as sp
for q in range(2, 26):
kind = "terminates" if long_division(1, q, 60)[2] is None else "repeats"
factors = sp.factorint(q) # factorint(n) = the prime factors of n, as {prime: power}
factor_text = " * ".join(f"{p}^{e}" for p, e in factors.items())
print(f"1/{q:<3} {kind:<11} q = {factor_text}")
print()
print("Pattern: 1/q terminates exactly when q has NO prime factor other than 2 and 5.")
print("Reason: a terminating decimal is N/10^k, and 10^k = 2^k * 5^k.")
1/2 terminates q = 2^1
1/3 repeats q = 3^1
1/4 terminates q = 2^2
1/5 terminates q = 5^1
1/6 repeats q = 2^1 * 3^1
1/7 repeats q = 7^1
1/8 terminates q = 2^3
1/9 repeats q = 3^2
1/10 terminates q = 2^1 * 5^1
1/11 repeats q = 11^1
1/12 repeats q = 2^2 * 3^1
1/13 repeats q = 13^1
1/14 repeats q = 2^1 * 7^1
1/15 repeats q = 3^1 * 5^1
1/16 terminates q = 2^4
1/17 repeats q = 17^1
1/18 repeats q = 2^1 * 3^2
1/19 repeats q = 19^1
1/20 terminates q = 2^2 * 5^1
1/21 repeats q = 3^1 * 7^1
1/22 repeats q = 2^1 * 11^1
1/23 repeats q = 23^1
1/24 repeats q = 2^3 * 3^1
1/25 terminates q = 5^2
Pattern: 1/q terminates exactly when q has NO prime factor other than 2 and 5.
Reason: a terminating decimal is N/10^k, and 10^k = 2^k * 5^k.
# --- absolute value as a picture: the graph of y = |x|, and the meaning of |x-3| <= 2 ---
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-6, 8, 801) # 801 sample points from -6 to 8
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4.2)) # 1 row, 2 drawings side by side
# left drawing: the V-shaped graph of the absolute value
ax1.plot(x, np.abs(x), color="#1f77b4", lw=2.5)
ax1.axhline(0, color="black", lw=1) # the x-axis
ax1.axvline(0, color="black", lw=1) # the y-axis
ax1.set_title(r"$y=|x|$: distance from $x$ to $0$", fontsize=12)
ax1.set_xlabel("x");
ax1.set_ylabel("y")
ax1.set_aspect("equal") # equal scales, so the V really looks like a 90-degree V
ax1.grid(alpha=0.3)
# right drawing: which x satisfy |x-3| <= 2 ?
y = np.abs(x - 3)
ax2.plot(x, y, color="#1f77b4", lw=2.5, label=r"$y=|x-3|$") # note: matplotlib writes "<=" as \leq
ax2.axhline(2, color="#d62728", lw=2, ls="--", label=r"$y=2$") # ls="--" = dashed line
sel = y <= 2 # a True/False array: which x satisfy the inequality
ax2.fill_between(x[sel], 0, 2, color="#2ca02c", alpha=0.25) # shade the solution region
ax2.plot([1, 5], [0, 0], "o", color="#2ca02c", markersize=9) # the two endpoints 1 and 5
ax2.set_title(r"$|x-3|\leq 2$ means $1\leq x\leq 5$, i.e. $[1,5]$", fontsize=12)
ax2.set_xlabel("x");
ax2.set_ylabel("y")
ax2.legend()
ax2.grid(alpha=0.3)
plt.tight_layout() # tight_layout = tidy the spacing so labels do not overlap
plt.show()

# --- a last look: the digits of sqrt(2) and of 1/7, side by side ---
# One of them settles into a pattern. The other never does.
import sympy as sp
digits_sqrt2 = str(sp.N(sp.sqrt(2), 60)) # 60 digits of an irrational number
# 60 digits of 1/7, WITHOUT stopping at the cycle, so we can watch the block come back
r, ds = 1, []
for _ in range(60):
digit, r = divmod(r * 10, 7) # one step of long division, 60 times
ds.append(digit)
print("sqrt(2) =", digits_sqrt2)
print("1/7 = 0." + "".join(map(str, ds)))
print()
print("Look at 1/7: 142857 142857 142857 ... a block that repeats for ever.")
print("Look at sqrt(2): no block ever repeats - and Theorem D tells us WHY it never can.")
sqrt(2) = 1.41421356237309504880168872420969807856967187537694807317668
1/7 = 0.142857142857142857142857142857142857142857142857142857142857
Look at 1/7: 142857 142857 142857 ... a block that repeats for ever.
Look at sqrt(2): no block ever repeats - and Theorem D tells us WHY it never can.
7. Exercises (20)
Rules of the game:
- Do them in order: they go from easy to hard, and the last four are proofs.
- Try each one by hand first, then use Python only to check.
- Write your answer in the empty cell under the question. Do not delete the question.
- If you get stuck for more than ten minutes, write down where you got stuck — that sentence is worth as much as the answer.
Exercise 1 — classify
For each number, say which of these it is: natural, integer, rational, irrational, real. A number can be several at once.
\[-7,\qquad \frac{0}{5},\qquad \frac{9}{4},\qquad \sqrt{16},\qquad \sqrt{7},\qquad 2.5\overline{1},\qquad -\pi\]My answer:
(write it here)
Exercise 2 — true or false, with a reason
- Every integer is a rational number.
- Every rational number is an integer.
- $0$ is a natural number.
- Some real number is both rational and irrational.
- $\sqrt{25}$ is irrational.
My answer:
(write it here)
Exercise 3 — interval notation
Write each set in interval notation, then draw all four on one number line with matplotlib (filled dot = included, hollow dot = excluded).
- ${x \mid -2 \le x < 7}$
- ${x \mid x > 3}$
- ${x \mid x \le 0}$
- ${x \mid -1 < x \le 1}$
# your work here
Exercise 4 — absolute values
Compute by hand, then check with Python:
\[|-7|,\qquad |3 - 9|,\qquad |5| - |-5|,\qquad |{-2}| \cdot |{-3}|,\qquad \bigl||{-4}| - |1|\bigr|\]# your work here
Exercise 5 — distance
- What is the distance between $-8$ and $3$ on the number line?
- What is the distance between $-8$ and $-13$?
- Write “the distance from $x$ to $6$ is $2$” as an equation with absolute value, and solve it.
My answer:
(write it here)
Exercise 6 — order of operations
Evaluate by hand, showing every step:
\[12 \div 3 \cdot 2 - \bigl[5 - (7 - 10)\bigr] + (-2)^{2}\]Then check with Python. If your answer differs from Python’s, find which step went wrong.
# your work here
Exercise 7 — use the distributive law
Simplify, and name the axiom used at each step:
\[3(x + 4) - 2(x - 5)\]My answer:
(write it here)
Exercise 8 — repeating decimal to fraction
Use the method of Theorem D, Part 2 (multiply by two powers of ten and subtract). Show the subtraction, and give the answer in lowest terms.
- $0.\overline{6}$
- $0.\overline{123}$
- $0.2\overline{45}$
My answer:
(write it here)
Exercise 9 — fraction to decimal
Turn each fraction into a decimal by long division on paper. Say whether it terminates or repeats, and give the repeating block if it repeats.
\[\frac{5}{8},\qquad \frac{7}{12},\qquad \frac{4}{11}\]Then check with the long_division function from this notebook.
# your work here
Exercise 10 — the terminating rule
Without dividing, decide which of these have a terminating decimal:
\[\frac{3}{40},\qquad \frac{7}{30},\qquad \frac{9}{16},\qquad \frac{11}{6},\qquad \frac{13}{50}\]Hint: look at the prime factors of the denominator after the fraction is in lowest terms, and remember $10 = 2 \times 5$. Write the rule in one sentence, then test it with Python.
# your work here
Exercise 11 — absolute value equations
Solve, and mark the solutions on a number line drawn with matplotlib:
-
$ x - 4 = 6$ -
$ 2x + 1 = 9$ -
$ x + 3 = -2$ (careful!)
# your work here
Exercise 12 — absolute value inequality
Solve $|x + 2| < 5$. Write the answer as an interval, and draw the solution set with matplotlib (shade the region, and mark the two endpoints with hollow dots).
# your work here
Exercise 13 — squeezing numbers in
- Find a rational number between $\sqrt{2}$ and $\sqrt{3}$. Prove your number really is between them.
- Find an irrational number between $1$ and $1.001$. Hint: $\sqrt{2}$ is irrational, and dividing an irrational number by a non-zero rational keeps it irrational (you may use this fact here; Exercise 17 is close to proving it).
My answer:
(write it here)
Exercise 14 — Python: find a repeating block
Using the long_division function from this notebook, find the repeating block of
$\frac{1}{13}$ and of $\frac{1}{17}$. How long is each block? Check that both lengths obey
the bound proved in Theorem D (block length $\le q-1$).
# your work here
Exercise 15 — Python: your own number line
Draw a number line from $-4$ to $4$ with matplotlib, and mark these numbers, using the notebook’s colour code (blue = integer, green = rational, red = irrational):
\[-\frac{5}{2},\qquad 0,\qquad \frac{7}{4},\qquad \sqrt{5},\qquad -\sqrt{2},\qquad 3\]Label every point with its exact symbol, not its decimal.
# your work here
Exercise 16 — is $0.\overline{9}$ equal to $1$?
- Apply the method of Theorem D, Part 2 to $x = 0.\overline{9}$ and see what you get.
- Many people feel this must be wrong. Explain in your own words what the equation really says. Hint: if $0.\overline{9} \neq 1$, then by Theorem G there is a rational number strictly between them. Can you name one?
My answer:
(write it here)
Exercise 17 — proof
Prove: if $r$ is rational and $t$ is irrational, then $r + t$ is irrational.
Hint: proof by contradiction. Assume $r + t$ is rational and show that $t$ would then have to be rational too. You will need the fact that the difference of two rationals is rational — prove that little step as well, do not just assume it.
My proof:
(write it here — every step must name the rule you used)
Exercise 18 — proof
Prove that $\sqrt{3}$ is irrational.
Hint: copy the structure of Theorem E, but replace Lemma 2 by: “if $3$ divides $n^{2}$ then $3$ divides $n$”. To prove that lemma, write $n$ in one of the three forms $3k$, $3k+1$, $3k+2$ and square each one.
My proof:
(write it here — every step must name the rule you used)
Exercise 19 — proof from the axioms only
Using only the axioms of §3.7, Lemma 1, and Theorems A–C (say which one you use at each step), prove:
- $(-1) \cdot a = -a$ for every real $a$.
- If $a + c = b + c$, then $a = b$ (the cancellation law for addition).
My proof:
(write it here — every step must name the rule you used)
Exercise 20 — proof (hardest)
Prove: between any two different real numbers $x < y$ there is an irrational number.
Hint: you already have Theorem G for rationals. Apply it to the pair $\dfrac{x}{\sqrt2} < \dfrac{y}{\sqrt2}$ to get a rational $r$ in between, then multiply back by $\sqrt{2}$. Be careful with the case $r = 0$, and remember to justify that $r\sqrt{2}$ is irrational when $r \neq 0$ is rational.
My proof:
(write it here — every step must name the rule you used)
8. How to run this notebook (uv)
uv is the tool that manages this project: it installs the exact Python version and the
exact libraries listed in pyproject.toml, so the notebook runs the same way every time.
From the project folder math/:
uv sync # install Python 3.13+ and the dependencies (jupyterlab, numpy, sympy, matplotlib)
uv run jupyter lab # start JupyterLab in your browser
Then open notebooks/01-real-numbers.ipynb and run the cells from the top with
Shift + Enter.
If a future notebook needs a library we do not have yet, add it first:
uv add pandas # example: adds pandas to pyproject.toml and installs it
Never write import somelibrary for a package that is not in pyproject.toml — it will
fail for anyone who re-runs the notebook.
What we proved in this notebook
| # | Result | In one sentence |
|---|---|---|
| Lemma 1 | inverses are unique | ”$-a$” means one single number |
| A | $a\cdot 0 = 0$ | proved, not assumed |
| B | $ab=0 \Rightarrow a=0$ or $b=0$ | why factoring solves equations |
| C | $(-a)(-b) = ab$ | why minus times minus is plus |
| D | rational $\iff$ terminating or repeating decimal | pigeonhole on the remainders |
| E | $\sqrt2$ is irrational | proof by contradiction |
| F | $\lvert a+b\rvert \le \lvert a\rvert+\lvert b\rvert$ | the triangle inequality |
| G | a rational sits between any two reals | $\mathbb{Q}$ is dense in $\mathbb{R}$ |
Next topic: Algebra Essentials — but only after you have done the 20 exercises above.