Learning Python - Mark Lutz [84]
Supporting either Python
Although / behavior differs in 2.6 and 3.0, you can still support both versions in your code. If your programs depend on truncating integer division, use // in both 2.6 and 3.0. If your programs require floating-point results with remainders for integers, use float to guarantee that one operand is a float around a / when run in 2.6:
X = Y // Z # Always truncates, always an int result for ints in 2.6 and 3.0
X = Y / float(Z) # Guarantees float division with remainder in either 2.6 or 3.0
Alternatively, you can enable 3.0 / division in 2.6 with a __future__ import, rather than forcing it with float conversions:
C:\misc> C:\Python26\python
>>> from __future__ import division # Enable 3.0 "/" behavior
>>> 10 / 4
2.5
>>> 10 // 4
2
Floor versus truncation
One subtlety: the // operator is generally referred to as truncating division, but it’s more accurate to refer to it as floor division—it truncates the result down to its floor, which means the closest whole number below the true result. The net effect is to round down, not strictly truncate, and this matters for negatives. You can see the difference for yourself with the Python math module (modules must be imported before you can use their contents; more on this later):
>>> import math
>>> math.floor(2.5)
2
>>> math.floor(-2.5)
-3
>>> math.trunc(2.5)
2
>>> math.trunc(-2.5)
-2
When running division operators, you only really truncate for positive results, since truncation is the same as floor; for negatives, it’s a floor result (really, they are both floor, but floor is the same as truncation for positives). Here’s the case for 3.0:
C:\misc> c:\python30\python
>>> 5 / 2, 5 / −2
(2.5, −2.5)
>>> 5 // 2, 5 // −2 # Truncates to floor: rounds to first lower integer
(2, −3) # 2.5 becomes 2, −2.5 becomes −3
>>> 5 / 2.0, 5 / −2.0
(2.5, −2.5)
>>> 5 // 2.0, 5 // −2.0 # Ditto for floats, though result is float too
(2.0, −3.0)
The 2.6 case is similar, but / results differ again:
C:\misc> c:\python26\python
>>> 5 / 2, 5 / −2 # Differs in 3.0
(2, −3)
>>> 5 // 2, 5 // −2 # This and the rest are the same in 2.6 and 3.0
(2, −3)
>>> 5 / 2.0, 5 / −2.0
(2.5, −2.5)
>>> 5 // 2.0, 5 // −2.0
(2.0, −3.0)
If you really want truncation regardless of sign, you can always run a float division result through math.trunc, regardless of Python version (also see the round built-in for related functionality):
C:\misc> c:\python30\python
>>> import math
>>> 5 / −2 # Keep remainder
−2.5
>>> 5 // −2 # Floor below result
-3
>>> math.trunc(5 / −2) # Truncate instead of floor
−2
C:\misc> c:\python26\python
>>> import math
>>> 5 / float(−2) # Remainder in 2.6
−2.5
>>> 5 / −2, 5 // −2 # Floor in 2.6
(−3, −3)
>>> math.trunc(5 / float(−2)) # Truncate in 2.6
−2
Why does truncation matter?
If you are using 3.0, here is the short story on division operators for reference:
>>> (5 / 2), (5 / 2.0), (5 / −2.0), (5 / −2) # 3.0 true division
(2.5, 2.5, −2.5, −2.5)
>>> (5 // 2), (5 // 2.0), (5 // −2.0), (5 // −2) # 3.0 floor division
(2, 2.0, −3.0, −3)
>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0) # Both
(3.0, 3.0, 3, 3.0)
For 2.6 readers, division works as follows:
>>> (5 / 2), (5 / 2.0), (5 / −2.0), (5 / −2) # 2.6 classic division
(2, 2.5, −2.5, −3)
>>> (5 // 2), (5 // 2.0), (5 // −2.0), (5 // −2) # 2.6 floor division (same)
(2, 2.0, −3.0, −3)
>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0) # Both
(3, 3.0, 3, 3.0)
Although results have yet to come in, it’s possible that the nontruncating behavior of / in 3.0 may break a significant number of programs.