All 57 lessons

Lesson 4 of 57 · Getting Started

Numbers and Operators in Python

By Skillancy Editorial Team

Run the code in the free Python Compiler or on your own computer. Lessons that read files use the FreshBasket practice data: download the dataset (ZIP).

Analytics is mostly arithmetic done at scale: totals, averages, percentages, growth rates, discounts and taxes. Python handles all of it, and once you understand a handful of operators and one famous quirk about decimals, you can express almost any business calculation in a single readable line.

This lesson covers the numeric operators, the order in which Python evaluates them, the difference between true division and floor division, rounding, and why 0.1 + 0.2 does not give exactly 0.3. Every example uses FreshBasket pricing and delivery numbers so the calculations feel like real work.

The arithmetic operators

OperatorMeaningExampleResult
+Addition7 + 310
-Subtraction7 - 34
*Multiplication7 * 321
/True division (always a float)7 / 23.5
//Floor division (whole part)7 // 23
%Modulo (remainder)7 % 21
**Power (exponent)7 ** 249

Two of these deserve special attention. Division with / always returns a float, even when the answer is whole: 10 / 5 is 2.0. Floor division // throws away the fractional part and keeps the whole number of times one value fits in another, and % gives what is left over. Together they answer questions such as "how many full boxes, and how many items are left over?".

Precedence: who goes first?

Python follows the same order as school maths, often remembered as BODMAS or PEMDAS: brackets first, then powers, then multiplication, division, floor division and modulo (left to right), and finally addition and subtraction. So 2 + 3 * 4 is 14, not 20. When in doubt, add brackets. They cost nothing and make your intent obvious to the next reader.

Worked examples

Example 1: GST on a basket

Question: A customer's basket is ₹864 before tax. With 5% GST and a ₹25 delivery fee, what is the total?

basket = 864
gst = basket * 5 / 100
total = basket + gst + 25
print(gst, total)

Output

43.2 932.2

How it works: basket * 5 / 100 multiplies first, then divides (left to right), giving the tax amount. We add tax and the delivery fee to the basket. Because / was involved, the results are floats.

Reading the result: GST is ₹43.2 and the customer pays ₹932.2. Notice that gst is a float even though 864 and 5 are integers: / always produces a float.

Example 2: Percentage discounts and percentage change

Question: Yesterday's revenue was ₹1,85,000 and today's is ₹2,12,750. What is the percentage growth? Then apply a 15% coupon to a ₹649 basket.

yesterday = 185000
today = 212750

growth_pct = (today - yesterday) / yesterday * 100
print(round(growth_pct, 2))

coupon_basket = 649 * (1 - 15 / 100)
print(round(coupon_basket, 2))

Output

15.0
551.65

How it works: Percentage change is always (new minus old) divided by old, times 100. The brackets force the subtraction to happen before the division. For the coupon, 1 - 15/100 gives 0.85, the fraction the customer still pays.

Reading the result: Revenue grew by 15.0%, and the discounted basket is ₹551.65. Writing 1 - discount is a neat way to avoid subtracting a discount amount in a second step.

Example 3: Floor division and remainder

Question: A rider can carry 8 orders at a time. For 61 orders waiting at a dark store, how many full trips are needed and how many orders are left for a final partial trip?

orders_waiting = 61
capacity = 8

full_trips = orders_waiting // capacity
leftover = orders_waiting % capacity
print(full_trips, leftover)
print(divmod(orders_waiting, capacity))

Output

7 5
(7, 5)

How it works: // counts how many times 8 fits into 61 and % returns what remains. The built-in divmod(a, b) returns both in one call, as a pair.

Reading the result: There are 7 full trips with 5 orders left over, so the store needs 8 trips in total. The identity full_trips * capacity + leftover == orders_waiting always holds, which is a good sanity check.

Example 4: Converting minutes to hours and minutes

Question: A rider worked 487 minutes today. Display that as hours and minutes.

worked = 487
hours, minutes = divmod(worked, 60)
print(f"{hours}h {minutes}m")

Output

8h 7m

How it works: Dividing minutes by 60 with divmod gives whole hours and the remaining minutes. The pair is unpacked straight into two variables, a technique you saw in the variables lesson.

Reading the result: 487 minutes is 8 hours and 7 minutes. The same trick converts seconds to minutes, days to weeks, or paise to rupees.

Example 5: Rounding up, down and to the nearest

Question: Each delivery box holds 12 items. A customer orders 50 items. How many boxes are needed? Compare it with ordinary rounding.

import math

items = 50
per_box = 12

print(items / per_box)
print(round(items / per_box))
print(math.floor(items / per_box))
print(math.ceil(items / per_box))

Output

4.166666666666667
4
4
5

How it works: / gives 4.1667 (rounded). round() goes to the nearest whole number, math.floor() always rounds down and math.ceil() always rounds up. When you need a whole number of containers you must round up, because a fifth, partly filled box still has to exist.

Reading the result: The right answer is 5 boxes, and ordinary rounding would have given 4, leaving two items without a box. Choosing the right rounding direction is a business decision, not just a maths one.

Example 6: Python's banker's rounding and decimal places

Question: How does round() treat halves, and how do I keep two decimal places?

print(round(2.5), round(3.5), round(4.5))
print(round(7.456, 2), round(7.454, 2))
print(round(1234.5678, -2))

Output

2 4 4
7.46 7.45
1200.0

How it works: For exact halves, Python's round() goes to the nearest even number (called banker's rounding), so 2.5 becomes 2 and 3.5 becomes 4. This reduces bias when you round many numbers. The second argument is the number of decimal places, and a negative number rounds to tens, hundreds and so on.

Reading the result: The first line prints 2 4 4, the second 7.46 7.45, and the third rounds to the nearest hundred, giving 1200.0. If your business needs "round half up" (as most invoices do), use the decimal module, shown in the next example.

Example 7: The famous 0.1 + 0.2 problem

Question: Why does Python say 0.1 + 0.2 is not 0.3?

print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(round(0.1 + 0.2, 2) == 0.3)

Output

0.30000000000000004
False
True

How it works: Computers store decimals in binary, and numbers such as 0.1 cannot be written exactly in binary, just as 1/3 cannot be written exactly in decimal. Each float is a very close approximation, and tiny errors can appear after arithmetic. This is true in every mainstream programming language. Excel uses the same binary format, but it rounds what it displays, which hides the effect most of the time.

Reading the result: The sum prints as 0.30000000000000004, so the equality test is False. The practical rules are: never compare floats with == (round first, or use math.isclose), and display results with round() or an f-string. For exact money arithmetic, use whole paise as integers or Python's Decimal:

from decimal import Decimal, ROUND_HALF_UP

price = Decimal("19.995")
print(price.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(Decimal("0.1") + Decimal("0.2"))

Output

20.00
0.3

Decimal stores numbers as written, so 0.1 + 0.2 is exactly 0.3, and quantize rounds half up the way an invoice would. For analysis on large datasets, ordinary floats are fine; pandas uses them throughout.

Example 8: Powers, compound growth and useful built-ins

Question: If FreshBasket grows orders by 8% every month, how many daily orders will a store have after 6 months starting from 150? Also find the cheapest and costliest of four item prices.

start_orders = 150
monthly_growth = 0.08

after_6 = start_orders * (1 + monthly_growth) ** 6
print(round(after_6))

prices = [49, 245, 118, 62]
print(min(prices), max(prices), sum(prices), abs(-37))

Output

238
49 245 474 37

How it works: Compound growth multiplies by (1 + rate) once per period, which is (1 + rate) ** periods. The power operator ** binds tighter than multiplication, so the growth factor is calculated first. min, max and sum work on lists (covered soon), and abs returns the absolute value, removing the minus sign.

Reading the result: Starting at 150 orders a day, six months of 8% growth gives about 238 orders a day. The cheapest item costs ₹49, the dearest ₹245, and the four together cost ₹474.

Example 9: Readable large numbers

Question: How do I write big numbers without miscounting zeros?

annual_revenue = 12_50_00_000
crore = 1_00_00_000
print(annual_revenue / crore)
print(1.5e3, 2e-2)
print(f"{annual_revenue:,}")

Output

12.5
1500.0 0.02
125,000,000

How it works: Underscores inside number literals are ignored by Python and exist only to help human eyes. You can group them in thousands, or in the Indian lakh and crore style as above. Scientific notation 1.5e3 means 1.5 × 10³. In output, the , format adds Western thousand separators.

Reading the result: The annual revenue is 12.5 crore rupees. The scientific values print as 1500.0 and 0.02. Python's f-string , format does not group by lakhs, so for Indian-style grouping you need a small custom function, which we build in the functions lesson.

Common mistakes

1. Expecting / to return an integer. 10 / 2 is 5.0. Use // for a whole-number result.

2. Forgetting precedence. 100 - 20 / 2 is 90.0, not 40.0. Add brackets: (100 - 20) / 2.

3. Dividing by zero. This crashes the program, and in analytics it happens when a denominator is empty.

conversion_rate = 120 / 0

Output

Traceback (most recent call last):
  File "example.py", line 1, in <module>
    conversion_rate = 120 / 0
                      ~~~~^~~
ZeroDivisionError: division by zero

4. Comparing floats with ==. Use round() or math.isclose(a, b) instead.

5. Using ^ for powers. In Python ^ means bitwise XOR, not exponent. Write 2 ** 3 for 8.

Practice questions

Practice 1 (Easy): Bill with discount

A basket of ₹1,240 gets a 10% discount, then 5% GST is added on the discounted amount. What is the final amount, rounded to two decimals?

Show solution
basket = 1240
after_discount = basket * (1 - 0.10)
final = after_discount * (1 + 0.05)
print(round(final, 2))

Output

1171.8

GST applies after the discount, so we first reduce the basket and then multiply by 1.05. The answer is ₹1171.8.

Practice 2 (Medium): Packing trays

FreshBasket packs eggs in trays of 30. A store receives 1,000 eggs. How many full trays can it make, how many loose eggs remain, and how many trays are needed if every egg must be in a tray?

Show solution
import math

eggs = 1000
full_trays, loose = divmod(eggs, 30)
trays_needed = math.ceil(eggs / 30)
print(full_trays, loose, trays_needed)

Output

33 10 34

divmod returns 33 full trays and 10 loose eggs, so one extra tray is required, making 34 in total.

Practice 3 (Hard): Break-even growth

A store makes 200 orders a day and wants to reach 500. At 6% monthly growth, how many whole months will it take? Use a calculation, not a loop (hint: try math.log).

Show solution
import math

months = math.log(500 / 200) / math.log(1.06)
print(round(months, 2), math.ceil(months))

Output

15.73 16

We solve 200 × 1.06ⁿ = 500 for n. Taking logarithms gives n = log(500/200) / log(1.06), about 15.73 months, and since we need whole months we round up to 16.

Key takeaways

  • / always returns a float, // returns the whole part, % returns the remainder, and ** is the power operator.
  • Python follows BODMAS; use brackets when you want to be explicit.
  • Percentage change is (new - old) / old * 100; a discount of d% multiplies the price by 1 - d/100.
  • Use math.ceil when you need enough containers, math.floor for complete units, and round for the nearest, remembering that Python rounds halves to the nearest even number.
  • Floats are approximate: round for display, never compare with ==, and use Decimal for exact money.
  • divmod(a, b) gives quotient and remainder together, and underscores such as 12_50_00_000 make big numbers readable.

Frequently asked questions

Why does 7 / 2 give 3.5 but 7 // 2 give 3?

/ is true division and always returns a float. // is floor division: it divides and then rounds down to the nearest whole number. With negative numbers, floor division rounds toward minus infinity, so -7 // 2 is -4.

What is the difference between % and a percentage?

% is the modulo operator and returns a remainder. To calculate a percentage you multiply by the rate divided by 100. Python has no percent operator.

How big can an integer be in Python?

There is effectively no limit; Python integers grow as needed, limited only by memory. Floats, however, have a fixed range and about 15 to 16 digits of precision.

Should I use float or Decimal for money?

For small calculations that need exact rounding, such as invoices, use Decimal or whole paise stored as integers. For analysing large datasets, floats are standard and faster. Round only when you display or report a value.

Why does round(2.675, 2) give 2.67?

Because 2.675 cannot be represented exactly in binary, the stored value is slightly below 2.675, so it rounds down. This is the same floating-point effect described above.

Is there a built-in function for average?

Not in the core language, but sum(values) / len(values) works, and the statistics module has mean(). In pandas you will simply call .mean() on a column.

Newsletter

Keep learning Python

One email a week with Python and analytics guides, new practice questions and cohort dates. No spam, unsubscribe anytime.

Ready to practise? Try the Python interview questions