Numbers & Math
Almost every program does some maths: a bill total, an average, a percentage, the number of buses needed for a school trip. Python handles numbers well, but it has a few behaviours that surprise beginners, especially around division, rounding and decimal values like money.
In this lesson you will learn Python's number types, the arithmetic operators, how rounding really works, how to handle rupees and paise correctly with the decimal module, and the most useful functions in the math module.
Three kinds of numbers
Python has three built-in number types:
int: whole numbers such as42,-7or0. They can be as large as your memory allows.float: numbers with a decimal point, such as3.14or1299.50.complex: complex numbers such as3+4j, used in engineering and science.
population = 1_00_00_000 # underscores are ignored, so this is one crore
price = 1299.50
big = 2 ** 100
print(population)
print(type(price))
print(big)10000000 <class 'float'> 1267650600228229401496703205376
You can put underscores between digits to make long numbers readable, and Python ignores them. They can go anywhere between digits, so the Indian lakh and crore grouping works fine. Notice also that 2 ** 100 gives the exact answer: Python integers never overflow.
Arithmetic operators
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ | Add | 7 + 2 | 9 |
- | Subtract | 7 - 2 | 5 |
* | Multiply | 7 * 2 | 14 |
/ | Divide | 7 / 2 | 3.5 |
// | Integer (floor) division | 7 // 2 | 3 |
% | Remainder (modulo) | 7 % 2 | 1 |
** | Power | 7 ** 2 | 49 |
The plain / always gives a float, even when the division is exact: 10 / 2 is 5.0. Use // when you want a whole-number answer. The // and % operators are a team: one tells you how many times something fits, the other tells you what is left over.
laddoos = 17
children = 5
each = laddoos // children
left_over = laddoos % children
print("Each child gets", each, "and", left_over, "are left")
print(divmod(laddoos, children))
print("Is 17 even?", laddoos % 2 == 0)Each child gets 3 and 2 are left (3, 2) Is 17 even? False
The built-in divmod() gives both answers at once. And % 2 == 0 is the standard test for an even number.
With negative numbers, // rounds down towards minus infinity, not towards zero, so -17 // 5 is -4 and -17 % 5 is 3. You rarely need this, but it explains a surprising result if you see one.
Floats are not exact
Computers store floats in binary, and many decimal fractions, such as 0.1, cannot be stored exactly. Tiny errors appear:
import math
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(math.isclose(0.1 + 0.2, 0.3))0.30000000000000004 False True
This is not a Python bug; every language that uses standard floats behaves this way. Never compare floats with ==. Use math.isclose() instead, which allows for tiny differences.
Rounding with round()
round(number, digits) rounds to a number of decimal places. With no second argument it rounds to a whole number. A negative second argument rounds to tens, hundreds and so on.
print(round(1234.5678, 2))
print(round(1234.5678, -2))
print(round(2.5), round(3.5), round(4.5))
print(round(2.675, 2))1234.57 1200.0 2 4 4 2.67
Two results need explaining:
round(2.5)is2, not3. When a number is exactly halfway, Python rounds to the nearest even number. This is called banker's rounding, and it avoids pushing totals upwards when you round many values.round(2.675, 2)is2.67. The float 2.675 is really stored as 2.67499999..., so it rounds down.
Money: use decimal
Because floats are not exact, they are a poor choice for money. Python's decimal module stores decimal numbers exactly. Create a Decimal from a string, not from a float.
from decimal import Decimal, ROUND_HALF_UP
price = Decimal("1299")
gst_rate = Decimal("0.18")
gst = price * gst_rate
total = price + gst
print("GST:", gst)
print("Total: ₹", total)
amount = Decimal("2.675")
print(amount.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))GST: 233.82 Total: ₹ 1532.82 2.68
quantize(Decimal("0.01")) rounds to two decimal places, that is, to paise. Passing rounding=ROUND_HALF_UP gives the "school" rounding most bills use, where 0.5 always goes up. Without it, Decimal also uses banker's rounding.
The math module
The math module has the functions you remember from school maths. You import it once at the top of the file, then use math. before each name. You will learn more about importing in Modules & Imports.
import math
students = 130
seats_per_bus = 40
print("Buses needed:", math.ceil(students / seats_per_bus))
print(math.floor(7.8), math.sqrt(144), math.pi)
print(math.gcd(48, 36), math.factorial(5), math.prod([2, 3, 4]))
print(abs(-250), max(78, 91, 85), min(78, 91, 85))Buses needed: 4 7 12.0 3.141592653589793 12 120 24 250 91 78
math.ceil() rounds up and math.floor() rounds down, which is exactly what you need for the bus question: 3.25 buses means you must book 4. abs(), max(), min(), sum() and pow() are built in, so they need no import.
Complex numbers have their own uses. A complex number has a real part and an imaginary part written with j: for z = 3+4j, z.real is 3.0, z.imag is 4.0, and abs(z) is 5.0.
Common mistakes
- Expecting
/to give anint.10 / 2is5.0. Use//for whole-number results. - Using
^for power. In Python^means something else (bitwise XOR), so2 ^ 3is1. Use2 ** 3. - Using floats for money. Small errors add up across thousands of bills. Use
Decimalwith string values. - Expecting
round(2.5)to be 3. Python uses banker's rounding. UseDecimalwithROUND_HALF_UPwhen you need 0.5 to always round up.
Key points
intis for whole numbers (no size limit),floatfor decimals,complexfor complex numbers./always returns a float;//gives the whole-number part and%the remainder.- Floats are not exact: compare them with
math.isclose(), not==. round()uses banker's rounding: halfway values go to the nearest even number.- Use
decimal.Decimal("...")for money andquantize()to round to paise. import mathgivesceil,floor,sqrt,pi,gcd,factorial,prodand more.
Exercise
A school in Pune is taking 245 students on a trip. Each bus holds 50 students and costs ₹4,750. Write a program that prints the number of buses needed, how many seats will be empty, and the total bus cost. Then work out the cost per student as a Decimal, rounded to paise with ROUND_HALF_UP.
Show solution
import math
from decimal import Decimal, ROUND_HALF_UP
students = 245
seats = 50
bus_cost = 4750
buses = math.ceil(students / seats)
empty = buses * seats - students
total = buses * bus_cost
print("Buses:", buses, "Empty seats:", empty, "Total: ₹", total)
per_student = Decimal(total) / Decimal(students)
print("Per student: ₹", per_student.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))Buses: 5 Empty seats: 5 Total: ₹ 23750 Per student: ₹ 96.94
math.ceil() rounds 4.9 buses up to 5. Decimal(total) is safe because total is an int, and quantize() rounds the result to two decimal places.
Quick Quiz
1. What is 17 // 5?
// is floor division: it gives the whole-number part of the answer.
2. What does round(2.5) return in Python?
Python uses banker's rounding, so an exact half goes to the nearest even number.
3. Which is the safest way to store a price of ₹19.99?
A Decimal made from a string is exact. Decimal(19.99) copies the float's tiny error.
4. How do you calculate 3 to the power of 4?
** is the power operator. ^ is bitwise XOR, and the math module has no power function.
Learn Python with a mentor
Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
