forked from python/peps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pep-0242.txt
237 lines (176 loc) · 8.27 KB
/
pep-0242.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
PEP: 242
Title: Numeric Kinds
Author: Paul F. Dubois <[email protected]>
Status: Rejected
Type: Standards Track
Content-Type: text/x-rst
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 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.
Rejection
=========
This PEP has been closed by the author. The kinds module will not
be added to the standard library.
There was no opposition to the proposal but only mild interest in
using it, not enough to justify adding the module to the standard
library. Instead, it will be made available as a separate
distribution item at the Numerical Python site. At the next
release of Numerical Python, it will no longer be a part of the
Numeric distribution.
Copyright
=========
This document has been placed in the public domain.