Arithmetic — division, remainders, and the decimal trap
The seven arithmetic operators, which one runs first, where integer division and remainders earn their keep, and why decimals sometimes answer strangely.
- 1Encounter
- 2Understand
- 3Worked
- 4Predict
- 5Apply
- 6Stretch
The problem we are solving
There are 17 books and a box holds 5. How many boxes, and how many books are left over?
The answer is not 17 / 5. That gives 3.4, and there is no such thing as 3.4 boxes. You need two separate answers: how many whole ones and how much is left. Python has an operator for each, and they turn out to be two of the most useful ones you will learn — pagination, splitting seconds into hours and minutes, testing whether a number is even, all come from here.
There is a second thing that stops everyone the first time they see it: in Python, 0.1 + 0.2 does not give 0.3. Why it does not, and what to do about it, is also in this mission.
By the end of this mission you can
- Use the seven arithmetic operators
- Say which calculation runs first, and when parentheses are needed
- Recognise where
//and%are the right tool - Explain why
/always produces a decimal, even when the division is exact - Write calculations that respect the precision limits of decimal numbers
Prerequisites: Variables and types.
The seven operators
print(10 + 3)
print(10 - 3)
print(10 * 3)
print(10 / 3)
print(10 // 3)
print(10 % 3)
print(10 ** 3)13
7
30
3.3333333333333335
3
1
1000The last three deserve a word:
//— floor division. Divides and keeps the whole part, discarding the rest%— modulo, the remainder. What is left after the division**— power.10 ** 3is ten cubed
/always produces a decimal. Even10 / 5answers2.0, not2. If the type depended on whether the division came out exact, a program's behaviour would be unpredictable, so Python keeps one rule here:/meansfloat. When you need a whole number, use//.
Solving the box problem
books = 17
per_box = 5
full_boxes = books // per_box
left_over = books % per_box
print("Full boxes:", full_boxes)
print("Left over :", left_over)Full boxes: 3
Left over : 2Three boxes fill up and 2 books stay outside. // and % come as a pair — one says "how many whole ones", the other "how much is left".
The same pair shows up in plenty of other places:
total_seconds = 500
minutes = total_seconds // 60
seconds = total_seconds % 60
print(minutes, "min", seconds, "sec")8 min 20 secAnd % is how you test even and odd. Divide any number by 2 and the remainder is 0 (even) or 1 (odd):
print(14 % 2)
print(15 % 2)0
1That remainder is exactly what the mission on conditions will build on.
Which calculation runs first
Python follows the ordinary rules of arithmetic — multiplication and division before addition and subtraction:
print(10 + 5 * 2)
print((10 + 5) * 2)20
30On the first line 5 * 2 happened first, then 10 was added. On the second, the parentheses changed the order.
Highest to lowest:
***,/,//,%+,-
print(2 + 3 * 4 ** 2)504 ** 2 is 16, then 3 * 16 is 48, then 2 + 48 is 50.
When in doubt, use parentheses. Even knowing the rules,(a + b) / 2is better written thana + b / 2— the next person to read it does not have to recall any rule. Extra parentheses do not slow the code down; they only make it clear.
This is the single most common beginner mistake, and it shows up when averaging:
a = 10
b = 20
c = 30
wrong = a + b + c / 3
right = (a + b + c) / 3
print("Wrong:", wrong)
print("Right:", right)Wrong: 40.0
Right: 20.0The program raised no error. Nothing in red, nothing broken — just a wrong answer. That is the most dangerous class of bug there is, because Python will not warn you. Only checking the arithmetic yourself catches it.
The decimal trap
print(0.1 + 0.2)0.30000000000000004This is not Python's fault. Computers store numbers in base two, and 0.1 cannot be written exactly in base two — just as 1/3 cannot be written exactly in decimal, where 0.3333... runs on forever. So the computer stores something extremely close, and adding two of them makes the tiny difference visible. JavaScript, Java and C all behave the same way.
Two practical consequences:
One — round when you display:
total = 0.1 + 0.2
print(round(total, 2))0.3round(total, 2) means keep two places after the decimal point.
Two — never compare two decimals with ==:
print(0.1 + 0.2 == 0.3)FalseThis is the trap that produces wrong answers in financial calculations. Serious projects do not hold money in a float — they store the smallest unit as a whole number (49.99 becomes 4999), or they use the separate decimal module. For now just know where the limit is; modules come later.
A complete example
packing.py:
# Work out packing and shipping for one order
total_items = 47
items_per_box = 6
box_cost = 35.5
full_boxes = total_items // items_per_box
loose_items = total_items % items_per_box
# A partly filled box still costs a full box
boxes_needed = full_boxes
if loose_items > 0:
boxes_needed = full_boxes + 1
shipping = boxes_needed * box_cost
print("Items :", total_items)
print("Full boxes :", full_boxes)
print("Loose items :", loose_items)
print("Boxes needed :", boxes_needed)
print("Shipping :", round(shipping, 2))Items : 47
Full boxes : 7
Loose items : 5
Boxes needed : 8
Shipping : 284.0The if line has not been taught yet — that is what the next few missions are for. For now just read it: if any items are left loose, one more box is needed.
When it breaks
ZeroDivisionError: division by zero Something was divided by zero. It is undefined in mathematics too, so Python stops. You have to check the divisor before dividing — which gets easy once you have conditions.
10 / 5 gave 2.0 and I need 2 Use //, or write int(10 / 5). The first is better: the intent is visible in the code.
// answers oddly on negative numbers -7 // 2 gives -4, not -3. Python rounds down, not towards zero. Worth remembering if you work with negatives.
The calculation looks right but the answer is wrong Count the parentheses, and break each step onto its own line and print it. The mistake is almost always operator precedence.
A long tail of digits after the decimal point That is not an error, it is how decimals behave. Shorten it with round() when you display it.
Step 4 of 6 — Predict
Check your understanding
All three lines work on the same two numbers, with a different operator each time. What is the output?
print(7 / 2)
print(7 // 2)
print(7 % 2)- A3.5 3 1
- B3.5 3.5 1
- C3 3 1
- D3.5 4 1
The program runs without any error but reports the average as 40.0. Why?
a = 10
b = 20
c = 30
average = a + b + c / 3
print("Average:", average)- A`/` runs first, so only `c` was divided — it needs to be `(a + b + c) / 3`
- BAverages must use `//`, not `/`
- CThe three numbers are `int`, which makes the result wrong
- D`average` is a reserved word, so the value was not stored properly
What is the output of these two lines?
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)- A0.30000000000000004 False
- B0.3 True
- C0.30000000000000004 True
- D0.3 False
Answering needs an account
Sign in to check your answers
The questions are above, and working them out in your head is the part that matters. Sign in to see the answers, the explanations and the three-level hints.
Your turn
Write a file called time_split.py that splits a number of seconds into hours, minutes and seconds.
Start from total_seconds = 7385, and the output should be:
2 h 3 m 5 sThree conditions:
- Use only
//and%— do not type any of the results by hand - Keep the three values in three separate, meaningfully named variables
- Then change
total_secondsto59,60,3600and86399and run each one — check that all four come out right
Do not skip that last step. A program that works for one input does not work; a program that also holds at the edges does.
There is more in this mission
What you read above is the complete mission — nothing was cut out of it. Pro adds:
- What actually happens underneath — how Python runs this
- The full solution to the exercise, worked step by step
- Harder extra exercises
- The interview question on this topic, with a model answer
Step 6 of 6
Stretch — the chapter quiz
Ten questions from easy to hard. The last ones are difficult on purpose.
Sign in to take the quiz