Arithmetic, and Where It Surprises You
Two slashes and one slash look like a typo of each other, and they hand back different types on purpose. Divide the same two numbers both ways and see exactly where a float appears uninvited.
Two slashes and one slash look like a typo of each other. They are not — they answer two different questions, and confusing them is one of the most common bugs a beginner writes without noticing.
Two kinds of division
$ >>> 7 / 2$ 3.5$ >>> 7 // 2$ 3/ is true division — it answers “what is 7 divided by 2, exactly?” and always returns a float, even when the numbers divide evenly. // is floor division — it answers “how many whole times does 2 go into 7?” and rounds the result down. Use // when the question is really about a count, like splitting 7 items into groups of 2.
The two show up together more often than either shows up alone. // gives you the number of whole groups; %, the modulo operator, gives you what is left over once those groups are taken out.
$ >>> 7 // 2$ 3$ >>> 7 % 2$ 1Seven items split into groups of two makes three full groups, with one item left over — // and % are the same division, read two different ways.
>>> 7 / 2
3.5
type: float
The order operations actually run in
True division. Always returns a float, even 6 / 3.
Floor division. Rounds the result down to a whole number.
Modulo. The remainder left over after floor division.
Exponentiation. Binds tighter than every other operator here.
Python follows the order you were taught in school — exponents, then multiplication and division, then addition and subtraction — with ** added at the top, binding tighter than everything else.
$ >>> 2 + 3 * 4$ 14$ >>> 2 ** 3 * 4$ 32Exponentiation has one more quirk: stack two of them, and Python works right to left instead of left to right the way every other operator here does.
$ >>> 2 ** 3 ** 2$ 512Read left to right, 2 ** 3 ** 2 looks like (2 ** 3) ** 2, which is 64. Python actually computes 3 ** 2 first, then 2 ** 9, which is 512. When an expression gets more than two operators deep, add parentheses even where they are not required — (2 + 3) * 4 costs you two characters and removes any question of what the next reader thinks runs first.
Not every decimal fits in binary
Ask Python for something that should be trivial, and it hands back an answer that looks broken.
$ >>> 0.1 + 0.2$ 0.30000000000000004Python did the arithmetic correctly. The problem sits one step earlier: 0.1 itself cannot be stored exactly in binary floating point, the same way 1/3 cannot be written exactly in decimal — the digits repeat forever, and a float only has 64 bits to hold them in. Both 0.1 and 0.2 are already tiny approximations before you add anything, and the sum surfaces the rounding error that was hiding in them the whole time.
This is not a Python bug, and switching languages will not fix it — JavaScript, Java, and C all print the identical 0.30000000000000004 for the same sum, because they store floats in the same IEEE 754 format underneath. It only surprises people the first time, because most code never prints a float with enough decimal places to expose it.
Where an int quietly becomes a float
Whole numbers in Python are int. Numbers with a decimal point are float. Mixing them in one expression is allowed, and Python resolves it by upgrading the int — the result comes back as a float, even if the value looks whole.
$ >>> 6 / 3$ 2.0$ >>> type(6 / 3)$ <class 'float'>The rule holds for every operator, not just /. Even floor division upgrades to a float the moment one side already is one — 7.0 // 2 is 3.0, not 3, because once a float enters an expression it never quietly turns back into an int on its own.
Going the other way needs to be asked for explicitly. int() converts a float to an int, and it truncates — it cuts off everything after the decimal point rather than rounding to the nearest whole number.
$ >>> int(9.9)$ 9$ >>> int(-9.9)$ -9Why an int can grow forever
In most languages, an integer has a fixed size in memory, and arithmetic that runs past the top of that size wraps around silently — a 32-bit signed integer, for instance, tops out at 2,147,483,647 and flips to a large negative number the moment you add one more. Python integers do not have a ceiling.
$ >>> 2 ** 100$ 1267650600228229401496703205376$ >>> 2 ** 100 + 1$ 1267650600228229401496703205377That is not a special case handled somewhere — a Python int automatically grows to however many digits the answer needs, limited only by how much memory the machine actually has. There is no maximum int constant to check yourself against, and no silent wraparound bug waiting in code that happens to compute something unexpectedly large.
Key takeaways
- / is true division and always returns a float. // is floor division and rounds down; % gives you what // left over.
- ** is exponentiation, and it binds tighter than every other operator, right to left — 2 ** 3 ** 2 is 512, not 64.
- Mixing an int and a float in one expression upgrades the whole result to a float, and it stays a float from then on.
- Never compare floats with == after arithmetic. 0.1 + 0.2 == 0.3 is False, because neither side can be stored exactly in binary.
- A Python int never overflows — it grows to however many digits the answer needs, unlike the fixed-size integers most other languages use.
Quick check
Answer these to unlock the next chapter — 3 of 4 to pass. You can retake it anytime.
Answer every question to check.
Make a free account to read on
Every chapter is free — an account is how your progress, XP, and streak follow you from your laptop to your phone, and how you show up on the leaderboard. No payment, no trial.