[Python-Dev] Non-integer Division

Guido van Rossum guido@digicool.com
Sun, 11 Mar 2001 18:37:37 -0500


Good start, Moshe!  Some comments below.

> PEP: XXX
> Title: Non-integer Division
> Version: $Revision$
> Author: pep@zadka.site.co.il (Moshe Zadka)
> Status: Draft
> Python-Version: 2.2
> Type: Standards Track
> Created: 11-Mar-2001
> Post-History:
> 
> 
> Abstract
> 
>     Dividing integers returns the floor of the quantities. This
>     behaviour is known as integer division, and is similar to what C
>     and FORTRAN do.  This has the useful property that all
>     operations on integers return integers, but it does tend to put
>     a hump in the learning curve when new programmers are surprised
>     that
> 
>                   1/2 == 0
> 
>     This proposal shows a way to change this will keeping backward 
>     compatability issues in mind.
> 
> Rationale
> 
>     The behaviour of integer division is a major stumbling block
>     found in user testing of Python. This manages to trip up new
>     programmers regularily and even causes the experienced
>     programmer to make the occasional bugs. The work arounds, like
>     explicitly coerce one of the operands to float or use a
>     non-integer literal, are very non-intuitive and lower the
>     readability of the program.

There is a specific kind of example that shows why this is bad.
Python's polymorphism and treatment of mixed-mode arithmetic
(e.g. int+float => float) suggests that functions taking float
arguments and doing some math on them should also be callable with int
arguments.  But sometimes that doesn't work.  For example, in
electronics, Ohm's law suggests that current (I) equals voltage (U)
divided by resistance (R).  So here's a function to calculate the
current:

    >>> def I(U, R):
    ...     return U/R
    ...
    >>> print I(110, 100) # Current through a 100 Ohm resistor at 110 Volt
    1
    >>> 

This answer is wrong! It should be 1.1.  While there's a work-around
(return 1.0*U/R), it's ugly, and moreover because no exception is
raised, simple code testing may not reveal the bug.  I've seen this
reported many times.

> // Operator

Note: we could wind up using a different way to spell this operator,
e.g. Pascal uses 'div'.  The disadvantage of 'div' is that it
introduces a new reserved word, with all the issues it creates.  The
disadvantage of '//' is that it means something very different to Java
and C++ users.

>     A '//' operator which will be introduced, which will call the
>     nb_intdivide or __intdiv__ slots. This operator will be
>     implemented in all the Python numeric types, and will have the
>     semantics of
> 
>                  a // b == floor(a/b)
> 
>     Except that the type of a//b will be the type a and b will be
>     coerced into (specifically, if a and b are of the same type,
>     a//b will be of that type too).
> 
> Changing the Semantics of the / Operator
> 
>     The nb_divide slot on integers (and long integers, if these are
>     a seperate type) will issue a warning when given integers a and
>     b such that
> 
>                   a % b != 0
> 
>     The warning will be off by default in the 2.2 release, and on by
>     default for in the next Python release, and will stay in effect
>     for 24 months.  The next Python release after 24 months, it will
>     implement
> 
>                   (a/b) * b = a (more or less)
> 
>     The type of a/b will be either a float or a rational, depending
>     on other PEPs.
> 
> __future__
> 
>     A special opcode, FUTURE_DIV will be added that does the equivalent

Maybe for compatibility of bytecode files we should come up with a
better name, e.g. FLOAT_DIV?

>     of
> 
>         if type(a) in (types.IntType, types.LongType):
>              if type(b) in (types.IntType, types.LongType):
>                  if a % b != 0:
>                       return float(a)/b
>         return a/b
> 
>     (or rational(a)/b, depending on whether 0.5 is rational or float)
> 
>     If "from __future__ import non_integer_division" is present in the
>     releases until the IntType nb_divide is changed, the "/" operator is
>     compiled to FUTURE_DIV

I find "non_integer_division" rather long.  Maybe it should be called
"float_division"?

> Copyright
> 
>     This document has been placed in the public domain.
> 
> 
> 
> Local Variables:
> mode: indented-text
> indent-tabs-mode: nil
> End:

--Guido van Rossum (home page: http://www.python.org/~guido/)