Skip to Content
Python Division and Rounding: /, //, % and round() Without Surprises
Beginner
0 likes
Tutorials

Python Division and Rounding: /, //, % and round() Without Surprises

/, //, % and round() each do exactly what they say, and that's not always what school math taught you. Negative numbers, halves and money are where the surprises are, and where Decimal comes in.

Python has three division operators and one rounding function, and each one does exactly what it says. The surprises come from assuming they work like the math you learned in school. Most of the time they do. With negative numbers, halves and decimals, they don't.

Skip ahead: If you only need the short version: / always gives a float, // rounds down (not toward zero), % gives the remainder with the sign of the divisor, and round() rounds halves to the even number. The examples below show why each one matters.

The three operators

print(7 / 2)
print(6 / 2)
print(7 // 2)
print(7 % 2)
print(divmod(7, 2))
3.5
3.0
3
1
(3, 1)
  • **/ is true division.** It always returns a float, even when the answer is whole. 6 / 2 is 3.0, not 3.
  • **// is floor division. It divides, then rounds down** to the whole number below.
  • **% is the remainder** (modulo). 7 % 2 is 1, because 2 goes into 7 three times with 1 left.
  • **divmod()** gives you both at once, as a pair.

3.0 instead of 3 looks like a small thing. It isn't when you use the result as a list index: items[6 / 2] crashes with TypeError: list indices must be integers or slices, not float. Use // when you need a whole number.

A real use: splitting minutes and items

// and % together answer "how many full ones, and how many left over":

total_minutes = 135
hours, minutes = divmod(total_minutes, 60)
print(f"{hours}h {minutes}m")

guests = 23
per_table = 6
full_tables = guests // per_table
left_over = guests % per_table
print(full_tables, "full tables,", left_over, "guests left over")

for number in range(1, 7):
    print(number, "even" if number % 2 == 0 else "odd")
2h 15m
3 full tables, 5 guests left over
1 odd
2 even
3 odd
4 even
5 odd
6 even

number % 2 == 0 is the standard way to check for an even number. You'll see it everywhere.

Negative numbers: where // surprises people

print(-7 // 2)
print(int(-7 / 2))
print(-7 % 2)
print(7 % -2)
-4
-3
1
-1

-7 / 2 is -3.5. Floor means "round down", and down from -3.5 is -4, not -3. If you expected -3, you wanted "drop the decimal part", which is int(-7 / 2).

The remainder follows the same rule, so it takes the sign of the number you divide by. -7 % 2 is 1, because -4 * 2 + 1 = -7. This is on purpose. It means n % 7 always gives 0 to 6 for days of the week, even for negative numbers.

💡 Tip: With positive numbers, none of this matters. // and dropping the decimals give the same answer. Only think about it when negatives are possible, like temperatures, balances or time differences.

round(): halves go to the even number

print(round(2.5))
print(round(3.5))
print(round(0.5))
print(round(2.675, 2))
2
4
0
2.67

Yes, round(2.5) is 2. Python rounds halves to the nearest even number. It's called banker's rounding, and the reason is fairness: if you always round halves up, a long list of rounded numbers drifts upward. Rounding to even spreads it out.

The last one, 2.675 becoming 2.67, is a different issue. Computers store decimals in binary, and 2.675 can't be stored exactly. What's stored is a tiny bit less than 2.675, so it rounds down. Python is right about the number it actually has.

When the rounding must be exact: money

If the rule is "halves round up", like on many receipts and invoices, use the decimal module and give it the numbers as text:

from decimal import Decimal, ROUND_HALF_UP

price = Decimal("2.675")
print(price.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))

print(0.1 + 0.2)
print(Decimal("0.1") + Decimal("0.2"))
2.68
0.30000000000000004
0.3

âš  Warning: Write Decimal("2.675"), not Decimal(2.675). Passing a float copies the float's tiny error into the Decimal, and you're back where you started.

Rounding for display vs rounding the value

These are two different jobs:

  • For display, don't change the number. Format it: f"{total:.2f}" shows two decimals and leaves total alone.
  • For the stored value, round once, at a clear point, with a clear rule. Not a little bit in every step.
total = 1234.5678
print(f"{total:.2f}")
print(f"{total:,.2f}")
print(total)
1234.57
1,234.57
1234.5678

Common mistakes

  • **Using / where you need a whole number.** Indexes, counts and range() need //.
  • **Expecting // to drop decimals with negatives.** It rounds down. Use int() for "toward zero".
  • **Expecting round(2.5) to be 3.** It's 2. If that's wrong for your case, use Decimal with ROUND_HALF_UP.
  • Rounding in the middle of a calculation. Every early rounding adds a small error. Round at the end.

What happens if you get it wrong

Usually nothing visible. The program runs. A total is off by one centavo, a progress bar shows 99%, a list of 23 guests puts one of them at no table. These bugs don't crash. They get found by a customer.

If an invoice has 1,000 lines and each one rounds a half the "wrong" way, how far off can the total be, and who will notice first?

About

True division, floor division, remainders, banker's rounding and exact money rounding with Decimal, each with code you can run. After this, your totals and splits come out the way you expect.

Responsible
John G
Last Update
09/19/2026
Reading Time
5 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.