PY-01-003-P · Primer — Numbers & Arithmetic
The idea in one sentence
Python has two everyday number types — int for whole numbers and float for numbers with a decimal point — and a small set of arithmetic operators (+ - * / // % **) whose results follow a couple of rules that surprise almost every beginner exactly once.
Why it exists
Every program that touches money, quantities, scores, timers, or measurements is doing arithmetic, so a language needs numbers you can trust and operators that read like math. Python gives you int and float as the two you'll reach for constantly: int counts things that come in whole units — people in a room, items in a cart, the number of times a loop ran — and float measures things that don't — a price of 4.99, a temperature of 98.6, an average of 3.5. The reason the language bothers to keep them as separate types is that they behave differently in ways you care about: int is exact and can grow arbitrarily large, while float trades a little accuracy for the ability to represent fractions. And it exists because arithmetic hides two forks — what does dividing do? and how precise is a decimal, really? — that you want the language to answer predictably rather than mysteriously.
How it works
The five operators you'll use daily are +, -, * for add/subtract/multiply, plus ** for powers (2 ** 10 is 2 to the 10th). Division splits into two: / is true division and always gives a float, even when the numbers divide evenly, while // is floor division, which divides and then rounds down to a whole number. The % operator (modulo) gives the remainder left over after floor division — 7 % 2 is 1 because 2 goes into 7 three times with 1 left over. The type of a result follows a simple rule: mix any float in and you get a float; use / and you always get a float; stick to ints with the other operators and you keep an int. You can always check with the built-in type():
print(7 + 3) # 10 -> int (whole number in, whole number out)
print(7 / 2) # 3.5 -> float (/ is ALWAYS a float)
print(7 // 2) # 3 -> int (floor division rounds down)
print(7 % 2) # 1 -> int (the remainder)
print(2 ** 10) # 1024 -> int (2 to the power of 10)
print(type(6 / 3)) # <class 'float'> (6/3 is 2.0, a float, not 2)
print(type(4)) # <class 'int'>
Notice 6 / 3 is 2.0, not 2 — the / rule wins even when the answer is whole.
The one gotcha
float cannot represent most decimals exactly, so 0.1 + 0.2 is not 0.3. This shocks everyone the first time, but it isn't a Python bug — it's how the hardware in every computer stores decimals, using binary fractions that can't land precisely on values like 0.1 any more than you can write 1/3 exactly in decimal digits. The tiny error is usually invisible, but it becomes visible the moment you print the sum or compare it with ==:
print(0.1 + 0.2) # 0.30000000000000004 (a whisker too big)
print(0.1 + 0.2 == 0.3) # False (never test floats with ==)
The practical rule: never compare floats with ==. When you need equality, check that the difference is tiny (abs(a - b) < 1e-9), and for exact money use whole int cents or Python's decimal.Decimal. This same "which type do I get?" awareness is why 10 / 2 gives 5.0 when you may have wanted the int 5 — reach for // when you truly want a whole number.
See it — how an arithmetic expression picks its result type
flowchart TD
A["Two numbers +<br/>an operator"] --> B{"Which operator?"}
B -->|"/ (true division)"| C["Result is ALWAYS<br/>a float, e.g. 6/3 = 2.0"]
B -->|"// or % or ** or<br/>+ - *"| D{"Any float<br/>in the inputs?"}
D -->|"Yes"| E["Result is a float"]
D -->|"No, all ints"| F["Result is an int"]
C --> G{"Comparing floats<br/>with ==?"}
E --> G
G -->|"Yes"| H["Danger: precision<br/>error, may be False"]
G -->|"No"| I["Safe: exact int, or<br/>use abs diff for floats"]
F --> I
The one-line takeaway
int is whole and exact while float is decimal and approximate; / always makes a float, // and % split into quotient and remainder, and you never compare floats with ==.
Where you'll meet it
You'll meet these rules the very first time you compute an average and get 3.5 where you expected a tidy number, or divide two counts and are startled to see 5.0 instead of 5. // and % become your workhorses for splitting things into groups — total // per_page pages with total % per_page items left over — and % is the standard trick for "is this number even?" (n % 2 == 0) or "every Nth item" in a loop. The 0.1 + 0.2 surprise will find you the moment you add up prices or sum a column of measurements and a test that should pass mysteriously fails; recognizing it instantly — and knowing to use int cents, round(), or decimal.Decimal for money — is one of the first marks of someone who actually understands how computers do arithmetic. From loop counters to totals to timers, almost every program you write from here on is standing on these few operators.
Named concepts: int vs float, arithmetic and // % ** operators, integer vs float division, numeric precision pitfalls
