PEP 242 Released

Paul F. Dubois paul at pfdubois.com
Tue Mar 20 18:56:06 EST 2001


PEP: 242
Title: Numeric Kinds
Version: $Revision: 1.1 $
Author: paul at pfdubois.com (Paul F. Dubois)
Status: Draft
Type: Standards Track
Created: 17-Mar-2001
Python-Version: 2.2
Post-History:


Abstract

    This proposal gives the user optional control over the precision
    and range of numeric computations so that a computation can be
    written once and run anywhere with at least the desired precision
    and range.  It is backward compatible with existing code.  The
    meaning of decimal literals is clarified.


Rationale

    Currently it is impossible in every language except Fortran 90 to
    write a program in a portable way that uses floating point and
    gets roughly the same answer regardless of platform -- or refuses
    to compile if that is not possible.  Python currently has only one
    floating point type, equal to a C double in the C implementation.

    No type exists corresponding to single or quad floats.  It would
    complicate the language to try to introduce such types directly
    and their subsequent use would not be portable.  This proposal is
    similar to the Fortran 90 "kind" solution, adapted to the Python
    environment.  With this facility an entire calculation can be
    switched from one level of precision to another by changing a
    single line.  If the desired precision does not exist on a
    particular machine, the program will fail rather than get the
    wrong answer.  Since coding in this style would involve an early
    call to the routine that will fail, this is the next best thing to
    not compiling.


Supported Kinds

    Each Python compiler may define as many "kinds" of integer and
    floating point numbers as it likes, except that it must support at
    least two kinds of integer corresponding to the existing int and
    long, and must support at least one kind of floating point number,
    equivalent to the present float.  The range and precision of the
    these kinds are processor dependent, as at present, except for the
    "long integer" kind, which can hold an arbitrary integer.  The
    built-in functions int(), float(), long() and complex() convert
    inputs to these default kinds as they do at present.  (Note that a
    Unicode string is actually a different "kind" of string and that a
    sufficiently knowledgeable person might be able to expand this PEP
    to cover that case.)

    Within each type (integer, floating, and complex) the compiler
    supports a linearly-ordered set of kinds, with the ordering
    determined by the ability to hold numbers of an increased range
    and/or precision.


Kind Objects

    Three new standard functions are defined in a module named
    "kinds".  They return callable objects called kind objects.  Each
    int or floating kind object f has the signature result = f(x), and
    each complex kind object has the signature result = f(x, y=0.).

    int_kind(n)
        For n >= 1, return a callable object whose result is an
        integer kind that will hold an integer number in the open
        interval (-10**n,10**n).  This function always succeeds, since
        it can return the 'long' kind if it has to. The kind object
        accepts arguments that are integers including longs.  If n ==
        0, returns the kind object corresponding to long.

    float_kind(nd, n)
        For nd >= 0 and n >= 1, return a callable object whose result
        is a floating point kind that will hold a floating-point
        number with at least nd digits of precision and a base-10
        exponent in the open interval (-n, n).  The kind object
        accepts arguments that are integer or real.

    complex_kind(nd, n)
        Return a callable object whose result is a complex kind that
        will will hold a complex number each of whose components
        (.real, .imag) is of kind float_kind(nd, n).  The kind object
        will accept one argument that is integer, real, or complex, or
        two arguments, each integer or real.

    The compiler will return a kind object corresponding to the least
    of its available set of kinds for that type that has the desired
    properties.  If no kind with the desired qualities exists in a
    given implementation an OverflowError exception is thrown.  A kind
    function converts its argument to the target kind, but if the
    result does not fit in the target kind's range, an OverflowError
    exception is thrown.

    Kind objects also accept a string argument for conversion of
    literal notation to their kind.

    Besides their callable behavior, kind objects have attributes
    giving the traits of the kind in question.  The list of traits
    needs to be completed.


The Meaning of Literal Values

    Literal integer values without a trailing L are of the least
    integer kind required to represent them.  An integer literal with
    a trailing L is a long.  Literal decimal values are of the
    greatest available binary floating-point kind.


Concerning Infinite Floating Precision

    This section makes no proposals and can be omitted from
    consideration.  It is for illuminating an intentionally
    unimplemented 'corner' of the design.

    This PEP does not propose the creation of an infinite precision
    floating point type, just leaves room for it.  Just as int_kind(0)
    returns the long kind object, if in the future an infinitely
    precise decimal kind is available, float_kind(0,0) could return a
    function that converts to that type.  Since such a kind function
    accepts string arguments, programs could then be written that are
    completely precise.  Perhaps in analogy to r'a raw string', 1.3r
    might be available as syntactic sugar for calling the infinite
    floating kind object with argument '1.3'.  r could be thought of
    as meaning 'rational'.


Complex numbers and kinds

    Complex numbers are always pairs of floating-point numbers with
    the same kind.  A Python compiler must support a complex analog of
    each floating point kind it supports, if it supports complex
    numbers at all.


Coercion

    In an expression, coercion between different kinds is to the
    greater kind.  For this purpose, all complex kinds are "greater
    than" all floating-point kinds, and all floating-point kinds are
    "greater than" all integer kinds.


Examples

    In module myprecision.py:

        import kinds
        tinyint = kinds.int_kind(1)
        single = kinds.float_kind(6, 90)
        double = kinds.float_kind(15, 300)
        csingle = kinds.complex_kind(6, 90)

    In the rest of my code:

        from myprecision import tinyint, single, double, csingle
        n = tinyint(3)
        x = double(1.e20)
        z = 1.2
        # builtin float gets you the default float kind, properties unknown
        w = x * float(x)
        w = x * double(z)
        u = csingle(x + z * 1.0j)
        u2 = csingle(x+z, 1.0)

    Note how that entire code can then be changed to a higher
    precision by changing the arguments in myprecision.py.

    Comment: note that you aren't promised that single != double; but
    you are promised that double(1.e20) will hold a number with 15
    decimal digits of precision and a range up to 10**300 or that the
    float_kind call will fail.


Open Issues

    The assertion that a decimal literal means a binary floating-point
    value of the largest available kind is in conflict with other
    proposals about Python's numeric model.  This PEP asserts that
    these other proposals are wrong and that part of them should not
    be implemented.

    Determine the exact list of traits for integer and floating point
    numbers.  There are some standard Fortran routines that do this
    but I have to track them down.  Also there should be information
    sufficient to create a Numeric array of an equal or greater kind.


Copyright

    This document has been placed in the public domain.




Local Variables:
mode: indented-text
indent-tabs-mode: nil
End:





More information about the Python-list mailing list