RizTech Academy logo
RizTech Academy
Variables and Data TypesLesson 2 of 520 min

Numbers: integers, floats, and the floating point trap

Python has two number types you will use constantly, and one piece of behaviour that looks like a bug in Python but is actually a fact about computers. Meeting it deliberately here is much better than meeting it in a program that handles money.

Two types

count = 7        # int   — a whole number
price = 19.99    # float — a number with a decimal point

An int is a whole number: 7, 0, -340. A float is a number with a fractional part: 19.99, 0.5, -2.0. Note that 2.0 is a float even though its value is whole — the decimal point is what decides it.

Ask Python which is which:

print(type(7))
print(type(19.99))
<class 'int'>
<class 'float'>

type() is genuinely useful when something is not behaving. Before guessing why a calculation is wrong, check that the values are the types you assumed.

One pleasant thing about Python: integers have no size limit.

print(2 ** 1000)

That prints a 302-digit number, exactly. In Java or C that overflows and gives a wrong answer silently. Python just grows the number.

Arithmetic

print(10 + 3)    # 13
print(10 - 3)    # 7
print(10 * 3)    # 30
print(10 / 3)    # 3.3333333333333335
print(10 // 3)   # 3
print(10 % 3)    # 1
print(10 ** 3)   # 1000

Three of those deserve attention.

/ always gives a float. Even when it divides evenly:

print(10 / 2)
5.0

Not 5. If you need a whole number, say so.

// is floor division — divide and throw away the fraction:

print(10 // 3)    # 3
print(-10 // 3)   # -4

"Floor" means it rounds down, towards negative infinity, not towards zero. That second result surprises people. It is consistent, not arbitrary.

% is the remainder, and it is more useful than it first appears:

print(17 % 5)     # 2
print(10 % 2)     # 0
print(7 % 2)      # 1

n % 2 == 0 is how you test whether a number is even. n % 15 == 0 is how you test divisibility by fifteen. You will reach for % constantly once you have loops.

Together, // and % split a number cleanly:

total_minutes = 137
hours = total_minutes // 60
minutes = total_minutes % 60
print(hours, "hours", minutes, "minutes")
2 hours 17 minutes

Order of operations

Python follows normal mathematical precedence: ** first, then * / // %, then + -.

print(2 + 3 * 4)      # 14, not 20
print((2 + 3) * 4)    # 20

Use brackets even when they are not strictly needed. (a * b) + c costs you two characters and removes any doubt for whoever reads it next.

The floating point trap

Try this:

print(0.1 + 0.2)
0.30000000000000004

That is not a Python bug. It happens in JavaScript, Java, C and every other language using standard floating point, and it is worth understanding rather than memorising.

Computers store numbers in binary. Some fractions that are tidy in base ten are infinitely repeating in base two — 0.1 is one of them, in the same way that one third is 0.3333... forever in base ten. The computer stores the closest value it can fit, which is very slightly off. Add two slightly-off numbers and the error becomes visible.

The consequence that will actually bite you:

print(0.1 + 0.2 == 0.3)
False

Never compare floats with ==. Compare the difference against a small tolerance instead:

result = 0.1 + 0.2
print(abs(result - 0.3) < 0.000001)
True

When it is money, do not use floats

This is the rule that matters commercially. Never store currency as a float. Rounding errors accumulate, and an accounting system whose totals drift by paise is a serious problem.

Two correct approaches:

Work in the smallest unit as integers. Store paise, not rupees. ₹19.99 becomes 1999. All arithmetic is exact because integers are exact, and you divide by 100 only when displaying.

Or use Decimal:

from decimal import Decimal

price = Decimal("19.99")
tax = Decimal("0.18")
print(price + (price * tax))
23.5882

Note the quotes: Decimal("19.99"), not Decimal(19.99). Passing a float hands it a value that is already slightly wrong, and it faithfully preserves the error.

Decimal is slower and wordier, which is why it is not the default. For money it is worth it.

Rounding

print(round(3.7))        # 4
print(round(3.2))        # 3
print(round(2.675, 2))   # 2.67

That last one is the REPL example from module 1. Two things are happening.

The obvious one is floating point again: 2.675 is stored as very slightly less than 2.675, so rounding it down is correct given what is actually stored.

The less obvious one is that Python uses banker's rounding — exact halves go to the nearest even number:

print(round(0.5))    # 0
print(round(1.5))    # 2
print(round(2.5))    # 2

This is deliberate. Always rounding halves upward introduces a small upward bias across many values; alternating removes it. It is the correct default for statistics and surprising everywhere else.

Two other useful functions:

print(abs(-7))        # 7    — distance from zero
print(divmod(17, 5))  # (3, 2) — floor division and remainder together

Practice

  1. Print the result of 7 / 2, 7 // 2 and 7 % 2. Say in your own words what each one does before running it.
  2. Write code that turns total_seconds = 9045 into "2 hours, 30 minutes, 45 seconds" using only // and %.
  3. Verify for yourself that 0.1 + 0.2 != 0.3, then write a comparison using a tolerance that correctly reports True.
  4. Calculate 18% tax on ₹1,250 twice — once with floats, once with Decimal. Print both. Are they the same?
  5. Write a check for whether a year is a leap year using only %. The rule: divisible by 4, except years divisible by 100, unless also divisible by 400. Test it with 2024 (yes), 1900 (no) and 2000 (yes).

Question 5 is harder than it looks and is worth the struggle. If you get stuck, write the three conditions out in English first, then translate them one at a time.

Next: strings, and the single most useful piece of syntax in modern Python.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship