Browse DevX
Sign up for e-mail newsletters from DevX


A Developer's Guide to Python 3.0: Numbers, Strings, and Data : Page 2

Python 3.0 makes critical—and not-backwardly-compatible—changes to data types. Find out how these changes will affect your code.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

PEP 238: Changing the Division Operator

In Python 2.x the division operator is divided (no pun intended) between integer division and float/complex division. Integer division is actually floor division, where the result is always rounded down to the nearest integer (int or long):

>>> 5 / 2 2 >>> -5 / 2 -3

Float/complex division is true division that returns a reasonable approximation of the mathematical result:

>>> 5.0 / 2 2.5 >>> -5 / 2.0 -2.5 >>> complex(5, 0) / 2 (2.5+0j)

This is arguably the most serious problem in the design of the language. In the context of writing numeric algorithms that operate on integers and floats/complex numbers it makes life really hard. For a function library writer who wants to ensure true division (I'll get to the __future__ workaround later) it is not immediately clear how to do it in a safe manner.

Suppose you want to write an average function that operates on integers, floats, and complex numbers. Here's a naive implementation:

def average(*numbers): return sum(numbers) / len(numbers)

This function will fail if all the numbers are integers and the average is not an integer:

>>> average(1,4) 2

So, how do you make sure you get true division? You can try something like casting all the arguments to floats—but then it wouldn't work on complex numbers. You can try adding 0.0 to each number, but if the original number was the float -0.0 you might lose the sign (yes, there is a difference between 0.0 and -0.0 according to the IEEE 754 "floating point" standard):

>>> x=-0.0 >>> x -0.0 >>> x + 0.0 0.0

It turns out that the only safe way to preserve type and sign and enforce true division is by multiplying all the arguments by 1.0—a solution that might easily escape someone writing a simple average function, and one that has a non-negligible overhead:

def average(*numbers): return sum([n * 1.0 for n in numbers]) / len(numbers) >>> average(1,4) 2.5

Fortunately, in Python 3.0, division is always a true division that returns a float (even if the result is integer) or complex (if one of the operands is complex):

>>> 5 / 2 2.5 >>> -5 / 2 -2.5 >>> 4 / 2 2.0 >>> complex(5, 0) / 2 (2.5+0j)

To get floor division in Python 3.0, use the // operator. If both operands are integers, the result will be an integer. If one of the operands is a float and the other is a float or integer the result is float (but a float that equals an integer). Floor division doesn't work on complex numbers:

>>> 5 // 2 2 >>> 5.0 // 2 2.0 >>> complex(5,0) // 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't take floor of a complex number.

It's not well known, but explicit floor division has been available in Python since Python 2.2. Moreover, this true division behavior is also available in Python 2.2 if you use the following statement:

from __future__ import division

This can be useful if you want to incrementally prepare your code for Python 3.0 migration. If you have numeric code, or if you call into code that uses the division operation in its Python 2.x form, you might run into nasty bugs. That's because you will have to check every call site; you can't just change the code that uses the division operator itself. You'll see more specific information about how to attack the division operator issue about migrating to Python 3.0 in a future article.

You can also control the division behavior by passing the -Q command-line argument to the interpreter with valid values of: old (default), warn, warnall, and new (true division); however, I don't recommend using it unless you know exactly what you are doing and why. It is pretty brittle to rely on command-line arguments to control a concept as central as division behavior.

Thanks for your registration, follow us on our social networks to keep up-to-date