Topic 1.2
Whole Numbers: int
In one line
An int is a whole number, positive, negative or zero, with no size limit. Python adds, subtracts and multiplies it exactly, and has special operators for division with a quotient (//), a remainder (%) and powers (**).
Think of it like this
Counting marbles. You can have 0, 7 or 3,000 marbles, and you can owe a friend 2 (minus 2). You can never have 3.5 marbles in a whole-number count. The kind of number that counts whole things is the integer, written int in Python.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- int (integer)
- A whole number with no decimal part and no size limit.
- Literal
- A value written directly in code, such as
42or "hello". - Floor division (`//`)
- Division that rounds the answer down to a whole number.
- Remainder (modulo, `%`)
- What is left over after dividing as many whole times as possible.
- Power (`**`)
- Multiply a number by itself several times:
2 ** 3is 8. - Overflow
- A number too big for its storage. Python's
intnever overflows. - Binary / hexadecimal
- Ways to write numbers using base 2 (digits 0 and 1) or base 16 (digits 0-9 and a-f).
- ZeroDivisionError
- The error Python raises when you divide by zero.
Step by step
01Integers have no limit
A normal computer stores a number in a fixed number of bits (a bit is one tiny 0-or-1 switch), so there is a largest value. Python's int grows as needed: it keeps adding more storage for the digits. You can compute 2 ** 100, or multiply every number from 1 to 1000 together, without special tools.
The underscore in 1_400_000_000 is only for readers. It is the same number as 1400000000.
population = 1_400_000_000
print(population) # 1400000000
print(2 ** 100) # 126765060022822940149670320537602Other bases
People count in tens (base 10), computers think in twos (base 2), and programmers often use sixteen (base 16, hexadecimal) because one hex digit equals exactly four bits. Python lets you type numbers in any of these.
0b1010 is 8 + 2 = 10. 0o17 is 1 * 8 + 7 = 15. 0xFF is 15 * 16 + 15 = 255. Printing shows normal decimal numbers, because the value is the same whichever way you typed it.
print(0b1010, 0o17, 0xFF) # 10 15 255
print(bin(10), oct(15), hex(255)) # 0b1010 0o17 0xff03The four kinds of division arithmetic
Think of sharing 17 sweets among 5 children. Each child gets 17 // 5 = 3 sweets, and 17 % 5 = 2 sweets are left over. True division 17 / 5 = 3.4 answers a different question: how much is each share if the sweets could be cut.
print(17 / 5) # 3.4 true division, always a float
print(17 // 5) # 3 floor division
print(17 % 5) # 2 remainder
print(2 ** 10) # 1024 power
print(divmod(17, 5)) # (3, 2)04Negative numbers and floor division
Floor division rounds toward minus infinity. On the number line, -3.4 lies between -4 and -3, and the floor is the one on the left: -4. So -17 // 5 is -4.
To keep (a // b) * b + a % b == a true, the remainder has to be -17 - (-4 * 5) = 3. That is why -17 % 5 is 3 in Python. In C and Java the remainder would be -2, which surprises people switching languages. The Python rule is more useful: % 7 always gives 0 to 6, even for negative numbers.
print(-17 // 5, -17 % 5) # -4 3
print(divmod(-17, 5)) # (-4, 3)05divmod splits a total into parts
To turn 135 minutes into hours and minutes, you need the quotient and the remainder of dividing by 60. divmod gives both in one call. Assigning the pair to two names (multiple assignment from Topic 1.1) makes it read like English.
total_minutes = 135
hours, minutes = divmod(total_minutes, 60)
print(hours, "h", minutes, "min") # 2 h 15 min06Remainders make cycles
A week has 7 days. If today is day 5 and you look 3 days ahead, the plain sum is 8, but there is no day 8. (5 + 3) % 7 wraps back to 1. Remainders turn endless counting into a loop that repeats. They appear in clocks, calendars and anything that wraps around to the start.
n % 2 == 0 tests whether n is even. You will use this idea often once you meet if in Phase 2.
07Dividing by zero
Zero cannot divide anything. /, // and % all raise ZeroDivisionError if the right side is zero. Python stops the program at that line and shows the traceback. The error message differs a little between operators, so read it.
Try it yourself
- 1
Find the hours and minutes
Change
total_minutesto 59, 60, 61 and 1000. Predicthoursandminuteseach time, then run. - 2
Floor towards minus infinity
Predict
-7 // 2and-7 % 2before you run them. Then check that(-7 // 2) * 2 + (-7 % 2)gives back -7. - 3
A very big number
Print
2 ** 1000and count its digits roughly. Python has no trouble. Think about why a fixed-size number could never hold it.
Code & diagrams
Change 17 and 5 to other numbers. Try a negative first number.
Expected output
1400000000
1267650600228229401496703205376
10 15 255
0b1010 0o17 0xff
3.4 3 2 1024
(3, 2)
-4 3
(-4, 3)The third line proves the rule that ties // and % together. type() tells you the kind of a value (Topic 1.6): 10 / 2 is a float, 10 // 2 is an int.
Expected output
2 h 15 min
True
day after 3 days: 1
3 -4 -4
<class 'float'> <class 'int'>
<class 'int'> <class 'float'>Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Divide by zero
Set people = 0 and run boxes // people.
boxes = 10
people = 0
print(boxes // people)Break #2
Zero in front of a number
Write a room number with a leading zero: 007.
room = 007Myth vs fact
Myth
/ and // do the same thing.
Fact
/ always returns a float (10 / 2 is 5.0). // returns the floored whole number. They differ even when the answer looks whole.
Myth
-17 % 5 should be -2, as in Java or C.
Fact
In Python the remainder takes the sign of the right operand, so -17 % 5 is 3. This keeps (a // b) * b + a % b == a true.
Myth
Integers overflow if they get too big.
Fact
Python's int grows as needed. Only memory is the limit. (NumPy's fixed-size integers do overflow: Phase 14.)
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
CPython stores an
intas an array of 30-bit "digits", so big integers cost more time and memory the more digits they have. Multiplying two huge numbers uses Karatsuba, not the school method. - ▸
Since the security fixes of Python 3.11 (also back-ported to older releases), converting a huge int to a decimal string, or the other way round, is limited to 4300 digits by default, to stop denial-of-service attacks on slow conversions (the cost grows with the square of the length).
str(10 ** 4300)andint("9" * 5000)raiseValueError: Exceeds the limit (4300 digits) for integer string conversion.sys.set_int_max_str_digits()or thePYTHONINTMAXSTRDIGITSenvironment variable changes the limit (0 removes it). Only bases that are not a power of two are limited, so hexadecimal and binary conversions are not. - ▸
Two more facts interviewers like.
int.bit_length()gives the bits needed ((255).bit_length()is 8), and the power-of-two testn > 0 and n & (n - 1) == 0works as written in Python, because comparisons bind looser than&(in C the same line would group the other way and be a bug; Topic 1.7). Bit operators on negative ints behave as if the number had infinitely many leading sign bits (two's complement), so-1 & 0xFFis 255 and~5is -6. And//and%on floats work too and follow the same floor rule:-7.5 // 2is-4.0. - ▸
For exactness with big numbers Python is a good choice: cryptography teaching code and combinatorics both rely on unlimited ints. For speed on millions of numbers use NumPy (Phase 14), but remember its integers have a fixed size and do overflow.
- ▸
The
%operator is how hash tables and ring buffers pick a slot. The same idea appears in the DSA course (/dsa) in hashing and circular queues.
Remember this
- 1
Python's
inthas no size limit except your computer's memory.2 ** 100is a 31-digit number, and Python prints it exactly. In many other languages the number would overflow: Java'sintsilently wraps around, and C's signedintis undefined behaviour. This is one reason Python is pleasant for number work. - 2
You can write big numbers with underscores for readability:
1_400_000_000. Python ignores the underscores. You can also write whole numbers in other bases: binary with0b1010, octal with0o17, and hexadecimal with0xFF. They are all the same kind ofint; only the way you type them differs.bin(),oct()andhex()turn an int into text in those bases. - 3
Python has two kinds of division.
/always gives a float (a decimal number):17 / 5is3.4.//is floor division: it gives the whole-number quotient,17 // 5is3.%is the remainder (the modulo):17 % 5is2.**is the power:2 ** 10is1024. - 4
Floor division always rounds down toward minus infinity, not toward zero. So
-17 // 5is-4, not-3. The remainder follows the matching rule: it takes the sign of the divisor, so-17 % 5is3. The two always agree:(a // b) * b + a % b == a. - 5
divmod(a, b)returns both results at once, as a pair(quotient, remainder). It is the natural tool for splitting a total into parts: 135 minutes isdivmod(135, 60), which is 2 hours and 15 minutes. - 6
The remainder is the key to anything that repeats in a cycle: days of the week (
% 7), clock hours (% 12), even or odd (% 2), wrapping an index around a list. Dividing by zero with//,%or/is an error:ZeroDivisionError.
Explain it without notes
What is the difference between /, // and %? Give an example for each.
Why is -17 // 5 equal to -4, and what is -17 % 5?
What does it mean that Python integers are unlimited, and what is the trade-off?
How would you turn 3725 seconds into hours, minutes and seconds?
Practice
A shop sells pens in packs of 12. You have 100 pens. Print how many full packs you can make and how many pens are left over.
Print the last digit of 4729 and the number with its last digit removed, using % and //.
A clock shows hour 10. Print the hour on the clock 5 hours later, on a 12-hour clock where the hours are 0 to 11.
Trade-offs
- ↔
Unlimited precision vs. speed. Python never overflows, which removes a whole family of bugs, but each operation on big ints is slower than a machine instruction.
- ↔
Floor division vs. truncation. Python's
//rounds down, which makes%always positive for a positive divisor and is better for cycles. Engineers coming from C must remember that the result for negatives is different.
Done when you can
Done when you can write a large number with underscores and a number in binary or hex.
Done when you can say what
/,//,%and**each return, with an example.Done when you can predict
-17 // 5and-17 % 5.Done when you can use
divmodto split minutes into hours and minutes.Done when you can read a
ZeroDivisionErrortraceback.