Python / vs //: True Division and Floor Division

Python has two division operators. / is true division and always returns a float, so 7 / 2 is 3.5 and even 8 / 4 is 2.0. // is floor division: it divides and then rounds down, so 7 // 2 is 3. The difference that catches people out is negative numbers, where -7 // 3 is -3 and not -2, because rounding down means towards minus infinity rather than towards zero. This guide runs both operators side by side, covers the types they return, the remainder rules, and the cases where each one is the right choice.

Every example was run with Python 3.12.5 in the Windows Command Prompt, and the output shown is the real output. Reference: binary arithmetic operations in the Python language reference.

Python / vs //: the short answer

Three operators work together: / gives the exact answer as a float, // gives the whole part, and % gives what is left over:

print(7 / 2)        # true division: always a float
print(7 // 2)       # floor division: rounds down to a whole number
print(7 % 2)        # the remainder left over

print(type(7 / 2).__name__, type(7 // 2).__name__)

total_pages = 47 // 10      # whole pages
print("full pages:", total_pages, "| leftover items:", 47 % 10)

Output:

3.5
3
1
float int
full pages: 4 | leftover items: 7
Command Prompt output comparing 7 divided by 2 with the slash and double slash operators in Python and showing the types float and int
/ keeps the fraction, // throws it away by rounding down.
/ true division// floor division
7 and 23.53
8 and 42.0 (still a float)2
-7 and 3-2.3333...-3 (rounds down)
Result typealways floatint only if both operands are int
Exact for huge numbersNo, floats lose digitsYes, integers stay exact
Typical useaverages, percentages, pricespages, batches, minutes, indexes

If you only want to understand // on its own, we have a dedicated guide to what the double slash means in Python. This page is about choosing between the two.

// does not always return an int

This surprises people who think of // as “integer division”. The operator rounds down; the type follows the operands, so one float anywhere makes the result a float:

print(8 / 4, type(8 / 4).__name__)        # a float even when it divides exactly
print(8 // 4, type(8 // 4).__name__)      # both ints -> int

print(7.0 // 2, type(7.0 // 2).__name__)  # one float -> float
print(7 // 2.0)
print(True / 2, True // 2)                # bool counts as an int

Output:

2.0 float
2 int
3.0 float
3.0
0.5 0

Negative numbers: why -7 // 3 is -3

Floor division rounds towards minus infinity, so a negative result moves away from zero: -7 / 3 is -2.333..., and the next whole number down is -3. Truncating with int() moves towards zero instead and gives -2. math.floor() agrees with //, while math.trunc() agrees with int():

import math

value, divisor = -7, 3

print("-7 // 3      =", value // divisor)          # floors: towards minus infinity
print("int(-7 / 3)  =", int(value / divisor))      # truncates: towards zero
print("math.floor() =", math.floor(value / divisor))
print("math.trunc() =", math.trunc(value / divisor))
print("round()      =", round(value / divisor))

print()
print(f"{'a':>4} {'b':>3} {'a // b':>7} {'int(a / b)':>11} {'a % b':>6}")
for a, b in ((7, 3), (-7, 3), (7, -3), (-7, -3)):
    print(f"{a:>4} {b:>3} {a // b:>7} {int(a / b):>11} {a % b:>6}")

Output:

-7 // 3      = -3
int(-7 / 3)  = -2
math.floor() = -3
math.trunc() = -2
round()      = -2

   a   b  a // b  int(a / b)  a % b
   7   3       2           2      1
  -7   3      -3          -2      2
   7  -3      -3          -2     -2
  -7  -3       2           2     -1
Command Prompt table showing Python floor division and int division of negative numbers, where -7 // 3 is -3 and int(-7 / 3) is -2
The four-row table is the whole rule: // and int() only agree when the result is positive.

This is also where Python differs from C, Java and JavaScript, which truncate towards zero. Code translated from those languages needs int(a / b) rather than a // b to keep the same answers for negative values.

The remainder: % and divmod()

The sign of % follows the divisor in Python, which is what makes the identity below hold for negative numbers too. divmod() gives you both halves in one call, and chaining it is the tidiest way to split a total into units:

print(divmod(-7, 3))            # (quotient, remainder) in one call

a, b = -7, 3
print(a == (a // b) * b + a % b)   # the rule Python guarantees

seconds = 3725
minutes, rest = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
print(f"{seconds} seconds = {hours}h {minutes}m {rest}s")

Output:

(-3, 2)
True
3725 seconds = 1h 2m 5s

Integers stay exact, floats do not

This is the strongest practical reason to prefer // for whole-number work. A Python int has no size limit, while a float carries about 15 to 17 significant digits, so int(big / 3) is quietly wrong long before you notice. The same trap appears when rounding up with math.ceil():

big = 10 ** 18

print("big // 3      =", big // 3)        # exact: ints never lose precision
print("int(big / 3)  =", int(big / 3))    # the float division rounded first
print("equal?", big // 3 == int(big / 3))

print("remainder:", big % 3)

Output:

big // 3      = 333333333333333333
int(big / 3)  = 333333333333333312
equal? False
remainder: 1
Command Prompt output showing floor division of ten to the power eighteen by three being exact while int of the float division is wrong
Same calculation, two answers: only the integer one is right.

Floor division with floats can still surprise you

// on floats rounds down in the same way, but it works from the values as they are really stored, and binary floating point cannot hold 0.1 exactly. Ten of those stored tenths add up to slightly more than 1.0, so only nine of them fit:

print(1.0 // 0.1)          # expected 10.0
print(1.0 / 0.1)           # true division reports a clean 10.0
print(f"{0.1:.20f}")       # but 0.1 is stored as slightly MORE than a tenth

print(7.5 // 2, 7.5 % 2)
print(float("inf") // 2, float("nan") // 2)

Output:

9.0
10.0
0.10000000000000000555
3.0 1.5
nan nan

True division hides this by rounding its answer to a clean 10.0, which is why the two operators disagree. When exact steps matter, work in integers (count tenths, not fractions) or use Decimal. Note too that infinity and nan give nan rather than an error, so a stray inf spreads through a calculation silently.

Decimal floor division truncates instead of flooring

Here is a genuine trap that almost nothing documents clearly. Decimal follows the decimal arithmetic standard, where // truncates towards zero, so it disagrees with int floor division on negative values. If you switched to Decimal for money and exact decimals, this can change your numbers:

from decimal import Decimal
from fractions import Fraction

print("int   :", -7 // 3, divmod(-7, 3))                              # floors
print("Decimal:", Decimal(-7) // Decimal(3), divmod(Decimal(-7), Decimal(3)))   # truncates!
print("Fraction:", Fraction(-7, 3) // 1)                              # floors, like int

# to floor a Decimal, use the floor of the true division
print("floored Decimal:", (Decimal(-7) / Decimal(3)).to_integral_value(rounding="ROUND_FLOOR"))

Output:

int   : -3 (-3, 2)
Decimal: -2 (Decimal('-2'), Decimal('-1'))
Fraction: -3
floored Decimal: -3
Command Prompt output showing that Decimal floor division of minus seven by three gives minus two while integer floor division gives minus three
Decimal(-7) // Decimal(3) is -2; -7 // 3 is -3.

Dividing by zero: three different messages

Both operators raise ZeroDivisionError, but with different text, which is useful when you are reading a traceback. Guard the division rather than catching the error when a zero divisor is expected, as in a program that divides two numbers from user input:

for expression in ("7 / 0", "7 // 0", "7 % 0", "7.0 // 0.0"):
    try:
        eval(expression)
    except ZeroDivisionError as error:
        print(f"{expression:>10}  ->  ZeroDivisionError: {error}")

def safe_divide(a, b, default=0.0):
    return a / b if b else default

print(safe_divide(7, 0), safe_divide(7, 2))

Output:

     7 / 0  ->  ZeroDivisionError: division by zero
    7 // 0  ->  ZeroDivisionError: integer division or modulo by zero
     7 % 0  ->  ZeroDivisionError: integer modulo by zero
7.0 // 0.0  ->  ZeroDivisionError: float floor division by zero
0.0 3.5
Command Prompt output of the three ZeroDivisionError messages for slash, double slash and modulo by zero in Python
The message tells you which operator failed.

So which should you use?

  • Use / when the fraction matters: averages, percentages, unit prices, anything a person reads as a decimal.
  • Use // when you want whole units: pages, batches, boxes, minutes from seconds, list indexes.
  • Use // for large integers, where a float would lose digits.
  • Use int(a / b) only when you deliberately want truncation towards zero, and say so in a comment.
  • Use divmod(a, b) when you need the quotient and the remainder together.

More Python number guides worth reading:

Frequently asked questions

What is the difference between / and // in Python?

/ is true division and always returns a float. // is floor division: it divides and rounds the result down to a whole number.

Why does Python return 2.0 instead of 2 for 8 / 4?

Because / always produces a float in Python 3, even when the division is exact. Use 8 // 4 if you want the int 2.

Does // always return an integer?

No. It returns an int only when both operands are integers. 7.0 // 2 gives 3.0, a float.

What does -7 // 3 return in Python?

-3. Floor division rounds towards minus infinity, so it goes down from -2.333 to -3, not up to -2.

Can I use int(a / b) instead of a // b?

Only for positive numbers. int() truncates towards zero, and it also loses precision with very large integers, where // stays exact.

How do I get the quotient and the remainder together?

Use divmod(a, b), which returns (a // b, a % b) in one call.

Why does Decimal floor division give a different answer?

Decimal follows the decimal standard and truncates towards zero, so Decimal(-7) // Decimal(3) is -2 while -7 // 3 is -3.