221 lines
8.3 KiB
Plaintext
221 lines
8.3 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: 17-Apr-2001
|
||
|
||
|
||
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 of Ints and Floats
|
||
|
||
Complex numbers are treated separately below, since Python can be
|
||
built without them.
|
||
|
||
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 required kinds are processor
|
||
dependent, as at present, except for the "long integer" kind,
|
||
which can hold an arbitrary integer.
|
||
|
||
The built-in functions int(), long(), and float() 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) 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
|
||
|
||
Two 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 an integer argument 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). The kind object accepts
|
||
arguments that are integers including longs. If n == 0,
|
||
returns the kind object corresponding to the Python literal 0.
|
||
|
||
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 closed interval [-n, n]. The kind object
|
||
accepts arguments that are integer or float.
|
||
|
||
If nd and n are both zero, returns the kind object
|
||
corresponding to the Python literal 0.0.
|
||
|
||
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.
|
||
|
||
Besides their callable behavior, kind objects have attributes
|
||
giving the traits of the kind in question.
|
||
|
||
1. name is the name of the kind. The standard kinds are called
|
||
int, long, double.
|
||
|
||
2. typecode is a single-letter string that would be appropriate
|
||
for use with Numeric or module array to form an array of this
|
||
kind. The standard types' typecodes are 'i', 'O', 'd'
|
||
respectively.
|
||
|
||
3. Integer kinds have these additional attributes: MAX, equal to
|
||
the maximum permissible integer of this kind, or None for the
|
||
long kind. MIN, equal to the most negative permissible integer
|
||
of this kind, or None for the long kind.
|
||
|
||
4. Float kinds have these additional attributes whose properties
|
||
are equal to the corresponding value for the corresponding C
|
||
type in the standard header file "float.h". MAX, MIN, DIG,
|
||
MANT_DIG, EPSILON, MAX_EXP, MAX_10_EXP, MIN_EXP, MIN_10_EXP,
|
||
RADIX, ROUNDS (== FLT_RADIX, FLT_ROUNDS in float.h). These
|
||
values are of type integer except for MAX, MIN, and EPSILON,
|
||
which are of the Python floating type to which the kind
|
||
corresponds.
|
||
|
||
|
||
Attributes of Module kinds
|
||
|
||
int_kinds is a list of the available integer kinds, sorted from lowest
|
||
to highest kind. By definition, int_kinds[-1] is the
|
||
long kind.
|
||
|
||
float_kinds is a list of the available floating point kinds, sorted
|
||
from lowest to highest kind.
|
||
|
||
default_int_kind is the kind object corresponding to the Python
|
||
literal 0
|
||
|
||
default_long_kind is the kind object corresponding to the Python
|
||
literal 0L
|
||
|
||
default_float_kind is the kind object corresponding to the Python
|
||
literal 0.0
|
||
|
||
|
||
Complex Numbers
|
||
|
||
If supported, complex numbers have real and imaginary parts that
|
||
are 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.
|
||
|
||
If complex numbers are supported, the following are available in
|
||
module kinds:
|
||
|
||
complex_kind(nd, n)
|
||
Return a callable object whose result is a complex kind that
|
||
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 of any integer, real, or complex
|
||
kind, or two arguments, each integer or real.
|
||
|
||
complex_kinds is a list of the available complex kinds, sorted
|
||
from lowest to highest kind.
|
||
|
||
default_complex_kind is the kind object corresponding to the
|
||
Python literal 0.0j. The name of this kind
|
||
is doublecomplex, and its typecode is 'D'.
|
||
|
||
Complex kind objects have these addition attributes:
|
||
|
||
floatkind is the kind object of the corresponding float type.
|
||
|
||
|
||
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)
|
||
# but in the following case we know w has kind "double".
|
||
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
|
||
|
||
No open issues have been raised at this time.
|
||
|
||
Copyright
|
||
|
||
This document has been placed in the public domain.
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
End:
|