Skip to content

Commit 1919b7e

Browse files
author
Stefan Krah
committed
Issue #7652: Integrate the decimal floating point libmpdec library to speed
up the decimal module. Performance gains of the new C implementation are between 12x and 80x, depending on the application.
1 parent 8bfccd8 commit 1919b7e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+30818
-437
lines changed

Doc/library/decimal.rst

Lines changed: 147 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
.. moduleauthor:: Raymond Hettinger <python at rcn.com>
1010
.. moduleauthor:: Aahz <aahz at pobox.com>
1111
.. moduleauthor:: Tim Peters <tim.one at comcast.net>
12+
.. moduleauthor:: Stefan Krah <skrah at bytereef.org>
1213
.. sectionauthor:: Raymond D. Hettinger <python at rcn.com>
1314

1415
.. import modules for testing inline doctests with the Sphinx doctest builder
@@ -20,8 +21,9 @@
2021
# make sure each group gets a fresh context
2122
setcontext(Context())
2223

23-
The :mod:`decimal` module provides support for decimal floating point
24-
arithmetic. It offers several advantages over the :class:`float` datatype:
24+
The :mod:`decimal` module provides support for fast correctly-rounded
25+
decimal floating point arithmetic. It offers several advantages over the
26+
:class:`float` datatype:
2527

2628
* Decimal "is based on a floating-point model which was designed with people
2729
in mind, and necessarily has a paramount guiding principle -- computers must
@@ -92,7 +94,7 @@ computation. Depending on the needs of the application, signals may be ignored,
9294
considered as informational, or treated as exceptions. The signals in the
9395
decimal module are: :const:`Clamped`, :const:`InvalidOperation`,
9496
:const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`,
95-
:const:`Overflow`, and :const:`Underflow`.
97+
:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`.
9698

9799
For each signal there is a flag and a trap enabler. When a signal is
98100
encountered, its flag is set to one, then, if the trap enabler is
@@ -122,7 +124,7 @@ precision, rounding, or enabled traps::
122124

123125
>>> from decimal import *
124126
>>> getcontext()
125-
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
127+
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
126128
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
127129
InvalidOperation])
128130

@@ -132,7 +134,7 @@ Decimal instances can be constructed from integers, strings, floats, or tuples.
132134
Construction from an integer or a float performs an exact conversion of the
133135
value of that integer or float. Decimal numbers include special values such as
134136
:const:`NaN` which stands for "Not a number", positive and negative
135-
:const:`Infinity`, and :const:`-0`.
137+
:const:`Infinity`, and :const:`-0`::
136138

137139
>>> getcontext().prec = 28
138140
>>> Decimal(10)
@@ -152,6 +154,25 @@ value of that integer or float. Decimal numbers include special values such as
152154
>>> Decimal('-Infinity')
153155
Decimal('-Infinity')
154156

157+
If the :exc:`FloatOperation` signal is trapped, accidental mixing of
158+
decimals and floats in constructors or ordering comparisons raises
159+
an exception::
160+
161+
>>> c = getcontext()
162+
>>> c.traps[FloatOperation] = True
163+
>>> Decimal(3.14)
164+
Traceback (most recent call last):
165+
File "<stdin>", line 1, in <module>
166+
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
167+
>>> Decimal('3.5') < 3.7
168+
Traceback (most recent call last):
169+
File "<stdin>", line 1, in <module>
170+
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
171+
>>> Decimal('3.5') == 3.5
172+
True
173+
174+
.. versionadded:: 3.3
175+
155176
The significance of a new Decimal is determined solely by the number of digits
156177
input. Context precision and rounding only come into play during arithmetic
157178
operations.
@@ -169,6 +190,16 @@ operations.
169190
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
170191
Decimal('5.85988')
171192

193+
If the internal limits of the C version are exceeded, constructing
194+
a decimal raises :class:`InvalidOperation`::
195+
196+
>>> Decimal("1e9999999999999999999")
197+
Traceback (most recent call last):
198+
File "<stdin>", line 1, in <module>
199+
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
200+
201+
.. versionchanged:: 3.3
202+
172203
Decimals interact well with much of the rest of Python. Here is a small decimal
173204
floating point flying circus:
174205

@@ -244,7 +275,7 @@ enabled:
244275
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
245276

246277
>>> ExtendedContext
247-
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
278+
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
248279
capitals=1, clamp=0, flags=[], traps=[])
249280
>>> setcontext(ExtendedContext)
250281
>>> Decimal(1) / Decimal(7)
@@ -269,7 +300,7 @@ using the :meth:`clear_flags` method. ::
269300
>>> Decimal(355) / Decimal(113)
270301
Decimal('3.14159292')
271302
>>> getcontext()
272-
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
303+
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
273304
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
274305

275306
The *flags* entry shows that the rational approximation to :const:`Pi` was
@@ -358,6 +389,10 @@ Decimal objects
358389
The argument to the constructor is now permitted to be a :class:`float`
359390
instance.
360391

392+
.. versionchanged:: 3.3
393+
:class:`float` arguments raise an exception if the :exc:`FloatOperation`
394+
trap is set. By default the trap is off.
395+
361396
Decimal floating point objects share many properties with the other built-in
362397
numeric types such as :class:`float` and :class:`int`. All of the usual math
363398
operations and special methods apply. Likewise, decimal objects can be
@@ -880,39 +915,33 @@ described below. In addition, the module provides three pre-made contexts:
880915
In single threaded environments, it is preferable to not use this context at
881916
all. Instead, simply create contexts explicitly as described below.
882917

883-
The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps
884-
for Overflow, InvalidOperation, and DivisionByZero.
918+
The default values are :attr:`prec`\ =\ :const:`28`,
919+
:attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`,
920+
and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and
921+
:class:`DivisionByZero`.
885922

886923
In addition to the three supplied contexts, new contexts can be created with the
887924
:class:`Context` constructor.
888925

889926

890-
.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None)
927+
.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
891928

892929
Creates a new context. If a field is not specified or is :const:`None`, the
893930
default values are copied from the :const:`DefaultContext`. If the *flags*
894931
field is not specified or is :const:`None`, all flags are cleared.
895932

896-
The *prec* field is a positive integer that sets the precision for arithmetic
897-
operations in the context.
898-
899-
The *rounding* option is one of:
933+
*prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets
934+
the precision for arithmetic operations in the context.
900935

901-
* :const:`ROUND_CEILING` (towards :const:`Infinity`),
902-
* :const:`ROUND_DOWN` (towards zero),
903-
* :const:`ROUND_FLOOR` (towards :const:`-Infinity`),
904-
* :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero),
905-
* :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer),
906-
* :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or
907-
* :const:`ROUND_UP` (away from zero).
908-
* :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero
909-
would have been 0 or 5; otherwise towards zero)
936+
The *rounding* option is one of the constants listed in the section
937+
`Rounding Modes`_.
910938

911939
The *traps* and *flags* fields list any signals to be set. Generally, new
912940
contexts should only set traps and leave the flags clear.
913941

914942
The *Emin* and *Emax* fields are integers specifying the outer limits allowable
915-
for exponents.
943+
for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`],
944+
*Emax* in the range [:const:`0`, :const:`MAX_EMAX`].
916945

917946
The *capitals* field is either :const:`0` or :const:`1` (the default). If set to
918947
:const:`1`, exponents are printed with a capital :const:`E`; otherwise, a
@@ -951,6 +980,12 @@ In addition to the three supplied contexts, new contexts can be created with the
951980

952981
Resets all of the flags to :const:`0`.
953982

983+
.. method:: clear_traps()
984+
985+
Resets all of the traps to :const:`0`.
986+
987+
.. versionadded:: 3.3
988+
954989
.. method:: copy()
955990

956991
Return a duplicate of the context.
@@ -1250,8 +1285,13 @@ In addition to the three supplied contexts, new contexts can be created with the
12501285
With two arguments, compute ``x**y``. If ``x`` is negative then ``y``
12511286
must be integral. The result will be inexact unless ``y`` is integral and
12521287
the result is finite and can be expressed exactly in 'precision' digits.
1253-
The result should always be correctly rounded, using the rounding mode of
1254-
the current thread's context.
1288+
The rounding mode of the context is used. Results are always correctly-rounded
1289+
in the Python version.
1290+
1291+
.. versionchanged:: 3.3
1292+
The C module computes :meth:`power` in terms of the correctly-rounded
1293+
:meth:`exp` and :meth:`ln` functions. The result is well-defined but
1294+
only "almost always correctly-rounded".
12551295

12561296
With three arguments, compute ``(x**y) % modulo``. For the three argument
12571297
form, the following restrictions on the arguments hold:
@@ -1339,6 +1379,66 @@ In addition to the three supplied contexts, new contexts can be created with the
13391379

13401380
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13411381
1382+
.. _decimal-rounding-modes:
1383+
1384+
Constants
1385+
---------
1386+
1387+
The constants in this section are only relevant for the C module. They
1388+
are also included in the pure Python version for compatibility.
1389+
1390+
+--------------------+---------------------+------------------------------+
1391+
| | 32-bit | 64-bit |
1392+
+====================+=====================+==============================+
1393+
| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` |
1394+
+--------------------+---------------------+------------------------------+
1395+
| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` |
1396+
+--------------------+---------------------+------------------------------+
1397+
| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` |
1398+
+--------------------+---------------------+------------------------------+
1399+
1400+
.. data:: HAVE_THREADS
1401+
1402+
The default value is True. If Python is compiled without threads, the
1403+
C version automatically disables the expensive thread local context
1404+
machinery. In this case, the value is False.
1405+
1406+
Rounding modes
1407+
--------------
1408+
1409+
.. data:: ROUND_CEILING
1410+
1411+
Round towards :const:`Infinity`.
1412+
1413+
.. data:: ROUND_DOWN
1414+
1415+
Round towards zero.
1416+
1417+
.. data:: ROUND_FLOOR
1418+
1419+
Round towards :const:`-Infinity`.
1420+
1421+
.. data:: ROUND_HALF_DOWN
1422+
1423+
Round to nearest with ties going towards zero.
1424+
1425+
.. data:: ROUND_HALF_EVEN
1426+
1427+
Round to nearest with ties going to nearest even integer.
1428+
1429+
.. data:: ROUND_HALF_UP
1430+
1431+
Round to nearest with ties going away from zero.
1432+
1433+
.. data:: ROUND_UP
1434+
1435+
Round away from zero.
1436+
1437+
.. data:: ROUND_05UP
1438+
1439+
Round away from zero if last digit after rounding towards zero would have
1440+
been 0 or 5; otherwise round towards zero.
1441+
13421442

13431443
.. _decimal-signals:
13441444

@@ -1403,7 +1503,6 @@ condition.
14031503
Infinity / Infinity
14041504
x % 0
14051505
Infinity % x
1406-
x._rescale( non-integer )
14071506
sqrt(-x) and x > 0
14081507
0 ** 0
14091508
x ** (non-integer)
@@ -1446,6 +1545,23 @@ condition.
14461545
Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact`
14471546
and :class:`Subnormal` are also signaled.
14481547

1548+
1549+
.. class:: FloatOperation
1550+
1551+
Enable stricter semantics for mixing floats and Decimals.
1552+
1553+
If the signal is not trapped (default), mixing floats and Decimals is
1554+
permitted in the :class:`~decimal.Decimal` constructor,
1555+
:meth:`~decimal.Context.create_decimal` and all comparison operators.
1556+
Both conversion and comparisons are exact. Any occurrence of a mixed
1557+
operation is silently recorded by setting :exc:`FloatOperation` in the
1558+
context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float`
1559+
or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag.
1560+
1561+
Otherwise (the signal is trapped), only equality comparisons and explicit
1562+
conversions are silent. All other mixed operations raise :exc:`FloatOperation`.
1563+
1564+
14491565
The following table summarizes the hierarchy of signals::
14501566

14511567
exceptions.ArithmeticError(exceptions.Exception)
@@ -1458,10 +1574,12 @@ The following table summarizes the hierarchy of signals::
14581574
InvalidOperation
14591575
Rounded
14601576
Subnormal
1577+
FloatOperation
14611578

14621579
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14631580
14641581
1582+
14651583
.. _decimal-notes:
14661584

14671585
Floating Point Notes
@@ -1571,7 +1689,7 @@ normalized floating point representations, it is not immediately obvious that
15711689
the following calculation returns a value equal to zero:
15721690

15731691
>>> 1 / Decimal('Infinity')
1574-
Decimal('0E-1000000026')
1692+
Decimal('0E-1000026')
15751693

15761694
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15771695
@@ -1583,7 +1701,7 @@ Working with threads
15831701

15841702
The :func:`getcontext` function accesses a different :class:`Context` object for
15851703
each thread. Having separate thread contexts means that threads may make
1586-
changes (such as ``getcontext.prec=10``) without interfering with other threads.
1704+
changes (such as ``getcontext().prec=10``) without interfering with other threads.
15871705

15881706
Likewise, the :func:`setcontext` function automatically assigns its target to
15891707
the current thread.

Doc/library/numeric.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ Numeric and Mathematical Modules
88
The modules described in this chapter provide numeric and math-related functions
99
and data types. The :mod:`numbers` module defines an abstract hierarchy of
1010
numeric types. The :mod:`math` and :mod:`cmath` modules contain various
11-
mathematical functions for floating-point and complex numbers. For users more
12-
interested in decimal accuracy than in speed, the :mod:`decimal` module supports
13-
exact representations of decimal numbers.
11+
mathematical functions for floating-point and complex numbers. The :mod:`decimal`
12+
module supports exact representations of decimal numbers, using arbitrary precision
13+
arithmetic.
1414

1515
The following modules are documented in this chapter:
1616

0 commit comments

Comments
 (0)