205 lines
7.8 KiB
Plaintext
205 lines
7.8 KiB
Plaintext
PEP: 242
|
||
Title: Numeric Kinds
|
||
Version: $Revision$
|
||
Author: paul@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:
|