Five Friends and One Bill
It is Sneha’s birthday, and five friends go out for dinner at a restaurant in Pune. The food is great. Then the bill arrives: a subtotal of Rs. 1,990, a 10% birthday discount, and 5% GST added on top. Who pays how much? One friend says Rs. 376, another says Rs. 380, and somebody forgets the GST completely.
Calculations like this happen everywhere: shop bills, mobile recharges, exam percentages, EMI amounts and salary slips. Computers are excellent at them, as long as you tell them exactly what to do. In this lesson you will learn how Python does arithmetic, how it decides the order of a calculation, how to round numbers, and how to avoid a few surprises with decimals. At the end, you will build a bill splitter for the birthday dinner.
The Basic Operators
An operator is a symbol that does something with values. Python uses these for arithmetic:
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ | Add | 450 + 320 | 770 |
- | Subtract | 1000 - 770 | 230 |
* | Multiply | 3 * 180 | 540 |
/ | Divide | 900 / 5 | 180.0 |
// | Floor division (whole part only) | 135 // 60 | 2 |
% | Remainder (called modulus) | 135 % 60 | 15 |
** | Power | 2 ** 3 | 8 |
print(450 + 320) # 770
print(1000 - 770) # 230
print(3 * 180) # 540
print(900 / 5) # 180.0 (/ always gives a float)
print(1000 / 3) # 333.3333333333333
print(type(900 / 5)) # <class 'float'>
print(type(3 * 180)) # <class 'int'>
Python has two number types. An int is a whole number, like 540. A float has a decimal point, like 180.0. The / operator always gives a float, even when the answer is a whole number. That is why 900 / 5 shows 180.0.
// and %: Whole Parts and Remainders
Remember division in primary school? 135 divided by 60 is “2, remainder 15”. Python gives you both parts with two operators:
//(floor division) gives the whole part:135 // 60is2.%(modulus) gives the remainder:135 % 60is15.
They are perfect for turning minutes into hours and minutes, or for packing things into boxes:
# How long did the dinner take?
minutes = 135
hours = minutes // 60 # whole hours
left_over = minutes % 60 # minutes that remain
print(hours, "hours and", left_over, "minutes") # 2 hours and 15 minutes
# Packing 50 laddoos into boxes of 12
laddoos = 50
box_size = 12
print("Full boxes:", laddoos // box_size) # Full boxes: 4
print("Laddoos left over:", laddoos % box_size) # Laddoos left over: 2
The % sign here has nothing to do with percentages. In Python it always means remainder. A common use: number % 2 is 0 for even numbers and 1 for odd numbers.
** for Powers
Two stars mean “to the power of”. 2 ** 3 means 2 × 2 × 2. Powers are useful for areas, for growth such as interest, and for big round numbers.
print(2 ** 3) # 8 (2 x 2 x 2)
print(12 ** 2) # 144 (the area of a 12 by 12 floor in square feet)
print(10 ** 5) # 100000 (one lakh)
# Savings of Rs. 10000 that grow by 10% for 2 years
print(10000 * 1.1 ** 2) # 12100.000000000002 (see "float surprises" below)
Order of Operations
When a line has several operators, Python follows the same order you learned in school maths (often remembered as BODMAS):
- Brackets
( )first - Then powers
** - Then
*,/,//and%, from left to right - Then
+and-, from left to right
print(100 + 50 * 2) # 200 (* first, then +)
print((100 + 50) * 2) # 300 (brackets first)
# 10% discount on a Rs. 800 bill
bill = 800
print(bill - bill * 10 / 100) # 720.0
print((bill - bill) * 10 / 100) # 0.0 (wrong brackets, wrong answer)
When you are not sure, add brackets. They make the order clear to Python and to anyone reading your code.
Handy Built-in Functions: round, abs, min, max
Python has some number tools ready to use, with no setup:
round(x)rounds to the nearest whole number.round(x, 2)keeps 2 decimal places, which is what you want for rupees and paise.abs(x)gives the absolute value: the number without its minus sign. Useful for “how far apart are these two amounts?”min(...)andmax(...)give the smallest and biggest of several values.
share = 376.1125
print(round(share)) # 376 (nearest whole number)
print(round(share, 2)) # 376.11 (2 decimal places)
print(round(2.5)) # 2 (exactly halfway goes to the even number)
print(round(3.5)) # 4
print(abs(-150)) # 150 (distance from zero, never negative)
print(min(240, 310, 275)) # 240 (smallest)
print(max(240, 310, 275)) # 310 (biggest)
A rounding surprise: when a number is exactly halfway, like 2.5,round()picks the nearest even number, soround(2.5)is 2 andround(3.5)is 4. This is called banker’s rounding. It keeps totals fair when you round many numbers.
The math Module: sqrt, ceil and floor
A module is a toolbox of extra functions that comes with Python. You open it with import at the top of your program, then use its tools with a dot: math.sqrt().
import math
print(math.sqrt(144)) # 12.0 (square root)
print(math.ceil(376.11)) # 377 (always rounds UP)
print(math.floor(376.99)) # 376 (always rounds DOWN)
print(math.pi) # 3.141592653589793
math.ceil() is the friend of bill splitting. If each share is Rs. 376.11, rounding up to Rs. 377 makes sure the restaurant is never paid less than the bill. math.floor() does the opposite and always rounds down.
Float Surprises and Money Tips
Run this and look at the first line carefully:
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
# Fix 1: round the result before you show or compare it
print(round(0.1 + 0.2, 2)) # 0.3
# Fix 2: count money in paise (whole numbers), convert at the end
tea_paise = 1050 # Rs. 10.50
samosa_paise = 1525 # Rs. 15.25
total_paise = tea_paise + samosa_paise
print(total_paise) # 2575
print(total_paise / 100) # 25.75
This is not a mistake in your code. Computers store numbers in binary (only 0s and 1s), and some simple decimals like 0.1 cannot be stored exactly, just as 1 ÷ 3 cannot be written exactly as a decimal (0.3333...). The tiny error appears when you add them. Almost every programming language does the same.
For money, follow these habits:
- Round at the end. Do the full calculation, then use
round(amount, 2)when you show the result. - Count in paise for exact sums. Rs. 10.50 becomes
1050. Whole numbers are always exact. - Do not compare floats with
==. Round both sides first.
Python also has a decimal module for exact decimal money calculations, which you may meet later in bigger projects.
Real-Life Example: The Birthday Bill Splitter
Here is the full calculation for Sneha’s birthday dinner. The rates are stored as constants, the discount comes before GST, and each share is rounded up. The small extra amount is left as a tip.
import math
# Birthday dinner for 5 friends at a restaurant in Pune
paneer_tikka = 2 * 260 # 2 plates at Rs. 260
veg_biryani = 3 * 220 # 3 plates at Rs. 220
butter_naan = 8 * 45 # 8 naan at Rs. 45
lassi = 5 * 90 # 5 glasses at Rs. 90
FRIENDS = 5
DISCOUNT_PERCENT = 10 # birthday offer
GST_PERCENT = 5 # tax added by this restaurant
subtotal = paneer_tikka + veg_biryani + butter_naan + lassi
discount = subtotal * DISCOUNT_PERCENT / 100
after_discount = subtotal - discount
gst = after_discount * GST_PERCENT / 100
total = after_discount + gst
exact_share = total / FRIENDS
each_pays = math.ceil(exact_share) # round UP to whole rupees
collected = each_pays * FRIENDS
tip = collected - total
print("Subtotal: Rs.", subtotal)
print("Discount: Rs.", round(discount, 2))
print("GST (5%): Rs.", round(gst, 2))
print("Total: Rs.", round(total, 2))
print("Exact share: Rs.", round(exact_share, 2))
print("Each pays: Rs.", each_pays)
print("Extra left as a tip: Rs.", round(tip, 2))
The output is:
Subtotal: Rs. 1990
Discount: Rs. 199.0
GST (5%): Rs. 89.55
Total: Rs. 1880.55
Exact share: Rs. 376.11
Each pays: Rs. 377
Extra left as a tip: Rs. 4.45
Try these changes:
- Change
FRIENDSto4. How much does each person pay now, and how big is the tip? - Change the discount to 15%. Notice that the GST also becomes smaller, because it is worked out after the discount.
- Use
max()to print the most expensive line of the order (paneer tikka, biryani, naan or lassi).
Common Mistakes
- Writing a percentage with the % sign. In Python
%means remainder, so18%on its own is an error:
bill = 1000
gst = bill * 18% # ERROR: SyntaxError
Write the percentage as a division by 100 instead:
bill = 1000
gst = bill * 18 / 100
print(gst) # 180.0
- Using
xor^. Multiply with*, notx. For powers use**. The^sign means something else in Python, so2 ^ 3gives1, not8. - Expecting
/to give a whole number.10 / 2is5.0. Use//if you really want only the whole part. - Forgetting brackets.
800 + 200 * 5 / 100adds GST only to the 200. Write(800 + 200) * 5 / 100for GST on the full Rs. 1,000. - Rounding too early. If you round every small step, the errors add up. Keep full values while you calculate and round only the final answers.
Practice Task: The Canteen Order
Four friends order food in the college canteen after their exam. Complete the starter code so that it:
- Adds up the subtotal of the dosas, the coffees and the momo plate
- Adds 5% GST and prints the total rounded to 2 decimal places
- Prints each friend’s share, rounded up with
math.ceil() - Uses
//and%to share 30 momos equally and print how many are left over
import math
# Canteen order for 4 friends after the exam
masala_dosa = 4 * 70
cold_coffee = 4 * 60
momos = 30 # pieces of momos in the order
momo_price = 150 # for the whole plate of 30
FRIENDS = 4
# TODO 1: Work out the subtotal (dosa + coffee + momo plate)
# TODO 2: Add 5% GST and print the total, rounded to 2 decimals
# TODO 3: Each friend's share, rounded UP to whole rupees with math.ceil
# TODO 4: How many momos does each friend get, and how many are left over?
Show one possible answer (try it yourself first!)
import math
masala_dosa = 4 * 70
cold_coffee = 4 * 60
momos = 30
momo_price = 150
FRIENDS = 4
subtotal = masala_dosa + cold_coffee + momo_price
gst = subtotal * 5 / 100
total = subtotal + gst
print("Total: Rs.", round(total, 2)) # Total: Rs. 703.5
each_pays = math.ceil(total / FRIENDS)
print("Each pays: Rs.", each_pays) # Each pays: Rs. 176
print("Momos each:", momos // FRIENDS) # Momos each: 7
print("Momos left over:", momos % FRIENDS) # Momos left over: 2
Key Takeaways
- Python uses
+,-,*and/for arithmetic, and/always gives a float. //gives the whole part and%gives the remainder: great for hours and minutes or packing boxes.**is the power operator. Brackets come first, then powers, then* / // %, then+ -.round(),abs(),min()andmax()are built in.math.sqrt(),math.ceil()andmath.floor()needimport math.- Decimals like 0.1 are not stored exactly. Round money only at the end, or count in paise.