[Python-Dev] [Very Long (11K)] Numeric PEPs, first public posts

Moshe Zadka moshez@zadka.site.co.il
Fri, 16 Mar 2001 15:18:43 +0200


After the brouhaha at IPC9, it was decided that while PEP-0228 should stay
as a possible goal, there should be more concrete PEPs suggesting specific
changes in Python numerical model, with implementation suggestions and
migration paths fleshed out. So, there are four new PEPs now, all proposing
changes to Python's numeric model. There are some connections between them,
but each is supposed to be accepted or rejected according to its own merits.

To facilitate discussion, I'm including copies of the PEPs concerned
(for reference purposes, these are PEPs 0237-0240, and the latest public
version is always in the Python CVS under non-dist/peps/ . A reasonably
up to date version is linked from http://python.sourceforge.net)

Please direct all future discussion to python-numerics@lists.sourceforge.net
This list has been especially set-up to discuss those subjects.

PEP: 237
Title: Unifying Long Integers and Integers
Version: $Revision: 1.2 $
Author: pep@zadka.site.co.il (Moshe Zadka)
Status: Draft
Type: Standards Track
Created: 11-Mar-2001
Python-Version: 2.2
Post-History:


Abstract

    Python has both integers (machine word size integral) types, and
    long integers (unbounded integral) types.  When integers
    operations overflow the machine registers, they raise an error.
    This PEP proposes to do away with the distinction, and unify the
    types from the perspective of both the Python interpreter and the
    C API.


Rationale

    Having the machine word size exposed to the language hinders
    portability.  For examples Python source files and .pyc's are not
    portable because of this.  Many programs find a need to deal with
    larger numbers after the fact, and changing the algorithms later
    is not only bothersome, but hinders performance in the normal
    case.


Literals

    A trailing 'L' at the end of an integer literal will stop having
    any meaning, and will be eventually phased out.  This will be done
    using warnings when encountering such literals.  The warning will
    be off by default in Python 2.2, on for 12 months, which will
    probably mean Python 2.3 and 2.4, and then will no longer be
    supported.


Builtin Functions

    The function long() will call the function int(), issuing a
    warning.  The warning will be off in 2.2, and on for two revisions
    before removing the function.  A FAQ will be added to explain that
    a solutions for old modules are:

         long=int

    at the top of the module, or:

         import __builtin__
         __builtin__.long=int

    In site.py.


C API

    All PyLong_As* will call PyInt_As*.  If PyInt_As* does not exist,
    it will be added.  Similarly for PyLong_From*.  A similar path of
    warnings as for the Python builtins will be followed.


Overflows

    When an arithmetic operation on two numbers whose internal
    representation is as machine-level integers returns something
    whose internal representation is a bignum, a warning which is
    turned off by default will be issued.  This is only a debugging
    aid, and has no guaranteed semantics.


Implementation

    The PyInt type's slot for a C long will be turned into a 

        union {
            long i;
            struct {
                unsigned long length;
                digit digits[1];
            } bignum;
        };

    Only the n-1 lower bits of the long have any meaning; the top bit
    is always set.  This distinguishes the union.  All PyInt functions
    will check this bit before deciding which types of operations to
    use.


Jython Issues

    Jython will have a PyInt interface which is implemented by both
    from PyFixNum and PyBigNum.


Open Issues

    What to do about sys.maxint?

    What to do about PyInt_AS_LONG failures?

    What do do about %u, %o, %x formatting operators?

    How to warn about << not cutting integers?

    Should the overflow warning be on a portable maximum size?

    Will unification of types and classes help with a more straightforward
    implementations?


Copyright

    This document has been placed in the public domain.


PEP: 238
Title: Non-integer Division
Version: $Revision: 1.1 $
Author: pep@zadka.site.co.il (Moshe Zadka)
Status: Draft
Type: Standards Track
Created: 11-Mar-2001
Python-Version: 2.2
Post-History:


Abstract

    Dividing integers currently returns the floor of the quantities.
    This behavior 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 while keeping backward
    compatibility issues in mind.


Rationale

    The behavior of integer division is a major stumbling block found
    in user testing of Python.  This manages to trip up new
    programmers regularly and even causes the experienced programmer
    to make the occasional mistake.  The workarounds, like explicitly
    coercing one of the operands to float or use a non-integer
    literal, are very non-intuitive and lower the readability of the
    program.


// Operator

    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
    separate type, but see PEP 237[1]) 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[2, 3].


__future__

    A special opcode, FUTURE_DIV will be added that does the
    equivalent 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
    module, until the IntType nb_divide is changed, the "/" operator
    is compiled to FUTURE_DIV.


Open Issues

    Should the // operator be renamed to "div"?


References

    [1] PEP 237, Unifying Long Integers and Integers, Zadka,
        http://python.sourceforge.net/peps/pep-0237.html

    [2] PEP 239, Adding a Rational Type to Python, Zadka,
        http://python.sourceforge.net/peps/pep-0239.html

    [3] PEP 240, Adding a Rational Literal to Python, Zadka,
        http://python.sourceforge.net/peps/pep-0240.html


Copyright

    This document has been placed in the public domain.


PEP: 239
Title: Adding a Rational Type to Python
Version: $Revision: 1.1 $
Author: pep@zadka.site.co.il (Moshe Zadka)
Status: Draft
Type: Standards Track
Created: 11-Mar-2001
Python-Version: 2.2
Post-History:


Abstract

    Python has no numeric type with the semantics of an unboundedly
    precise rational number.  This proposal explains the semantics of
    such a type, and suggests builtin functions and literals to
    support such a type.  This PEP suggests no literals for rational
    numbers; that is left for another PEP[1].


Rationale

    While sometimes slower and more memory intensive (in general,
    unboundedly so) rational arithmetic captures more closely the
    mathematical ideal of numbers, and tends to have behavior which is
    less surprising to newbies.  Though many Python implementations of
    rational numbers have been written, none of these exist in the
    core, or are documented in any way.  This has made them much less
    accessible to people who are less Python-savvy.


RationalType

    There will be a new numeric type added called RationalType.  Its
    unary operators will do the obvious thing.  Binary operators will
    coerce integers and long integers to rationals, and rationals to
    floats and complexes.

    The following attributes will be supported: .numerator and
    .denominator.  The language definition will not define these other
    then that:

        r.denominator * r == r.numerator

    In particular, no guarantees are made regarding the GCD or the
    sign of the denominator, even though in the proposed
    implementation, the GCD is always 1 and the denominator is always
    positive.

    The method r.trim(max_denominator) will return the closest
    rational s to r such that abs(s.denominator) <= max_denominator.


The rational() Builtin

    This function will have the signature rational(n, d=1).  n and d
    must both be integers, long integers or rationals.  A guarantee is
    made that

        rational(n, d) * d == n


References

    [1] PEP 240, Adding a Rational Literal to Python, Zadka,
        http://python.sourceforge.net/peps/pep-0240.html


Copyright

    This document has been placed in the public domain.


PEP: 240
Title: Adding a Rational Literal to Python
Version: $Revision: 1.1 $
Author: pep@zadka.site.co.il (Moshe Zadka)
Status: Draft
Type: Standards Track
Created: 11-Mar-2001
Python-Version: 2.2
Post-History:


Abstract

    A different PEP[1] suggests adding a builtin rational type to
    Python.  This PEP suggests changing the ddd.ddd float literal to a
    rational in Python, and modifying non-integer division to return
    it.


Rationale

    Rational numbers are useful, and are much harder to use without
    literals.  Making the "obvious" non-integer type one with more
    predictable semantics will surprise new programmers less then
    using floating point numbers.


Proposal

    Literals conforming to the regular expression '\d*.\d*' will be
    rational numbers.


Backwards Compatibility

    The only backwards compatible issue is the type of literals
    mentioned above.  The following migration is suggested:

    1. "from __future__ import rational_literals" will cause all such
       literals to be treated as rational numbers.

    2. Python 2.2 will have a warning, turned off by default, about
       such literals in the absence of a __future__ statement.  The
       warning message will contain information about the __future__
       statement, and indicate that to get floating point literals,
       they should be suffixed with "e0".

    3. Python 2.3 will have the warning turned on by default.  This
       warning will stay in place for 24 months, at which time the
       literals will be rationals and the warning will be removed.


References

    [1] PEP 239, Adding a Rational Type to Python, Zadka,
        http://python.sourceforge.net/peps/pep-0239.html


Copyright

    This document has been placed in the public domain.