Here's a new revision of PEP 238. I've incorporated clarifications of

issues that were brought up during the discussion of rev 1.10 -- from

typos via rewording of ambiguous phrasing to the addition of new open

issues. I've decided not to go for the "quotient and ratio"

terminology -- my rationale is in the PEP.

IF YOU WANT ME TO SEE YOUR COMMENTS, DON'T CHANGE THE SUBJECT OF YOUR

FOLLOWUP. I cannot follow all of c.l.py, but I will follow this one

thread. Please don't fragment the thread -- I won't see other

threads, guaranteed.

--Guido van Rossum (home page: http://www.*-*-*.com/ ~guido/)

PEP: 238

Title: Changing the Division Operator

Version: $Revision: 1.12 $

Status: Draft

Type: Standards Track

Created: 11-Mar-2001

Python-Version: 2.2

Post-History: 16-Mar-2001, 26-Jul-2001, 27-Jul-2001

Abstract

The current division (/) operator has an ambiguous meaning for

numerical arguments: it returns the floor of the mathematical

result of division if the arguments are ints or longs, but it

returns a reasonable approximation of the division result if the

arguments are floats or complex. This makes expressions expecting

float or complex results error-prone when integers are not

expected but possible as inputs.

We propose to fix this by introducing different operators for

different operations: x/y to return a reasonable approximation of

the mathematical result of the division ("true division"), x//y to

return the floor ("floor division"). We call the current, mixed

meaning of x/y "classic division".

Because of severe backwards compatibility issues, not to mention a

major flamewar on c.l.py, we propose the following transitional

measures (starting with python 2.2):

- Classic division will remain the default in the Python 2.x

series; true division will be standard in Python 3.0.

- The // operator will be available to request floor division

unambiguously.

- The future division statement, spelled "from __future__ import

division", will change the / operator to mean true division

throughout the module.

- A command line option will enable run-time warnings for classic

division applied to int or long arguments; another command line

option will make true division the default.

- The standard library will use the future division statement and

the // operator when appropriate, so as to completely avoid

classic division.

Motivation

The classic division operator makes it hard to write numerical

expressions that are supposed to give correct results from

arbitrary numerical inputs. For all other operators, one can

write down a formula such as x*y**2 + z, and the calculated result

will be close to the mathematical result (within the limits of

numerical accuracy, of course) for any numerical input type (int,

long, float, or complex). But division poses a problem: if the

expressions for both arguments happen to have an integral type, it

implements floor division rather than true division.

The problem is unique to dynamically typed languages: in a

statically typed language like C, the inputs, typically function

arguments, would be declared as double or float, and when a call

passes an integer argument, it is converted to double or float at

the time of the call. Python doesn't have argument type

declarations, so integer arguments can easily find their way into

an expression.

The problem is particularly pernicious since ints are perfect

substitutes for floats in all other circumstances: math.sqrt(2)

returns the same value as math.sqrt(2.0), 3.14*100 and 3.14*100.0

return the same value, and so on. Thus, the author of a numerical

routine may only use floating point numbers to test his code, and

believe that it works correctly, and a user may accidentally pass

in an integer input value and get incorrect results.

Another way to look at this is that classic division makes it

difficult to write polymorphic functions that work well with

either float or int arguments; all other operators already do the

right thing. No algorithm that works for both ints and floats has

a need for truncating division in one case and true division in

the other.

The correct work-around is subtle: casting an argument to float()

is wrong if it could be a complex number; adding 0.0 to an

argument doesn't preserve the sign of the argument if it was minus

zero. The only solution without either downside is multiplying an

argument (typically the first) by 1.0. This leaves the value and

sign unchanged for float and complex, and turns int and long into

a float with the corresponding value.

It is the opinion of the authors that this is a real design bug in

Python, and that it should be fixed sooner rather than later.

Assuming Python usage will continue to grow, the cost of leaving

this bug in the language will eventually outweigh the cost of

fixing old code -- there is an upper bound to the amount of code

to be fixed, but the amount of code that might be affected by the

bug in the future is unbounded.

Another reason for this change is the desire to ultimately unify

Python's numeric model. This is the subject of PEP 228[0] (which

is currently incomplete). A unified numeric model removes most of

the user's need to be aware of different numerical types. This is

good for beginners, but also takes away concerns about different

numeric behavior for advanced programmers. (Of course, it won't

remove concerns about numerical stability and accuracy.)

In a unified numeric model, the different types (int, long, float,

complex, and possibly others, such as a new rational type) serve

mostly as storage optimizations, and to some extent to indicate

orthogonal properties such as inexactness or complexity. In a

unified model, the integer 1 should be indistinguishable from the

floating point number 1.0 (except for its inexactness), and both

should behave the same in all numeric contexts. Clearly, in a

unified numeric model, if a==b and c==d, a/c should equal b/d

(taking some liberties due to rounding for inexact numbers), and

since everybody agrees that 1.0/2.0 equals 0.5, 1/2 should also

equal 0.5. Likewise, since 1//2 equals zero, 1.0//2.0 should also

equal zero.

Variations

Aesthetically, x//y doesn't please everyone, and hence several

variations have been proposed: x div y, or div(x, y), sometimes in

combination with x mod y or mod(x, y) as an alternative spelling

for x%y.

We consider these solutions inferior, on the following grounds.

- Using x div y would introduce a new keyword. Since div is a

popular identifier, this would break a fair amount of existing

code, unless the new keyword was only recognized under a future

division statement. Since it is expected that the majority of

code that needs to be converted is dividing integers, this would

greatly increase the need for the future division statement.

Even with a future statement, the general sentiment against

adding new keywords unless absolutely necessary argues against

this.

- Using div(x, y) makes the conversion of old code much harder.

Replacing x/y with x//y or x div y can be done with a simple

query replace; in most cases the programmer can easily verify

that a particular module only works with integers so all

occurrences of x/y can be replaced. (The query replace is still

needed to weed out slashes occurring in comments or string

literals.) Replacing x/y with div(x, y) would require a much

more intelligent tool, since the extent of the expressions to

the left and right of the / must be analyzed before the

placement of the "div(" and ")" part can be decided.

Alternatives

In order to reduce the amount of old code that needs to be

converted, several alternative proposals have been put forth.

Here is a brief discussion of each proposal (or category of

proposals). If you know of an alternative that was discussed on

c.l.py that isn't mentioned here, please mail the second author.

- Let / keep its classic semantics; introduce // for true

division. This still leaves a broken operator in the language,

and invites to use the broken behavior. It also shuts off the

road to a unified numeric model a la PEP 228[0].

- Let int division return a special "portmanteau" type that

behaves as an integer in integer context, but like a float in a

float context. The problem with this is that after a few

operations, the int and the float value could be miles apart,

it's unclear which value should be used in comparisons, and of

course many contexts (like conversion to string) don't have a

clear integer or float context.

- Use a directive to use specific division semantics in a module,

rather than a future statement. This retains classic division

as a permanent wart in the language, requiring future

generations of Python programmers to be aware of the problem and

the remedies.

- Use "from __past__ import division" to use classic division

semantics in a module. This also retains the classic division

as a permanent wart, or at least for a long time (eventually the

past division statement could raise an ImportError).

- Use a directive (or some other way) to specify the Python

version for which a specific piece of code was developed. This

requires future Python interpreters to be able to emulate

*exactly* several previous versions of Python, and moreover to

do so for

...

**read more »**