summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2012-03-21 17:25:23 (GMT)
committerStefan Krah <skrah@bytereef.org>2012-03-21 17:25:23 (GMT)
commit1919b7e72bc43315b32f38a6f5f01e8c717907f4 (patch)
treeef7490b66425fd2c622740ef9adfb03d806b7517
parent8bfccd852e2bceb04664b4832fc80eb3b7584918 (diff)
downloadcpython-1919b7e72bc43315b32f38a6f5f01e8c717907f4.zip
cpython-1919b7e72bc43315b32f38a6f5f01e8c717907f4.tar.gz
cpython-1919b7e72bc43315b32f38a6f5f01e8c717907f4.tar.bz2
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.
-rw-r--r--Doc/library/decimal.rst176
-rw-r--r--Doc/library/numeric.rst6
-rw-r--r--Doc/whatsnew/3.3.rst87
-rw-r--r--Include/longintrepr.h2
-rw-r--r--Lib/decimal.py194
-rw-r--r--Lib/test/support.py4
-rw-r--r--Lib/test/test_decimal.py3310
-rw-r--r--Lib/test/test_fractions.py12
-rw-r--r--Lib/test/test_numeric_tower.py2
-rw-r--r--Misc/NEWS4
-rw-r--r--Misc/valgrind-python.supp13
-rw-r--r--Modules/_decimal/ISSUES.txt56
-rw-r--r--Modules/_decimal/README.txt46
-rw-r--r--Modules/_decimal/_decimal.c5512
-rw-r--r--Modules/_decimal/docstrings.h753
-rw-r--r--Modules/_decimal/libmpdec/README.txt90
-rw-r--r--Modules/_decimal/libmpdec/basearith.c635
-rw-r--r--Modules/_decimal/libmpdec/basearith.h213
-rw-r--r--Modules/_decimal/libmpdec/bits.h192
-rw-r--r--Modules/_decimal/libmpdec/constants.c132
-rw-r--r--Modules/_decimal/libmpdec/constants.h83
-rw-r--r--Modules/_decimal/libmpdec/context.c286
-rw-r--r--Modules/_decimal/libmpdec/convolute.c174
-rw-r--r--Modules/_decimal/libmpdec/convolute.h43
-rw-r--r--Modules/_decimal/libmpdec/crt.c179
-rw-r--r--Modules/_decimal/libmpdec/crt.h40
-rw-r--r--Modules/_decimal/libmpdec/difradix2.c173
-rw-r--r--Modules/_decimal/libmpdec/difradix2.h41
-rw-r--r--Modules/_decimal/libmpdec/fnt.c81
-rw-r--r--Modules/_decimal/libmpdec/fnt.h42
-rw-r--r--Modules/_decimal/libmpdec/fourstep.c255
-rw-r--r--Modules/_decimal/libmpdec/fourstep.h41
-rw-r--r--Modules/_decimal/libmpdec/io.c1575
-rw-r--r--Modules/_decimal/libmpdec/io.h59
-rw-r--r--Modules/_decimal/libmpdec/literature/REFERENCES.txt51
-rw-r--r--Modules/_decimal/libmpdec/literature/bignum.txt83
-rw-r--r--Modules/_decimal/libmpdec/literature/fnt.py208
-rw-r--r--Modules/_decimal/libmpdec/literature/matrix-transform.txt256
-rw-r--r--Modules/_decimal/libmpdec/literature/mulmod-64.txt127
-rw-r--r--Modules/_decimal/libmpdec/literature/mulmod-ppro.txt269
-rw-r--r--Modules/_decimal/libmpdec/literature/six-step.txt63
-rw-r--r--Modules/_decimal/libmpdec/literature/umodarith.lisp692
-rw-r--r--Modules/_decimal/libmpdec/memory.c292
-rw-r--r--Modules/_decimal/libmpdec/memory.h44
-rw-r--r--Modules/_decimal/libmpdec/mpdecimal.c7596
-rw-r--r--Modules/_decimal/libmpdec/mpdecimal.h800
-rw-r--r--Modules/_decimal/libmpdec/numbertheory.c132
-rw-r--r--Modules/_decimal/libmpdec/numbertheory.h71
-rw-r--r--Modules/_decimal/libmpdec/sixstep.c212
-rw-r--r--Modules/_decimal/libmpdec/sixstep.h41
-rw-r--r--Modules/_decimal/libmpdec/transpose.c276
-rw-r--r--Modules/_decimal/libmpdec/transpose.h55
-rw-r--r--Modules/_decimal/libmpdec/typearith.h669
-rw-r--r--Modules/_decimal/libmpdec/umodarith.h650
-rw-r--r--Modules/_decimal/libmpdec/vccompat.h62
-rw-r--r--Modules/_decimal/libmpdec/vcdiv64.asm48
-rw-r--r--Modules/_decimal/libmpdec/vcstdint.h232
-rw-r--r--Modules/_decimal/tests/README.txt15
-rw-r--r--Modules/_decimal/tests/bench.py116
-rw-r--r--Modules/_decimal/tests/deccheck.py1074
-rw-r--r--Modules/_decimal/tests/formathelper.py344
-rw-r--r--Modules/_decimal/tests/randdec.py559
-rw-r--r--Modules/_decimal/tests/randfloat.py250
-rw-r--r--Modules/_decimal/tests/runall-memorydebugger.sh175
-rw-r--r--Modules/_decimal/tests/runall.bat121
-rw-r--r--PCbuild/_decimal.vcproj743
-rw-r--r--PCbuild/pcbuild.sln21
-rwxr-xr-xconfigure171
-rw-r--r--configure.ac100
-rw-r--r--pyconfig.h.in13
-rw-r--r--setup.py113
71 files changed, 30818 insertions, 437 deletions
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
index ef8b43f..4c5f3cd 100644
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -9,6 +9,7 @@
.. moduleauthor:: Raymond Hettinger <python at rcn.com>
.. moduleauthor:: Aahz <aahz at pobox.com>
.. moduleauthor:: Tim Peters <tim.one at comcast.net>
+.. moduleauthor:: Stefan Krah <skrah at bytereef.org>
.. sectionauthor:: Raymond D. Hettinger <python at rcn.com>
.. import modules for testing inline doctests with the Sphinx doctest builder
@@ -20,8 +21,9 @@
# make sure each group gets a fresh context
setcontext(Context())
-The :mod:`decimal` module provides support for decimal floating point
-arithmetic. It offers several advantages over the :class:`float` datatype:
+The :mod:`decimal` module provides support for fast correctly-rounded
+decimal floating point arithmetic. It offers several advantages over the
+:class:`float` datatype:
* Decimal "is based on a floating-point model which was designed with people
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,
considered as informational, or treated as exceptions. The signals in the
decimal module are: :const:`Clamped`, :const:`InvalidOperation`,
:const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`,
-:const:`Overflow`, and :const:`Underflow`.
+:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`.
For each signal there is a flag and a trap enabler. When a signal is
encountered, its flag is set to one, then, if the trap enabler is
@@ -122,7 +124,7 @@ precision, rounding, or enabled traps::
>>> from decimal import *
>>> getcontext()
- Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
+ Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
@@ -132,7 +134,7 @@ Decimal instances can be constructed from integers, strings, floats, or tuples.
Construction from an integer or a float performs an exact conversion of the
value of that integer or float. Decimal numbers include special values such as
:const:`NaN` which stands for "Not a number", positive and negative
-:const:`Infinity`, and :const:`-0`.
+:const:`Infinity`, and :const:`-0`::
>>> getcontext().prec = 28
>>> Decimal(10)
@@ -152,6 +154,25 @@ value of that integer or float. Decimal numbers include special values such as
>>> Decimal('-Infinity')
Decimal('-Infinity')
+If the :exc:`FloatOperation` signal is trapped, accidental mixing of
+decimals and floats in constructors or ordering comparisons raises
+an exception::
+
+ >>> c = getcontext()
+ >>> c.traps[FloatOperation] = True
+ >>> Decimal(3.14)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
+ >>> Decimal('3.5') < 3.7
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
+ >>> Decimal('3.5') == 3.5
+ True
+
+.. versionadded:: 3.3
+
The significance of a new Decimal is determined solely by the number of digits
input. Context precision and rounding only come into play during arithmetic
operations.
@@ -169,6 +190,16 @@ operations.
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
+If the internal limits of the C version are exceeded, constructing
+a decimal raises :class:`InvalidOperation`::
+
+ >>> Decimal("1e9999999999999999999")
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
+
+.. versionchanged:: 3.3
+
Decimals interact well with much of the rest of Python. Here is a small decimal
floating point flying circus:
@@ -244,7 +275,7 @@ enabled:
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
- Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
+ Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
@@ -269,7 +300,7 @@ using the :meth:`clear_flags` method. ::
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
- Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
+ Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
The *flags* entry shows that the rational approximation to :const:`Pi` was
@@ -358,6 +389,10 @@ Decimal objects
The argument to the constructor is now permitted to be a :class:`float`
instance.
+ .. versionchanged:: 3.3
+ :class:`float` arguments raise an exception if the :exc:`FloatOperation`
+ trap is set. By default the trap is off.
+
Decimal floating point objects share many properties with the other built-in
numeric types such as :class:`float` and :class:`int`. All of the usual math
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:
In single threaded environments, it is preferable to not use this context at
all. Instead, simply create contexts explicitly as described below.
- The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps
- for Overflow, InvalidOperation, and DivisionByZero.
+ The default values are :attr:`prec`\ =\ :const:`28`,
+ :attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`,
+ and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and
+ :class:`DivisionByZero`.
In addition to the three supplied contexts, new contexts can be created with the
:class:`Context` constructor.
-.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None)
+.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
Creates a new context. If a field is not specified or is :const:`None`, the
default values are copied from the :const:`DefaultContext`. If the *flags*
field is not specified or is :const:`None`, all flags are cleared.
- The *prec* field is a positive integer that sets the precision for arithmetic
- operations in the context.
-
- The *rounding* option is one of:
+ *prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets
+ the precision for arithmetic operations in the context.
- * :const:`ROUND_CEILING` (towards :const:`Infinity`),
- * :const:`ROUND_DOWN` (towards zero),
- * :const:`ROUND_FLOOR` (towards :const:`-Infinity`),
- * :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero),
- * :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer),
- * :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or
- * :const:`ROUND_UP` (away from zero).
- * :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero
- would have been 0 or 5; otherwise towards zero)
+ The *rounding* option is one of the constants listed in the section
+ `Rounding Modes`_.
The *traps* and *flags* fields list any signals to be set. Generally, new
contexts should only set traps and leave the flags clear.
The *Emin* and *Emax* fields are integers specifying the outer limits allowable
- for exponents.
+ for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`],
+ *Emax* in the range [:const:`0`, :const:`MAX_EMAX`].
The *capitals* field is either :const:`0` or :const:`1` (the default). If set to
: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
Resets all of the flags to :const:`0`.
+ .. method:: clear_traps()
+
+ Resets all of the traps to :const:`0`.
+
+ .. versionadded:: 3.3
+
.. method:: copy()
Return a duplicate of the context.
@@ -1250,8 +1285,13 @@ In addition to the three supplied contexts, new contexts can be created with the
With two arguments, compute ``x**y``. If ``x`` is negative then ``y``
must be integral. The result will be inexact unless ``y`` is integral and
the result is finite and can be expressed exactly in 'precision' digits.
- The result should always be correctly rounded, using the rounding mode of
- the current thread's context.
+ The rounding mode of the context is used. Results are always correctly-rounded
+ in the Python version.
+
+ .. versionchanged:: 3.3
+ The C module computes :meth:`power` in terms of the correctly-rounded
+ :meth:`exp` and :meth:`ln` functions. The result is well-defined but
+ only "almost always correctly-rounded".
With three arguments, compute ``(x**y) % modulo``. For the three argument
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
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+.. _decimal-rounding-modes:
+
+Constants
+---------
+
+The constants in this section are only relevant for the C module. They
+are also included in the pure Python version for compatibility.
+
++--------------------+---------------------+------------------------------+
+| | 32-bit | 64-bit |
++====================+=====================+==============================+
+| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` |
++--------------------+---------------------+------------------------------+
+| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` |
++--------------------+---------------------+------------------------------+
+| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` |
++--------------------+---------------------+------------------------------+
+
+.. data:: HAVE_THREADS
+
+ The default value is True. If Python is compiled without threads, the
+ C version automatically disables the expensive thread local context
+ machinery. In this case, the value is False.
+
+Rounding modes
+--------------
+
+.. data:: ROUND_CEILING
+
+ Round towards :const:`Infinity`.
+
+.. data:: ROUND_DOWN
+
+ Round towards zero.
+
+.. data:: ROUND_FLOOR
+
+ Round towards :const:`-Infinity`.
+
+.. data:: ROUND_HALF_DOWN
+
+ Round to nearest with ties going towards zero.
+
+.. data:: ROUND_HALF_EVEN
+
+ Round to nearest with ties going to nearest even integer.
+
+.. data:: ROUND_HALF_UP
+
+ Round to nearest with ties going away from zero.
+
+.. data:: ROUND_UP
+
+ Round away from zero.
+
+.. data:: ROUND_05UP
+
+ Round away from zero if last digit after rounding towards zero would have
+ been 0 or 5; otherwise round towards zero.
+
.. _decimal-signals:
@@ -1403,7 +1503,6 @@ condition.
Infinity / Infinity
x % 0
Infinity % x
- x._rescale( non-integer )
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
@@ -1446,6 +1545,23 @@ condition.
Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact`
and :class:`Subnormal` are also signaled.
+
+.. class:: FloatOperation
+
+ Enable stricter semantics for mixing floats and Decimals.
+
+ If the signal is not trapped (default), mixing floats and Decimals is
+ permitted in the :class:`~decimal.Decimal` constructor,
+ :meth:`~decimal.Context.create_decimal` and all comparison operators.
+ Both conversion and comparisons are exact. Any occurrence of a mixed
+ operation is silently recorded by setting :exc:`FloatOperation` in the
+ context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float`
+ or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag.
+
+ Otherwise (the signal is trapped), only equality comparisons and explicit
+ conversions are silent. All other mixed operations raise :exc:`FloatOperation`.
+
+
The following table summarizes the hierarchy of signals::
exceptions.ArithmeticError(exceptions.Exception)
@@ -1458,10 +1574,12 @@ The following table summarizes the hierarchy of signals::
InvalidOperation
Rounded
Subnormal
+ FloatOperation
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
.. _decimal-notes:
Floating Point Notes
@@ -1571,7 +1689,7 @@ normalized floating point representations, it is not immediately obvious that
the following calculation returns a value equal to zero:
>>> 1 / Decimal('Infinity')
- Decimal('0E-1000000026')
+ Decimal('0E-1000026')
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1583,7 +1701,7 @@ Working with threads
The :func:`getcontext` function accesses a different :class:`Context` object for
each thread. Having separate thread contexts means that threads may make
-changes (such as ``getcontext.prec=10``) without interfering with other threads.
+changes (such as ``getcontext().prec=10``) without interfering with other threads.
Likewise, the :func:`setcontext` function automatically assigns its target to
the current thread.
diff --git a/Doc/library/numeric.rst b/Doc/library/numeric.rst
index ba22cb6..2732a84 100644
--- a/Doc/library/numeric.rst
+++ b/Doc/library/numeric.rst
@@ -8,9 +8,9 @@ Numeric and Mathematical Modules
The modules described in this chapter provide numeric and math-related functions
and data types. The :mod:`numbers` module defines an abstract hierarchy of
numeric types. The :mod:`math` and :mod:`cmath` modules contain various
-mathematical functions for floating-point and complex numbers. For users more
-interested in decimal accuracy than in speed, the :mod:`decimal` module supports
-exact representations of decimal numbers.
+mathematical functions for floating-point and complex numbers. The :mod:`decimal`
+module supports exact representations of decimal numbers, using arbitrary precision
+arithmetic.
The following modules are documented in this chapter:
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index ca123cd..6646b61 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -596,6 +596,93 @@ curses
(Contributed by IƱigo Serna in :issue:`6755`)
+decimal
+-------
+
+:issue:`7652` - integrate fast native decimal arithmetic.
+ C-module and libmpdec written by Stefan Krah.
+
+The new C version of the decimal module integrates the high speed libmpdec
+library for arbitrary precision correctly-rounded decimal arithmetic.
+libmpdec conforms to IBM's General Decimal Arithmetic Specification.
+
+Performance gains range from 12x for database applications to 80x for
+numerically intensive applications:
+
+ +---------+-------------+--------------+-------------+
+ | | decimal.py | _decimal | speedup |
+ +=========+=============+==============+=============+
+ | pi | 42.75s | 0.58s | 74x |
+ +---------+-------------+--------------+-------------+
+ | telco | 172.19s | 5.68s | 30x |
+ +---------+-------------+--------------+-------------+
+ | psycopg | 3.57s | 0.29s | 12x |
+ +---------+-------------+--------------+-------------+
+
+Features
+~~~~~~~~
+
+* The :exc:`~decimal.FloatOperation` signal optionally enables stricter
+ semantics for mixing floats and Decimals.
+
+* If Python is compiled without threads, the C version automatically
+ disables the expensive thread local context machinery. In this case,
+ the variable :data:`~decimal.HAVE_THREADS` is set to False.
+
+API changes
+~~~~~~~~~~~
+
+* The C module has the following context limits, depending on the machine
+ architecture:
+
+ +-------------------+---------------------+------------------------------+
+ | | 32-bit | 64-bit |
+ +===================+=====================+==============================+
+ | :const:`MAX_PREC` | :const:`425000000` | :const:`999999999999999999` |
+ +-------------------+---------------------+------------------------------+
+ | :const:`MAX_EMAX` | :const:`425000000` | :const:`999999999999999999` |
+ +-------------------+---------------------+------------------------------+
+ | :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` |
+ +-------------------+---------------------+------------------------------+
+
+* In the context templates (:class:`~decimal.DefaultContext`,
+ :class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`)
+ the magnitude of :attr:`~decimal.Context.Emax` and
+ :attr:`~decimal.Context.Emin` has changed to :const:`999999`.
+
+* The :class:`~decimal.Decimal` constructor in decimal.py does not observe
+ the context limits and converts values with arbitrary exponents or precision
+ exactly. Since the C version has internal limits, the following scheme is
+ used: If possible, values are converted exactly, otherwise
+ :exc:`~decimal.InvalidOperation` is raised and the result is NaN. In the
+ latter case it is always possible to use :meth:`~decimal.Context.create_decimal`
+ in order to obtain a rounded or inexact value.
+
+
+* The power function in decimal.py is always correctly-rounded. In the
+ C version, it is defined in terms of the correctly-rounded
+ :meth:`~decimal.Decimal.exp` and :meth:`~decimal.Decimal.ln` functions,
+ but the final result is only "almost always correctly rounded".
+
+
+* In the C version, the context dictionary containing the signals is a
+ :class:`~collections.abc.MutableMapping`. For speed reasons,
+ :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` always
+ refer to the same :class:`~collections.abc.MutableMapping` that the context
+ was initialized with. If a new signal dictionary is assigned,
+ :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps`
+ are updated with the new values, but they do not reference the RHS
+ dictionary.
+
+
+* Pickling a :class:`~decimal.Context` produces a different output in order
+ to have a common interchange format for the Python and C versions.
+
+
+* The order of arguments in the :class:`~decimal.Context` constructor has been
+ changed to match the order displayed by :func:`repr`.
+
+
faulthandler
------------
diff --git a/Include/longintrepr.h b/Include/longintrepr.h
index b94f7b2..3a45bad 100644
--- a/Include/longintrepr.h
+++ b/Include/longintrepr.h
@@ -6,7 +6,7 @@ extern "C" {
#endif
-/* This is published for the benefit of "friend" marshal.c only. */
+/* This is published for the benefit of "friends" marshal.c and _decimal.c. */
/* Parameters of the long integer representation. There are two different
sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit
diff --git a/Lib/decimal.py b/Lib/decimal.py
index e946182..b6f66ab 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -46,8 +46,8 @@ Decimal('1')
Decimal('-0.0123')
>>> Decimal(123456)
Decimal('123456')
->>> Decimal('123.45e12345678901234567890')
-Decimal('1.2345E+12345678901234567892')
+>>> Decimal('123.45e12345678')
+Decimal('1.2345E+12345680')
>>> Decimal('1.33') + Decimal('1.27')
Decimal('2.60')
>>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41')
@@ -122,13 +122,20 @@ __all__ = [
# Exceptions
'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero',
'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow',
+ 'FloatOperation',
# Constants for use in setting up contexts
'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING',
'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP',
# Functions for manipulating contexts
- 'setcontext', 'getcontext', 'localcontext'
+ 'setcontext', 'getcontext', 'localcontext',
+
+ # Limits for the C version for compatibility
+ 'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY',
+
+ # C version: compile time choice that enables the thread local context
+ 'HAVE_THREADS'
]
__version__ = '1.70' # Highest version of the spec this complies with
@@ -137,6 +144,7 @@ __version__ = '1.70' # Highest version of the spec this complies with
import copy as _copy
import math as _math
import numbers as _numbers
+import sys
try:
from collections import namedtuple as _namedtuple
@@ -154,6 +162,19 @@ ROUND_UP = 'ROUND_UP'
ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
ROUND_05UP = 'ROUND_05UP'
+# Compatibility with the C version
+HAVE_THREADS = True
+if sys.maxsize == 2**63-1:
+ MAX_PREC = 999999999999999999
+ MAX_EMAX = 999999999999999999
+ MIN_EMIN = -999999999999999999
+else:
+ MAX_PREC = 425000000
+ MAX_EMAX = 425000000
+ MIN_EMIN = -425000000
+
+MIN_ETINY = MIN_EMIN - (MAX_PREC-1)
+
# Errors
class DecimalException(ArithmeticError):
@@ -370,9 +391,24 @@ class Underflow(Inexact, Rounded, Subnormal):
In all cases, Inexact, Rounded, and Subnormal will also be raised.
"""
+class FloatOperation(DecimalException):
+ """Enable stricter semantics for mixing floats and Decimals.
+
+ If the signal is not trapped (default), mixing floats and Decimals is
+ permitted in the Decimal() constructor, context.create_decimal() and
+ all comparison operators. Both conversion and comparisons are exact.
+ Any occurrence of a mixed operation is silently recorded by setting
+ FloatOperation in the context flags. Explicit conversions with
+ Decimal.from_float() or context.create_decimal_from_float() do not
+ set the flag.
+
+ Otherwise (the signal is trapped), only equality comparisons and explicit
+ conversions are silent. All other mixed operations raise FloatOperation.
+ """
+
# List of public traps and flags
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
- Underflow, InvalidOperation, Subnormal]
+ Underflow, InvalidOperation, Subnormal, FloatOperation]
# Map conditions (per the spec) to signals
_condition_map = {ConversionSyntax:InvalidOperation,
@@ -380,6 +416,10 @@ _condition_map = {ConversionSyntax:InvalidOperation,
DivisionUndefined:InvalidOperation,
InvalidContext:InvalidOperation}
+# Valid rounding modes
+_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING,
+ ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP)
+
##### Context Functions ##################################################
# The getcontext() and setcontext() function manage access to a thread-local
@@ -392,12 +432,11 @@ try:
import threading
except ImportError:
# Python was compiled without threads; create a mock object instead
- import sys
class MockThreading(object):
def local(self, sys=sys):
return sys.modules[__name__]
threading = MockThreading()
- del sys, MockThreading
+ del MockThreading
try:
threading.local
@@ -650,6 +689,11 @@ class Decimal(object):
return self
if isinstance(value, float):
+ if context is None:
+ context = getcontext()
+ context._raise_error(FloatOperation,
+ "strict semantics for mixing floats and Decimals are "
+ "enabled")
value = Decimal.from_float(value)
self._exp = value._exp
self._sign = value._sign
@@ -684,7 +728,9 @@ class Decimal(object):
"""
if isinstance(f, int): # handle integer inputs
return cls(f)
- if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float
+ if not isinstance(f, float):
+ raise TypeError("argument must be int or float.")
+ if _math.isinf(f) or _math.isnan(f):
return cls(repr(f))
if _math.copysign(1.0, f) == 1.0:
sign = 0
@@ -1906,11 +1952,12 @@ class Decimal(object):
def _power_modulo(self, other, modulo, context=None):
"""Three argument version of __pow__"""
- # if can't convert other and modulo to Decimal, raise
- # TypeError; there's no point returning NotImplemented (no
- # equivalent of __rpow__ for three argument pow)
- other = _convert_other(other, raiseit=True)
- modulo = _convert_other(modulo, raiseit=True)
+ other = _convert_other(other)
+ if other is NotImplemented:
+ return other
+ modulo = _convert_other(modulo)
+ if modulo is NotImplemented:
+ return modulo
if context is None:
context = getcontext()
@@ -3832,11 +3879,9 @@ class Context(object):
clamp - If 1, change exponents if too high (Default 0)
"""
- def __init__(self, prec=None, rounding=None,
- traps=None, flags=None,
- Emin=None, Emax=None,
- capitals=None, clamp=None,
- _ignored_flags=None):
+ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
+ capitals=None, clamp=None, flags=None, traps=None,
+ _ignored_flags=None):
# Set defaults; for everything except flags and _ignored_flags,
# inherit from DefaultContext.
try:
@@ -3859,17 +3904,78 @@ class Context(object):
if traps is None:
self.traps = dc.traps.copy()
elif not isinstance(traps, dict):
- self.traps = dict((s, int(s in traps)) for s in _signals)
+ self.traps = dict((s, int(s in traps)) for s in _signals + traps)
else:
self.traps = traps
if flags is None:
self.flags = dict.fromkeys(_signals, 0)
elif not isinstance(flags, dict):
- self.flags = dict((s, int(s in flags)) for s in _signals)
+ self.flags = dict((s, int(s in flags)) for s in _signals + flags)
else:
self.flags = flags
+ def _set_integer_check(self, name, value, vmin, vmax):
+ if not isinstance(value, int):
+ raise TypeError("%s must be an integer" % name)
+ if vmin == '-inf':
+ if value > vmax:
+ raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value))
+ elif vmax == 'inf':
+ if value < vmin:
+ raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value))
+ else:
+ if value < vmin or value > vmax:
+ raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value))
+ return object.__setattr__(self, name, value)
+
+ def _set_signal_dict(self, name, d):
+ if not isinstance(d, dict):
+ raise TypeError("%s must be a signal dict" % d)
+ for key in d:
+ if not key in _signals:
+ raise KeyError("%s is not a valid signal dict" % d)
+ for key in _signals:
+ if not key in d:
+ raise KeyError("%s is not a valid signal dict" % d)
+ return object.__setattr__(self, name, d)
+
+ def __setattr__(self, name, value):
+ if name == 'prec':
+ return self._set_integer_check(name, value, 1, 'inf')
+ elif name == 'Emin':
+ return self._set_integer_check(name, value, '-inf', 0)
+ elif name == 'Emax':
+ return self._set_integer_check(name, value, 0, 'inf')
+ elif name == 'capitals':
+ return self._set_integer_check(name, value, 0, 1)
+ elif name == 'clamp':
+ return self._set_integer_check(name, value, 0, 1)
+ elif name == 'rounding':
+ if not value in _rounding_modes:
+ # raise TypeError even for strings to have consistency
+ # among various implementations.
+ raise TypeError("%s: invalid rounding mode" % value)
+ return object.__setattr__(self, name, value)
+ elif name == 'flags' or name == 'traps':
+ return self._set_signal_dict(name, value)
+ elif name == '_ignored_flags':
+ return object.__setattr__(self, name, value)
+ else:
+ raise AttributeError(
+ "'decimal.Context' object has no attribute '%s'" % name)
+
+ def __delattr__(self, name):
+ raise AttributeError("%s cannot be deleted" % name)
+
+ # Support for pickling, copy, and deepcopy
+ def __reduce__(self):
+ flags = [sig for sig, v in self.flags.items() if v]
+ traps = [sig for sig, v in self.traps.items() if v]
+ return (self.__class__,
+ (self.prec, self.rounding, self.Emin, self.Emax,
+ self.capitals, self.clamp, flags, traps))
+
def __repr__(self):
"""Show the current context."""
s = []
@@ -3888,18 +3994,24 @@ class Context(object):
for flag in self.flags:
self.flags[flag] = 0
+ def clear_traps(self):
+ """Reset all traps to zero"""
+ for flag in self.traps:
+ self.traps[flag] = 0
+
def _shallow_copy(self):
"""Returns a shallow copy from self."""
- nc = Context(self.prec, self.rounding, self.traps,
- self.flags, self.Emin, self.Emax,
- self.capitals, self.clamp, self._ignored_flags)
+ nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
+ self.capitals, self.clamp, self.flags, self.traps,
+ self._ignored_flags)
return nc
def copy(self):
"""Returns a deep copy from self."""
- nc = Context(self.prec, self.rounding, self.traps.copy(),
- self.flags.copy(), self.Emin, self.Emax,
- self.capitals, self.clamp, self._ignored_flags)
+ nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
+ self.capitals, self.clamp,
+ self.flags.copy(), self.traps.copy(),
+ self._ignored_flags)
return nc
__copy__ = copy
@@ -4062,6 +4174,8 @@ class Context(object):
>>> ExtendedContext.canonical(Decimal('2.50'))
Decimal('2.50')
"""
+ if not isinstance(a, Decimal):
+ raise TypeError("canonical requires a Decimal as an argument.")
return a.canonical(context=self)
def compare(self, a, b):
@@ -4372,6 +4486,8 @@ class Context(object):
>>> ExtendedContext.is_canonical(Decimal('2.50'))
True
"""
+ if not isinstance(a, Decimal):
+ raise TypeError("is_canonical requires a Decimal as an argument.")
return a.is_canonical()
def is_finite(self, a):
@@ -4964,7 +5080,7 @@ class Context(object):
+Normal
+Infinity
- >>> c = Context(ExtendedContext)
+ >>> c = ExtendedContext.copy()
>>> c.Emin = -999
>>> c.Emax = 999
>>> c.number_class(Decimal('Infinity'))
@@ -5916,6 +6032,12 @@ def _convert_for_comparison(self, other, equality_op=False):
if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
other = other.real
if isinstance(other, float):
+ context = getcontext()
+ if equality_op:
+ context.flags[FloatOperation] = 1
+ else:
+ context._raise_error(FloatOperation,
+ "strict semantics for mixing floats and Decimals are enabled")
return self, Decimal.from_float(other)
return NotImplemented, NotImplemented
@@ -5929,8 +6051,8 @@ DefaultContext = Context(
prec=28, rounding=ROUND_HALF_EVEN,
traps=[DivisionByZero, Overflow, InvalidOperation],
flags=[],
- Emax=999999999,
- Emin=-999999999,
+ Emax=999999,
+ Emin=-999999,
capitals=1,
clamp=0
)
@@ -6080,7 +6202,7 @@ def _parse_format_specifier(format_spec, _localeconv=None):
# if format type is 'g' or 'G' then a precision of 0 makes little
# sense; convert it to 1. Same if format type is unspecified.
if format_dict['precision'] == 0:
- if format_dict['type'] is None or format_dict['type'] in 'gG':
+ if format_dict['type'] is None or format_dict['type'] in 'gGn':
format_dict['precision'] = 1
# determine thousands separator, grouping, and decimal separator, and
@@ -6254,16 +6376,26 @@ _SignedInfinity = (_Infinity, _NegativeInfinity)
# Constants related to the hash implementation; hash(x) is based
# on the reduction of x modulo _PyHASH_MODULUS
-import sys
_PyHASH_MODULUS = sys.hash_info.modulus
# hash values to use for positive and negative infinities, and nans
_PyHASH_INF = sys.hash_info.inf
_PyHASH_NAN = sys.hash_info.nan
-del sys
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
+del sys
+try:
+ import _decimal
+except ImportError:
+ pass
+else:
+ s1 = set(dir())
+ s2 = set(dir(_decimal))
+ for name in s1 - s2:
+ del globals()[name]
+ del s1, s2, name
+ from _decimal import *
if __name__ == '__main__':
import doctest, decimal
diff --git a/Lib/test/support.py b/Lib/test/support.py
index c384222..0cdf791 100644
--- a/Lib/test/support.py
+++ b/Lib/test/support.py
@@ -1416,7 +1416,7 @@ def run_unittest(*classes):
#=======================================================================
# doctest driver.
-def run_doctest(module, verbosity=None):
+def run_doctest(module, verbosity=None, optionflags=0):
"""Run doctest on the given module. Return (#failures, #tests).
If optional argument verbosity is not specified (or is None), pass
@@ -1431,7 +1431,7 @@ def run_doctest(module, verbosity=None):
else:
verbosity = None
- f, t = doctest.testmod(module, verbose=verbosity)
+ f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags)
if f:
raise TestFailed("%d of %d doctests failed" % (f, t))
if verbose:
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 014e9c7..af31b38 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -16,7 +16,7 @@ test the pythonic behaviour according to PEP 327.
Cowlishaw's tests can be downloaded from:
- www2.hursley.ibm.com/decimal/dectest.zip
+ http://speleotrove.com/decimal/dectest.zip
This test module can be called from command line with one parameter (Arithmetic
or Behaviour) to test each part, or without parameter to test both parts. If
@@ -30,37 +30,74 @@ import operator
import warnings
import pickle, copy
import unittest
-from decimal import *
import numbers
+import locale
from test.support import (run_unittest, run_doctest, is_resource_enabled,
requires_IEEE_754)
-from test.support import check_warnings
+from test.support import check_warnings, import_fresh_module, TestFailed
import random
+import time
+import warnings
try:
import threading
except ImportError:
threading = None
-# Useful Test Constant
-Signals = tuple(getcontext().flags.keys())
+C = import_fresh_module('decimal', fresh=['_decimal'])
+P = import_fresh_module('decimal', blocked=['_decimal'])
+orig_sys_decimal = sys.modules['decimal']
+
+# fractions module must import the correct decimal module.
+cfractions = import_fresh_module('fractions', fresh=['fractions'])
+sys.modules['decimal'] = P
+pfractions = import_fresh_module('fractions', fresh=['fractions'])
+sys.modules['decimal'] = C
+fractions = {C:cfractions, P:pfractions}
+sys.modules['decimal'] = orig_sys_decimal
+
+
+# Useful Test Constant
+Signals = {
+ C: tuple(C.getcontext().flags.keys()) if C else None,
+ P: tuple(P.getcontext().flags.keys())
+}
# Signals ordered with respect to precedence: when an operation
# produces multiple signals, signals occurring later in the list
# should be handled before those occurring earlier in the list.
-OrderedSignals = (Clamped, Rounded, Inexact, Subnormal,
- Underflow, Overflow, DivisionByZero, InvalidOperation)
+OrderedSignals = {
+ C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow,
+ C.Overflow, C.DivisionByZero, C.InvalidOperation,
+ C.FloatOperation] if C else None,
+ P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow,
+ P.Overflow, P.DivisionByZero, P.InvalidOperation,
+ P.FloatOperation]
+}
+def assert_signals(cls, context, attr, expected):
+ d = getattr(context, attr)
+ cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d))
+
+RoundingModes = {
+ C: (C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR,
+ C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN,
+ C.ROUND_05UP) if C else None,
+ P: (P.ROUND_UP, P.ROUND_DOWN, P.ROUND_CEILING, P.ROUND_FLOOR,
+ P.ROUND_HALF_UP, P.ROUND_HALF_DOWN, P.ROUND_HALF_EVEN,
+ P.ROUND_05UP)
+}
# Tests are built around these assumed context defaults.
# test_main() restores the original context.
-def init():
- global ORIGINAL_CONTEXT
- ORIGINAL_CONTEXT = getcontext().copy()
- DefaultTestContext = Context(
- prec = 9,
- rounding = ROUND_HALF_EVEN,
- traps = dict.fromkeys(Signals, 0)
- )
- setcontext(DefaultTestContext)
+ORIGINAL_CONTEXT = {
+ C: C.getcontext().copy() if C else None,
+ P: P.getcontext().copy()
+}
+def init(m):
+ if not m: return
+ DefaultTestContext = m.Context(
+ prec=9, rounding=m.ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0)
+ )
+ m.setcontext(DefaultTestContext)
TESTDATADIR = 'decimaltestdata'
if __name__ == '__main__':
@@ -72,149 +109,175 @@ directory = testdir + os.sep + TESTDATADIR + os.sep
skip_expected = not os.path.isdir(directory)
-# list of individual .decTest test ids that correspond to tests that
-# we're skipping for one reason or another.
-skipped_test_ids = set([
- # Skip implementation-specific scaleb tests.
- 'scbx164',
- 'scbx165',
-
- # For some operations (currently exp, ln, log10, power), the decNumber
- # reference implementation imposes additional restrictions on the context
- # and operands. These restrictions are not part of the specification;
- # however, the effect of these restrictions does show up in some of the
- # testcases. We skip testcases that violate these restrictions, since
- # Decimal behaves differently from decNumber for these testcases so these
- # testcases would otherwise fail.
- 'expx901',
- 'expx902',
- 'expx903',
- 'expx905',
- 'lnx901',
- 'lnx902',
- 'lnx903',
- 'lnx905',
- 'logx901',
- 'logx902',
- 'logx903',
- 'logx905',
- 'powx1183',
- 'powx1184',
- 'powx4001',
- 'powx4002',
- 'powx4003',
- 'powx4005',
- 'powx4008',
- 'powx4010',
- 'powx4012',
- 'powx4014',
- ])
-
# Make sure it actually raises errors when not expected and caught in flags
# Slower, since it runs some things several times.
EXTENDEDERRORTEST = False
-#Map the test cases' error names to the actual errors
-ErrorNames = {'clamped' : Clamped,
- 'conversion_syntax' : InvalidOperation,
- 'division_by_zero' : DivisionByZero,
- 'division_impossible' : InvalidOperation,
- 'division_undefined' : InvalidOperation,
- 'inexact' : Inexact,
- 'invalid_context' : InvalidOperation,
- 'invalid_operation' : InvalidOperation,
- 'overflow' : Overflow,
- 'rounded' : Rounded,
- 'subnormal' : Subnormal,
- 'underflow' : Underflow}
-
-
-def Nonfunction(*args):
- """Doesn't do anything."""
- return None
-
-RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
- 'down' : ROUND_DOWN,
- 'floor' : ROUND_FLOOR,
- 'half_down' : ROUND_HALF_DOWN,
- 'half_even' : ROUND_HALF_EVEN,
- 'half_up' : ROUND_HALF_UP,
- 'up' : ROUND_UP,
- '05up' : ROUND_05UP}
-
-# Name adapter to be able to change the Decimal and Context
-# interface without changing the test files from Cowlishaw
-nameAdapter = {'and':'logical_and',
- 'apply':'_apply',
- 'class':'number_class',
- 'comparesig':'compare_signal',
- 'comparetotal':'compare_total',
- 'comparetotmag':'compare_total_mag',
- 'copy':'copy_decimal',
- 'copyabs':'copy_abs',
- 'copynegate':'copy_negate',
- 'copysign':'copy_sign',
- 'divideint':'divide_int',
- 'invert':'logical_invert',
- 'iscanonical':'is_canonical',
- 'isfinite':'is_finite',
- 'isinfinite':'is_infinite',
- 'isnan':'is_nan',
- 'isnormal':'is_normal',
- 'isqnan':'is_qnan',
- 'issigned':'is_signed',
- 'issnan':'is_snan',
- 'issubnormal':'is_subnormal',
- 'iszero':'is_zero',
- 'maxmag':'max_mag',
- 'minmag':'min_mag',
- 'nextminus':'next_minus',
- 'nextplus':'next_plus',
- 'nexttoward':'next_toward',
- 'or':'logical_or',
- 'reduce':'normalize',
- 'remaindernear':'remainder_near',
- 'samequantum':'same_quantum',
- 'squareroot':'sqrt',
- 'toeng':'to_eng_string',
- 'tointegral':'to_integral_value',
- 'tointegralx':'to_integral_exact',
- 'tosci':'to_sci_string',
- 'xor':'logical_xor',
- }
-
-# The following functions return True/False rather than a Decimal instance
-
-LOGICAL_FUNCTIONS = (
- 'is_canonical',
- 'is_finite',
- 'is_infinite',
- 'is_nan',
- 'is_normal',
- 'is_qnan',
- 'is_signed',
- 'is_snan',
- 'is_subnormal',
- 'is_zero',
- 'same_quantum',
- )
+# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY).
+EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False
+requires_extra_functionality = unittest.skipUnless(
+ EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY")
+skip_if_extra_functionality = unittest.skipIf(
+ EXTRA_FUNCTIONALITY, "test requires regular build")
-class DecimalTest(unittest.TestCase):
- """Class which tests the Decimal class against the test cases.
- Changed for unittest.
- """
+class IBMTestCases(unittest.TestCase):
+ """Class which tests the Decimal class against the IBM test cases."""
+
def setUp(self):
- self.context = Context()
+ self.context = self.decimal.Context()
+ self.readcontext = self.decimal.Context()
self.ignore_list = ['#']
- # Basically, a # means return NaN InvalidOperation.
- # Different from a sNaN in trim
+ # List of individual .decTest test ids that correspond to tests that
+ # we're skipping for one reason or another.
+ self.skipped_test_ids = set([
+ # Skip implementation-specific scaleb tests.
+ 'scbx164',
+ 'scbx165',
+
+ # For some operations (currently exp, ln, log10, power), the decNumber
+ # reference implementation imposes additional restrictions on the context
+ # and operands. These restrictions are not part of the specification;
+ # however, the effect of these restrictions does show up in some of the
+ # testcases. We skip testcases that violate these restrictions, since
+ # Decimal behaves differently from decNumber for these testcases so these
+ # testcases would otherwise fail.
+ 'expx901',
+ 'expx902',
+ 'expx903',
+ 'expx905',
+ 'lnx901',
+ 'lnx902',
+ 'lnx903',
+ 'lnx905',
+ 'logx901',
+ 'logx902',
+ 'logx903',
+ 'logx905',
+ 'powx1183',
+ 'powx1184',
+ 'powx4001',
+ 'powx4002',
+ 'powx4003',
+ 'powx4005',
+ 'powx4008',
+ 'powx4010',
+ 'powx4012',
+ 'powx4014',
+ ])
+
+ if self.decimal == C:
+ # status has additional Subnormal, Underflow
+ self.skipped_test_ids.add('pwsx803')
+ self.skipped_test_ids.add('pwsx805')
+ # Correct rounding (skipped for decNumber, too)
+ self.skipped_test_ids.add('powx4302')
+ self.skipped_test_ids.add('powx4303')
+ self.skipped_test_ids.add('powx4342')
+ self.skipped_test_ids.add('powx4343')
+ # http://bugs.python.org/issue7049
+ self.skipped_test_ids.add('pwmx325')
+ self.skipped_test_ids.add('pwmx326')
+
+ # Map test directives to setter functions.
self.ChangeDict = {'precision' : self.change_precision,
- 'rounding' : self.change_rounding_method,
- 'maxexponent' : self.change_max_exponent,
- 'minexponent' : self.change_min_exponent,
- 'clamp' : self.change_clamp}
+ 'rounding' : self.change_rounding_method,
+ 'maxexponent' : self.change_max_exponent,
+ 'minexponent' : self.change_min_exponent,
+ 'clamp' : self.change_clamp}
+
+ # Name adapter to be able to change the Decimal and Context
+ # interface without changing the test files from Cowlishaw.
+ self.NameAdapter = {'and':'logical_and',
+ 'apply':'_apply',
+ 'class':'number_class',
+ 'comparesig':'compare_signal',
+ 'comparetotal':'compare_total',
+ 'comparetotmag':'compare_total_mag',
+ 'copy':'copy_decimal',
+ 'copyabs':'copy_abs',
+ 'copynegate':'copy_negate',
+ 'copysign':'copy_sign',
+ 'divideint':'divide_int',
+ 'invert':'logical_invert',
+ 'iscanonical':'is_canonical',
+ 'isfinite':'is_finite',
+ 'isinfinite':'is_infinite',
+ 'isnan':'is_nan',
+ 'isnormal':'is_normal',
+ 'isqnan':'is_qnan',
+ 'issigned':'is_signed',
+ 'issnan':'is_snan',
+ 'issubnormal':'is_subnormal',
+ 'iszero':'is_zero',
+ 'maxmag':'max_mag',
+ 'minmag':'min_mag',
+ 'nextminus':'next_minus',
+ 'nextplus':'next_plus',
+ 'nexttoward':'next_toward',
+ 'or':'logical_or',
+ 'reduce':'normalize',
+ 'remaindernear':'remainder_near',
+ 'samequantum':'same_quantum',
+ 'squareroot':'sqrt',
+ 'toeng':'to_eng_string',
+ 'tointegral':'to_integral_value',
+ 'tointegralx':'to_integral_exact',
+ 'tosci':'to_sci_string',
+ 'xor':'logical_xor'}
+
+ # Map test-case names to roundings.
+ self.RoundingDict = {'ceiling' : self.decimal.ROUND_CEILING,
+ 'down' : self.decimal.ROUND_DOWN,
+ 'floor' : self.decimal.ROUND_FLOOR,
+ 'half_down' : self.decimal.ROUND_HALF_DOWN,
+ 'half_even' : self.decimal.ROUND_HALF_EVEN,
+ 'half_up' : self.decimal.ROUND_HALF_UP,
+ 'up' : self.decimal.ROUND_UP,
+ '05up' : self.decimal.ROUND_05UP}
+
+ # Map the test cases' error names to the actual errors.
+ self.ErrorNames = {'clamped' : self.decimal.Clamped,
+ 'conversion_syntax' : self.decimal.InvalidOperation,
+ 'division_by_zero' : self.decimal.DivisionByZero,
+ 'division_impossible' : self.decimal.InvalidOperation,
+ 'division_undefined' : self.decimal.InvalidOperation,
+ 'inexact' : self.decimal.Inexact,
+ 'invalid_context' : self.decimal.InvalidOperation,
+ 'invalid_operation' : self.decimal.InvalidOperation,
+ 'overflow' : self.decimal.Overflow,
+ 'rounded' : self.decimal.Rounded,
+ 'subnormal' : self.decimal.Subnormal,
+ 'underflow' : self.decimal.Underflow}
+
+ # The following functions return True/False rather than a
+ # Decimal instance.
+ self.LogicalFunctions = ('is_canonical',
+ 'is_finite',
+ 'is_infinite',
+ 'is_nan',
+ 'is_normal',
+ 'is_qnan',
+ 'is_signed',
+ 'is_snan',
+ 'is_subnormal',
+ 'is_zero',
+ 'same_quantum')
+
+ def read_unlimited(self, v, context):
+ """Work around the limitations of the 32-bit _decimal version. The
+ guaranteed maximum values for prec, Emax etc. are 425000000,
+ but higher values usually work, except for rare corner cases.
+ In particular, all of the IBM tests pass with maximum values
+ of 1070000000."""
+ if self.decimal == C and self.decimal.MAX_EMAX == 425000000:
+ self.readcontext._unsafe_setprec(1070000000)
+ self.readcontext._unsafe_setemax(1070000000)
+ self.readcontext._unsafe_setemin(-1070000000)
+ return self.readcontext.create_decimal(v)
+ else:
+ return self.decimal.Decimal(v, context)
def eval_file(self, file):
global skip_expected
@@ -227,7 +290,7 @@ class DecimalTest(unittest.TestCase):
#print line
try:
t = self.eval_line(line)
- except DecimalException as exception:
+ except self.decimal.DecimalException as exception:
#Exception raised where there shouldn't have been one.
self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line)
@@ -254,23 +317,23 @@ class DecimalTest(unittest.TestCase):
def eval_directive(self, s):
funct, value = (x.strip().lower() for x in s.split(':'))
if funct == 'rounding':
- value = RoundingDict[value]
+ value = self.RoundingDict[value]
else:
try:
value = int(value)
except ValueError:
pass
- funct = self.ChangeDict.get(funct, Nonfunction)
+ funct = self.ChangeDict.get(funct, (lambda *args: None))
funct(value)
def eval_equation(self, s):
- #global DEFAULT_PRECISION
- #print DEFAULT_PRECISION
if not TEST_ALL and random.random() < 0.90:
return
+ self.context.clear_flags()
+
try:
Sides = s.split('->')
L = Sides[0].strip().split()
@@ -283,26 +346,26 @@ class DecimalTest(unittest.TestCase):
ans = L[0]
exceptions = L[1:]
except (TypeError, AttributeError, IndexError):
- raise InvalidOperation
+ raise self.decimal.InvalidOperation
def FixQuotes(val):
val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote')
val = val.replace("'", '').replace('"', '')
val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"')
return val
- if id in skipped_test_ids:
+ if id in self.skipped_test_ids:
return
- fname = nameAdapter.get(funct, funct)
+ fname = self.NameAdapter.get(funct, funct)
if fname == 'rescale':
return
funct = getattr(self.context, fname)
vals = []
conglomerate = ''
quote = 0
- theirexceptions = [ErrorNames[x.lower()] for x in exceptions]
+ theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions]
- for exception in Signals:
+ for exception in Signals[self.decimal]:
self.context.traps[exception] = 1 #Catch these bugs...
for exception in theirexceptions:
self.context.traps[exception] = 0
@@ -324,7 +387,7 @@ class DecimalTest(unittest.TestCase):
funct(self.context.create_decimal(v))
except error:
pass
- except Signals as e:
+ except Signals[self.decimal] as e:
self.fail("Raised %s in %s when %s disabled" % \
(e, s, error))
else:
@@ -332,7 +395,7 @@ class DecimalTest(unittest.TestCase):
self.context.traps[error] = 0
v = self.context.create_decimal(v)
else:
- v = Decimal(v, self.context)
+ v = self.read_unlimited(v, self.context)
vals.append(v)
ans = FixQuotes(ans)
@@ -344,7 +407,7 @@ class DecimalTest(unittest.TestCase):
funct(*vals)
except error:
pass
- except Signals as e:
+ except Signals[self.decimal] as e:
self.fail("Raised %s in %s when %s disabled" % \
(e, s, error))
else:
@@ -352,14 +415,14 @@ class DecimalTest(unittest.TestCase):
self.context.traps[error] = 0
# as above, but add traps cumulatively, to check precedence
- ordered_errors = [e for e in OrderedSignals if e in theirexceptions]
+ ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions]
for error in ordered_errors:
self.context.traps[error] = 1
try:
funct(*vals)
except error:
pass
- except Signals as e:
+ except Signals[self.decimal] as e:
self.fail("Raised %s in %s; expected %s" %
(type(e), s, error))
else:
@@ -373,54 +436,69 @@ class DecimalTest(unittest.TestCase):
print("--", self.context)
try:
result = str(funct(*vals))
- if fname in LOGICAL_FUNCTIONS:
+ if fname in self.LogicalFunctions:
result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
- except Signals as error:
+ except Signals[self.decimal] as error:
self.fail("Raised %s in %s" % (error, s))
except: #Catch any error long enough to state the test case.
print("ERROR:", s)
raise
myexceptions = self.getexceptions()
- self.context.clear_flags()
myexceptions.sort(key=repr)
theirexceptions.sort(key=repr)
self.assertEqual(result, ans,
'Incorrect answer for ' + s + ' -- got ' + result)
+
self.assertEqual(myexceptions, theirexceptions,
'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions))
return
def getexceptions(self):
- return [e for e in Signals if self.context.flags[e]]
+ return [e for e in Signals[self.decimal] if self.context.flags[e]]
def change_precision(self, prec):
- self.context.prec = prec
+ if self.decimal == C and self.decimal.MAX_PREC == 425000000:
+ self.context._unsafe_setprec(prec)
+ else:
+ self.context.prec = prec
def change_rounding_method(self, rounding):
self.context.rounding = rounding
def change_min_exponent(self, exp):
- self.context.Emin = exp
+ if self.decimal == C and self.decimal.MAX_PREC == 425000000:
+ self.context._unsafe_setemin(exp)
+ else:
+ self.context.Emin = exp
def change_max_exponent(self, exp):
- self.context.Emax = exp
+ if self.decimal == C and self.decimal.MAX_PREC == 425000000:
+ self.context._unsafe_setemax(exp)
+ else:
+ self.context.Emax = exp
def change_clamp(self, clamp):
self.context.clamp = clamp
-
+class CIBMTestCases(IBMTestCases):
+ decimal = C
+class PyIBMTestCases(IBMTestCases):
+ decimal = P
# The following classes test the behaviour of Decimal according to PEP 327
-class DecimalExplicitConstructionTest(unittest.TestCase):
+class ExplicitConstructionTest(unittest.TestCase):
'''Unit tests for Explicit Construction cases of Decimal.'''
def test_explicit_empty(self):
+ Decimal = self.decimal.Decimal
self.assertEqual(Decimal(), Decimal("0"))
def test_explicit_from_None(self):
+ Decimal = self.decimal.Decimal
self.assertRaises(TypeError, Decimal, None)
def test_explicit_from_int(self):
+ Decimal = self.decimal.Decimal
#positive
d = Decimal(45)
@@ -438,7 +516,18 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
d = Decimal(0)
self.assertEqual(str(d), '0')
+ # single word longs
+ for n in range(0, 32):
+ for sign in (-1, 1):
+ for x in range(-5, 5):
+ i = sign * (2**n + x)
+ d = Decimal(i)
+ self.assertEqual(str(d), str(i))
+
def test_explicit_from_string(self):
+ Decimal = self.decimal.Decimal
+ InvalidOperation = self.decimal.InvalidOperation
+ localcontext = self.decimal.localcontext
#empty
self.assertEqual(str(Decimal('')), 'NaN')
@@ -458,8 +547,35 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
#leading and trailing whitespace permitted
self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4')
self.assertEqual(str(Decimal(' -7.89')), '-7.89')
+ self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679')
+
+ # unicode whitespace
+ for lead in ["", ' ', '\u00a0', '\u205f']:
+ for trail in ["", ' ', '\u00a0', '\u205f']:
+ self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)),
+ '9.311E+28')
+
+ with localcontext() as c:
+ c.traps[InvalidOperation] = True
+ # Invalid string
+ self.assertRaises(InvalidOperation, Decimal, "xyz")
+ # Two arguments max
+ self.assertRaises(TypeError, Decimal, "1234", "x", "y")
+
+ # space within the numeric part
+ self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03")
+ self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0")
+
+ # unicode whitespace
+ self.assertRaises(InvalidOperation, Decimal, "\u00a0")
+ self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0")
+
+ # embedded NUL
+ self.assertRaises(InvalidOperation, Decimal, "12\u00003")
+
def test_explicit_from_tuples(self):
+ Decimal = self.decimal.Decimal
#zero
d = Decimal( (0, (0,), 0) )
@@ -477,6 +593,10 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
self.assertEqual(str(d), '-4.34913534E-17')
+ #inf
+ d = Decimal( (0, (), "F") )
+ self.assertEqual(str(d), 'Infinity')
+
#wrong number of items
self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) )
@@ -491,45 +611,63 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') )
#bad coefficients
+ self.assertRaises(ValueError, Decimal, (1, "xyz", 2) )
self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
+ def test_explicit_from_list(self):
+ Decimal = self.decimal.Decimal
+
+ d = Decimal([0, [0], 0])
+ self.assertEqual(str(d), '0')
+
+ d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25])
+ self.assertEqual(str(d), '-4.34913534E-17')
+
+ d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25])
+ self.assertEqual(str(d), '-4.34913534E-17')
+
+ d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25))
+ self.assertEqual(str(d), '-4.34913534E-17')
+
def test_explicit_from_bool(self):
+ Decimal = self.decimal.Decimal
+
self.assertIs(bool(Decimal(0)), False)
self.assertIs(bool(Decimal(1)), True)
self.assertEqual(Decimal(False), Decimal(0))
self.assertEqual(Decimal(True), Decimal(1))
def test_explicit_from_Decimal(self):
+ Decimal = self.decimal.Decimal
#positive
d = Decimal(45)
e = Decimal(d)
self.assertEqual(str(e), '45')
- self.assertNotEqual(id(d), id(e))
#very large positive
d = Decimal(500000123)
e = Decimal(d)
self.assertEqual(str(e), '500000123')
- self.assertNotEqual(id(d), id(e))
#negative
d = Decimal(-45)
e = Decimal(d)
self.assertEqual(str(e), '-45')
- self.assertNotEqual(id(d), id(e))
#zero
d = Decimal(0)
e = Decimal(d)
self.assertEqual(str(e), '0')
- self.assertNotEqual(id(d), id(e))
@requires_IEEE_754
def test_explicit_from_float(self):
+
+ Decimal = self.decimal.Decimal
+
r = Decimal(0.1)
self.assertEqual(type(r), Decimal)
self.assertEqual(str(r),
@@ -550,8 +688,11 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
self.assertEqual(x, float(Decimal(x))) # roundtrip
def test_explicit_context_create_decimal(self):
+ Decimal = self.decimal.Decimal
+ InvalidOperation = self.decimal.InvalidOperation
+ Rounded = self.decimal.Rounded
- nc = copy.copy(getcontext())
+ nc = copy.copy(self.decimal.getcontext())
nc.prec = 3
# empty
@@ -592,7 +733,73 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
d = nc.create_decimal(prevdec)
self.assertEqual(str(d), '5.00E+8')
+ # more integers
+ nc.prec = 28
+ nc.traps[InvalidOperation] = True
+
+ for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0,
+ 2**31-1, 2**31, 2**63-1, 2**63]:
+ d = nc.create_decimal(v)
+ self.assertTrue(isinstance(d, Decimal))
+ self.assertEqual(int(d), v)
+
+ nc.prec = 3
+ nc.traps[Rounded] = True
+ self.assertRaises(Rounded, nc.create_decimal, 1234)
+
+ # from string
+ nc.prec = 28
+ self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17')
+ self.assertEqual(str(nc.create_decimal('45')), '45')
+ self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity')
+ self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123')
+
+ # invalid arguments
+ self.assertRaises(InvalidOperation, nc.create_decimal, "xyz")
+ self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25))
+ self.assertRaises(TypeError, nc.create_decimal, "1234", "5678")
+
+ # too many NaN payload digits
+ nc.prec = 3
+ self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345')
+ self.assertRaises(InvalidOperation, nc.create_decimal,
+ Decimal('NaN12345'))
+
+ nc.traps[InvalidOperation] = False
+ self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN')
+ self.assertTrue(nc.flags[InvalidOperation])
+
+ nc.flags[InvalidOperation] = False
+ self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN')
+ self.assertTrue(nc.flags[InvalidOperation])
+
+ def test_explicit_context_create_from_float(self):
+
+ Decimal = self.decimal.Decimal
+
+ nc = self.decimal.Context()
+ r = nc.create_decimal(0.1)
+ self.assertEqual(type(r), Decimal)
+ self.assertEqual(str(r), '0.1000000000000000055511151231')
+ self.assertTrue(nc.create_decimal(float('nan')).is_qnan())
+ self.assertTrue(nc.create_decimal(float('inf')).is_infinite())
+ self.assertTrue(nc.create_decimal(float('-inf')).is_infinite())
+ self.assertEqual(str(nc.create_decimal(float('nan'))),
+ str(nc.create_decimal('NaN')))
+ self.assertEqual(str(nc.create_decimal(float('inf'))),
+ str(nc.create_decimal('Infinity')))
+ self.assertEqual(str(nc.create_decimal(float('-inf'))),
+ str(nc.create_decimal('-Infinity')))
+ self.assertEqual(str(nc.create_decimal(float('-0.0'))),
+ str(nc.create_decimal('-0')))
+ nc.prec = 100
+ for i in range(200):
+ x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
+ self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip
+
def test_unicode_digits(self):
+ Decimal = self.decimal.Decimal
+
test_values = {
'\uff11': '1',
'\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372',
@@ -601,29 +808,41 @@ class DecimalExplicitConstructionTest(unittest.TestCase):
for input, expected in test_values.items():
self.assertEqual(str(Decimal(input)), expected)
+class CExplicitConstructionTest(ExplicitConstructionTest):
+ decimal = C
+class PyExplicitConstructionTest(ExplicitConstructionTest):
+ decimal = P
-class DecimalImplicitConstructionTest(unittest.TestCase):
+class ImplicitConstructionTest(unittest.TestCase):
'''Unit tests for Implicit Construction cases of Decimal.'''
def test_implicit_from_None(self):
- self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals())
+ Decimal = self.decimal.Decimal
+ self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals())
def test_implicit_from_int(self):
+ Decimal = self.decimal.Decimal
+
#normal
self.assertEqual(str(Decimal(5) + 45), '50')
#exceeding precision
self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000))
def test_implicit_from_string(self):
- self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals())
+ Decimal = self.decimal.Decimal
+ self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals())
def test_implicit_from_float(self):
- self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals())
+ Decimal = self.decimal.Decimal
+ self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals())
def test_implicit_from_Decimal(self):
+ Decimal = self.decimal.Decimal
self.assertEqual(Decimal(5) + Decimal(45), Decimal(50))
def test_rop(self):
+ Decimal = self.decimal.Decimal
+
# Allow other classes to be trained to interact with Decimals
class E:
def __divmod__(self, other):
@@ -671,10 +890,16 @@ class DecimalImplicitConstructionTest(unittest.TestCase):
self.assertEqual(eval('Decimal(10)' + sym + 'E()'),
'10' + rop + 'str')
+class CImplicitConstructionTest(ImplicitConstructionTest):
+ decimal = C
+class PyImplicitConstructionTest(ImplicitConstructionTest):
+ decimal = P
-class DecimalFormatTest(unittest.TestCase):
+class FormatTest(unittest.TestCase):
'''Unit tests for the format function.'''
def test_formatting(self):
+ Decimal = self.decimal.Decimal
+
# triples giving a format, a Decimal, and the expected result
test_values = [
('e', '0E-15', '0e-15'),
@@ -730,6 +955,7 @@ class DecimalFormatTest(unittest.TestCase):
('g', '0E-7', '0e-7'),
('g', '-0E2', '-0e+2'),
('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig
+ ('.0n', '3.14159265', '3'), # same for 'n'
('.1g', '3.14159265', '3'),
('.2g', '3.14159265', '3.1'),
('.5g', '3.14159265', '3.1416'),
@@ -814,56 +1040,60 @@ class DecimalFormatTest(unittest.TestCase):
# issue 6850
('a=-7.0', '0.12345', 'aaaa0.1'),
-
- # Issue 7094: Alternate formatting (specified by #)
- ('.0e', '1.0', '1e+0'),
- ('#.0e', '1.0', '1.e+0'),
- ('.0f', '1.0', '1'),
- ('#.0f', '1.0', '1.'),
- ('g', '1.1', '1.1'),
- ('#g', '1.1', '1.1'),
- ('.0g', '1', '1'),
- ('#.0g', '1', '1.'),
- ('.0%', '1.0', '100%'),
- ('#.0%', '1.0', '100.%'),
]
for fmt, d, result in test_values:
self.assertEqual(format(Decimal(d), fmt), result)
+ # bytes format argument
+ self.assertRaises(TypeError, Decimal(1).__format__, b'-020')
+
def test_n_format(self):
+ Decimal = self.decimal.Decimal
+
try:
from locale import CHAR_MAX
except ImportError:
return
+ def make_grouping(lst):
+ return ''.join([chr(x) for x in lst]) if self.decimal == C else lst
+
+ def get_fmt(x, override=None, fmt='n'):
+ if self.decimal == C:
+ return Decimal(x).__format__(fmt, override)
+ else:
+ return Decimal(x).__format__(fmt, _localeconv=override)
+
# Set up some localeconv-like dictionaries
en_US = {
'decimal_point' : '.',
- 'grouping' : [3, 3, 0],
- 'thousands_sep': ','
+ 'grouping' : make_grouping([3, 3, 0]),
+ 'thousands_sep' : ','
}
fr_FR = {
'decimal_point' : ',',
- 'grouping' : [CHAR_MAX],
+ 'grouping' : make_grouping([CHAR_MAX]),
'thousands_sep' : ''
}
ru_RU = {
'decimal_point' : ',',
- 'grouping' : [3, 3, 0],
+ 'grouping': make_grouping([3, 3, 0]),
'thousands_sep' : ' '
}
crazy = {
'decimal_point' : '&',
- 'grouping' : [1, 4, 2, CHAR_MAX],
+ 'grouping': make_grouping([1, 4, 2, CHAR_MAX]),
'thousands_sep' : '-'
}
-
- def get_fmt(x, locale, fmt='n'):
- return Decimal.__format__(Decimal(x), fmt, _localeconv=locale)
+ dotsep_wide = {
+ 'decimal_point' : b'\xc2\xbf'.decode('utf-8'),
+ 'grouping': make_grouping([3, 3, 0]),
+ 'thousands_sep' : b'\xc2\xb4'.decode('utf-8')
+ }
self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7')
self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7')
@@ -902,11 +1132,33 @@ class DecimalFormatTest(unittest.TestCase):
self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6')
self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6')
+ # wide char separator and decimal point
+ self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'),
+ '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5')
-class DecimalArithmeticOperatorsTest(unittest.TestCase):
+ def test_wide_char_separator_decimal_point(self):
+ # locale with wide char separator and decimal point
+ Decimal = self.decimal.Decimal
+
+ try:
+ locale.setlocale(locale.LC_ALL, 'ps_AF')
+ except locale.Error:
+ return
+
+ self.assertEqual(format(Decimal('100000000.123'), 'n'),
+ '100\u066c000\u066c000\u066b123')
+ locale.resetlocale()
+
+class CFormatTest(FormatTest):
+ decimal = C
+class PyFormatTest(FormatTest):
+ decimal = P
+
+class ArithmeticOperatorsTest(unittest.TestCase):
'''Unit tests for all arithmetic operators, binary and unary.'''
def test_addition(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('-11.1')
d2 = Decimal('22.2')
@@ -934,6 +1186,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('16.1'))
def test_subtraction(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('-11.1')
d2 = Decimal('22.2')
@@ -961,6 +1214,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('-38.3'))
def test_multiplication(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('-5')
d2 = Decimal('3')
@@ -988,6 +1242,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('-75'))
def test_division(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('-5')
d2 = Decimal('2')
@@ -1015,6 +1270,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('-0.625'))
def test_floor_division(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('5')
d2 = Decimal('2')
@@ -1042,6 +1298,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('1'))
def test_powering(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('5')
d2 = Decimal('2')
@@ -1069,6 +1326,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('390625'))
def test_module(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('5')
d2 = Decimal('2')
@@ -1096,6 +1354,7 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(d1, Decimal('1'))
def test_floor_div_module(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('5')
d2 = Decimal('2')
@@ -1122,6 +1381,8 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertEqual(type(q), type(d1))
def test_unary_operators(self):
+ Decimal = self.decimal.Decimal
+
self.assertEqual(+Decimal(45), Decimal(+45)) # +
self.assertEqual(-Decimal(45), Decimal(-45)) # -
self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
@@ -1134,6 +1395,9 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
# equality comparisons (==, !=) involving only quiet nans
# don't signal, but return False or True respectively.
+ Decimal = self.decimal.Decimal
+ InvalidOperation = self.decimal.InvalidOperation
+ localcontext = self.decimal.localcontext
n = Decimal('NaN')
s = Decimal('sNaN')
@@ -1179,53 +1443,124 @@ class DecimalArithmeticOperatorsTest(unittest.TestCase):
self.assertRaises(InvalidOperation, op, x, y)
def test_copy_sign(self):
- d = Decimal(1).copy_sign(Decimal(-2))
+ Decimal = self.decimal.Decimal
+ d = Decimal(1).copy_sign(Decimal(-2))
self.assertEqual(Decimal(1).copy_sign(-2), d)
self.assertRaises(TypeError, Decimal(1).copy_sign, '-2')
+class CArithmeticOperatorsTest(ArithmeticOperatorsTest):
+ decimal = C
+class PyArithmeticOperatorsTest(ArithmeticOperatorsTest):
+ decimal = P
+
# The following are two functions used to test threading in the next class
def thfunc1(cls):
+ Decimal = cls.decimal.Decimal
+ InvalidOperation = cls.decimal.InvalidOperation
+ DivisionByZero = cls.decimal.DivisionByZero
+ Overflow = cls.decimal.Overflow
+ Underflow = cls.decimal.Underflow
+ Inexact = cls.decimal.Inexact
+ getcontext = cls.decimal.getcontext
+ localcontext = cls.decimal.localcontext
+
d1 = Decimal(1)
d3 = Decimal(3)
test1 = d1/d3
- cls.synchro.wait()
- test2 = d1/d3
+
cls.finish1.set()
+ cls.synchro.wait()
- cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
- cls.assertEqual(test2, Decimal('0.3333333333333333333333333333'))
+ test2 = d1/d3
+ with localcontext() as c2:
+ cls.assertTrue(c2.flags[Inexact])
+ cls.assertRaises(DivisionByZero, c2.divide, d1, 0)
+ cls.assertTrue(c2.flags[DivisionByZero])
+ with localcontext() as c3:
+ cls.assertTrue(c3.flags[Inexact])
+ cls.assertTrue(c3.flags[DivisionByZero])
+ cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN'))
+ cls.assertTrue(c3.flags[InvalidOperation])
+ del c3
+ cls.assertFalse(c2.flags[InvalidOperation])
+ del c2
+
+ cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
+ cls.assertEqual(test2, Decimal('0.333333333333333333333333'))
+
+ c1 = getcontext()
+ cls.assertTrue(c1.flags[Inexact])
+ for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
+ cls.assertFalse(c1.flags[sig])
return
def thfunc2(cls):
+ Decimal = cls.decimal.Decimal
+ InvalidOperation = cls.decimal.InvalidOperation
+ DivisionByZero = cls.decimal.DivisionByZero
+ Overflow = cls.decimal.Overflow
+ Underflow = cls.decimal.Underflow
+ Inexact = cls.decimal.Inexact
+ getcontext = cls.decimal.getcontext
+ localcontext = cls.decimal.localcontext
+
d1 = Decimal(1)
d3 = Decimal(3)
test1 = d1/d3
+
thiscontext = getcontext()
thiscontext.prec = 18
test2 = d1/d3
+
+ with localcontext() as c2:
+ cls.assertTrue(c2.flags[Inexact])
+ cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999)
+ cls.assertTrue(c2.flags[Overflow])
+ with localcontext(thiscontext) as c3:
+ cls.assertTrue(c3.flags[Inexact])
+ cls.assertFalse(c3.flags[Overflow])
+ c3.traps[Underflow] = True
+ cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999)
+ cls.assertTrue(c3.flags[Underflow])
+ del c3
+ cls.assertFalse(c2.flags[Underflow])
+ cls.assertFalse(c2.traps[Underflow])
+ del c2
+
cls.synchro.set()
cls.finish2.set()
- cls.assertEqual(test1, Decimal('0.3333333333333333333333333333'))
+ cls.assertEqual(test1, Decimal('0.333333333333333333333333'))
cls.assertEqual(test2, Decimal('0.333333333333333333'))
- return
-
-class DecimalUseOfContextTest(unittest.TestCase):
- '''Unit tests for Use of Context cases in Decimal.'''
+ cls.assertFalse(thiscontext.traps[Underflow])
+ cls.assertTrue(thiscontext.flags[Inexact])
+ for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
+ cls.assertFalse(thiscontext.flags[sig])
+ return
- try:
- import threading
- except ImportError:
- threading = None
+class ThreadingTest(unittest.TestCase):
+ '''Unit tests for thread local contexts in Decimal.'''
# Take care executing this test from IDLE, there's an issue in threading
# that hangs IDLE and I couldn't find it
def test_threading(self):
- #Test the "threading isolation" of a Context.
+ DefaultContext = self.decimal.DefaultContext
+
+ if self.decimal == C and not self.decimal.HAVE_THREADS:
+ self.skipTest("compiled without threading")
+ # Test the "threading isolation" of a Context. Also test changing
+ # the DefaultContext, which acts as a template for the thread-local
+ # contexts.
+ save_prec = DefaultContext.prec
+ save_emax = DefaultContext.Emax
+ save_emin = DefaultContext.Emin
+ DefaultContext.prec = 24
+ DefaultContext.Emax = 425000000
+ DefaultContext.Emin = -425000000
self.synchro = threading.Event()
self.finish1 = threading.Event()
@@ -1239,17 +1574,29 @@ class DecimalUseOfContextTest(unittest.TestCase):
self.finish1.wait()
self.finish2.wait()
- return
- if threading is None:
- del test_threading
+ for sig in Signals[self.decimal]:
+ self.assertFalse(DefaultContext.flags[sig])
+ DefaultContext.prec = save_prec
+ DefaultContext.Emax = save_emax
+ DefaultContext.Emin = save_emin
+ return
-class DecimalUsabilityTest(unittest.TestCase):
+@unittest.skipUnless(threading, 'threading required')
+class CThreadingTest(ThreadingTest):
+ decimal = C
+@unittest.skipUnless(threading, 'threading required')
+class PyThreadingTest(ThreadingTest):
+ decimal = P
+
+class UsabilityTest(unittest.TestCase):
'''Unit tests for Usability cases of Decimal.'''
def test_comparison_operators(self):
+ Decimal = self.decimal.Decimal
+
da = Decimal('23.42')
db = Decimal('23.42')
dc = Decimal('45')
@@ -1283,6 +1630,8 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertEqual(a, b)
def test_decimal_float_comparison(self):
+ Decimal = self.decimal.Decimal
+
da = Decimal('0.25')
db = Decimal('3.0')
self.assertLess(da, 3.0)
@@ -1299,7 +1648,71 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertEqual(3.0, db)
self.assertNotEqual(0.1, Decimal('0.1'))
+ def test_decimal_complex_comparison(self):
+ Decimal = self.decimal.Decimal
+
+ da = Decimal('0.25')
+ db = Decimal('3.0')
+ self.assertNotEqual(da, (1.5+0j))
+ self.assertNotEqual((1.5+0j), da)
+ self.assertEqual(da, (0.25+0j))
+ self.assertEqual((0.25+0j), da)
+ self.assertEqual((3.0+0j), db)
+ self.assertEqual(db, (3.0+0j))
+
+ self.assertNotEqual(db, (3.0+1j))
+ self.assertNotEqual((3.0+1j), db)
+
+ self.assertIs(db.__lt__(3.0+0j), NotImplemented)
+ self.assertIs(db.__le__(3.0+0j), NotImplemented)
+ self.assertIs(db.__gt__(3.0+0j), NotImplemented)
+ self.assertIs(db.__le__(3.0+0j), NotImplemented)
+
+ def test_decimal_fraction_comparison(self):
+ D = self.decimal.Decimal
+ F = fractions[self.decimal].Fraction
+ Context = self.decimal.Context
+ localcontext = self.decimal.localcontext
+ InvalidOperation = self.decimal.InvalidOperation
+
+
+ emax = C.MAX_EMAX if C else 999999999
+ emin = C.MIN_EMIN if C else -999999999
+ etiny = C.MIN_ETINY if C else -1999999997
+ c = Context(Emax=emax, Emin=emin)
+
+ with localcontext(c):
+ c.prec = emax
+ self.assertLess(D(0), F(1,9999999999999999999999999999999999999))
+ self.assertLess(F(-1,9999999999999999999999999999999999999), D(0))
+ self.assertLess(F(0,1), D("1e" + str(etiny)))
+ self.assertLess(D("-1e" + str(etiny)), F(0,1))
+ self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny)))
+ self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999))
+
+ self.assertEqual(D("0.1"), F(1,10))
+ self.assertEqual(F(1,10), D("0.1"))
+
+ c.prec = 300
+ self.assertNotEqual(D(1)/3, F(1,3))
+ self.assertNotEqual(F(1,3), D(1)/3)
+
+ self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax)))
+ self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999))
+
+ self.assertGreater(D('inf'), F(99999999999,123))
+ self.assertGreater(D('inf'), F(-99999999999,123))
+ self.assertLess(D('-inf'), F(99999999999,123))
+ self.assertLess(D('-inf'), F(-99999999999,123))
+
+ self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123))
+ self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan')))
+ self.assertNotEqual(D('nan'), F(-9,123))
+ self.assertNotEqual(F(-9,123), D('nan'))
+
def test_copy_and_deepcopy_methods(self):
+ Decimal = self.decimal.Decimal
+
d = Decimal('43.24')
c = copy.copy(d)
self.assertEqual(id(c), id(d))
@@ -1307,6 +1720,10 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertEqual(id(dc), id(d))
def test_hash_method(self):
+
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+
def hashit(d):
a = hash(d)
b = d.__hash__()
@@ -1367,24 +1784,27 @@ class DecimalUsabilityTest(unittest.TestCase):
d = Decimal(s)
self.assertEqual(hashit(f), hashit(d))
- # check that the value of the hash doesn't depend on the
- # current context (issue #1757)
- c = getcontext()
- old_precision = c.prec
- x = Decimal("123456789.1")
+ with localcontext() as c:
+ # check that the value of the hash doesn't depend on the
+ # current context (issue #1757)
+ x = Decimal("123456789.1")
+
+ c.prec = 6
+ h1 = hashit(x)
+ c.prec = 10
+ h2 = hashit(x)
+ c.prec = 16
+ h3 = hashit(x)
- c.prec = 6
- h1 = hashit(x)
- c.prec = 10
- h2 = hashit(x)
- c.prec = 16
- h3 = hashit(x)
+ self.assertEqual(h1, h2)
+ self.assertEqual(h1, h3)
- self.assertEqual(h1, h2)
- self.assertEqual(h1, h3)
- c.prec = old_precision
+ c.prec = 10000
+ x = 1100 ** 1248
+ self.assertEqual(hashit(Decimal(x)), hashit(x))
def test_min_and_max_methods(self):
+ Decimal = self.decimal.Decimal
d1 = Decimal('15.32')
d2 = Decimal('28.5')
@@ -1404,6 +1824,8 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertIs(max(d2,l1), d2)
def test_as_nonzero(self):
+ Decimal = self.decimal.Decimal
+
#as false
self.assertFalse(Decimal(0))
#as true
@@ -1411,6 +1833,7 @@ class DecimalUsabilityTest(unittest.TestCase):
def test_tostring_methods(self):
#Test str and repr methods.
+ Decimal = self.decimal.Decimal
d = Decimal('15.32')
self.assertEqual(str(d), '15.32') # str
@@ -1418,6 +1841,7 @@ class DecimalUsabilityTest(unittest.TestCase):
def test_tonum_methods(self):
#Test float and int methods.
+ Decimal = self.decimal.Decimal
d1 = Decimal('66')
d2 = Decimal('15.32')
@@ -1440,6 +1864,7 @@ class DecimalUsabilityTest(unittest.TestCase):
('-11.0', -11),
('0.0', 0),
('-0E3', 0),
+ ('89891211712379812736.1', 89891211712379812736),
]
for d, i in test_pairs:
self.assertEqual(math.floor(Decimal(d)), i)
@@ -1459,6 +1884,7 @@ class DecimalUsabilityTest(unittest.TestCase):
('-11.0', -11),
('0.0', 0),
('-0E3', 0),
+ ('89891211712379812736.1', 89891211712379812737),
]
for d, i in test_pairs:
self.assertEqual(math.ceil(Decimal(d)), i)
@@ -1516,9 +1942,8 @@ class DecimalUsabilityTest(unittest.TestCase):
for d, n, r in test_triples:
self.assertEqual(str(round(Decimal(d), n)), r)
-
-
def test_eval_round_trip(self):
+ Decimal = self.decimal.Decimal
#with zero
d = Decimal( (0, (0,), 0) )
@@ -1537,6 +1962,7 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertEqual(d, eval(repr(d)))
def test_as_tuple(self):
+ Decimal = self.decimal.Decimal
#with zero
d = Decimal(0)
@@ -1550,7 +1976,7 @@ class DecimalUsabilityTest(unittest.TestCase):
d = Decimal("-4.34913534E-17")
self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) )
- #inf
+ # XXX non-compliant infinity payload.
d = Decimal("Infinity")
self.assertEqual(d.as_tuple(), (0, (0,), 'F') )
@@ -1570,87 +1996,16 @@ class DecimalUsabilityTest(unittest.TestCase):
d = Decimal( (1, (), 'n') )
self.assertEqual(d.as_tuple(), (1, (), 'n') )
- #coefficient in infinity should be ignored
- d = Decimal( (0, (4, 5, 3, 4), 'F') )
- self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
- d = Decimal( (1, (0, 2, 7, 1), 'F') )
- self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
-
- def test_immutability_operations(self):
- # Do operations and check that it didn't change change internal objects.
-
- d1 = Decimal('-25e55')
- b1 = Decimal('-25e55')
- d2 = Decimal('33e+33')
- b2 = Decimal('33e+33')
-
- def checkSameDec(operation, useOther=False):
- if useOther:
- eval("d1." + operation + "(d2)")
- self.assertEqual(d1._sign, b1._sign)
- self.assertEqual(d1._int, b1._int)
- self.assertEqual(d1._exp, b1._exp)
- self.assertEqual(d2._sign, b2._sign)
- self.assertEqual(d2._int, b2._int)
- self.assertEqual(d2._exp, b2._exp)
- else:
- eval("d1." + operation + "()")
- self.assertEqual(d1._sign, b1._sign)
- self.assertEqual(d1._int, b1._int)
- self.assertEqual(d1._exp, b1._exp)
- return
-
- Decimal(d1)
- self.assertEqual(d1._sign, b1._sign)
- self.assertEqual(d1._int, b1._int)
- self.assertEqual(d1._exp, b1._exp)
-
- checkSameDec("__abs__")
- checkSameDec("__add__", True)
- checkSameDec("__divmod__", True)
- checkSameDec("__eq__", True)
- checkSameDec("__ne__", True)
- checkSameDec("__le__", True)
- checkSameDec("__lt__", True)
- checkSameDec("__ge__", True)
- checkSameDec("__gt__", True)
- checkSameDec("__float__")
- checkSameDec("__floordiv__", True)
- checkSameDec("__hash__")
- checkSameDec("__int__")
- checkSameDec("__trunc__")
- checkSameDec("__mod__", True)
- checkSameDec("__mul__", True)
- checkSameDec("__neg__")
- checkSameDec("__bool__")
- checkSameDec("__pos__")
- checkSameDec("__pow__", True)
- checkSameDec("__radd__", True)
- checkSameDec("__rdivmod__", True)
- checkSameDec("__repr__")
- checkSameDec("__rfloordiv__", True)
- checkSameDec("__rmod__", True)
- checkSameDec("__rmul__", True)
- checkSameDec("__rpow__", True)
- checkSameDec("__rsub__", True)
- checkSameDec("__str__")
- checkSameDec("__sub__", True)
- checkSameDec("__truediv__", True)
- checkSameDec("adjusted")
- checkSameDec("as_tuple")
- checkSameDec("compare", True)
- checkSameDec("max", True)
- checkSameDec("min", True)
- checkSameDec("normalize")
- checkSameDec("quantize", True)
- checkSameDec("remainder_near", True)
- checkSameDec("same_quantum", True)
- checkSameDec("sqrt")
- checkSameDec("to_eng_string")
- checkSameDec("to_integral")
+ # XXX coefficient in infinity should raise an error
+ if self.decimal == P:
+ d = Decimal( (0, (4, 5, 3, 4), 'F') )
+ self.assertEqual(d.as_tuple(), (0, (0,), 'F'))
+ d = Decimal( (1, (0, 2, 7, 1), 'F') )
+ self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
def test_subclassing(self):
# Different behaviours when subclassing Decimal
+ Decimal = self.decimal.Decimal
class MyDecimal(Decimal):
pass
@@ -1663,7 +2018,18 @@ class DecimalUsabilityTest(unittest.TestCase):
d = d1.max(d2)
self.assertIs(type(d), Decimal)
+ d = copy.copy(d1)
+ self.assertIs(type(d), MyDecimal)
+ self.assertEqual(d, d1)
+
+ d = copy.deepcopy(d1)
+ self.assertIs(type(d), MyDecimal)
+ self.assertEqual(d, d1)
+
def test_implicit_context(self):
+ Decimal = self.decimal.Decimal
+ getcontext = self.decimal.getcontext
+
# Check results when context given implicitly. (Issue 2478)
c = getcontext()
self.assertEqual(str(Decimal(0).sqrt()),
@@ -1672,6 +2038,8 @@ class DecimalUsabilityTest(unittest.TestCase):
def test_conversions_from_int(self):
# Check that methods taking a second Decimal argument will
# always accept an integer in place of a Decimal.
+ Decimal = self.decimal.Decimal
+
self.assertEqual(Decimal(4).compare(3),
Decimal(4).compare(Decimal(3)))
self.assertEqual(Decimal(4).compare_signal(3),
@@ -1716,22 +2084,58 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assertEqual(Decimal(-12).fma(45, Decimal(67)),
Decimal(-12).fma(Decimal(45), Decimal(67)))
+class CUsabilityTest(UsabilityTest):
+ decimal = C
+class PyUsabilityTest(UsabilityTest):
+ decimal = P
-class DecimalPythonAPItests(unittest.TestCase):
+class PythonAPItests(unittest.TestCase):
def test_abc(self):
+ Decimal = self.decimal.Decimal
+
self.assertTrue(issubclass(Decimal, numbers.Number))
self.assertFalse(issubclass(Decimal, numbers.Real))
self.assertIsInstance(Decimal(0), numbers.Number)
self.assertNotIsInstance(Decimal(0), numbers.Real)
def test_pickle(self):
+ Decimal = self.decimal.Decimal
+
+ savedecimal = sys.modules['decimal']
+
+ # Round trip
+ sys.modules['decimal'] = self.decimal
d = Decimal('-3.141590000')
p = pickle.dumps(d)
e = pickle.loads(p)
self.assertEqual(d, e)
+ if C:
+ # Test interchangeability
+ x = C.Decimal('-3.123e81723')
+ y = P.Decimal('-3.123e81723')
+
+ sys.modules['decimal'] = C
+ sx = pickle.dumps(x)
+ sys.modules['decimal'] = P
+ r = pickle.loads(sx)
+ self.assertIsInstance(r, P.Decimal)
+ self.assertEqual(r, y)
+
+ sys.modules['decimal'] = P
+ sy = pickle.dumps(y)
+ sys.modules['decimal'] = C
+ r = pickle.loads(sy)
+ self.assertIsInstance(r, C.Decimal)
+ self.assertEqual(r, x)
+
+ sys.modules['decimal'] = savedecimal
+
def test_int(self):
+ Decimal = self.decimal.Decimal
+ ROUND_DOWN = self.decimal.ROUND_DOWN
+
for x in range(-250, 250):
s = '%0.2f' % (x / 100.0)
# should work the same as for floats
@@ -1747,6 +2151,9 @@ class DecimalPythonAPItests(unittest.TestCase):
self.assertRaises(OverflowError, int, Decimal('-inf'))
def test_trunc(self):
+ Decimal = self.decimal.Decimal
+ ROUND_DOWN = self.decimal.ROUND_DOWN
+
for x in range(-250, 250):
s = '%0.2f' % (x / 100.0)
# should work the same as for floats
@@ -1758,9 +2165,13 @@ class DecimalPythonAPItests(unittest.TestCase):
def test_from_float(self):
- class MyDecimal(Decimal):
+ Decimal = self.decimal.Decimal
+
+ class MyDecimal(Decimal):
pass
+ self.assertTrue(issubclass(MyDecimal, Decimal))
+
r = MyDecimal.from_float(0.1)
self.assertEqual(type(r), MyDecimal)
self.assertEqual(str(r),
@@ -1782,6 +2193,12 @@ class DecimalPythonAPItests(unittest.TestCase):
self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
def test_create_decimal_from_float(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ ROUND_DOWN = self.decimal.ROUND_DOWN
+ ROUND_UP = self.decimal.ROUND_UP
+ Inexact = self.decimal.Inexact
+
context = Context(prec=5, rounding=ROUND_DOWN)
self.assertEqual(
context.create_decimal_from_float(math.pi),
@@ -1805,27 +2222,249 @@ class DecimalPythonAPItests(unittest.TestCase):
self.assertEqual(repr(context.create_decimal_from_float(10)),
"Decimal('10')")
+ def test_quantize(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ InvalidOperation = self.decimal.InvalidOperation
+ ROUND_DOWN = self.decimal.ROUND_DOWN
+
+ c = Context(Emax=99999, Emin=-99999)
+ self.assertEqual(
+ Decimal('7.335').quantize(Decimal('.01')),
+ Decimal('7.34')
+ )
+ self.assertEqual(
+ Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN),
+ Decimal('7.33')
+ )
+ self.assertRaises(
+ InvalidOperation,
+ Decimal("10e99999").quantize, Decimal('1e100000'), context=c
+ )
+
+ c = Context()
+ d = Decimal("0.871831e800")
+ x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
+ self.assertEqual(x, Decimal('8.71E+799'))
+
+ def test_complex(self):
+ Decimal = self.decimal.Decimal
+
+ x = Decimal("9.8182731e181273")
+ self.assertEqual(x.real, x)
+ self.assertEqual(x.imag, 0)
+ self.assertEqual(x.conjugate(), x)
+
+ x = Decimal("1")
+ self.assertEqual(complex(x), complex(float(1)))
+
+ self.assertRaises(AttributeError, setattr, x, 'real', 100)
+ self.assertRaises(AttributeError, setattr, x, 'imag', 100)
+ self.assertRaises(AttributeError, setattr, x, 'conjugate', 100)
+ self.assertRaises(AttributeError, setattr, x, '__complex__', 100)
+
+ def test_named_parameters(self):
+ D = self.decimal.Decimal
+ Context = self.decimal.Context
+ localcontext = self.decimal.localcontext
+ InvalidOperation = self.decimal.InvalidOperation
+ Overflow = self.decimal.Overflow
+
+ xc = Context()
+ xc.prec = 1
+ xc.Emax = 1
+ xc.Emin = -1
+
+ with localcontext() as c:
+ c.clear_flags()
+
+ self.assertEqual(D(9, xc), 9)
+ self.assertEqual(D(9, context=xc), 9)
+ self.assertEqual(D(context=xc, value=9), 9)
+ self.assertEqual(D(context=xc), 0)
+ xc.clear_flags()
+ self.assertRaises(InvalidOperation, D, "xyz", context=xc)
+ self.assertTrue(xc.flags[InvalidOperation])
+ self.assertFalse(c.flags[InvalidOperation])
+
+ xc.clear_flags()
+ self.assertEqual(D(2).exp(context=xc), 7)
+ self.assertRaises(Overflow, D(8).exp, context=xc)
+ self.assertTrue(xc.flags[Overflow])
+ self.assertFalse(c.flags[Overflow])
+
+ xc.clear_flags()
+ self.assertEqual(D(2).ln(context=xc), D('0.7'))
+ self.assertRaises(InvalidOperation, D(-1).ln, context=xc)
+ self.assertTrue(xc.flags[InvalidOperation])
+ self.assertFalse(c.flags[InvalidOperation])
+
+ self.assertEqual(D(0).log10(context=xc), D('-inf'))
+ self.assertEqual(D(-1).next_minus(context=xc), -2)
+ self.assertEqual(D(-1).next_plus(context=xc), D('-0.9'))
+ self.assertEqual(D("9.73").normalize(context=xc), D('1E+1'))
+ self.assertEqual(D("9999").to_integral(context=xc), 9999)
+ self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000)
+ self.assertEqual(D("123").to_integral_value(context=xc), 123)
+ self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2'))
+
+ self.assertEqual(D("0.0625").compare(context=xc, other=3), -1)
+ xc.clear_flags()
+ self.assertRaises(InvalidOperation,
+ D("0").compare_signal, D('nan'), context=xc)
+ self.assertTrue(xc.flags[InvalidOperation])
+ self.assertFalse(c.flags[InvalidOperation])
+ self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
+ self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0'))
+ self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc),
+ D('-0.3'))
+ self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0'))
+ self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc),
+ D('0.0'))
+ self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1'))
+ xc.clear_flags()
+ self.assertRaises(InvalidOperation,
+ D("0.2").quantize, D('1e10'), context=xc)
+ self.assertTrue(xc.flags[InvalidOperation])
+ self.assertFalse(c.flags[InvalidOperation])
+ self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc),
+ D('-0.5'))
+
+ self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7),
+ D('7E+1'))
+
+ self.assertRaises(TypeError, D(1).is_canonical, context=xc)
+ self.assertRaises(TypeError, D(1).is_finite, context=xc)
+ self.assertRaises(TypeError, D(1).is_infinite, context=xc)
+ self.assertRaises(TypeError, D(1).is_nan, context=xc)
+ self.assertRaises(TypeError, D(1).is_qnan, context=xc)
+ self.assertRaises(TypeError, D(1).is_snan, context=xc)
+ self.assertRaises(TypeError, D(1).is_signed, context=xc)
+ self.assertRaises(TypeError, D(1).is_zero, context=xc)
+
+ self.assertFalse(D("0.01").is_normal(context=xc))
+ self.assertTrue(D("0.01").is_subnormal(context=xc))
+
+ self.assertRaises(TypeError, D(1).adjusted, context=xc)
+ self.assertRaises(TypeError, D(1).conjugate, context=xc)
+ self.assertRaises(TypeError, D(1).radix, context=xc)
+
+ self.assertEqual(D(-111).logb(context=xc), 2)
+ self.assertEqual(D(0).logical_invert(context=xc), 1)
+ self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal')
+ self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21')
+
+ self.assertEqual(D('11').logical_and(D('10'), context=xc), 0)
+ self.assertEqual(D('11').logical_or(D('10'), context=xc), 1)
+ self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1)
+ self.assertEqual(D('23').rotate(1, context=xc), 3)
+ self.assertEqual(D('23').rotate(1, context=xc), 3)
+ xc.clear_flags()
+ self.assertRaises(Overflow,
+ D('23').scaleb, 1, context=xc)
+ self.assertTrue(xc.flags[Overflow])
+ self.assertFalse(c.flags[Overflow])
+ self.assertEqual(D('23').shift(-1, context=xc), 0)
+
+ self.assertRaises(TypeError, D.from_float, 1.1, context=xc)
+ self.assertRaises(TypeError, D(0).as_tuple, context=xc)
+
+ if (self.decimal == C):
+ self.assertRaises(TypeError, D(1).canonical, context=xc)
+ self.assertEqual(D("-1").copy_abs(context=xc), 1)
+ self.assertEqual(D("1").copy_negate(context=xc), -1)
+ else:
+ self.assertEqual(D(1).canonical(context=xc), 1)
+ self.assertRaises(TypeError, D("-1").copy_abs, context=xc)
+ self.assertRaises(TypeError, D("-1").copy_negate, context=xc)
+
+class CPythonAPItests(PythonAPItests):
+ decimal = C
+class PyPythonAPItests(PythonAPItests):
+ decimal = P
+
class ContextAPItests(unittest.TestCase):
def test_pickle(self):
+
+ Context = self.decimal.Context
+
+ savedecimal = sys.modules['decimal']
+
+ # Round trip
+ sys.modules['decimal'] = self.decimal
c = Context()
e = pickle.loads(pickle.dumps(c))
- for k in vars(c):
- v1 = vars(c)[k]
- v2 = vars(e)[k]
- self.assertEqual(v1, v2)
+
+ self.assertEqual(c.prec, e.prec)
+ self.assertEqual(c.Emin, e.Emin)
+ self.assertEqual(c.Emax, e.Emax)
+ self.assertEqual(c.rounding, e.rounding)
+ self.assertEqual(c.capitals, e.capitals)
+ self.assertEqual(c.clamp, e.clamp)
+ self.assertEqual(c.flags, e.flags)
+ self.assertEqual(c.traps, e.traps)
+
+ # Test interchangeability
+ combinations = [(C, P), (P, C)] if C else [(P, P)]
+ for dumper, loader in combinations:
+ for ri, _ in enumerate(RoundingModes[dumper]):
+ for fi, _ in enumerate(OrderedSignals[dumper]):
+ for ti, _ in enumerate(OrderedSignals[dumper]):
+
+ prec = random.randrange(1, 100)
+ emin = random.randrange(-100, 0)
+ emax = random.randrange(1, 100)
+ caps = random.randrange(2)
+ clamp = random.randrange(2)
+
+ # One module dumps
+ sys.modules['decimal'] = dumper
+ c = dumper.Context(
+ prec=prec, Emin=emin, Emax=emax,
+ rounding=RoundingModes[dumper][ri],
+ capitals=caps, clamp=clamp,
+ flags=OrderedSignals[dumper][:fi],
+ traps=OrderedSignals[dumper][:ti]
+ )
+ s = pickle.dumps(c)
+
+ # The other module loads
+ sys.modules['decimal'] = loader
+ d = pickle.loads(s)
+ self.assertIsInstance(d, loader.Context)
+
+ self.assertEqual(d.prec, prec)
+ self.assertEqual(d.Emin, emin)
+ self.assertEqual(d.Emax, emax)
+ self.assertEqual(d.rounding, RoundingModes[loader][ri])
+ self.assertEqual(d.capitals, caps)
+ self.assertEqual(d.clamp, clamp)
+ assert_signals(self, d, 'flags', OrderedSignals[loader][:fi])
+ assert_signals(self, d, 'traps', OrderedSignals[loader][:ti])
+
+ sys.modules['decimal'] = savedecimal
def test_equality_with_other_types(self):
+ Decimal = self.decimal.Decimal
+
self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}])
self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}])
def test_copy(self):
# All copies should be deep
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.copy()
self.assertNotEqual(id(c), id(d))
self.assertNotEqual(id(c.flags), id(d.flags))
self.assertNotEqual(id(c.traps), id(d.traps))
+ k1 = set(c.flags.keys())
+ k2 = set(d.flags.keys())
+ self.assertEqual(k1, k2)
+ self.assertEqual(c.flags, d.flags)
def test__clamp(self):
# In Python 3.2, the private attribute `_clamp` was made
@@ -1834,17 +2473,23 @@ class ContextAPItests(unittest.TestCase):
# only, the attribute should be gettable/settable via both
# `clamp` and `_clamp`; in Python 3.3, `_clamp` should be
# removed.
+ Context = self.decimal.Context
c = Context()
- with self.assertRaises(AttributeError):
- clamp_value = c._clamp
+ self.assertRaises(AttributeError, getattr, c, '_clamp')
def test_abs(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.abs(Decimal(-1))
self.assertEqual(c.abs(-1), d)
self.assertRaises(TypeError, c.abs, '-1')
def test_add(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.add(Decimal(1), Decimal(1))
self.assertEqual(c.add(1, 1), d)
@@ -1854,6 +2499,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.add, 1, '1')
def test_compare(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.compare(Decimal(1), Decimal(1))
self.assertEqual(c.compare(1, 1), d)
@@ -1863,6 +2511,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.compare, 1, '1')
def test_compare_signal(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.compare_signal(Decimal(1), Decimal(1))
self.assertEqual(c.compare_signal(1, 1), d)
@@ -1872,6 +2523,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.compare_signal, 1, '1')
def test_compare_total(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.compare_total(Decimal(1), Decimal(1))
self.assertEqual(c.compare_total(1, 1), d)
@@ -1881,6 +2535,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.compare_total, 1, '1')
def test_compare_total_mag(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.compare_total_mag(Decimal(1), Decimal(1))
self.assertEqual(c.compare_total_mag(1, 1), d)
@@ -1890,24 +2547,36 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.compare_total_mag, 1, '1')
def test_copy_abs(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.copy_abs(Decimal(-1))
self.assertEqual(c.copy_abs(-1), d)
self.assertRaises(TypeError, c.copy_abs, '-1')
def test_copy_decimal(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.copy_decimal(Decimal(-1))
self.assertEqual(c.copy_decimal(-1), d)
self.assertRaises(TypeError, c.copy_decimal, '-1')
def test_copy_negate(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.copy_negate(Decimal(-1))
self.assertEqual(c.copy_negate(-1), d)
self.assertRaises(TypeError, c.copy_negate, '-1')
def test_copy_sign(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.copy_sign(Decimal(1), Decimal(-2))
self.assertEqual(c.copy_sign(1, -2), d)
@@ -1917,6 +2586,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.copy_sign, 1, '-2')
def test_divide(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.divide(Decimal(1), Decimal(2))
self.assertEqual(c.divide(1, 2), d)
@@ -1926,6 +2598,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.divide, 1, '2')
def test_divide_int(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.divide_int(Decimal(1), Decimal(2))
self.assertEqual(c.divide_int(1, 2), d)
@@ -1935,6 +2610,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.divide_int, 1, '2')
def test_divmod(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.divmod(Decimal(1), Decimal(2))
self.assertEqual(c.divmod(1, 2), d)
@@ -1944,12 +2622,18 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.divmod, 1, '2')
def test_exp(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.exp(Decimal(10))
self.assertEqual(c.exp(10), d)
self.assertRaises(TypeError, c.exp, '10')
def test_fma(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.fma(Decimal(2), Decimal(3), Decimal(4))
self.assertEqual(c.fma(2, 3, 4), d)
@@ -1973,78 +2657,117 @@ class ContextAPItests(unittest.TestCase):
Decimal('snan'), 1.222)
def test_is_finite(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_finite(Decimal(10))
self.assertEqual(c.is_finite(10), d)
self.assertRaises(TypeError, c.is_finite, '10')
def test_is_infinite(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_infinite(Decimal(10))
self.assertEqual(c.is_infinite(10), d)
self.assertRaises(TypeError, c.is_infinite, '10')
def test_is_nan(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_nan(Decimal(10))
self.assertEqual(c.is_nan(10), d)
self.assertRaises(TypeError, c.is_nan, '10')
def test_is_normal(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_normal(Decimal(10))
self.assertEqual(c.is_normal(10), d)
self.assertRaises(TypeError, c.is_normal, '10')
def test_is_qnan(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_qnan(Decimal(10))
self.assertEqual(c.is_qnan(10), d)
self.assertRaises(TypeError, c.is_qnan, '10')
def test_is_signed(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_signed(Decimal(10))
self.assertEqual(c.is_signed(10), d)
self.assertRaises(TypeError, c.is_signed, '10')
def test_is_snan(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_snan(Decimal(10))
self.assertEqual(c.is_snan(10), d)
self.assertRaises(TypeError, c.is_snan, '10')
def test_is_subnormal(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_subnormal(Decimal(10))
self.assertEqual(c.is_subnormal(10), d)
self.assertRaises(TypeError, c.is_subnormal, '10')
def test_is_zero(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.is_zero(Decimal(10))
self.assertEqual(c.is_zero(10), d)
self.assertRaises(TypeError, c.is_zero, '10')
def test_ln(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.ln(Decimal(10))
self.assertEqual(c.ln(10), d)
self.assertRaises(TypeError, c.ln, '10')
def test_log10(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.log10(Decimal(10))
self.assertEqual(c.log10(10), d)
self.assertRaises(TypeError, c.log10, '10')
def test_logb(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.logb(Decimal(10))
self.assertEqual(c.logb(10), d)
self.assertRaises(TypeError, c.logb, '10')
def test_logical_and(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.logical_and(Decimal(1), Decimal(1))
self.assertEqual(c.logical_and(1, 1), d)
@@ -2054,12 +2777,18 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.logical_and, 1, '1')
def test_logical_invert(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.logical_invert(Decimal(1000))
self.assertEqual(c.logical_invert(1000), d)
self.assertRaises(TypeError, c.logical_invert, '1000')
def test_logical_or(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.logical_or(Decimal(1), Decimal(1))
self.assertEqual(c.logical_or(1, 1), d)
@@ -2069,6 +2798,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.logical_or, 1, '1')
def test_logical_xor(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.logical_xor(Decimal(1), Decimal(1))
self.assertEqual(c.logical_xor(1, 1), d)
@@ -2078,6 +2810,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.logical_xor, 1, '1')
def test_max(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.max(Decimal(1), Decimal(2))
self.assertEqual(c.max(1, 2), d)
@@ -2087,6 +2822,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.max, 1, '2')
def test_max_mag(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.max_mag(Decimal(1), Decimal(2))
self.assertEqual(c.max_mag(1, 2), d)
@@ -2096,6 +2834,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.max_mag, 1, '2')
def test_min(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.min(Decimal(1), Decimal(2))
self.assertEqual(c.min(1, 2), d)
@@ -2105,6 +2846,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.min, 1, '2')
def test_min_mag(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.min_mag(Decimal(1), Decimal(2))
self.assertEqual(c.min_mag(1, 2), d)
@@ -2114,12 +2858,18 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.min_mag, 1, '2')
def test_minus(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.minus(Decimal(10))
self.assertEqual(c.minus(10), d)
self.assertRaises(TypeError, c.minus, '10')
def test_multiply(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.multiply(Decimal(1), Decimal(2))
self.assertEqual(c.multiply(1, 2), d)
@@ -2129,18 +2879,27 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.multiply, 1, '2')
def test_next_minus(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.next_minus(Decimal(10))
self.assertEqual(c.next_minus(10), d)
self.assertRaises(TypeError, c.next_minus, '10')
def test_next_plus(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.next_plus(Decimal(10))
self.assertEqual(c.next_plus(10), d)
self.assertRaises(TypeError, c.next_plus, '10')
def test_next_toward(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.next_toward(Decimal(1), Decimal(2))
self.assertEqual(c.next_toward(1, 2), d)
@@ -2150,36 +2909,50 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.next_toward, 1, '2')
def test_normalize(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.normalize(Decimal(10))
self.assertEqual(c.normalize(10), d)
self.assertRaises(TypeError, c.normalize, '10')
def test_number_class(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
self.assertEqual(c.number_class(123), c.number_class(Decimal(123)))
self.assertEqual(c.number_class(0), c.number_class(Decimal(0)))
self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45)))
- def test_power(self):
- c = Context()
- d = c.power(Decimal(1), Decimal(4), Decimal(2))
- self.assertEqual(c.power(1, 4, 2), d)
- self.assertEqual(c.power(Decimal(1), 4, 2), d)
- self.assertEqual(c.power(1, Decimal(4), 2), d)
- self.assertEqual(c.power(1, 4, Decimal(2)), d)
- self.assertEqual(c.power(Decimal(1), Decimal(4), 2), d)
- self.assertRaises(TypeError, c.power, '1', 4, 2)
- self.assertRaises(TypeError, c.power, 1, '4', 2)
- self.assertRaises(TypeError, c.power, 1, 4, '2')
-
def test_plus(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.plus(Decimal(10))
self.assertEqual(c.plus(10), d)
self.assertRaises(TypeError, c.plus, '10')
+ def test_power(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
+ c = Context()
+ d = c.power(Decimal(1), Decimal(4))
+ self.assertEqual(c.power(1, 4), d)
+ self.assertEqual(c.power(Decimal(1), 4), d)
+ self.assertEqual(c.power(1, Decimal(4)), d)
+ self.assertEqual(c.power(Decimal(1), Decimal(4)), d)
+ self.assertRaises(TypeError, c.power, '1', 4)
+ self.assertRaises(TypeError, c.power, 1, '4')
+ self.assertEqual(c.power(modulo=5, b=8, a=2), 1)
+
def test_quantize(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.quantize(Decimal(1), Decimal(2))
self.assertEqual(c.quantize(1, 2), d)
@@ -2189,6 +2962,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.quantize, 1, '2')
def test_remainder(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.remainder(Decimal(1), Decimal(2))
self.assertEqual(c.remainder(1, 2), d)
@@ -2198,6 +2974,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.remainder, 1, '2')
def test_remainder_near(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.remainder_near(Decimal(1), Decimal(2))
self.assertEqual(c.remainder_near(1, 2), d)
@@ -2207,6 +2986,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.remainder_near, 1, '2')
def test_rotate(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.rotate(Decimal(1), Decimal(2))
self.assertEqual(c.rotate(1, 2), d)
@@ -2216,12 +2998,18 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.rotate, 1, '2')
def test_sqrt(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.sqrt(Decimal(10))
self.assertEqual(c.sqrt(10), d)
self.assertRaises(TypeError, c.sqrt, '10')
def test_same_quantum(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.same_quantum(Decimal(1), Decimal(2))
self.assertEqual(c.same_quantum(1, 2), d)
@@ -2231,6 +3019,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.same_quantum, 1, '2')
def test_scaleb(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.scaleb(Decimal(1), Decimal(2))
self.assertEqual(c.scaleb(1, 2), d)
@@ -2240,6 +3031,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.scaleb, 1, '2')
def test_shift(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.shift(Decimal(1), Decimal(2))
self.assertEqual(c.shift(1, 2), d)
@@ -2249,6 +3043,9 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.shift, 1, '2')
def test_subtract(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.subtract(Decimal(1), Decimal(2))
self.assertEqual(c.subtract(1, 2), d)
@@ -2258,35 +3055,56 @@ class ContextAPItests(unittest.TestCase):
self.assertRaises(TypeError, c.subtract, 1, '2')
def test_to_eng_string(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.to_eng_string(Decimal(10))
self.assertEqual(c.to_eng_string(10), d)
self.assertRaises(TypeError, c.to_eng_string, '10')
def test_to_sci_string(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.to_sci_string(Decimal(10))
self.assertEqual(c.to_sci_string(10), d)
self.assertRaises(TypeError, c.to_sci_string, '10')
def test_to_integral_exact(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.to_integral_exact(Decimal(10))
self.assertEqual(c.to_integral_exact(10), d)
self.assertRaises(TypeError, c.to_integral_exact, '10')
def test_to_integral_value(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+
c = Context()
d = c.to_integral_value(Decimal(10))
self.assertEqual(c.to_integral_value(10), d)
self.assertRaises(TypeError, c.to_integral_value, '10')
+ self.assertRaises(TypeError, c.to_integral_value, 10, 'x')
-class WithStatementTest(unittest.TestCase):
+class CContextAPItests(ContextAPItests):
+ decimal = C
+class PyContextAPItests(ContextAPItests):
+ decimal = P
+
+class ContextWithStatement(unittest.TestCase):
# Can't do these as docstrings until Python 2.6
# as doctest can't handle __future__ statements
def test_localcontext(self):
# Use a copy of the current context in the block
+ getcontext = self.decimal.getcontext
+ localcontext = self.decimal.localcontext
+
orig_ctx = getcontext()
with localcontext() as enter_ctx:
set_ctx = getcontext()
@@ -2297,6 +3115,11 @@ class WithStatementTest(unittest.TestCase):
def test_localcontextarg(self):
# Use a copy of the supplied context in the block
+ Context = self.decimal.Context
+ getcontext = self.decimal.getcontext
+ localcontext = self.decimal.localcontext
+
+ localcontext = self.decimal.localcontext
orig_ctx = getcontext()
new_ctx = Context(prec=42)
with localcontext(new_ctx) as enter_ctx:
@@ -2307,17 +3130,131 @@ class WithStatementTest(unittest.TestCase):
self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
+ def test_nested_with_statements(self):
+ # Use a copy of the supplied context in the block
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ getcontext = self.decimal.getcontext
+ localcontext = self.decimal.localcontext
+ Clamped = self.decimal.Clamped
+ Overflow = self.decimal.Overflow
+
+ orig_ctx = getcontext()
+ orig_ctx.clear_flags()
+ new_ctx = Context(Emax=384)
+ with localcontext() as c1:
+ self.assertEqual(c1.flags, orig_ctx.flags)
+ self.assertEqual(c1.traps, orig_ctx.traps)
+ c1.traps[Clamped] = True
+ c1.Emin = -383
+ self.assertNotEqual(orig_ctx.Emin, -383)
+ self.assertRaises(Clamped, c1.create_decimal, '0e-999')
+ self.assertTrue(c1.flags[Clamped])
+ with localcontext(new_ctx) as c2:
+ self.assertEqual(c2.flags, new_ctx.flags)
+ self.assertEqual(c2.traps, new_ctx.traps)
+ self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2)
+ self.assertFalse(c2.flags[Clamped])
+ self.assertTrue(c2.flags[Overflow])
+ del c2
+ self.assertFalse(c1.flags[Overflow])
+ del c1
+ self.assertNotEqual(orig_ctx.Emin, -383)
+ self.assertFalse(orig_ctx.flags[Clamped])
+ self.assertFalse(orig_ctx.flags[Overflow])
+ self.assertFalse(new_ctx.flags[Clamped])
+ self.assertFalse(new_ctx.flags[Overflow])
+
+ def test_with_statements_gc1(self):
+ localcontext = self.decimal.localcontext
+
+ with localcontext() as c1:
+ del c1
+ with localcontext() as c2:
+ del c2
+ with localcontext() as c3:
+ del c3
+ with localcontext() as c4:
+ del c4
+
+ def test_with_statements_gc2(self):
+ localcontext = self.decimal.localcontext
+
+ with localcontext() as c1:
+ with localcontext(c1) as c2:
+ del c1
+ with localcontext(c2) as c3:
+ del c2
+ with localcontext(c3) as c4:
+ del c3
+ del c4
+
+ def test_with_statements_gc3(self):
+ Context = self.decimal.Context
+ localcontext = self.decimal.localcontext
+ getcontext = self.decimal.getcontext
+ setcontext = self.decimal.setcontext
+
+ with localcontext() as c1:
+ del c1
+ n1 = Context(prec=1)
+ setcontext(n1)
+ with localcontext(n1) as c2:
+ del n1
+ self.assertEqual(c2.prec, 1)
+ del c2
+ n2 = Context(prec=2)
+ setcontext(n2)
+ del n2
+ self.assertEqual(getcontext().prec, 2)
+ n3 = Context(prec=3)
+ setcontext(n3)
+ self.assertEqual(getcontext().prec, 3)
+ with localcontext(n3) as c3:
+ del n3
+ self.assertEqual(c3.prec, 3)
+ del c3
+ n4 = Context(prec=4)
+ setcontext(n4)
+ del n4
+ self.assertEqual(getcontext().prec, 4)
+ with localcontext() as c4:
+ self.assertEqual(c4.prec, 4)
+ del c4
+
+class CContextWithStatement(ContextWithStatement):
+ decimal = C
+class PyContextWithStatement(ContextWithStatement):
+ decimal = P
+
class ContextFlags(unittest.TestCase):
+
def test_flags_irrelevant(self):
# check that the result (numeric result + flags raised) of an
# arithmetic operation doesn't depend on the current flags
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ Inexact = self.decimal.Inexact
+ Rounded = self.decimal.Rounded
+ Underflow = self.decimal.Underflow
+ Clamped = self.decimal.Clamped
+ Subnormal = self.decimal.Subnormal
+ ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN
+
+ def raise_error(context, flag):
+ if self.decimal == C:
+ context.flags[flag] = True
+ if context.traps[flag]:
+ raise flag
+ else:
+ context._raise_error(flag)
- context = Context(prec=9, Emin = -999999999, Emax = 999999999,
- rounding=ROUND_HALF_EVEN, traps=[], flags=[])
+ context = Context(prec=9, Emin = -425000000, Emax = 425000000,
+ rounding=ROUND_HALF_EVEN, traps=[], flags=[])
# operations that raise various flags, in the form (function, arglist)
operations = [
- (context._apply, [Decimal("100E-1000000009")]),
+ (context._apply, [Decimal("100E-425000010")]),
(context.sqrt, [Decimal(2)]),
(context.add, [Decimal("1.23456789"), Decimal("9.87654321")]),
(context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]),
@@ -2338,7 +3275,7 @@ class ContextFlags(unittest.TestCase):
# set flags, before calling operation
context.clear_flags()
for flag in extra_flags:
- context._raise_error(flag)
+ raise_error(context, flag)
new_ans = fn(*args)
# flags that we expect to be set after the operation
@@ -2359,6 +3296,1651 @@ class ContextFlags(unittest.TestCase):
"operation raises different flags depending on flags set: " +
"expected %s, got %s" % (expected_flags, new_flags))
+ def test_flag_comparisons(self):
+ Context = self.decimal.Context
+ Inexact = self.decimal.Inexact
+ Rounded = self.decimal.Rounded
+
+ c = Context()
+
+ # Valid SignalDict
+ self.assertNotEqual(c.flags, c.traps)
+ self.assertNotEqual(c.traps, c.flags)
+
+ c.flags = c.traps
+ self.assertEqual(c.flags, c.traps)
+ self.assertEqual(c.traps, c.flags)
+
+ c.flags[Rounded] = True
+ c.traps = c.flags
+ self.assertEqual(c.flags, c.traps)
+ self.assertEqual(c.traps, c.flags)
+
+ d = {}
+ d.update(c.flags)
+ self.assertEqual(d, c.flags)
+ self.assertEqual(c.flags, d)
+
+ d[Inexact] = True
+ self.assertNotEqual(d, c.flags)
+ self.assertNotEqual(c.flags, d)
+
+ # Invalid SignalDict
+ d = {Inexact:False}
+ self.assertNotEqual(d, c.flags)
+ self.assertNotEqual(c.flags, d)
+
+ d = ["xyz"]
+ self.assertNotEqual(d, c.flags)
+ self.assertNotEqual(c.flags, d)
+
+ @requires_IEEE_754
+ def test_float_operation(self):
+ Decimal = self.decimal.Decimal
+ FloatOperation = self.decimal.FloatOperation
+ localcontext = self.decimal.localcontext
+
+ with localcontext() as c:
+ ##### trap is off by default
+ self.assertFalse(c.traps[FloatOperation])
+
+ # implicit conversion sets the flag
+ c.clear_flags()
+ self.assertEqual(Decimal(7.5), 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ self.assertEqual(c.create_decimal(7.5), 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ # explicit conversion does not set the flag
+ c.clear_flags()
+ x = Decimal.from_float(7.5)
+ self.assertFalse(c.flags[FloatOperation])
+ # comparison sets the flag
+ self.assertEqual(x, 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ x = c.create_decimal_from_float(7.5)
+ self.assertFalse(c.flags[FloatOperation])
+ self.assertEqual(x, 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ ##### set the trap
+ c.traps[FloatOperation] = True
+
+ # implicit conversion raises
+ c.clear_flags()
+ self.assertRaises(FloatOperation, Decimal, 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ self.assertRaises(FloatOperation, c.create_decimal, 7.5)
+ self.assertTrue(c.flags[FloatOperation])
+
+ # explicit conversion is silent
+ c.clear_flags()
+ x = Decimal.from_float(7.5)
+ self.assertFalse(c.flags[FloatOperation])
+
+ c.clear_flags()
+ x = c.create_decimal_from_float(7.5)
+ self.assertFalse(c.flags[FloatOperation])
+
+ def test_float_comparison(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ FloatOperation = self.decimal.FloatOperation
+ localcontext = self.decimal.localcontext
+
+ def assert_attr(a, b, attr, context, signal=None):
+ context.clear_flags()
+ f = getattr(a, attr)
+ if signal == FloatOperation:
+ self.assertRaises(signal, f, b)
+ else:
+ self.assertIs(f(b), True)
+ self.assertTrue(context.flags[FloatOperation])
+
+ small_d = Decimal('0.25')
+ big_d = Decimal('3.0')
+ small_f = 0.25
+ big_f = 3.0
+
+ zero_d = Decimal('0.0')
+ neg_zero_d = Decimal('-0.0')
+ zero_f = 0.0
+ neg_zero_f = -0.0
+
+ inf_d = Decimal('Infinity')
+ neg_inf_d = Decimal('-Infinity')
+ inf_f = float('inf')
+ neg_inf_f = float('-inf')
+
+ def doit(c, signal=None):
+ # Order
+ for attr in '__lt__', '__le__':
+ assert_attr(small_d, big_f, attr, c, signal)
+
+ for attr in '__gt__', '__ge__':
+ assert_attr(big_d, small_f, attr, c, signal)
+
+ # Equality
+ assert_attr(small_d, small_f, '__eq__', c, None)
+
+ assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None)
+ assert_attr(neg_zero_d, zero_f, '__eq__', c, None)
+
+ assert_attr(zero_d, neg_zero_f, '__eq__', c, None)
+ assert_attr(zero_d, zero_f, '__eq__', c, None)
+
+ assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None)
+ assert_attr(inf_d, inf_f, '__eq__', c, None)
+
+ # Inequality
+ assert_attr(small_d, big_f, '__ne__', c, None)
+
+ assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None)
+
+ assert_attr(neg_inf_d, inf_f, '__ne__', c, None)
+ assert_attr(inf_d, neg_inf_f, '__ne__', c, None)
+
+ assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None)
+
+ def test_containers(c, signal=None):
+ c.clear_flags()
+ s = set([100.0, Decimal('100.0')])
+ self.assertEqual(len(s), 1)
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ if signal:
+ self.assertRaises(signal, sorted, [1.0, Decimal('10.0')])
+ else:
+ s = sorted([10.0, Decimal('10.0')])
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ b = 10.0 in [Decimal('10.0'), 1.0]
+ self.assertTrue(c.flags[FloatOperation])
+
+ c.clear_flags()
+ b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'}
+ self.assertTrue(c.flags[FloatOperation])
+
+ nc = Context()
+ with localcontext(nc) as c:
+ self.assertFalse(c.traps[FloatOperation])
+ doit(c, signal=None)
+ test_containers(c, signal=None)
+
+ c.traps[FloatOperation] = True
+ doit(c, signal=FloatOperation)
+ test_containers(c, signal=FloatOperation)
+
+ def test_float_operation_default(self):
+ Decimal = self.decimal.Decimal
+ Context = self.decimal.Context
+ Inexact = self.decimal.Inexact
+ FloatOperation= self.decimal.FloatOperation
+
+ context = Context()
+ self.assertFalse(context.flags[FloatOperation])
+ self.assertFalse(context.traps[FloatOperation])
+
+ context.clear_traps()
+ context.traps[Inexact] = True
+ context.traps[FloatOperation] = True
+ self.assertTrue(context.traps[FloatOperation])
+ self.assertTrue(context.traps[Inexact])
+
+class CContextFlags(ContextFlags):
+ decimal = C
+class PyContextFlags(ContextFlags):
+ decimal = P
+
+class SpecialContexts(unittest.TestCase):
+ """Test the context templates."""
+
+ def test_context_templates(self):
+ BasicContext = self.decimal.BasicContext
+ ExtendedContext = self.decimal.ExtendedContext
+ getcontext = self.decimal.getcontext
+ setcontext = self.decimal.setcontext
+ InvalidOperation = self.decimal.InvalidOperation
+ DivisionByZero = self.decimal.DivisionByZero
+ Overflow = self.decimal.Overflow
+ Underflow = self.decimal.Underflow
+ Clamped = self.decimal.Clamped
+
+ assert_signals(self, BasicContext, 'traps',
+ [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped]
+ )
+
+ savecontext = getcontext().copy()
+ basic_context_prec = BasicContext.prec
+ extended_context_prec = ExtendedContext.prec
+
+ ex = None
+ try:
+ BasicContext.prec = ExtendedContext.prec = 441
+ for template in BasicContext, ExtendedContext:
+ setcontext(template)
+ c = getcontext()
+ self.assertIsNot(c, template)
+ self.assertEqual(c.prec, 441)
+ except Exception as e:
+ ex = e.__class__
+ finally:
+ BasicContext.prec = basic_context_prec
+ ExtendedContext.prec = extended_context_prec
+ setcontext(savecontext)
+ if ex:
+ raise ex
+
+ def test_default_context(self):
+ DefaultContext = self.decimal.DefaultContext
+ BasicContext = self.decimal.BasicContext
+ ExtendedContext = self.decimal.ExtendedContext
+ getcontext = self.decimal.getcontext
+ setcontext = self.decimal.setcontext
+ InvalidOperation = self.decimal.InvalidOperation
+ DivisionByZero = self.decimal.DivisionByZero
+ Overflow = self.decimal.Overflow
+
+ self.assertEqual(BasicContext.prec, 9)
+ self.assertEqual(ExtendedContext.prec, 9)
+
+ assert_signals(self, DefaultContext, 'traps',
+ [InvalidOperation, DivisionByZero, Overflow]
+ )
+
+ savecontext = getcontext().copy()
+ default_context_prec = DefaultContext.prec
+
+ ex = None
+ try:
+ c = getcontext()
+ saveprec = c.prec
+
+ DefaultContext.prec = 961
+ c = getcontext()
+ self.assertEqual(c.prec, saveprec)
+
+ setcontext(DefaultContext)
+ c = getcontext()
+ self.assertIsNot(c, DefaultContext)
+ self.assertEqual(c.prec, 961)
+ except Exception as e:
+ ex = e.__class__
+ finally:
+ DefaultContext.prec = default_context_prec
+ setcontext(savecontext)
+ if ex:
+ raise ex
+
+class CSpecialContexts(SpecialContexts):
+ decimal = C
+class PySpecialContexts(SpecialContexts):
+ decimal = P
+
+class ContextInputValidation(unittest.TestCase):
+
+ def test_invalid_context(self):
+ Context = self.decimal.Context
+ DefaultContext = self.decimal.DefaultContext
+
+ c = DefaultContext.copy()
+
+ # prec, Emax
+ for attr in ['prec', 'Emax']:
+ setattr(c, attr, 999999)
+ self.assertEqual(getattr(c, attr), 999999)
+ self.assertRaises(ValueError, setattr, c, attr, -1)
+ self.assertRaises(TypeError, setattr, c, attr, 'xyz')
+
+ # Emin
+ setattr(c, 'Emin', -999999)
+ self.assertEqual(getattr(c, 'Emin'), -999999)
+ self.assertRaises(ValueError, setattr, c, 'Emin', 1)
+ self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3))
+
+ # rounding: always raise TypeError in order to get consistent
+ # exceptions across implementations. In decimal, rounding
+ # modes are strings, in _decimal they are integers. The idea
+ # is to view rounding as an abstract type and not mind the
+ # implementation details.
+ # Hence, a user should view the rounding modes as if they
+ # had been defined in a language that supports abstract
+ # data types, e.g. ocaml:
+ #
+ # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;;
+ #
+ self.assertRaises(TypeError, setattr, c, 'rounding', -1)
+ self.assertRaises(TypeError, setattr, c, 'rounding', 9)
+ self.assertRaises(TypeError, setattr, c, 'rounding', 1.0)
+ self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz')
+
+ # capitals, clamp
+ for attr in ['capitals', 'clamp']:
+ self.assertRaises(ValueError, setattr, c, attr, -1)
+ self.assertRaises(ValueError, setattr, c, attr, 2)
+ self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
+
+ # Invalid attribute
+ self.assertRaises(AttributeError, setattr, c, 'emax', 100)
+
+ # Invalid signal dict
+ self.assertRaises(TypeError, setattr, c, 'flags', [])
+ self.assertRaises(KeyError, setattr, c, 'flags', {})
+ self.assertRaises(KeyError, setattr, c, 'traps',
+ {'InvalidOperation':0})
+
+ # Attributes cannot be deleted
+ for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp',
+ 'flags', 'traps']:
+ self.assertRaises(AttributeError, c.__delattr__, attr)
+
+ # Invalid attributes
+ self.assertRaises(TypeError, getattr, c, 9)
+ self.assertRaises(TypeError, setattr, c, 9)
+
+ # Invalid values in constructor
+ self.assertRaises(TypeError, Context, rounding=999999)
+ self.assertRaises(TypeError, Context, rounding='xyz')
+ self.assertRaises(ValueError, Context, clamp=2)
+ self.assertRaises(ValueError, Context, capitals=-1)
+ self.assertRaises(KeyError, Context, flags=["P"])
+ self.assertRaises(KeyError, Context, traps=["Q"])
+
+ # Type error in conversion
+ self.assertRaises(TypeError, Context, flags=(0,1))
+ self.assertRaises(TypeError, Context, traps=(1,0))
+
+class CContextInputValidation(ContextInputValidation):
+ decimal = C
+class PyContextInputValidation(ContextInputValidation):
+ decimal = P
+
+class ContextSubclassing(unittest.TestCase):
+
+ def test_context_subclassing(self):
+ decimal = self.decimal
+ Decimal = decimal.Decimal
+ Context = decimal.Context
+ ROUND_HALF_EVEN = decimal.ROUND_HALF_EVEN
+ ROUND_DOWN = decimal.ROUND_DOWN
+ Clamped = decimal.Clamped
+ DivisionByZero = decimal.DivisionByZero
+ Inexact = decimal.Inexact
+ Overflow = decimal.Overflow
+ Rounded = decimal.Rounded
+ Subnormal = decimal.Subnormal
+ Underflow = decimal.Underflow
+ InvalidOperation = decimal.InvalidOperation
+
+ class MyContext(Context):
+ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
+ capitals=None, clamp=None, flags=None,
+ traps=None):
+ Context.__init__(self)
+ if prec is not None:
+ self.prec = prec
+ if rounding is not None:
+ self.rounding = rounding
+ if Emin is not None:
+ self.Emin = Emin
+ if Emax is not None:
+ self.Emax = Emax
+ if capitals is not None:
+ self.capitals = capitals
+ if clamp is not None:
+ self.clamp = clamp
+ if flags is not None:
+ if isinstance(flags, list):
+ flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags}
+ self.flags = flags
+ if traps is not None:
+ if isinstance(traps, list):
+ traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps}
+ self.traps = traps
+
+ c = Context()
+ d = MyContext()
+ for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp',
+ 'flags', 'traps'):
+ self.assertEqual(getattr(c, attr), getattr(d, attr))
+
+ # prec
+ self.assertRaises(ValueError, MyContext, **{'prec':-1})
+ c = MyContext(prec=1)
+ self.assertEqual(c.prec, 1)
+ self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0)
+
+ # rounding
+ self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'})
+ c = MyContext(rounding=ROUND_DOWN, prec=1)
+ self.assertEqual(c.rounding, ROUND_DOWN)
+ self.assertEqual(c.plus(Decimal('9.9')), 9)
+
+ # Emin
+ self.assertRaises(ValueError, MyContext, **{'Emin':5})
+ c = MyContext(Emin=-1, prec=1)
+ self.assertEqual(c.Emin, -1)
+ x = c.add(Decimal('1e-99'), Decimal('2.234e-2000'))
+ self.assertEqual(x, Decimal('0.0'))
+ for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped):
+ self.assertTrue(c.flags[signal])
+
+ # Emax
+ self.assertRaises(ValueError, MyContext, **{'Emax':-1})
+ c = MyContext(Emax=1, prec=1)
+ self.assertEqual(c.Emax, 1)
+ self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000'))
+ if self.decimal == C:
+ for signal in (Inexact, Overflow, Rounded):
+ self.assertTrue(c.flags[signal])
+
+ # capitals
+ self.assertRaises(ValueError, MyContext, **{'capitals':-1})
+ c = MyContext(capitals=0)
+ self.assertEqual(c.capitals, 0)
+ x = c.create_decimal('1E222')
+ self.assertEqual(c.to_sci_string(x), '1e+222')
+
+ # clamp
+ self.assertRaises(ValueError, MyContext, **{'clamp':2})
+ c = MyContext(clamp=1, Emax=99)
+ self.assertEqual(c.clamp, 1)
+ x = c.plus(Decimal('1e99'))
+ self.assertEqual(str(x), '1.000000000000000000000000000E+99')
+
+ # flags
+ self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'})
+ c = MyContext(flags=[Rounded, DivisionByZero])
+ for signal in (Rounded, DivisionByZero):
+ self.assertTrue(c.flags[signal])
+ c.clear_flags()
+ for signal in OrderedSignals[decimal]:
+ self.assertFalse(c.flags[signal])
+
+ # traps
+ self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'})
+ c = MyContext(traps=[Rounded, DivisionByZero])
+ for signal in (Rounded, DivisionByZero):
+ self.assertTrue(c.traps[signal])
+ c.clear_traps()
+ for signal in OrderedSignals[decimal]:
+ self.assertFalse(c.traps[signal])
+
+class CContextSubclassing(ContextSubclassing):
+ decimal = C
+class PyContextSubclassing(ContextSubclassing):
+ decimal = P
+
+@skip_if_extra_functionality
+class CheckAttributes(unittest.TestCase):
+
+ def test_module_attributes(self):
+
+ # Architecture dependent context limits
+ self.assertEqual(C.MAX_PREC, P.MAX_PREC)
+ self.assertEqual(C.MAX_EMAX, P.MAX_EMAX)
+ self.assertEqual(C.MIN_EMIN, P.MIN_EMIN)
+ self.assertEqual(C.MIN_ETINY, P.MIN_ETINY)
+
+ self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
+ self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
+
+ self.assertEqual(C.__version__, P.__version__)
+
+ x = dir(C)
+ y = [s for s in dir(P) if '__' in s or not s.startswith('_')]
+ self.assertEqual(set(x) - set(y), {'MallocError'})
+
+ def test_context_attributes(self):
+
+ x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')]
+ y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')]
+ self.assertEqual(set(x) - set(y), set())
+
+ def test_decimal_attributes(self):
+
+ x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
+ y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')]
+ self.assertEqual(set(x) - set(y), set())
+
+class Coverage(unittest.TestCase):
+
+ def test_adjusted(self):
+ Decimal = self.decimal.Decimal
+
+ self.assertEqual(Decimal('1234e9999').adjusted(), 10002)
+ # XXX raise?
+ self.assertEqual(Decimal('nan').adjusted(), 0)
+ self.assertEqual(Decimal('inf').adjusted(), 0)
+
+ def test_canonical(self):
+ Decimal = self.decimal.Decimal
+ getcontext = self.decimal.getcontext
+
+ x = Decimal(9).canonical()
+ self.assertEqual(x, 9)
+
+ c = getcontext()
+ x = c.canonical(Decimal(9))
+ self.assertEqual(x, 9)
+
+ def test_context_repr(self):
+ c = self.decimal.DefaultContext.copy()
+
+ c.prec = 425000000
+ c.Emax = 425000000
+ c.Emin = -425000000
+ c.rounding = self.decimal.ROUND_HALF_DOWN
+ c.capitals = 0
+ c.clamp = 1
+ for sig in OrderedSignals[self.decimal]:
+ c.flags[sig] = False
+ c.traps[sig] = False
+
+ s = c.__repr__()
+ t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
+ "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
+ "flags=[], traps=[])"
+ self.assertEqual(s, t)
+
+ def test_implicit_context(self):
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+
+ with localcontext() as c:
+ c.prec = 1
+ c.Emax = 1
+ c.Emin = -1
+
+ # abs
+ self.assertEqual(abs(Decimal("-10")), 10)
+ # add
+ self.assertEqual(Decimal("7") + 1, 8)
+ # divide
+ self.assertEqual(Decimal("10") / 5, 2)
+ # divide_int
+ self.assertEqual(Decimal("10") // 7, 1)
+ # fma
+ self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1)
+ self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
+ # three arg power
+ self.assertEqual(pow(Decimal(10), 2, 7), 2)
+ # exp
+ self.assertEqual(Decimal("1.01").exp(), 3)
+ # is_normal
+ self.assertIs(Decimal("0.01").is_normal(), False)
+ # is_subnormal
+ self.assertIs(Decimal("0.01").is_subnormal(), True)
+ # ln
+ self.assertEqual(Decimal("20").ln(), 3)
+ # log10
+ self.assertEqual(Decimal("20").log10(), 1)
+ # logb
+ self.assertEqual(Decimal("580").logb(), 2)
+ # logical_invert
+ self.assertEqual(Decimal("10").logical_invert(), 1)
+ # minus
+ self.assertEqual(-Decimal("-10"), 10)
+ # multiply
+ self.assertEqual(Decimal("2") * 4, 8)
+ # next_minus
+ self.assertEqual(Decimal("10").next_minus(), 9)
+ # next_plus
+ self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1'))
+ # normalize
+ self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1'))
+ # number_class
+ self.assertEqual(Decimal("10").number_class(), '+Normal')
+ # plus
+ self.assertEqual(+Decimal("-1"), -1)
+ # remainder
+ self.assertEqual(Decimal("10") % 7, 3)
+ # subtract
+ self.assertEqual(Decimal("10") - 7, 3)
+ # to_integral_exact
+ self.assertEqual(Decimal("1.12345").to_integral_exact(), 1)
+
+ # Boolean functions
+ self.assertTrue(Decimal("1").is_canonical())
+ self.assertTrue(Decimal("1").is_finite())
+ self.assertTrue(Decimal("1").is_finite())
+ self.assertTrue(Decimal("snan").is_snan())
+ self.assertTrue(Decimal("-1").is_signed())
+ self.assertTrue(Decimal("0").is_zero())
+ self.assertTrue(Decimal("0").is_zero())
+
+ # Copy
+ with localcontext() as c:
+ c.prec = 10000
+ x = 1228 ** 1523
+ y = -Decimal(x)
+
+ z = y.copy_abs()
+ self.assertEqual(z, x)
+
+ z = y.copy_negate()
+ self.assertEqual(z, x)
+
+ z = y.copy_sign(Decimal(1))
+ self.assertEqual(z, x)
+
+ def test_divmod(self):
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+ InvalidOperation = self.decimal.InvalidOperation
+ DivisionByZero = self.decimal.DivisionByZero
+
+ with localcontext() as c:
+ q, r = divmod(Decimal("10912837129"), 1001)
+ self.assertEqual(q, Decimal('10901935'))
+ self.assertEqual(r, Decimal('194'))
+
+ q, r = divmod(Decimal("NaN"), 7)
+ self.assertTrue(q.is_nan() and r.is_nan())
+
+ c.traps[InvalidOperation] = False
+ q, r = divmod(Decimal("NaN"), 7)
+ self.assertTrue(q.is_nan() and r.is_nan())
+
+ c.traps[InvalidOperation] = False
+ c.clear_flags()
+ q, r = divmod(Decimal("inf"), Decimal("inf"))
+ self.assertTrue(q.is_nan() and r.is_nan())
+ self.assertTrue(c.flags[InvalidOperation])
+
+ c.clear_flags()
+ q, r = divmod(Decimal("inf"), 101)
+ self.assertTrue(q.is_infinite() and r.is_nan())
+ self.assertTrue(c.flags[InvalidOperation])
+
+ c.clear_flags()
+ q, r = divmod(Decimal(0), 0)
+ self.assertTrue(q.is_nan() and r.is_nan())
+ self.assertTrue(c.flags[InvalidOperation])
+
+ c.traps[DivisionByZero] = False
+ c.clear_flags()
+ q, r = divmod(Decimal(11), 0)
+ self.assertTrue(q.is_infinite() and r.is_nan())
+ self.assertTrue(c.flags[InvalidOperation] and
+ c.flags[DivisionByZero])
+
+ def test_power(self):
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+ Overflow = self.decimal.Overflow
+ Rounded = self.decimal.Rounded
+
+ with localcontext() as c:
+ c.prec = 3
+ c.clear_flags()
+ self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00'))
+ self.assertTrue(c.flags[Rounded])
+
+ c.prec = 1
+ c.Emax = 1
+ c.Emin = -1
+ c.clear_flags()
+ c.traps[Overflow] = False
+ self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf'))
+ self.assertTrue(c.flags[Overflow])
+
+ def test_quantize(self):
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+ InvalidOperation = self.decimal.InvalidOperation
+
+ with localcontext() as c:
+ c.prec = 1
+ c.Emax = 1
+ c.Emin = -1
+ c.traps[InvalidOperation] = False
+ x = Decimal(99).quantize(Decimal("1e1"))
+ self.assertTrue(x.is_nan())
+
+ def test_radix(self):
+ Decimal = self.decimal.Decimal
+ getcontext = self.decimal.getcontext
+
+ c = getcontext()
+ self.assertEqual(Decimal("1").radix(), 10)
+ self.assertEqual(c.radix(), 10)
+
+ def test_rop(self):
+ Decimal = self.decimal.Decimal
+
+ for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__',
+ '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'):
+ self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented)
+
+ def test_round(self):
+ # Python3 behavior: round() returns Decimal
+ Decimal = self.decimal.Decimal
+ getcontext = self.decimal.getcontext
+
+ c = getcontext()
+ c.prec = 28
+
+ self.assertEqual(str(Decimal("9.99").__round__()), "10")
+ self.assertEqual(str(Decimal("9.99e-5").__round__()), "0")
+ self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457")
+ self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000")
+ self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10")
+
+ self.assertRaises(TypeError, Decimal("1.23").__round__, "5")
+ self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8)
+
+ def test_create_decimal(self):
+ c = self.decimal.Context()
+ self.assertRaises(ValueError, c.create_decimal, ["%"])
+
+ def test_int(self):
+ Decimal = self.decimal.Decimal
+ localcontext = self.decimal.localcontext
+
+ with localcontext() as c:
+ c.prec = 9999
+ x = Decimal(1221**1271) / 10**3923
+ self.assertEqual(int(x), 1)
+ self.assertEqual(x.to_integral(), 2)
+
+ def test_copy(self):
+ Context = self.decimal.Context
+
+ c = Context()
+ c.prec = 10000
+ x = -(1172 ** 1712)
+
+ y = c.copy_abs(x)
+ self.assertEqual(y, -x)
+
+ y = c.copy_negate(x)
+ self.assertEqual(y, -x)
+
+ y = c.copy_sign(x, 1)
+ self.assertEqual(y, -x)
+
+class CCoverage(Coverage):
+ decimal = C
+class PyCoverage(Coverage):
+ decimal = P
+
+class PyFunctionality(unittest.TestCase):
+ """Extra functionality in decimal.py"""
+
+ def test_py_quantize_watchexp(self):
+ # watchexp functionality
+ Decimal = P.Decimal
+ localcontext = P.localcontext
+
+ with localcontext() as c:
+ c.prec = 1
+ c.Emax = 1
+ c.Emin = -1
+ x = Decimal(99999).quantize(Decimal("1e3"), watchexp=False)
+ self.assertEqual(x, Decimal('1.00E+5'))
+
+ def test_py_alternate_formatting(self):
+ # triples giving a format, a Decimal, and the expected result
+ Decimal = P.Decimal
+ localcontext = P.localcontext
+
+ test_values = [
+ # Issue 7094: Alternate formatting (specified by #)
+ ('.0e', '1.0', '1e+0'),
+ ('#.0e', '1.0', '1.e+0'),
+ ('.0f', '1.0', '1'),
+ ('#.0f', '1.0', '1.'),
+ ('g', '1.1', '1.1'),
+ ('#g', '1.1', '1.1'),
+ ('.0g', '1', '1'),
+ ('#.0g', '1', '1.'),
+ ('.0%', '1.0', '100%'),
+ ('#.0%', '1.0', '100.%'),
+ ]
+ for fmt, d, result in test_values:
+ self.assertEqual(format(Decimal(d), fmt), result)
+
+class PyWhitebox(unittest.TestCase):
+ """White box testing for decimal.py"""
+
+ def test_py_exact_power(self):
+ # Rarely exercised lines in _power_exact.
+ Decimal = P.Decimal
+ localcontext = P.localcontext
+
+ with localcontext() as c:
+ c.prec = 8
+ x = Decimal(2**16) ** Decimal("-0.5")
+ self.assertEqual(x, Decimal('0.00390625'))
+
+ x = Decimal(2**16) ** Decimal("-0.6")
+ self.assertEqual(x, Decimal('0.0012885819'))
+
+ x = Decimal("256e7") ** Decimal("-0.5")
+
+ x = Decimal(152587890625) ** Decimal('-0.0625')
+ self.assertEqual(x, Decimal("0.2"))
+
+ x = Decimal("152587890625e7") ** Decimal('-0.0625')
+
+ x = Decimal(5**2659) ** Decimal('-0.0625')
+
+ c.prec = 1
+ x = Decimal("152587890625") ** Decimal('-0.5')
+ c.prec = 201
+ x = Decimal(2**578) ** Decimal("-0.5")
+
+ def test_py_immutability_operations(self):
+ # Do operations and check that it didn't change change internal objects.
+ Decimal = P.Decimal
+ DefaultContext = P.DefaultContext
+ setcontext = P.setcontext
+
+ c = DefaultContext.copy()
+ c.traps = dict((s, 0) for s in OrderedSignals[P])
+ setcontext(c)
+
+ d1 = Decimal('-25e55')
+ b1 = Decimal('-25e55')
+ d2 = Decimal('33e+33')
+ b2 = Decimal('33e+33')
+
+ def checkSameDec(operation, useOther=False):
+ if useOther:
+ eval("d1." + operation + "(d2)")
+ self.assertEqual(d1._sign, b1._sign)
+ self.assertEqual(d1._int, b1._int)
+ self.assertEqual(d1._exp, b1._exp)
+ self.assertEqual(d2._sign, b2._sign)
+ self.assertEqual(d2._int, b2._int)
+ self.assertEqual(d2._exp, b2._exp)
+ else:
+ eval("d1." + operation + "()")
+ self.assertEqual(d1._sign, b1._sign)
+ self.assertEqual(d1._int, b1._int)
+ self.assertEqual(d1._exp, b1._exp)
+ return
+
+ Decimal(d1)
+ self.assertEqual(d1._sign, b1._sign)
+ self.assertEqual(d1._int, b1._int)
+ self.assertEqual(d1._exp, b1._exp)
+
+ checkSameDec("__abs__")
+ checkSameDec("__add__", True)
+ checkSameDec("__divmod__", True)
+ checkSameDec("__eq__", True)
+ checkSameDec("__ne__", True)
+ checkSameDec("__le__", True)
+ checkSameDec("__lt__", True)
+ checkSameDec("__ge__", True)
+ checkSameDec("__gt__", True)
+ checkSameDec("__float__")
+ checkSameDec("__floordiv__", True)
+ checkSameDec("__hash__")
+ checkSameDec("__int__")
+ checkSameDec("__trunc__")
+ checkSameDec("__mod__", True)
+ checkSameDec("__mul__", True)
+ checkSameDec("__neg__")
+ checkSameDec("__bool__")
+ checkSameDec("__pos__")
+ checkSameDec("__pow__", True)
+ checkSameDec("__radd__", True)
+ checkSameDec("__rdivmod__", True)
+ checkSameDec("__repr__")
+ checkSameDec("__rfloordiv__", True)
+ checkSameDec("__rmod__", True)
+ checkSameDec("__rmul__", True)
+ checkSameDec("__rpow__", True)
+ checkSameDec("__rsub__", True)
+ checkSameDec("__str__")
+ checkSameDec("__sub__", True)
+ checkSameDec("__truediv__", True)
+ checkSameDec("adjusted")
+ checkSameDec("as_tuple")
+ checkSameDec("compare", True)
+ checkSameDec("max", True)
+ checkSameDec("min", True)
+ checkSameDec("normalize")
+ checkSameDec("quantize", True)
+ checkSameDec("remainder_near", True)
+ checkSameDec("same_quantum", True)
+ checkSameDec("sqrt")
+ checkSameDec("to_eng_string")
+ checkSameDec("to_integral")
+
+ def test_py_decimal_id(self):
+ Decimal = P.Decimal
+
+ d = Decimal(45)
+ e = Decimal(d)
+ self.assertEqual(str(e), '45')
+ self.assertNotEqual(id(d), id(e))
+
+ def test_py_rescale(self):
+ # Coverage
+ Decimal = P.Decimal
+ ROUND_UP = P.ROUND_UP
+ localcontext = P.localcontext
+
+ with localcontext() as c:
+ x = Decimal("NaN")._rescale(3, ROUND_UP)
+ self.assertTrue(x.is_nan())
+
+ def test_py__round(self):
+ # Coverage
+ Decimal = P.Decimal
+ ROUND_UP = P.ROUND_UP
+
+ self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP)
+
+class CFunctionality(unittest.TestCase):
+ """Extra functionality in _decimal"""
+
+ @requires_extra_functionality
+ def test_c_ieee_context(self):
+ # issue 8786: Add support for IEEE 754 contexts to decimal module.
+ IEEEContext = C.IEEEContext
+ DECIMAL32 = C.DECIMAL32
+ DECIMAL64 = C.DECIMAL64
+ DECIMAL128 = C.DECIMAL128
+
+ def assert_rest(self, context):
+ self.assertEqual(context.clamp, 1)
+ assert_signals(self, context, 'traps', [])
+ assert_signals(self, context, 'flags', [])
+
+ c = IEEEContext(DECIMAL32)
+ self.assertEqual(c.prec, 7)
+ self.assertEqual(c.Emax, 96)
+ self.assertEqual(c.Emin, -95)
+ assert_rest(self, c)
+
+ c = IEEEContext(DECIMAL64)
+ self.assertEqual(c.prec, 16)
+ self.assertEqual(c.Emax, 384)
+ self.assertEqual(c.Emin, -383)
+ assert_rest(self, c)
+
+ c = IEEEContext(DECIMAL128)
+ self.assertEqual(c.prec, 34)
+ self.assertEqual(c.Emax, 6144)
+ self.assertEqual(c.Emin, -6143)
+ assert_rest(self, c)
+
+ # Invalid values
+ self.assertRaises(OverflowError, IEEEContext, 2**63)
+ self.assertRaises(ValueError, IEEEContext, -1)
+ self.assertRaises(ValueError, IEEEContext, 1024)
+
+ @requires_extra_functionality
+ def test_c_context(self):
+ Context = C.Context
+
+ c = Context(flags=C.DecClamped, traps=C.DecRounded)
+ self.assertEqual(c._flags, C.DecClamped)
+ self.assertEqual(c._traps, C.DecRounded)
+
+ @requires_extra_functionality
+ def test_constants(self):
+ # Condition flags
+ cond = (
+ C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero,
+ C.DecDivisionImpossible, C.DecDivisionUndefined,
+ C.DecFpuError, C.DecInexact, C.DecInvalidContext,
+ C.DecInvalidOperation, C.DecMallocError,
+ C.DecFloatOperation, C.DecOverflow, C.DecRounded,
+ C.DecSubnormal, C.DecUnderflow
+ )
+
+ # IEEEContext
+ self.assertEqual(C.DECIMAL32, 32)
+ self.assertEqual(C.DECIMAL64, 64)
+ self.assertEqual(C.DECIMAL128, 128)
+ self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512)
+
+ # Rounding modes
+ for i, v in enumerate(RoundingModes[C]):
+ self.assertEqual(v, i)
+ self.assertEqual(C.ROUND_TRUNC, 8)
+
+ # Conditions
+ for i, v in enumerate(cond):
+ self.assertEqual(v, 1<<i)
+
+ self.assertEqual(C.DecIEEEInvalidOperation,
+ C.DecConversionSyntax|
+ C.DecDivisionImpossible|
+ C.DecDivisionUndefined|
+ C.DecFpuError|
+ C.DecInvalidContext|
+ C.DecInvalidOperation|
+ C.DecMallocError)
+
+ self.assertEqual(C.DecErrors,
+ C.DecIEEEInvalidOperation|
+ C.DecDivisionByZero)
+
+ self.assertEqual(C.DecTraps,
+ C.DecErrors|C.DecOverflow|C.DecUnderflow)
+
+class CWhitebox(unittest.TestCase):
+ """Whitebox testing for _decimal"""
+
+ def test_bignum(self):
+ # Not exactly whitebox, but too slow with pydecimal.
+
+ Decimal = C.Decimal
+ localcontext = C.localcontext
+
+ b1 = 10**35
+ b2 = 10**36
+ with localcontext() as c:
+ c.prec = 1000000
+ for i in range(5):
+ a = random.randrange(b1, b2)
+ b = random.randrange(1000, 1200)
+ x = a ** b
+ y = Decimal(a) ** Decimal(b)
+ self.assertEqual(x, y)
+
+ def test_invalid_construction(self):
+ self.assertRaises(TypeError, C.Decimal, 9, "xyz")
+
+ def test_c_input_restriction(self):
+ # Too large for _decimal to be converted exactly
+ Decimal = C.Decimal
+ InvalidOperation = C.InvalidOperation
+ Context = C.Context
+ localcontext = C.localcontext
+
+ with localcontext(Context()):
+ self.assertRaises(InvalidOperation, Decimal,
+ "1e9999999999999999999")
+
+ def test_c_context_repr(self):
+ # This test is _decimal-only because flags are not printed
+ # in the same order.
+ DefaultContext = C.DefaultContext
+ FloatOperation = C.FloatOperation
+ ROUND_HALF_DOWN = C.ROUND_HALF_DOWN
+
+ c = DefaultContext.copy()
+
+ c.prec = 425000000
+ c.Emax = 425000000
+ c.Emin = -425000000
+ c.rounding = ROUND_HALF_DOWN
+ c.capitals = 0
+ c.clamp = 1
+ for sig in OrderedSignals[C]:
+ c.flags[sig] = True
+ c.traps[sig] = True
+ c.flags[FloatOperation] = True
+ c.traps[FloatOperation] = True
+
+ s = c.__repr__()
+ t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \
+ "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \
+ "flags=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
+ "FloatOperation, Overflow, Rounded, Subnormal, Underflow], " \
+ "traps=[Clamped, InvalidOperation, DivisionByZero, Inexact, " \
+ "FloatOperation, Overflow, Rounded, Subnormal, Underflow])"
+ self.assertEqual(s, t)
+
+ def test_c_context_errors(self):
+ Context = C.Context
+ InvalidOperation = C.InvalidOperation
+ Overflow = C.Overflow
+ FloatOperation = C.FloatOperation
+ localcontext = C.localcontext
+ getcontext = C.getcontext
+ setcontext = C.setcontext
+ HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
+
+ c = Context()
+
+ # SignalDict: input validation
+ self.assertRaises(KeyError, c.flags.__setitem__, 801, 0)
+ self.assertRaises(KeyError, c.traps.__setitem__, 801, 0)
+ self.assertRaises(ValueError, c.flags.__delitem__, Overflow)
+ self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation)
+ self.assertRaises(TypeError, setattr, c, 'flags', ['x'])
+ self.assertRaises(TypeError, setattr, c,'traps', ['y'])
+ self.assertRaises(KeyError, setattr, c, 'flags', {0:1})
+ self.assertRaises(KeyError, setattr, c, 'traps', {0:1})
+
+ # Test assignment from a signal dict with the correct length but
+ # one invalid key.
+ d = c.flags.copy()
+ del d[FloatOperation]
+ d["XYZ"] = 91283719
+ self.assertRaises(KeyError, setattr, c, 'flags', d)
+ self.assertRaises(KeyError, setattr, c, 'traps', d)
+
+ # Input corner cases
+ int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
+ gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9
+
+ # prec, Emax, Emin
+ for attr in ['prec', 'Emax']:
+ self.assertRaises(ValueError, setattr, c, attr, gt_max_emax)
+ self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax)
+
+ # prec, Emax, Emin in context constructor
+ self.assertRaises(ValueError, Context, prec=gt_max_emax)
+ self.assertRaises(ValueError, Context, Emax=gt_max_emax)
+ self.assertRaises(ValueError, Context, Emin=-gt_max_emax)
+
+ # Overflow in conversion
+ self.assertRaises(OverflowError, Context, prec=int_max+1)
+ self.assertRaises(OverflowError, Context, Emax=int_max+1)
+ self.assertRaises(OverflowError, Context, Emin=-int_max-2)
+ self.assertRaises(OverflowError, Context, rounding=int_max+1)
+ self.assertRaises(OverflowError, Context, clamp=int_max+1)
+ self.assertRaises(OverflowError, Context, capitals=int_max+1)
+
+ # OverflowError, general ValueError
+ for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'):
+ self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
+ self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
+ if sys.platform != 'win32':
+ self.assertRaises(ValueError, setattr, c, attr, int_max)
+ self.assertRaises(ValueError, setattr, c, attr, -int_max-1)
+
+ # OverflowError, general TypeError
+ for attr in ('rounding',):
+ self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
+ self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
+ if sys.platform != 'win32':
+ self.assertRaises(TypeError, setattr, c, attr, int_max)
+ self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
+
+ # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
+ if C.MAX_PREC == 425000000:
+ self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'),
+ int_max+1)
+ self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'),
+ int_max+1)
+ self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'),
+ -int_max-2)
+
+ # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax
+ if C.MAX_PREC == 425000000:
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0)
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'),
+ 1070000001)
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1)
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'),
+ 1070000001)
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'),
+ -1070000001)
+ self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1)
+
+ # capitals, clamp
+ for attr in ['capitals', 'clamp']:
+ self.assertRaises(ValueError, setattr, c, attr, -1)
+ self.assertRaises(ValueError, setattr, c, attr, 2)
+ self.assertRaises(TypeError, setattr, c, attr, [1,2,3])
+ if HAVE_CONFIG_64:
+ self.assertRaises(ValueError, setattr, c, attr, 2**32)
+ self.assertRaises(ValueError, setattr, c, attr, 2**32+1)
+
+ # Invalid local context
+ self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass',
+ locals())
+
+ # setcontext
+ saved_context = getcontext()
+ self.assertRaises(TypeError, setcontext, "xyz")
+ setcontext(saved_context)
+
+ @requires_extra_functionality
+ def test_c_context_errors_extra(self):
+ Context = C.Context
+ InvalidOperation = C.InvalidOperation
+ Overflow = C.Overflow
+ localcontext = C.localcontext
+ getcontext = C.getcontext
+ setcontext = C.setcontext
+ HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
+
+ c = Context()
+
+ # Input corner cases
+ int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
+
+ # OverflowError, general ValueError
+ self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1)
+ self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2)
+ if sys.platform != 'win32':
+ self.assertRaises(ValueError, setattr, c, '_allcr', int_max)
+ self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1)
+
+ # OverflowError, general TypeError
+ for attr in ('_flags', '_traps'):
+ self.assertRaises(OverflowError, setattr, c, attr, int_max+1)
+ self.assertRaises(OverflowError, setattr, c, attr, -int_max-2)
+ if sys.platform != 'win32':
+ self.assertRaises(TypeError, setattr, c, attr, int_max)
+ self.assertRaises(TypeError, setattr, c, attr, -int_max-1)
+
+ # _allcr
+ self.assertRaises(ValueError, setattr, c, '_allcr', -1)
+ self.assertRaises(ValueError, setattr, c, '_allcr', 2)
+ self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3])
+ if HAVE_CONFIG_64:
+ self.assertRaises(ValueError, setattr, c, '_allcr', 2**32)
+ self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1)
+
+ # _flags, _traps
+ for attr in ['_flags', '_traps']:
+ self.assertRaises(TypeError, setattr, c, attr, 999999)
+ self.assertRaises(TypeError, setattr, c, attr, 'x')
+
+ def test_c_valid_context(self):
+ # These tests are for code coverage in _decimal.
+ DefaultContext = C.DefaultContext
+ ROUND_HALF_UP = C.ROUND_HALF_UP
+ Clamped = C.Clamped
+ Underflow = C.Underflow
+ Inexact = C.Inexact
+ Rounded = C.Rounded
+ Subnormal = C.Subnormal
+
+ c = DefaultContext.copy()
+
+ # Exercise all getters and setters
+ c.prec = 34
+ c.rounding = ROUND_HALF_UP
+ c.Emax = 3000
+ c.Emin = -3000
+ c.capitals = 1
+ c.clamp = 0
+
+ self.assertEqual(c.prec, 34)
+ self.assertEqual(c.rounding, ROUND_HALF_UP)
+ self.assertEqual(c.Emin, -3000)
+ self.assertEqual(c.Emax, 3000)
+ self.assertEqual(c.capitals, 1)
+ self.assertEqual(c.clamp, 0)
+
+ self.assertEqual(c.Etiny(), -3033)
+ self.assertEqual(c.Etop(), 2967)
+
+ # Exercise all unsafe setters
+ if C.MAX_PREC == 425000000:
+ c._unsafe_setprec(999999999)
+ c._unsafe_setemax(999999999)
+ c._unsafe_setemin(-999999999)
+ self.assertEqual(c.prec, 999999999)
+ self.assertEqual(c.Emax, 999999999)
+ self.assertEqual(c.Emin, -999999999)
+
+ @requires_extra_functionality
+ def test_c_valid_context_extra(self):
+ DefaultContext = C.DefaultContext
+
+ c = DefaultContext.copy()
+ self.assertEqual(c._allcr, 1)
+ c._allcr = 0
+ self.assertEqual(c._allcr, 0)
+
+ def test_c_round(self):
+ # Restricted input.
+ Decimal = C.Decimal
+ InvalidOperation = C.InvalidOperation
+ localcontext = C.localcontext
+ MAX_EMAX = C.MAX_EMAX
+ MIN_ETINY = C.MIN_ETINY
+ int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1
+
+ with localcontext() as c:
+ c.traps[InvalidOperation] = True
+ self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
+ -int_max-1)
+ self.assertRaises(InvalidOperation, Decimal("1.23").__round__,
+ int_max)
+ self.assertRaises(InvalidOperation, Decimal("1").__round__,
+ int(MAX_EMAX+1))
+ self.assertRaises(C.InvalidOperation, Decimal("1").__round__,
+ -int(MIN_ETINY-1))
+ self.assertRaises(OverflowError, Decimal("1.23").__round__,
+ -int_max-2)
+ self.assertRaises(OverflowError, Decimal("1.23").__round__,
+ int_max+1)
+
+ def test_c_format(self):
+ # Restricted input
+ Decimal = C.Decimal
+ InvalidOperation = C.InvalidOperation
+ Rounded = C.Rounded
+ localcontext = C.localcontext
+ HAVE_CONFIG_64 = (C.MAX_PREC > 425000000)
+
+ self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9)
+ self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9)
+ self.assertRaises(TypeError, Decimal(1).__format__, [])
+
+ with localcontext() as c:
+ c.traps[InvalidOperation] = True
+ c.traps[Rounded] = True
+ self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10")
+ maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1
+ self.assertRaises(InvalidOperation, Decimal("1.23456789").__format__,
+ "=%d.1" % maxsize)
+
+ def test_c_integral(self):
+ Decimal = C.Decimal
+ Inexact = C.Inexact
+ ROUND_UP = C.ROUND_UP
+ localcontext = C.localcontext
+
+ x = Decimal(10)
+ self.assertEqual(x.to_integral(), 10)
+ self.assertRaises(TypeError, x.to_integral, '10')
+ self.assertRaises(TypeError, x.to_integral, 10, 'x')
+ self.assertRaises(TypeError, x.to_integral, 10)
+
+ self.assertEqual(x.to_integral_value(), 10)
+ self.assertRaises(TypeError, x.to_integral_value, '10')
+ self.assertRaises(TypeError, x.to_integral_value, 10, 'x')
+ self.assertRaises(TypeError, x.to_integral_value, 10)
+
+ self.assertEqual(x.to_integral_exact(), 10)
+ self.assertRaises(TypeError, x.to_integral_exact, '10')
+ self.assertRaises(TypeError, x.to_integral_exact, 10, 'x')
+ self.assertRaises(TypeError, x.to_integral_exact, 10)
+
+ with localcontext() as c:
+ x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP)
+ self.assertEqual(x, Decimal('100000000000000000000000000'))
+
+ x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP)
+ self.assertEqual(x, Decimal('100000000000000000000000000'))
+
+ c.traps[Inexact] = True
+ self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP)
+
+ def test_c_funcs(self):
+ # Invalid arguments
+ Decimal = C.Decimal
+ InvalidOperation = C.InvalidOperation
+ DivisionByZero = C.DivisionByZero
+ ROUND_UP = C.ROUND_UP
+ getcontext = C.getcontext
+ localcontext = C.localcontext
+
+ self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9')
+
+ self.assertRaises(TypeError, pow, Decimal(1), 2, "3")
+ self.assertRaises(TypeError, Decimal(9).number_class, "x", "y")
+ self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y")
+
+ self.assertRaises(
+ TypeError,
+ Decimal("1.23456789").quantize, Decimal('1e-100000'), []
+ )
+ self.assertRaises(
+ TypeError,
+ Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext()
+ )
+ self.assertRaises(
+ TypeError,
+ Decimal("1.23456789").quantize, Decimal('1e-100000'), 10
+ )
+ self.assertRaises(
+ TypeError,
+ Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000
+ )
+
+ with localcontext() as c:
+ c.clear_traps()
+
+ # Invalid arguments
+ self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y")
+ self.assertRaises(TypeError, c.canonical, 200)
+ self.assertRaises(TypeError, c.is_canonical, 200)
+ self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y")
+ self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y")
+
+ self.assertEqual(str(c.canonical(Decimal(200))), '200')
+ self.assertEqual(c.radix(), 10)
+
+ c.traps[DivisionByZero] = True
+ self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0)
+ self.assertRaises(DivisionByZero, c.divmod, 9, 0)
+ self.assertTrue(c.flags[InvalidOperation])
+
+ c.clear_flags()
+ c.traps[InvalidOperation] = True
+ self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0)
+ self.assertRaises(InvalidOperation, c.divmod, 9, 0)
+ self.assertTrue(c.flags[DivisionByZero])
+
+ c.traps[InvalidOperation] = True
+ c.prec = 2
+ self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501)
+
+ @requires_extra_functionality
+ def test_c_context_templates(self):
+ self.assertEqual(
+ C.BasicContext._traps,
+ C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow|
+ C.DecUnderflow|C.DecClamped
+ )
+ self.assertEqual(
+ C.DefaultContext._traps,
+ C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow
+ )
+
+ @requires_extra_functionality
+ def test_c_signal_dict(self):
+
+ # SignalDict coverage
+ Context = C.Context
+ DefaultContext = C.DefaultContext
+
+ InvalidOperation = C.InvalidOperation
+ DivisionByZero = C.DivisionByZero
+ Overflow = C.Overflow
+ Subnormal = C.Subnormal
+ Underflow = C.Underflow
+ Rounded = C.Rounded
+ Inexact = C.Inexact
+ Clamped = C.Clamped
+
+ DecClamped = C.DecClamped
+ DecInvalidOperation = C.DecInvalidOperation
+ DecIEEEInvalidOperation = C.DecIEEEInvalidOperation
+
+ def assertIsExclusivelySet(signal, signal_dict):
+ for sig in signal_dict:
+ if sig == signal:
+ self.assertTrue(signal_dict[sig])
+ else:
+ self.assertFalse(signal_dict[sig])
+
+ c = DefaultContext.copy()
+
+ # Signal dict methods
+ self.assertTrue(Overflow in c.traps)
+ c.clear_traps()
+ for k in c.traps.keys():
+ c.traps[k] = True
+ for v in c.traps.values():
+ self.assertTrue(v)
+ c.clear_traps()
+ for k, v in c.traps.items():
+ self.assertFalse(v)
+
+ self.assertFalse(c.flags.get(Overflow))
+ self.assertIs(c.flags.get("x"), None)
+ self.assertEqual(c.flags.get("x", "y"), "y")
+ self.assertRaises(TypeError, c.flags.get, "x", "y", "z")
+
+ self.assertEqual(len(c.flags), len(c.traps))
+ s = sys.getsizeof(c.flags)
+ s = sys.getsizeof(c.traps)
+ s = c.flags.__repr__()
+
+ # Set flags/traps.
+ c.clear_flags()
+ c._flags = DecClamped
+ self.assertTrue(c.flags[Clamped])
+
+ c.clear_traps()
+ c._traps = DecInvalidOperation
+ self.assertTrue(c.traps[InvalidOperation])
+
+ # Set flags/traps from dictionary.
+ c.clear_flags()
+ d = c.flags.copy()
+ d[DivisionByZero] = True
+ c.flags = d
+ assertIsExclusivelySet(DivisionByZero, c.flags)
+
+ c.clear_traps()
+ d = c.traps.copy()
+ d[Underflow] = True
+ c.traps = d
+ assertIsExclusivelySet(Underflow, c.traps)
+
+ # Random constructors
+ IntSignals = {
+ Clamped: C.DecClamped,
+ Rounded: C.DecRounded,
+ Inexact: C.DecInexact,
+ Subnormal: C.DecSubnormal,
+ Underflow: C.DecUnderflow,
+ Overflow: C.DecOverflow,
+ DivisionByZero: C.DecDivisionByZero,
+ InvalidOperation: C.DecIEEEInvalidOperation
+ }
+ IntCond = [
+ C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError,
+ C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError,
+ C.DecConversionSyntax,
+ ]
+
+ lim = len(OrderedSignals[C])
+ for r in range(lim):
+ for t in range(lim):
+ for round in RoundingModes[C]:
+ flags = random.sample(OrderedSignals[C], r)
+ traps = random.sample(OrderedSignals[C], t)
+ prec = random.randrange(1, 10000)
+ emin = random.randrange(-10000, 0)
+ emax = random.randrange(0, 10000)
+ clamp = random.randrange(0, 2)
+ caps = random.randrange(0, 2)
+ cr = random.randrange(0, 2)
+ c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax,
+ capitals=caps, clamp=clamp, flags=list(flags),
+ traps=list(traps))
+
+ self.assertEqual(c.prec, prec)
+ self.assertEqual(c.rounding, round)
+ self.assertEqual(c.Emin, emin)
+ self.assertEqual(c.Emax, emax)
+ self.assertEqual(c.capitals, caps)
+ self.assertEqual(c.clamp, clamp)
+
+ f = 0
+ for x in flags:
+ f |= IntSignals[x]
+ self.assertEqual(c._flags, f)
+
+ f = 0
+ for x in traps:
+ f |= IntSignals[x]
+ self.assertEqual(c._traps, f)
+
+ for cond in IntCond:
+ c._flags = cond
+ self.assertTrue(c._flags&DecIEEEInvalidOperation)
+ assertIsExclusivelySet(InvalidOperation, c.flags)
+
+ for cond in IntCond:
+ c._traps = cond
+ self.assertTrue(c._traps&DecIEEEInvalidOperation)
+ assertIsExclusivelySet(InvalidOperation, c.traps)
+
+ def test_invalid_override(self):
+ Decimal = C.Decimal
+
+ try:
+ from locale import CHAR_MAX
+ except ImportError:
+ return
+
+ def make_grouping(lst):
+ return ''.join([chr(x) for x in lst])
+
+ def get_fmt(x, override=None, fmt='n'):
+ return Decimal(x).__format__(fmt, override)
+
+ invalid_grouping = {
+ 'decimal_point' : ',',
+ 'grouping' : make_grouping([255, 255, 0]),
+ 'thousands_sep' : ','
+ }
+ invalid_dot = {
+ 'decimal_point' : 'xxxxx',
+ 'grouping' : make_grouping([3, 3, 0]),
+ 'thousands_sep' : ','
+ }
+ invalid_sep = {
+ 'decimal_point' : '.',
+ 'grouping' : make_grouping([3, 3, 0]),
+ 'thousands_sep' : 'yyyyy'
+ }
+
+ if CHAR_MAX == 127: # negative grouping in override
+ self.assertRaises(ValueError, get_fmt, 12345,
+ invalid_grouping, 'g')
+
+ self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g')
+ self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g')
+
+
+all_tests = [
+ CExplicitConstructionTest, PyExplicitConstructionTest,
+ CImplicitConstructionTest, PyImplicitConstructionTest,
+ CFormatTest, PyFormatTest,
+ CArithmeticOperatorsTest, PyArithmeticOperatorsTest,
+ CThreadingTest, PyThreadingTest,
+ CUsabilityTest, PyUsabilityTest,
+ CPythonAPItests, PyPythonAPItests,
+ CContextAPItests, PyContextAPItests,
+ CContextWithStatement, PyContextWithStatement,
+ CContextFlags, PyContextFlags,
+ CSpecialContexts, PySpecialContexts,
+ CContextInputValidation, PyContextInputValidation,
+ CContextSubclassing, PyContextSubclassing,
+ CCoverage, PyCoverage,
+ CFunctionality, PyFunctionality,
+ CWhitebox, PyWhitebox,
+ CIBMTestCases, PyIBMTestCases,
+]
+
+# Delete C tests if _decimal.so is not present.
+if not C:
+ all_tests = all_tests[1::2]
+else:
+ all_tests.insert(0, CheckAttributes)
+
+
def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
""" Execute the tests.
@@ -2366,27 +4948,16 @@ def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
is enabled in regrtest.py
"""
- init()
+ init(C)
+ init(P)
global TEST_ALL, DEBUG
TEST_ALL = arith or is_resource_enabled('decimal')
DEBUG = debug
if todo_tests is None:
- test_classes = [
- DecimalExplicitConstructionTest,
- DecimalImplicitConstructionTest,
- DecimalArithmeticOperatorsTest,
- DecimalFormatTest,
- DecimalUseOfContextTest,
- DecimalUsabilityTest,
- DecimalPythonAPItests,
- ContextAPItests,
- DecimalTest,
- WithStatementTest,
- ContextFlags
- ]
+ test_classes = all_tests
else:
- test_classes = [DecimalTest]
+ test_classes = [CIBMTestCases, PyIBMTestCases]
# Dynamically build custom test definition for each file in the test
# directory and add the definitions to the DecimalTest class. This
@@ -2398,17 +4969,32 @@ def test_main(arith=False, verbose=None, todo_tests=None, debug=None):
if todo_tests is not None and head not in todo_tests:
continue
tester = lambda self, f=filename: self.eval_file(directory + f)
- setattr(DecimalTest, 'test_' + head, tester)
+ setattr(CIBMTestCases, 'test_' + head, tester)
+ setattr(PyIBMTestCases, 'test_' + head, tester)
del filename, head, tail, tester
try:
run_unittest(*test_classes)
if todo_tests is None:
- import decimal as DecimalModule
- run_doctest(DecimalModule, verbose)
+ from doctest import IGNORE_EXCEPTION_DETAIL
+ savedecimal = sys.modules['decimal']
+ if C:
+ sys.modules['decimal'] = C
+ run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL)
+ sys.modules['decimal'] = P
+ run_doctest(P, verbose)
+ sys.modules['decimal'] = savedecimal
finally:
- setcontext(ORIGINAL_CONTEXT)
+ if C: C.setcontext(ORIGINAL_CONTEXT[C])
+ P.setcontext(ORIGINAL_CONTEXT[P])
+ if not C:
+ warnings.warn('C tests skipped: no module named _decimal.',
+ UserWarning)
+ if not orig_sys_decimal is sys.modules['decimal']:
+ raise TestFailed("Internal error: unbalanced number of changes to "
+ "sys.modules['decimal'].")
+
if __name__ == '__main__':
import optparse
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 084ae0c..1fad921 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -401,14 +401,10 @@ class FractionTest(unittest.TestCase):
def testMixingWithDecimal(self):
# Decimal refuses mixed arithmetic (but not mixed comparisons)
- self.assertRaisesMessage(
- TypeError,
- "unsupported operand type(s) for +: 'Fraction' and 'Decimal'",
- operator.add, F(3,11), Decimal('3.1415926'))
- self.assertRaisesMessage(
- TypeError,
- "unsupported operand type(s) for +: 'Decimal' and 'Fraction'",
- operator.add, Decimal('3.1415926'), F(3,11))
+ self.assertRaises(TypeError, operator.add,
+ F(3,11), Decimal('3.1415926'))
+ self.assertRaises(TypeError, operator.add,
+ Decimal('3.1415926'), F(3,11))
def testComparisons(self):
self.assertTrue(F(1, 2) < F(2, 3))
diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py
index bef3d4c..3423d4e 100644
--- a/Lib/test/test_numeric_tower.py
+++ b/Lib/test/test_numeric_tower.py
@@ -150,7 +150,7 @@ class ComparisonTest(unittest.TestCase):
# int, float, Fraction, Decimal
test_values = [
float('-inf'),
- D('-1e999999999'),
+ D('-1e425000000'),
-1e308,
F(-22, 7),
-3.14,
diff --git a/Misc/NEWS b/Misc/NEWS
index 9a6cc44..17716b5 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,10 @@ Core and Builtins
Library
-------
+- 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.
+
- Issue #3573: IDLE hangs when passing invalid command line args
(directory(ies) instead of file(s)) (Patch by Guilherme Polo)
diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp
index 95e1b9e..81a07c9 100644
--- a/Misc/valgrind-python.supp
+++ b/Misc/valgrind-python.supp
@@ -456,3 +456,16 @@
fun:PyUnicode_FSConverter
}
+# Additional suppressions for the unified decimal tests:
+{
+ test_decimal
+ Memcheck:Addr4
+ fun:PyUnicodeUCS2_FSConverter
+}
+
+{
+ test_decimal2
+ Memcheck:Addr4
+ fun:PyUnicode_FSConverter
+}
+
diff --git a/Modules/_decimal/ISSUES.txt b/Modules/_decimal/ISSUES.txt
new file mode 100644
index 0000000..7a545c2
--- /dev/null
+++ b/Modules/_decimal/ISSUES.txt
@@ -0,0 +1,56 @@
+
+
+Normal priority:
+----------------
+
+1) Add C-API importable as capsule.
+
+2) Add --with-system-libmpdec to ./configure.
+
+3) Use same default emin/emax on 32-bit (MAX_EMAX=425000000) and 64-bit
+ (MAX_EMAX=10**18-1).
+
+4) Order of arguments in Context().
+
+5) Documentation.
+
+6) quantize()
+ - exp argument is misleading:
+ Decimal('0.321000e+2').quantize(exp=9) -> user might expect
+ that the result will have exp=9.
+ - watchexp
+
+7) Match the exception hierarchy of decimal.py:
+
+ exceptions.ArithmeticError(exceptions.Exception)
+ DecimalException
+ Clamped
+ DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
+ Inexact
+ Overflow(Inexact, Rounded)
+ Underflow(Inexact, Rounded, Subnormal)
+ InvalidOperation
+ Rounded
+ Subnormal
+ FloatOperation
+
+
+Low priority:
+-------------
+
+1) Convert tabs (wait until commit).
+
+2) Pre-ANSI compilers require '#' in the first column (should be done
+ for the whole Python source tree if we support such compilers). (?)
+
+3) FETCH_CURRENT_CONTEXT vs. CURRENT_CONTEXT?
+
+4) Justify remaining uses of exit on overflow in bignum arith. Short
+ answer: with correct context values the coefficients never get big
+ enough for that to happen.
+
+5) Justify remaining uses of abort() in mpdecimal: These uses are
+ for debug purposes and can't be reached when the library is used
+ correctly.
+
+
diff --git a/Modules/_decimal/README.txt b/Modules/_decimal/README.txt
new file mode 100644
index 0000000..3b17cff
--- /dev/null
+++ b/Modules/_decimal/README.txt
@@ -0,0 +1,46 @@
+
+
+About
+=====
+
+_decimal.c is a wrapper for the libmpdec library. libmpdec is a fast C
+library for correctly-rounded arbitrary precision decimal floating point
+arithmetic. It is a complete implementation of Mike Cowlishaw/IBM's
+General Decimal Arithmetic Specification.
+
+
+Build process for the module
+============================
+
+As usual, the build process for _decimal.so is driven by setup.py in the top
+level directory. setup.py autodetects the following build configurations:
+
+ 1) x64 - 64-bit Python, x86_64 processor (AMD, Intel)
+
+ 2) uint128 - 64-bit Python, compiler provides __uint128_t (gcc)
+
+ 3) ansi64 - 64-bit Python, ANSI C
+
+ 4) ppro - 32-bit Python, x86 CPU, PentiumPro or later
+
+ 5) ansi32 - 32-bit Python, ANSI C
+
+ 6) ansi-legacy - 32-bit Python, compiler without uint64_t
+
+ 7) universal - Mac OS only (multi-arch)
+
+
+It is possible to override autodetection by exporting:
+
+ PYTHON_DECIMAL_WITH_MACHINE=value, where value is one of the above options.
+
+
+NOTE
+====
+
+decimal.so is not built from a static libmpdec.a since doing so led to
+failures on AIX (user report) and Windows (mixing static and dynamic CRTs
+causes locale problems and more).
+
+
+
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
new file mode 100644
index 0000000..8a439c4
--- /dev/null
+++ b/Modules/_decimal/_decimal.c
@@ -0,0 +1,5512 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <Python.h>
+#include "longintrepr.h"
+#include "pythread.h"
+#include "structmember.h"
+#include "complexobject.h"
+#include "mpdecimal.h"
+
+#include <stdlib.h>
+
+#include "docstrings.h"
+#include "memory.h"
+
+
+/*
+ * Type sizes with assertions in mpdecimal.h and pyport.h:
+ * sizeof(size_t) == sizeof(Py_ssize_t)
+ * sizeof(size_t) == sizeof(mpd_uint_t) == sizeof(mpd_ssize_t)
+ */
+
+#ifdef TEST_COVERAGE
+ #undef Py_LOCAL_INLINE
+ #define Py_LOCAL_INLINE Py_LOCAL
+#endif
+
+#define MPD_Float_operation MPD_Not_implemented
+
+#define BOUNDS_CHECK(x, MIN, MAX) x = (x < MIN || MAX < x) ? MAX : x
+
+
+typedef struct {
+ PyObject_HEAD
+ mpd_t *dec;
+} PyDecObject;
+
+typedef struct {
+ PyObject_HEAD
+ uint32_t *flags;
+} PyDecSignalDictObject;
+
+typedef struct {
+ PyObject_HEAD
+ mpd_context_t ctx;
+ PyObject *traps;
+ PyObject *flags;
+ int capitals;
+} PyDecContextObject;
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *local;
+ PyObject *global;
+} PyDecContextManagerObject;
+
+
+#undef MPD
+#undef CTX
+static PyTypeObject PyDec_Type;
+static PyTypeObject *PyDecSignalDict_Type;
+static PyTypeObject PyDecContext_Type;
+static PyTypeObject PyDecContextManager_Type;
+#define PyDec_CheckExact(v) (Py_TYPE(v) == &PyDec_Type)
+#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type)
+#define PyDecSignalDict_Check(v) (Py_TYPE(v) == PyDecSignalDict_Type)
+#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type)
+#define MPD(v) (((PyDecObject *)v)->dec)
+#define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags)
+#define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags)
+#define CTX(v) (&((PyDecContextObject *)v)->ctx)
+#define CtxCaps(v) (((PyDecContextObject *)v)->capitals)
+
+
+Py_LOCAL_INLINE(PyObject *)
+incr_true(void)
+{
+ Py_INCREF(Py_True);
+ return Py_True;
+}
+
+Py_LOCAL_INLINE(PyObject *)
+incr_false(void)
+{
+ Py_INCREF(Py_False);
+ return Py_False;
+}
+
+
+#ifdef WITHOUT_THREADS
+/* Default module context */
+static PyObject *module_context = NULL;
+#else
+/* Key for thread state dictionary */
+static PyObject *tls_context_key = NULL;
+#endif
+
+/* Template for creating new thread contexts, calling Context() without
+ * arguments and initializing the module_context on first access. */
+static PyObject *default_context_template = NULL;
+/* Basic and extended context templates */
+static PyObject *basic_context_template = NULL;
+static PyObject *extended_context_template = NULL;
+
+
+/* Error codes for functions that return signals or conditions */
+#define DEC_INVALID_SIGNALS (MPD_Max_status+1U)
+#define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1)
+#define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED)
+
+typedef struct {
+ const char *name; /* condition or signal name */
+ const char *fqname; /* fully qualified name */
+ uint32_t flag; /* libmpdec flag */
+ PyObject *ex; /* corresponding exception */
+} DecCondMap;
+
+/* Top level Exception; inherits from ArithmeticError */
+static PyObject *DecimalException = NULL;
+
+/* Exceptions that correspond to IEEE signals; inherit from DecimalException */
+#define SIGNAL_MAP_LEN 9
+static DecCondMap signal_map[] = {
+ {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL},
+ {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL},
+ {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL},
+ {"Overflow", "decimal.Overflow", MPD_Overflow, NULL},
+ {"Underflow", "decimal.Underflow", MPD_Underflow, NULL},
+ {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL},
+ {"Inexact", "decimal.Inexact", MPD_Inexact, NULL},
+ {"Rounded", "decimal.Rounded", MPD_Rounded, NULL},
+ {"Clamped", "decimal.Clamped", MPD_Clamped, NULL},
+ {NULL}
+};
+
+/* Exceptions that inherit from InvalidOperation */
+static DecCondMap cond_map[] = {
+ {"InvalidOperation", "decimal.InvalidOperation", MPD_Invalid_operation, NULL},
+ {"ConversionSyntax", "decimal.ConversionSyntax", MPD_Conversion_syntax, NULL},
+ {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL},
+ {"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL},
+ {"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL},
+ {"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL},
+ {NULL}
+};
+
+static const char *dec_signal_string[MPD_NUM_FLAGS] = {
+ "Clamped",
+ "InvalidOperation",
+ "DivisionByZero",
+ "InvalidOperation",
+ "InvalidOperation",
+ "InvalidOperation",
+ "Inexact",
+ "InvalidOperation",
+ "InvalidOperation",
+ "InvalidOperation",
+ "FloatOperation",
+ "Overflow",
+ "Rounded",
+ "Subnormal",
+ "Underflow",
+};
+
+static const char *invalid_rounding_err =
+"valid values for rounding are:\n\
+ [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\
+ ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,\n\
+ ROUND_05UP]";
+
+static const char *invalid_signals_err =
+"valid values for signals are:\n\
+ [InvalidOperation, FloatOperation, DivisionByZero,\n\
+ Overflow, Underflow, Subnormal, Inexact, Rounded,\n\
+ Clamped]";
+
+#ifdef EXTRA_FUNCTIONALITY
+static const char *invalid_flags_err =
+"valid values for _flags or _traps are:\n\
+ signals:\n\
+ [DecIEEEInvalidOperation, DecFloatOperation, DecDivisionByZero,\n\
+ DecOverflow, DecUnderflow, DecSubnormal, DecInexact, DecRounded,\n\
+ DecClamped]\n\
+ conditions which trigger DecIEEEInvalidOperation:\n\
+ [DecInvalidOperation, DecConversionSyntax, DecDivisionImpossible,\n\
+ DecDivisionUndefined, DecFpuError, DecInvalidContext, DecMallocError]";
+#endif
+
+static int
+value_error_int(const char *mesg)
+{
+ PyErr_SetString(PyExc_ValueError, mesg);
+ return -1;
+}
+
+#ifdef CONFIG_32
+static PyObject *
+value_error_ptr(const char *mesg)
+{
+ PyErr_SetString(PyExc_ValueError, mesg);
+ return NULL;
+}
+#endif
+
+static int
+type_error_int(const char *mesg)
+{
+ PyErr_SetString(PyExc_TypeError, mesg);
+ return -1;
+}
+
+static PyObject *
+type_error_ptr(const char *mesg)
+{
+ PyErr_SetString(PyExc_TypeError, mesg);
+ return NULL;
+}
+
+static int
+runtime_error_int(const char *mesg)
+{
+ PyErr_SetString(PyExc_RuntimeError, mesg);
+ return -1;
+}
+#define INTERNAL_ERROR_INT(funcname) \
+ return runtime_error_int("internal error in " funcname)
+
+static PyObject *
+runtime_error_ptr(const char *mesg)
+{
+ PyErr_SetString(PyExc_RuntimeError, mesg);
+ return NULL;
+}
+#define INTERNAL_ERROR_PTR(funcname) \
+ return runtime_error_ptr("internal error in " funcname)
+
+static void
+dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */
+{ /* GCOV_NOT_REACHED */
+ return; /* GCOV_NOT_REACHED */
+}
+
+static PyObject *
+flags_as_exception(uint32_t flags)
+{
+ DecCondMap *cm;
+
+ for (cm = signal_map; cm->name != NULL; cm++) {
+ if (flags&cm->flag) {
+ return cm->ex;
+ }
+ }
+
+ INTERNAL_ERROR_PTR("flags_as_exception"); /* GCOV_NOT_REACHED */
+}
+
+Py_LOCAL_INLINE(uint32_t)
+exception_as_flag(PyObject *ex)
+{
+ DecCondMap *cm;
+
+ for (cm = signal_map; cm->name != NULL; cm++) {
+ if (cm->ex == ex) {
+ return cm->flag;
+ }
+ }
+
+ PyErr_SetString(PyExc_KeyError, invalid_signals_err);
+ return DEC_INVALID_SIGNALS;
+}
+
+static PyObject *
+flags_as_list(uint32_t flags)
+{
+ PyObject *list;
+ DecCondMap *cm;
+
+ list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ for (cm = cond_map; cm->name != NULL; cm++) {
+ if (flags&cm->flag) {
+ if (PyList_Append(list, cm->ex) < 0) {
+ goto error;
+ }
+ }
+ }
+ for (cm = signal_map+1; cm->name != NULL; cm++) {
+ if (flags&cm->flag) {
+ if (PyList_Append(list, cm->ex) < 0) {
+ goto error;
+ }
+ }
+ }
+
+ return list;
+
+error:
+ Py_DECREF(list);
+ return NULL;
+}
+
+static PyObject *
+signals_as_list(uint32_t flags)
+{
+ PyObject *list;
+ DecCondMap *cm;
+
+ list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ for (cm = signal_map; cm->name != NULL; cm++) {
+ if (flags&cm->flag) {
+ if (PyList_Append(list, cm->ex) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ }
+ }
+
+ return list;
+}
+
+static uint32_t
+list_as_flags(PyObject *list)
+{
+ PyObject *item;
+ uint32_t flags, x;
+ Py_ssize_t n, j;
+
+ assert(PyList_Check(list));
+
+ n = PyList_Size(list);
+ flags = 0;
+ for (j = 0; j < n; j++) {
+ item = PyList_GetItem(list, j);
+ x = exception_as_flag(item);
+ if (x & DEC_ERRORS) {
+ return x;
+ }
+ flags |= x;
+ }
+
+ return flags;
+}
+
+static PyObject *
+flags_as_dict(uint32_t flags)
+{
+ DecCondMap *cm;
+ PyObject *dict;
+
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+ for (cm = signal_map; cm->name != NULL; cm++) {
+ PyObject *b = flags&cm->flag ? Py_True : Py_False;
+ if (PyDict_SetItem(dict, cm->ex, b) < 0) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ }
+
+ return dict;
+}
+
+static uint32_t
+dict_as_flags(PyObject *val)
+{
+ PyObject *b;
+ DecCondMap *cm;
+ uint32_t flags = 0;
+ int x;
+
+ if (!PyDict_Check(val)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a signal dict");
+ return DEC_INVALID_SIGNALS;
+ }
+
+ if (PyDict_Size(val) != SIGNAL_MAP_LEN) {
+ PyErr_SetString(PyExc_KeyError,
+ "invalid signal dict");
+ return DEC_INVALID_SIGNALS;
+ }
+
+ for (cm = signal_map; cm->name != NULL; cm++) {
+ b = PyDict_GetItemWithError(val, cm->ex);
+ if (b == NULL) {
+ if (PyErr_Occurred()) {
+ return DEC_ERR_OCCURRED;
+ }
+ PyErr_SetString(PyExc_KeyError,
+ "invalid signal dict");
+ return DEC_INVALID_SIGNALS;
+ }
+
+ x = PyObject_IsTrue(b);
+ if (x < 0) {
+ return DEC_ERR_OCCURRED;
+ }
+ if (x == 1) {
+ flags |= cm->flag;
+ }
+ }
+
+ return flags;
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+static uint32_t
+long_as_flags(PyObject *v)
+{
+ long x;
+
+ x = PyLong_AsLong(v);
+ if (x == -1 && PyErr_Occurred()) {
+ return DEC_ERR_OCCURRED;
+ }
+ if (x < 0 || x > (long)MPD_Max_status) {
+ PyErr_SetString(PyExc_TypeError, invalid_flags_err);
+ return DEC_INVALID_SIGNALS;
+ }
+
+ return x;
+}
+#endif
+
+static int
+dec_addstatus(PyObject *context, uint32_t status)
+{
+ mpd_context_t *ctx = CTX(context);
+
+ ctx->status |= status;
+ if (ctx->traps&status) {
+ PyObject *ex, *siglist;
+
+ ex = flags_as_exception(ctx->traps&status);
+ if (ex == NULL) {
+ return 1; /* GCOV_NOT_REACHED */
+ }
+ siglist = flags_as_list(ctx->traps&status);
+ if (siglist == NULL) {
+ return 1;
+ }
+
+ PyErr_SetObject(ex, siglist);
+ Py_DECREF(siglist);
+ return 1;
+ }
+ return 0;
+}
+
+
+/******************************************************************************/
+/* SignalDict Object */
+/******************************************************************************/
+
+/* The SignalDict is a MutableMapping that provides access to the
+ mpd_context_t flags, which reside in the context object. When a
+ new context is created, context.traps and context.flags are
+ initialized to new SignalDicts. Once a SignalDict is tied to
+ a context, it cannot be deleted. */
+
+static int
+signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED)
+{
+ SdFlagAddr(self) = NULL;
+ return 0;
+}
+
+static Py_ssize_t
+signaldict_len(PyObject *self UNUSED)
+{
+ return SIGNAL_MAP_LEN;
+}
+
+static PyObject *SignalTuple;
+static PyObject *
+signaldict_iter(PyObject *self UNUSED)
+{
+ return PyTuple_Type.tp_iter(SignalTuple);
+}
+
+static PyObject *
+signaldict_getitem(PyObject *self, PyObject *key)
+{
+ uint32_t flag;
+
+ flag = exception_as_flag(key);
+ if (flag & DEC_ERRORS) {
+ return NULL;
+ }
+
+ return SdFlags(self)&flag ? incr_true() : incr_false();
+}
+
+static int
+signaldict_setitem(PyObject *self, PyObject *key, PyObject *value)
+{
+ uint32_t flag;
+ int x;
+
+ if (value == NULL) {
+ return value_error_int("signal keys cannot be deleted");
+ }
+
+ flag = exception_as_flag(key);
+ if (flag & DEC_ERRORS) {
+ return -1;
+ }
+
+ x = PyObject_IsTrue(value);
+ if (x < 0) {
+ return -1;
+ }
+
+ if (x == 1) {
+ SdFlags(self) |= flag;
+ }
+ else {
+ SdFlags(self) &= ~flag;
+ }
+
+ return 0;
+}
+
+static PyObject *
+signaldict_repr(PyObject *self)
+{
+ DecCondMap *cm;
+ const char *n[SIGNAL_MAP_LEN]; /* name */
+ const char *b[SIGNAL_MAP_LEN]; /* bool */
+ int i;
+
+ assert(SIGNAL_MAP_LEN == 9);
+
+ for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
+ n[i] = cm->fqname;
+ b[i] = SdFlags(self)&cm->flag ? "True" : "False";
+ }
+ return PyUnicode_FromFormat(
+ "{<class '%s'>:%s, <class '%s'>:%s, <class '%s'>:%s, "
+ "<class '%s'>:%s, <class '%s'>:%s, <class '%s'>:%s, "
+ "<class '%s'>:%s, <class '%s'>:%s, <class '%s'>:%s}",
+ n[0], b[0], n[1], b[1], n[2], b[2],
+ n[3], b[3], n[4], b[4], n[5], b[5],
+ n[6], b[6], n[7], b[7], n[8], b[8]);
+}
+
+static PyObject *
+signaldict_richcompare(PyObject *v, PyObject *w, int op)
+{
+ PyObject *res = Py_NotImplemented;
+
+ assert(PyDecSignalDict_Check(v));
+
+ if (op == Py_EQ || op == Py_NE) {
+ if (PyDecSignalDict_Check(w)) {
+ res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False;
+ }
+ else if (PyDict_Check(w)) {
+ uint32_t flags = dict_as_flags(w);
+ if (flags & DEC_ERRORS) {
+ if (flags & DEC_INVALID_SIGNALS) {
+ /* non-comparable: Py_NotImplemented */
+ PyErr_Clear();
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ res = (SdFlags(v)==flags) ^ (op==Py_NE) ? Py_True : Py_False;
+ }
+ }
+ }
+
+ Py_INCREF(res);
+ return res;
+}
+
+static PyObject *
+signaldict_copy(PyObject *self)
+{
+ return flags_as_dict(SdFlags(self));
+}
+
+
+static PyMappingMethods signaldict_as_mapping = {
+ (lenfunc)signaldict_len, /* mp_length */
+ (binaryfunc)signaldict_getitem, /* mp_subscript */
+ (objobjargproc)signaldict_setitem /* mp_ass_subscript */
+};
+
+static PyMethodDef signaldict_methods[] = {
+ { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL},
+ {NULL, NULL}
+};
+
+
+static PyTypeObject PyDecSignalDictMixin_Type =
+{
+ PyVarObject_HEAD_INIT(0, 0)
+ "decimal.SignalDictMixin", /* tp_name */
+ sizeof(PyDecSignalDictObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) 0, /* tp_getattr */
+ (setattrfunc) 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc) signaldict_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ &signaldict_as_mapping, /* tp_as_mapping */
+ PyObject_HashNotImplemented, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc) 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ (setattrofunc) 0, /* tp_setattro */
+ (PyBufferProcs *) 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|
+ Py_TPFLAGS_HAVE_GC, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ signaldict_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)signaldict_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ signaldict_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)signaldict_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+/******************************************************************************/
+/* Context Object, Part 1 */
+/******************************************************************************/
+
+#define Dec_CONTEXT_GET_SSIZE(mem) \
+static PyObject * \
+context_get##mem(PyObject *self, void *closure UNUSED) \
+{ \
+ return PyLong_FromSsize_t(mpd_get##mem(CTX(self))); \
+}
+
+#define Dec_CONTEXT_GET_ULONG(mem) \
+static PyObject * \
+context_get##mem(PyObject *self, void *closure UNUSED) \
+{ \
+ return PyLong_FromUnsignedLong(mpd_get##mem(CTX(self))); \
+}
+
+Dec_CONTEXT_GET_SSIZE(prec)
+Dec_CONTEXT_GET_SSIZE(emax)
+Dec_CONTEXT_GET_SSIZE(emin)
+Dec_CONTEXT_GET_SSIZE(round)
+Dec_CONTEXT_GET_SSIZE(clamp)
+
+#ifdef EXTRA_FUNCTIONALITY
+Dec_CONTEXT_GET_ULONG(traps)
+Dec_CONTEXT_GET_ULONG(status)
+#endif
+
+static PyObject *
+context_getcapitals(PyObject *self, void *closure UNUSED)
+{
+ return PyLong_FromLong(CtxCaps(self));
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+static PyObject *
+context_getallcr(PyObject *self, void *closure UNUSED)
+{
+ return PyLong_FromLong(mpd_getcr(CTX(self)));
+}
+#endif
+
+static PyObject *
+context_getetiny(PyObject *self, PyObject *dummy UNUSED)
+{
+ return PyLong_FromSsize_t(mpd_etiny(CTX(self)));
+}
+
+static PyObject *
+context_getetop(PyObject *self, PyObject *dummy UNUSED)
+{
+ return PyLong_FromSsize_t(mpd_etop(CTX(self)));
+}
+
+static int
+context_setprec(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetprec(ctx, x)) {
+ return value_error_int(
+ "valid range for prec is [1, MAX_PREC]");
+ }
+
+ return 0;
+}
+
+static int
+context_setemin(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetemin(ctx, x)) {
+ return value_error_int(
+ "valid range for Emin is [MIN_EMIN, 0]");
+ }
+
+ return 0;
+}
+
+static int
+context_setemax(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetemax(ctx, x)) {
+ return value_error_int(
+ "valid range for Emax is [0, MAX_EMAX]");
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_32
+static PyObject *
+context_unsafe_setprec(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx = CTX(self);
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ if (x < 1 || x > 1070000000L) {
+ return value_error_ptr(
+ "valid range for unsafe prec is [1, 1070000000]");
+ }
+
+ ctx->prec = x;
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+context_unsafe_setemin(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx = CTX(self);
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ if (x < -1070000000L || x > 0) {
+ return value_error_ptr(
+ "valid range for unsafe emin is [-1070000000, 0]");
+ }
+
+ ctx->emin = x;
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+context_unsafe_setemax(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx = CTX(self);
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ if (x < 0 || x > 1070000000L) {
+ return value_error_ptr(
+ "valid range for unsafe emax is [0, 1070000000]");
+ }
+
+ ctx->emax = x;
+ Py_RETURN_NONE;
+}
+#endif
+
+static int
+context_setround(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ BOUNDS_CHECK(x, INT_MIN, INT_MAX);
+
+ ctx = CTX(self);
+ if (!mpd_qsetround(ctx, (int)x)) {
+ return type_error_int(invalid_rounding_err);
+ }
+
+ return 0;
+}
+
+static int
+context_setcapitals(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+
+ if (x != 0 && x != 1) {
+ return value_error_int(
+ "valid values for capitals are 0 or 1");
+ }
+ CtxCaps(self) = (int)x;
+
+ return 0;
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+static int
+context_settraps(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ flags = long_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsettraps(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_settraps");
+ }
+
+ return 0;
+}
+#endif
+
+static int
+context_settraps_list(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ flags = list_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsettraps(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_settraps_list");
+ }
+
+ return 0;
+}
+
+static int
+context_settraps_dict(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ if (PyDecSignalDict_Check(value)) {
+ flags = SdFlags(value);
+ }
+ else {
+ flags = dict_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsettraps(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_settraps_dict");
+ }
+
+ return 0;
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+static int
+context_setstatus(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ flags = long_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetstatus(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_setstatus");
+ }
+
+ return 0;
+}
+#endif
+
+static int
+context_setstatus_list(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ flags = list_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetstatus(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_setstatus_list");
+ }
+
+ return 0;
+}
+
+static int
+context_setstatus_dict(PyObject *self, PyObject *value)
+{
+ mpd_context_t *ctx;
+ uint32_t flags;
+
+ if (PyDecSignalDict_Check(value)) {
+ flags = SdFlags(value);
+ }
+ else {
+ flags = dict_as_flags(value);
+ if (flags & DEC_ERRORS) {
+ return -1;
+ }
+ }
+
+ ctx = CTX(self);
+ if (!mpd_qsetstatus(ctx, flags)) {
+ INTERNAL_ERROR_INT("context_setstatus_dict");
+ }
+
+ return 0;
+}
+
+static int
+context_setclamp(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ BOUNDS_CHECK(x, INT_MIN, INT_MAX);
+
+ ctx = CTX(self);
+ if (!mpd_qsetclamp(ctx, (int)x)) {
+ return value_error_int("valid values for clamp are 0 or 1");
+ }
+
+ return 0;
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+static int
+context_setallcr(PyObject *self, PyObject *value, void *closure UNUSED)
+{
+ mpd_context_t *ctx;
+ mpd_ssize_t x;
+
+ x = PyLong_AsSsize_t(value);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ BOUNDS_CHECK(x, INT_MIN, INT_MAX);
+
+ ctx = CTX(self);
+ if (!mpd_qsetcr(ctx, (int)x)) {
+ return value_error_int("valid values for _allcr are 0 or 1");
+ }
+
+ return 0;
+}
+#endif
+
+static PyObject *
+context_getattr(PyObject *self, PyObject *name)
+{
+ PyObject *retval;
+
+ if (PyUnicode_Check(name)) {
+ if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) {
+ retval = ((PyDecContextObject *)self)->traps;
+ Py_INCREF(retval);
+ return retval;
+ }
+ if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) {
+ retval = ((PyDecContextObject *)self)->flags;
+ Py_INCREF(retval);
+ return retval;
+ }
+ }
+
+ return PyObject_GenericGetAttr(self, name);
+}
+
+static int
+context_setattr(PyObject *self, PyObject *name, PyObject *value)
+{
+ if (value == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "context attributes cannot be deleted");
+ return -1;
+ }
+
+ if (PyUnicode_Check(name)) {
+ if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) {
+ return context_settraps_dict(self, value);
+ }
+ if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) {
+ return context_setstatus_dict(self, value);
+ }
+ }
+
+ return PyObject_GenericSetAttr(self, name, value);
+}
+
+static PyObject *
+context_clear_traps(PyObject *self, PyObject *dummy UNUSED)
+{
+ CTX(self)->traps = 0;
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+context_clear_flags(PyObject *self, PyObject *dummy UNUSED)
+{
+ CTX(self)->status = 0;
+ Py_RETURN_NONE;
+}
+
+#define DEC_DFLT_EMAX 999999
+#define DEC_DFLT_EMIN -999999
+
+static mpd_context_t dflt_ctx = {
+ 28, DEC_DFLT_EMAX, DEC_DFLT_EMIN,
+ MPD_IEEE_Invalid_operation|MPD_Division_by_zero|MPD_Overflow,
+ 0, 0, MPD_ROUND_HALF_EVEN, 0, 1
+};
+
+static PyObject *
+context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED)
+{
+ PyDecContextObject *self = NULL;
+ mpd_context_t *ctx;
+
+ if (type == &PyDecContext_Type) {
+ self = PyObject_New(PyDecContextObject, &PyDecContext_Type);
+ }
+ else {
+ self = (PyDecContextObject *)type->tp_alloc(type, 0);
+ }
+
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL);
+ if (self->traps == NULL) {
+ self->flags = NULL;
+ Py_DECREF(self);
+ return NULL;
+ }
+ self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL);
+ if (self->flags == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ ctx = CTX(self);
+
+ if (default_context_template) {
+ *ctx = *CTX(default_context_template);
+ }
+ else {
+ *ctx = dflt_ctx;
+ }
+
+ SdFlagAddr(self->traps) = &ctx->traps;
+ SdFlagAddr(self->flags) = &ctx->status;
+
+ CtxCaps(self) = 1;
+
+ return (PyObject *)self;
+}
+
+static void
+context_dealloc(PyDecContextObject *self)
+{
+ Py_XDECREF(self->traps);
+ Py_XDECREF(self->flags);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+getround(PyObject *v)
+{
+ const char *s;
+ long x;
+ int i;
+
+ if (PyLong_Check(v)) {
+ x = PyLong_AsLong(v);
+ if (x == -1 && PyErr_Occurred()) {
+ return -1;
+ }
+ BOUNDS_CHECK(x, 0, INT_MAX);
+ return (int)x;
+ }
+ else if (PyUnicode_Check(v)) {
+ for (i = 0; i < MPD_ROUND_GUARD; i++) {
+ s = mpd_round_string[i];
+ if (PyUnicode_CompareWithASCIIString(v, s) == 0) {
+ return i;
+ }
+ }
+ }
+
+ return type_error_int("invalid rounding mode");
+}
+
+static int
+context_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {
+ "prec", "rounding", "Emin", "Emax", "capitals", "clamp",
+ "flags", "traps", NULL
+ };
+ PyObject *rounding = NULL;
+ PyObject *traps = NULL;
+ PyObject *status = NULL;
+ mpd_context_t *ctx, t;
+ int capitals = 1;
+ int ret;
+
+ assert(PyTuple_Check(args));
+ ctx = CTX(self);
+
+ t = *ctx;
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds,
+ "|nOnniiOO", kwlist,
+ &t.prec, &rounding, &t.emin, &t.emax, &capitals, &t.clamp,
+ &status, &traps
+ )) {
+ return -1;
+ }
+ if (rounding != NULL) {
+ t.round = getround(rounding);
+ if (t.round < 0) {
+ return -1;
+ }
+ }
+
+ if (!mpd_qsetprec(ctx, t.prec) ||
+ !mpd_qsetemin(ctx, t.emin) ||
+ !mpd_qsetemax(ctx, t.emax) ||
+ !mpd_qsetclamp(ctx, t.clamp)) {
+ return value_error_int("invalid context");
+ }
+ if (!mpd_qsetround(ctx, t.round) ||
+ !mpd_qsettraps(ctx, t.traps) ||
+ !mpd_qsetstatus(ctx, t.status)) {
+ return type_error_int("invalid context");
+ }
+
+ if (capitals != 0 && capitals != 1) {
+ return value_error_int("invalid context");
+ }
+ CtxCaps(self) = capitals;
+
+ if (traps != NULL) {
+ if (PyList_Check(traps)) {
+ ret = context_settraps_list(self, traps);
+ }
+#ifdef EXTRA_FUNCTIONALITY
+ else if (PyLong_Check(traps)) {
+ ret = context_settraps(self, traps, NULL);
+ }
+#endif
+ else {
+ ret = context_settraps_dict(self, traps);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ if (status != NULL) {
+ if (PyList_Check(status)) {
+ ret = context_setstatus_list(self, status);
+ }
+#ifdef EXTRA_FUNCTIONALITY
+ else if (PyLong_Check(status)) {
+ ret = context_setstatus(self, status, NULL);
+ }
+#endif
+ else {
+ ret = context_setstatus_dict(self, status);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static PyObject *
+context_repr(PyDecContextObject *self)
+{
+ mpd_context_t *ctx;
+ char flags[MPD_MAX_SIGNAL_LIST];
+ char traps[MPD_MAX_SIGNAL_LIST];
+ int n, mem;
+
+ assert(PyDecContext_Check(self));
+ ctx = CTX(self);
+
+ mem = MPD_MAX_SIGNAL_LIST;
+ n = mpd_lsnprint_signals(flags, mem, ctx->status, dec_signal_string);
+ if (n < 0 || n >= mem) {
+ INTERNAL_ERROR_PTR("context_repr");
+ }
+
+ n = mpd_lsnprint_signals(traps, mem, ctx->traps, dec_signal_string);
+ if (n < 0 || n >= mem) {
+ INTERNAL_ERROR_PTR("context_repr");
+ }
+
+ return PyUnicode_FromFormat(
+ "Context(prec=%zd, rounding=%s, Emin=%zd, Emax=%zd, "
+ "capitals=%d, clamp=%d, flags=%s, traps=%s)",
+ ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax,
+ self->capitals, ctx->clamp, flags, traps);
+}
+
+static void
+init_basic_context(PyObject *v)
+{
+ mpd_context_t ctx = dflt_ctx;
+
+ ctx.prec = 9;
+ ctx.traps |= (MPD_Underflow|MPD_Clamped);
+ ctx.round = MPD_ROUND_HALF_UP;
+
+ *CTX(v) = ctx;
+ CtxCaps(v) = 1;
+}
+
+static void
+init_extended_context(PyObject *v)
+{
+ mpd_context_t ctx = dflt_ctx;
+
+ ctx.prec = 9;
+ ctx.traps = 0;
+
+ *CTX(v) = ctx;
+ CtxCaps(v) = 1;
+}
+
+#ifdef EXTRA_FUNCTIONALITY
+/* Factory function for creating IEEE interchange format contexts */
+static PyObject *
+ieee_context(PyObject *dummy UNUSED, PyObject *v)
+{
+ PyObject *context;
+ mpd_ssize_t bits;
+ mpd_context_t ctx;
+
+ bits = PyLong_AsSsize_t(v);
+ if (bits == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ if (bits <= 0 || bits > INT_MAX) {
+ goto error;
+ }
+ if (mpd_ieee_context(&ctx, (int)bits) < 0) {
+ goto error;
+ }
+
+ context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL);
+ if (context == NULL) {
+ return NULL;
+ }
+ *CTX(context) = ctx;
+
+ return context;
+
+error:
+ PyErr_Format(PyExc_ValueError,
+ "argument must be a multiple of 32, with a maximum of %d",
+ MPD_IEEE_CONTEXT_MAX_BITS);
+
+ return NULL;
+}
+#endif
+
+static PyObject *
+context_copy(PyObject *self)
+{
+ PyObject *copy;
+
+ copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ *CTX(copy) = *CTX(self);
+ CTX(copy)->newtrap = 0;
+ CtxCaps(copy) = CtxCaps(self);
+
+ return copy;
+}
+
+static PyObject *
+context_reduce(PyObject *self, PyObject *args UNUSED)
+{
+ PyObject *flags;
+ PyObject *traps;
+ PyObject *ret;
+ mpd_context_t *ctx;
+
+ ctx = CTX(self);
+
+ flags = signals_as_list(ctx->status);
+ if (flags == NULL) {
+ return NULL;
+ }
+ traps = signals_as_list(ctx->traps);
+ if (traps == NULL) {
+ Py_DECREF(flags);
+ return NULL;
+ }
+
+ ret = Py_BuildValue(
+ "O(nsnniiOO)",
+ Py_TYPE(self),
+ ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax,
+ CtxCaps(self), ctx->clamp, flags, traps
+ );
+
+ Py_DECREF(flags);
+ Py_DECREF(traps);
+ return ret;
+}
+
+
+static PyGetSetDef context_getsets [] =
+{
+ { "prec", (getter)context_getprec, (setter)context_setprec, NULL, NULL},
+ { "Emax", (getter)context_getemax, (setter)context_setemax, NULL, NULL},
+ { "Emin", (getter)context_getemin, (setter)context_setemin, NULL, NULL},
+ { "rounding", (getter)context_getround, (setter)context_setround, NULL, NULL},
+ { "capitals", (getter)context_getcapitals, (setter)context_setcapitals, NULL, NULL},
+ { "clamp", (getter)context_getclamp, (setter)context_setclamp, NULL, NULL},
+#ifdef EXTRA_FUNCTIONALITY
+ { "_allcr", (getter)context_getallcr, (setter)context_setallcr, NULL, NULL},
+ { "_traps", (getter)context_gettraps, (setter)context_settraps, NULL, NULL},
+ { "_flags", (getter)context_getstatus, (setter)context_setstatus, NULL, NULL},
+#endif
+ {NULL}
+};
+
+
+#define CONTEXT_CHECK(obj) \
+ if (!PyDecContext_Check(obj)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "argument must be a context"); \
+ return NULL; \
+ }
+
+#define CONTEXT_CHECK_VA(obj) \
+ if (!PyDecContext_Check(obj)) { \
+ PyErr_SetString(PyExc_TypeError, \
+ "optional argument must be a context"); \
+ return NULL; \
+ }
+
+
+/******************************************************************************/
+/* Global, thread local and temporary contexts */
+/******************************************************************************/
+
+#ifdef WITHOUT_THREADS
+/* Return borrowed reference to the current context. When compiled
+ * without threads, this is always the module context. */
+static int module_context_set = 0;
+static PyObject *
+current_context(void)
+{
+ /* In decimal.py, the module context is automatically initialized
+ * from the DefaultContext when it is first accessed. This
+ * complicates the code and has a speed penalty of 1-2%. */
+ if (module_context_set) {
+ return module_context;
+ }
+
+ *CTX(module_context) = *CTX(default_context_template);
+ module_context_set = 1;
+ return module_context;
+}
+
+/* ctxobj := borrowed reference to the current context */
+#define CURRENT_CONTEXT(ctxobj) \
+ ctxobj = current_context()
+
+/* ctx := pointer to the mpd_context_t struct of the current context */
+#define CURRENT_CONTEXT_ADDR(ctx) \
+ ctx = CTX(current_context())
+
+/* Return current context, increment reference */
+static PyObject *
+PyDec_GetCurrentContext(void)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+
+ Py_INCREF(context);
+ return context;
+}
+
+/* Set the module context to a new context, decrement old reference */
+static PyObject *
+PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
+{
+ CONTEXT_CHECK(v);
+
+ /* If the new context is one of the templates, make a copy.
+ * This is the current behavior of decimal.py. */
+ if (v == default_context_template ||
+ v == basic_context_template ||
+ v == extended_context_template) {
+ v = context_copy(v);
+ if (v == NULL) {
+ return NULL;
+ }
+ }
+ else {
+ Py_INCREF(v);
+ }
+
+ Py_XDECREF(module_context);
+ module_context = v;
+ module_context_set = 1;
+ Py_RETURN_NONE;
+}
+#else
+/*
+ * Thread local storage currently has a speed penalty of about 16%.
+ * All functions that map Python's arithmetic operators to mpdecimal
+ * functions have to look up the current context for each and every
+ * operation.
+ */
+
+/* Return borrowed reference to thread local context. */
+static PyObject *
+current_context(void)
+{
+ PyObject *dict = NULL;
+ PyObject *tl_context = NULL;
+
+ dict = PyThreadState_GetDict();
+ if (dict == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot get thread state");
+ return NULL;
+ }
+
+ tl_context = PyDict_GetItemWithError(dict, tls_context_key);
+ if (tl_context != NULL) {
+ /* We already have a thread local context and
+ * return a borrowed reference. */
+ CONTEXT_CHECK(tl_context);
+ return tl_context;
+ }
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+
+ /* Otherwise, set up a new thread local context. */
+ tl_context = context_copy(default_context_template);
+ if (tl_context == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) {
+ Py_DECREF(tl_context);
+ return NULL;
+ }
+ Py_DECREF(tl_context);
+
+ /* refcount is 1 */
+ return tl_context;
+}
+
+/* ctxobj := borrowed reference to the current context */
+#define CURRENT_CONTEXT(ctxobj) \
+ ctxobj = current_context(); \
+ if (ctxobj == NULL) { \
+ return NULL; \
+ }
+
+/* ctx := pointer to the mpd_context_t struct of the current context */
+#define CURRENT_CONTEXT_ADDR(ctx) { \
+ PyObject *_c_t_x_o_b_j = current_context(); \
+ if (_c_t_x_o_b_j == NULL) { \
+ return NULL; \
+ } \
+ ctx = CTX(_c_t_x_o_b_j); \
+}
+
+/* Return current context, increment reference */
+static PyObject *
+PyDec_GetCurrentContext(void)
+{
+ PyObject *context;
+
+ context = current_context();
+ if (context == NULL) {
+ return NULL;
+ }
+
+ Py_INCREF(context);
+ return context;
+}
+
+/* Set the thread local context to a new context, decrement old reference */
+static PyObject *
+PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v)
+{
+ PyObject *dict;
+
+ CONTEXT_CHECK(v);
+
+ dict = PyThreadState_GetDict();
+ if (dict == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot get thread state");
+ return NULL;
+ }
+
+ /* If the new context is one of the templates, make a copy.
+ * This is the current behavior of decimal.py. */
+ if (v == default_context_template ||
+ v == basic_context_template ||
+ v == extended_context_template) {
+ v = context_copy(v);
+ if (v == NULL) {
+ return NULL;
+ }
+ }
+ else {
+ Py_INCREF(v);
+ }
+
+ if (PyDict_SetItem(dict, tls_context_key, v) < 0) {
+ Py_DECREF(v);
+ return NULL;
+ }
+
+ Py_DECREF(v);
+ Py_RETURN_NONE;
+}
+#endif
+
+/* Context manager object for the 'with' statement. The manager
+ * owns one reference to the global (outer) context and one
+ * to the local (inner) context. */
+static PyObject *
+ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args)
+{
+ PyDecContextManagerObject *self;
+ PyObject *local;
+ PyObject *global;
+
+ CURRENT_CONTEXT(global);
+ local = global;
+ if (!PyArg_ParseTuple(args, "|O", &local)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(local);
+
+ self = PyObject_New(PyDecContextManagerObject,
+ &PyDecContextManager_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ self->local = context_copy(local);
+ if (self->local == NULL) {
+ self->global = NULL;
+ Py_DECREF(self);
+ return NULL;
+ }
+ self->global = global;
+ Py_INCREF(self->global);
+
+ return (PyObject *)self;
+}
+
+static void
+ctxmanager_dealloc(PyDecContextManagerObject *self)
+{
+ Py_XDECREF(self->local);
+ Py_XDECREF(self->global);
+ PyObject_Del(self);
+}
+
+static PyObject *
+ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED)
+{
+ PyObject *ret;
+
+ ret = PyDec_SetCurrentContext(NULL, self->local);
+ if (ret == NULL) {
+ return NULL;
+ }
+ Py_DECREF(ret);
+
+ Py_INCREF(self->local);
+ return self->local;
+}
+
+static PyObject *
+ctxmanager_restore_global(PyDecContextManagerObject *self,
+ PyObject *args UNUSED)
+{
+ PyObject *ret;
+
+ ret = PyDec_SetCurrentContext(NULL, self->global);
+ if (ret == NULL) {
+ return NULL;
+ }
+ Py_DECREF(ret);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef ctxmanager_methods[] = {
+ {"__enter__", (PyCFunction)ctxmanager_set_local, METH_NOARGS, NULL},
+ {"__exit__", (PyCFunction)ctxmanager_restore_global, METH_VARARGS, NULL},
+ {NULL, NULL}
+};
+
+static PyTypeObject PyDecContextManager_Type =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "decimal.ContextManager", /* tp_name */
+ sizeof(PyDecContextManagerObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) ctxmanager_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) 0, /* tp_getattr */
+ (setattrfunc) 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc) 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */
+ (setattrofunc) 0, /* tp_setattro */
+ (PyBufferProcs *) 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ ctxmanager_methods, /* tp_methods */
+};
+
+
+/******************************************************************************/
+/* New Decimal Object */
+/******************************************************************************/
+
+static PyObject *
+PyDecType_New(PyTypeObject *type)
+{
+ PyObject *dec;
+
+ if (type == &PyDec_Type) {
+ dec = (PyObject *)PyObject_New(PyDecObject, &PyDec_Type);
+ }
+ else {
+ dec = type->tp_alloc(type, 0);
+ }
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ MPD(dec) = mpd_qnew();
+ if (MPD(dec) == NULL) {
+ Py_DECREF(dec);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ return dec;
+}
+#define dec_alloc() PyDecType_New(&PyDec_Type)
+
+static void
+dec_dealloc(PyObject *dec)
+{
+ if (MPD(dec)) {
+ mpd_del(MPD(dec));
+ }
+ Py_TYPE(dec)->tp_free(dec);
+}
+
+
+/******************************************************************************/
+/* Conversions to Decimal */
+/******************************************************************************/
+
+Py_LOCAL_INLINE(int)
+is_space(enum PyUnicode_Kind kind, void *data, Py_ssize_t pos)
+{
+ Py_UCS4 ch = PyUnicode_READ(kind, data, pos);
+ return Py_UNICODE_ISSPACE(ch);
+}
+
+/* Return the ASCII representation of a numeric Unicode string. The numeric
+ string may contain ascii characters in the range [1, 127], any Unicode
+ space and any unicode digit. If strip_ws is true, leading and trailing
+ whitespace is stripped.
+
+ Return NULL if malloc fails and an empty string if invalid characters
+ are found. */
+static char *
+numeric_as_ascii(const PyObject *u, int strip_ws)
+{
+ enum PyUnicode_Kind kind;
+ void *data;
+ Py_UCS4 ch;
+ char *res, *cp;
+ Py_ssize_t j, len;
+ int d;
+
+ assert(PyUnicode_IS_READY(u));
+
+ kind = PyUnicode_KIND(u);
+ data = PyUnicode_DATA(u);
+ len = PyUnicode_GET_LENGTH(u);
+
+ cp = res = PyMem_Malloc(len+1);
+ if (res == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ j = 0;
+ if (strip_ws) {
+ while (len > 0 && is_space(kind, data, len-1)) {
+ len--;
+ }
+ while (j < len && is_space(kind, data, j)) {
+ j++;
+ }
+ }
+
+ for (; j < len; j++) {
+ ch = PyUnicode_READ(kind, data, j);
+ if (0 < ch && ch <= 127) {
+ *cp++ = ch;
+ continue;
+ }
+ if (Py_UNICODE_ISSPACE(ch)) {
+ *cp++ = ' ';
+ continue;
+ }
+ d = Py_UNICODE_TODECIMAL(ch);
+ if (d < 0) {
+ /* empty string triggers ConversionSyntax */
+ *res = '\0';
+ return res;
+ }
+ *cp++ = '0' + d;
+ }
+ *cp = '\0';
+ return res;
+}
+
+/* Return a new PyDecObject or a subtype from a C string. Use the context
+ during conversion. */
+static PyObject *
+PyDecType_FromCString(PyTypeObject *type, const char *s,
+ PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ mpd_qset_string(MPD(dec), s, CTX(context), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+ return dec;
+}
+
+/* Return a new PyDecObject or a subtype from a C string. Attempt exact
+ conversion. If the operand cannot be converted exactly, set
+ InvalidOperation. */
+static PyObject *
+PyDecType_FromCStringExact(PyTypeObject *type, const char *s,
+ PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ mpd_maxcontext(&maxctx);
+
+ mpd_qset_string(MPD(dec), s, &maxctx, &status);
+ if (status & (MPD_Inexact|MPD_Rounded)) {
+ /* we want exact results */
+ mpd_seterror(MPD(dec), MPD_Invalid_operation, &status);
+ }
+ status &= MPD_Errors;
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+
+ return dec;
+}
+
+/* Return a new PyDecObject or a subtype from a PyUnicodeObject. */
+static PyObject *
+PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u,
+ PyObject *context)
+{
+ PyObject *dec;
+ char *s;
+
+ s = numeric_as_ascii(u, 0);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ dec = PyDecType_FromCString(type, s, context);
+ PyMem_Free(s);
+ return dec;
+}
+
+/* Return a new PyDecObject or a subtype from a PyUnicodeObject. Attempt exact
+ * conversion. If the conversion is not exact, fail with InvalidOperation.
+ * Allow leading and trailing whitespace in the input operand. */
+static PyObject *
+PyDecType_FromUnicodeExactWS(PyTypeObject *type, const PyObject *u,
+ PyObject *context)
+{
+ PyObject *dec;
+ char *s;
+
+ s = numeric_as_ascii(u, 1);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ dec = PyDecType_FromCStringExact(type, s, context);
+ PyMem_Free(s);
+ return dec;
+}
+
+/* Set PyDecObject from triple without any error checking. */
+Py_LOCAL_INLINE(void)
+_dec_settriple(PyObject *dec, uint8_t sign, uint32_t v, mpd_ssize_t exp)
+{
+
+#ifdef CONFIG_64
+ MPD(dec)->data[0] = v;
+ MPD(dec)->len = 1;
+#else
+ uint32_t q, r;
+ q = v / MPD_RADIX;
+ r = v - q * MPD_RADIX;
+ MPD(dec)->data[1] = q;
+ MPD(dec)->data[0] = r;
+ MPD(dec)->len = q ? 2 : 1;
+#endif
+ mpd_set_flags(MPD(dec), sign);
+ MPD(dec)->exp = exp;
+ mpd_setdigits(MPD(dec));
+}
+
+/* Return a new PyDecObject from an mpd_ssize_t. */
+static PyObject *
+PyDecType_FromSsize(PyTypeObject *type, mpd_ssize_t v, PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ mpd_qset_ssize(MPD(dec), v, CTX(context), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+ return dec;
+}
+
+/* Return a new PyDecObject from an mpd_ssize_t. Conversion is exact. */
+static PyObject *
+PyDecType_FromSsizeExact(PyTypeObject *type, mpd_ssize_t v, PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ mpd_maxcontext(&maxctx);
+
+ mpd_qset_ssize(MPD(dec), v, &maxctx, &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+ return dec;
+}
+
+/* Convert from a PyLongObject. The context is not modified; flags set
+ during conversion are accumulated in the status parameter. */
+static PyObject *
+dec_from_long(PyTypeObject *type, const PyObject *v,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ PyObject *dec;
+ PyLongObject *l = (PyLongObject *)v;
+ Py_ssize_t ob_size;
+ size_t len;
+ uint8_t sign;
+
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ ob_size = Py_SIZE(l);
+ if (ob_size == 0) {
+ _dec_settriple(dec, MPD_POS, 0, 0);
+ return dec;
+ }
+
+ if (ob_size < 0) {
+ len = -ob_size;
+ sign = MPD_NEG;
+ }
+ else {
+ len = ob_size;
+ sign = MPD_POS;
+ }
+
+ if (len == 1) {
+ _dec_settriple(dec, sign, *l->ob_digit, 0);
+ mpd_qfinalize(MPD(dec), ctx, status);
+ return dec;
+ }
+
+#if PYLONG_BITS_IN_DIGIT == 30
+ mpd_qimport_u32(MPD(dec), l->ob_digit, len, sign, PyLong_BASE,
+ ctx, status);
+#elif PYLONG_BITS_IN_DIGIT == 15
+ mpd_qimport_u16(MPD(dec), l->ob_digit, len, sign, PyLong_BASE,
+ ctx, status);
+#else
+ #error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
+#endif
+
+ return dec;
+}
+
+/* Return a new PyDecObject from a PyLongObject. Use the context for
+ conversion. */
+static PyObject *
+PyDecType_FromLong(PyTypeObject *type, const PyObject *pylong,
+ PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+
+ dec = dec_from_long(type, pylong, CTX(context), &status);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+
+ return dec;
+}
+
+/* Return a new PyDecObject from a PyLongObject. Use a maximum context
+ for conversion. If the conversion is not exact, set InvalidOperation. */
+static PyObject *
+PyDecType_FromLongExact(PyTypeObject *type, const PyObject *pylong,
+ PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+
+ mpd_maxcontext(&maxctx);
+ dec = dec_from_long(type, pylong, &maxctx, &status);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ if (status & (MPD_Inexact|MPD_Rounded)) {
+ /* we want exact results */
+ mpd_seterror(MPD(dec), MPD_Invalid_operation, &status);
+ }
+ status &= MPD_Errors;
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+
+ return dec;
+}
+
+/* Return a PyDecObject or a subtype from a PyFloatObject.
+ Conversion is exact. */
+static PyObject *
+PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v,
+ PyObject *context)
+{
+ PyObject *dec, *tmp;
+ PyObject *n, *d, *n_d;
+ mpd_ssize_t k;
+ double x;
+ int sign;
+ mpd_t *d1, *d2;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+
+
+ assert(PyType_IsSubtype(type, &PyDec_Type));
+
+ if (PyLong_Check(v)) {
+ return PyDecType_FromLongExact(type, v, context);
+ }
+ if (!PyFloat_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be int of float");
+ return NULL;
+ }
+
+ x = PyFloat_AsDouble(v);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ sign = (copysign(1.0, x) == 1.0) ? 0 : 1;
+
+ if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) {
+ dec = PyDecType_New(type);
+ if (dec == NULL) {
+ return NULL;
+ }
+ if (Py_IS_NAN(x)) {
+ /* decimal.py calls repr(float(+-nan)),
+ * which always gives a positive result. */
+ mpd_setspecial(MPD(dec), MPD_POS, MPD_NAN);
+ }
+ else {
+ mpd_setspecial(MPD(dec), sign, MPD_INF);
+ }
+ return dec;
+ }
+
+ /* absolute value of the float */
+ tmp = PyObject_CallMethod(v, "__abs__", NULL);
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ /* float as integer ratio: numerator/denominator */
+ n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL);
+ Py_DECREF(tmp);
+ if (n_d == NULL) {
+ return NULL;
+ }
+ n = PyTuple_GET_ITEM(n_d, 0);
+ d = PyTuple_GET_ITEM(n_d, 1);
+
+ tmp = PyObject_CallMethod(d, "bit_length", NULL);
+ if (tmp == NULL) {
+ Py_DECREF(n_d);
+ return NULL;
+ }
+ k = PyLong_AsSsize_t(tmp);
+ Py_DECREF(tmp);
+ if (k == -1 && PyErr_Occurred()) {
+ Py_DECREF(n_d);
+ return NULL;
+ }
+ k--;
+
+ dec = PyDecType_FromLongExact(type, n, context);
+ Py_DECREF(n_d);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ d1 = mpd_qnew();
+ if (d1 == NULL) {
+ Py_DECREF(dec);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ d2 = mpd_qnew();
+ if (d2 == NULL) {
+ mpd_del(d1);
+ Py_DECREF(dec);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ mpd_maxcontext(&maxctx);
+ mpd_qset_uint(d1, 5, &maxctx, &status);
+ mpd_qset_ssize(d2, k, &maxctx, &status);
+ mpd_qpow(d1, d1, d2, &maxctx, &status);
+ if (dec_addstatus(context, status)) {
+ mpd_del(d1);
+ mpd_del(d2);
+ Py_DECREF(dec);
+ return NULL;
+ }
+
+ /* result = n * 5**k */
+ mpd_qmul(MPD(dec), MPD(dec), d1, &maxctx, &status);
+ mpd_del(d1);
+ mpd_del(d2);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+ /* result = +- n * 5**k * 10**-k */
+ mpd_set_sign(MPD(dec), sign);
+ MPD(dec)->exp = -k;
+
+ return dec;
+}
+
+static PyObject *
+PyDecType_FromFloat(PyTypeObject *type, PyObject *v,
+ PyObject *context)
+{
+ PyObject *dec;
+ uint32_t status = 0;
+
+ dec = PyDecType_FromFloatExact(type, v, context);
+ if (dec == NULL) {
+ return NULL;
+ }
+
+ mpd_qfinalize(MPD(dec), CTX(context), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(dec);
+ return NULL;
+ }
+
+ return dec;
+}
+
+static PyObject *
+sequence_as_tuple(PyObject *v, PyObject *ex, const char *mesg)
+{
+ if (PyTuple_Check(v)) {
+ Py_INCREF(v);
+ return v;
+ }
+ if (PyList_Check(v)) {
+ return PyList_AsTuple(v);
+ }
+
+ PyErr_SetString(ex, mesg);
+ return NULL;
+}
+
+/* Return a new C string representation of a DecimalTuple. */
+static char *
+dectuple_as_str(PyObject *dectuple)
+{
+ PyObject *digits = NULL, *tmp;
+ char *decstring = NULL;
+ char sign_special[6];
+ char *cp;
+ long sign, l;
+ mpd_ssize_t exp = 0;
+ Py_ssize_t i, mem, tsize;
+ int n;
+
+ assert(PyTuple_Check(dectuple));
+
+ if (PyTuple_Size(dectuple) != 3) {
+ PyErr_SetString(PyExc_ValueError,
+ "argument must be a sequence of length 3");
+ goto error;
+ }
+
+ /* sign */
+ tmp = PyTuple_GET_ITEM(dectuple, 0);
+ if (!PyLong_Check(tmp)) {
+ PyErr_SetString(PyExc_ValueError,
+ "sign must be an integer with the value 0 or 1");
+ goto error;
+ }
+ sign = PyLong_AsLong(tmp);
+ if (sign == -1 && PyErr_Occurred()) {
+ goto error;
+ }
+ if (sign != 0 && sign != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "sign must be an integer with the value 0 or 1");
+ goto error;
+ }
+ sign_special[0] = sign ? '-' : '+';
+ sign_special[1] = '\0';
+
+ /* exponent or encoding for a special number */
+ tmp = PyTuple_GET_ITEM(dectuple, 2);
+ if (PyUnicode_Check(tmp)) {
+ /* special */
+ if (PyUnicode_CompareWithASCIIString(tmp, "F") == 0) {
+ strcat(sign_special, "Inf");
+ }
+ else if (PyUnicode_CompareWithASCIIString(tmp, "n") == 0) {
+ strcat(sign_special, "NaN");
+ }
+ else if (PyUnicode_CompareWithASCIIString(tmp, "N") == 0) {
+ strcat(sign_special, "sNaN");
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "string argument in the third position "
+ "must be 'F', 'n' or 'N'");
+ goto error;
+ }
+ }
+ else {
+ /* exponent */
+ if (!PyLong_Check(tmp)) {
+ PyErr_SetString(PyExc_ValueError,
+ "exponent must be an integer");
+ goto error;
+ }
+ exp = PyLong_AsSsize_t(tmp);
+ if (exp == -1 && PyErr_Occurred()) {
+ goto error;
+ }
+ }
+
+ /* coefficient */
+ digits = sequence_as_tuple(PyTuple_GET_ITEM(dectuple, 1),
+ PyExc_ValueError, "coefficient must be a tuple of digits");
+ if (digits == NULL) {
+ goto error;
+ }
+
+ tsize = PyTuple_Size(digits);
+ /* [sign][coeffdigits+1][E][-][expdigits+1]['\0'] */
+ mem = 1 + tsize + 3 + MPD_EXPDIGITS + 2;
+ cp = decstring = PyMem_Malloc(mem);
+ if (decstring == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+
+ n = snprintf(cp, mem, "%s", sign_special);
+ if (n < 0 || n >= mem) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "internal error in dec_sequence_as_str");
+ goto error;
+ }
+ cp += n;
+
+ if (tsize == 0 && sign_special[1] == '\0') {
+ /* empty tuple: zero coefficient, except for special numbers */
+ *cp++ = '0';
+ }
+ for (i = 0; i < tsize; i++) {
+ tmp = PyTuple_GET_ITEM(digits, i);
+ if (!PyLong_Check(tmp)) {
+ PyErr_SetString(PyExc_ValueError,
+ "coefficient must be a tuple of digits");
+ goto error;
+ }
+ l = PyLong_AsLong(tmp);
+ if (l == -1 && PyErr_Occurred()) {
+ goto error;
+ }
+ if (l < 0 || l > 9) {
+ PyErr_SetString(PyExc_ValueError,
+ "coefficient must be a tuple of digits");
+ goto error;
+ }
+ *cp++ = (char)l + '0';
+ }
+ *cp = '\0';
+
+ if (sign_special[1] == '\0') {
+ /* not a special number */
+ *cp++ = 'E';
+ n = snprintf(cp, MPD_EXPDIGITS+1, "%" PRI_mpd_ssize_t, exp);
+ if (n < 0 || n >= MPD_EXPDIGITS+1) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "internal error in dec_sequence_as_str");
+ goto error;
+ }
+ }
+
+ Py_XDECREF(digits);
+ return decstring;
+
+
+error:
+ Py_XDECREF(digits);
+ if (decstring) PyMem_Free(decstring);
+ return NULL;
+}
+
+/* Currently accepts tuples and lists. */
+static PyObject *
+PyDecType_FromSequence(PyTypeObject *type, PyObject *v,
+ PyObject *context)
+{
+ PyObject *dectuple;
+ PyObject *dec;
+ char *s;
+
+ dectuple = sequence_as_tuple(v, PyExc_TypeError,
+ "argument must be a tuple or list");
+ if (dectuple == NULL) {
+ return NULL;
+ }
+
+ s = dectuple_as_str(dectuple);
+ Py_DECREF(dectuple);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ dec = PyDecType_FromCString(type, s, context);
+
+ PyMem_Free(s);
+ return dec;
+}
+
+/* Currently accepts tuples and lists. */
+static PyObject *
+PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v,
+ PyObject *context)
+{
+ PyObject *dectuple;
+ PyObject *dec;
+ char *s;
+
+ dectuple = sequence_as_tuple(v, PyExc_TypeError,
+ "argument must be a tuple or list");
+ if (dectuple == NULL) {
+ return NULL;
+ }
+
+ s = dectuple_as_str(dectuple);
+ Py_DECREF(dectuple);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ dec = PyDecType_FromCStringExact(type, s, context);
+
+ PyMem_Free(s);
+ return dec;
+}
+
+#define PyDec_FromCString(str, context) \
+ PyDecType_FromCString(&PyDec_Type, str, context)
+#define PyDec_FromCStringExact(str, context) \
+ PyDecType_FromCStringExact(&PyDec_Type, str, context)
+
+#define PyDec_FromUnicode(unicode, context) \
+ PyDecType_FromUnicode(&PyDec_Type, unicode, context)
+#define PyDec_FromUnicodeExact(unicode, context) \
+ PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context)
+#define PyDec_FromUnicodeExactWS(unicode, context) \
+ PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context)
+
+#define PyDec_FromSsize(v, context) \
+ PyDecType_FromSsize(&PyDec_Type, v, context)
+#define PyDec_FromSsizeExact(v, context) \
+ PyDecType_FromSsizeExact(&PyDec_Type, v, context)
+
+#define PyDec_FromLong(pylong, context) \
+ PyDecType_FromLong(&PyDec_Type, pylong, context)
+#define PyDec_FromLongExact(pylong, context) \
+ PyDecType_FromLongExact(&PyDec_Type, pylong, context)
+
+#define PyDec_FromFloat(pyfloat, context) \
+ PyDecType_FromFloat(&PyDec_Type, pyfloat, context)
+#define PyDec_FromFloatExact(pyfloat, context) \
+ PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context)
+
+#define PyDec_FromSequence(sequence, context) \
+ PyDecType_FromSequence(&PyDec_Type, sequence, context)
+#define PyDec_FromSequenceExact(sequence, context) \
+ PyDecType_FromSequenceExact(&PyDec_Type, sequence, context)
+
+/* class method */
+static PyObject *
+dec_from_float(PyObject *dec, PyObject *pyfloat)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ return PyDecType_FromFloatExact((PyTypeObject *)dec, pyfloat, context);
+}
+
+/* create_decimal_from_float */
+static PyObject *
+ctx_from_float(PyObject *context, PyObject *v)
+{
+ return PyDec_FromFloat(v, context);
+}
+
+/* Apply the context to the input operand. Return a new PyDecObject. */
+static PyObject *
+dec_apply(PyObject *v, PyObject *context)
+{
+ PyObject *result;
+ uint32_t status = 0;
+
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ mpd_qcopy(MPD(result), MPD(v), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ mpd_qfinalize(MPD(result), CTX(context), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/* 'v' can have any type accepted by the Decimal constructor. Attempt
+ an exact conversion. If the result does not meet the restrictions
+ for an mpd_t, fail with InvalidOperation. */
+static PyObject *
+PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context)
+{
+ if (v == NULL) {
+ return PyDecType_FromSsizeExact(type, 0, context);
+ }
+ else if (PyDec_Check(v)) {
+ Py_INCREF(v);
+ return v;
+ }
+ else if (PyUnicode_Check(v)) {
+ return PyDecType_FromUnicodeExactWS(type, v, context);
+ }
+ else if (PyLong_Check(v)) {
+ return PyDecType_FromLongExact(type, v, context);
+ }
+ else if (PyTuple_Check(v) || PyList_Check(v)) {
+ return PyDecType_FromSequenceExact(type, v, context);
+ }
+ else if (PyFloat_Check(v)) {
+ if (dec_addstatus(context, MPD_Float_operation)) {
+ return NULL;
+ }
+ return PyDecType_FromFloatExact(type, v, context);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "conversion from %s to Decimal is not supported",
+ v->ob_type->tp_name);
+ return NULL;
+ }
+}
+
+/* The context is used during conversion. This function is the
+ equivalent of context.create_decimal(). */
+static PyObject *
+PyDec_FromObject(PyObject *v, PyObject *context)
+{
+ if (v == NULL) {
+ return PyDec_FromSsize(0, context);
+ }
+ else if (PyDec_Check(v)) {
+ mpd_context_t *ctx = CTX(context);
+ if (mpd_isnan(MPD(v)) &&
+ MPD(v)->digits > ctx->prec - ctx->clamp) {
+ /* Special case: too many NaN payload digits */
+ PyObject *result;
+ if (dec_addstatus(context, MPD_Conversion_syntax)) {
+ return NULL;
+ }
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+ mpd_setspecial(MPD(result), MPD_POS, MPD_NAN);
+ return result;
+ }
+ return dec_apply(v, context);
+ }
+ else if (PyUnicode_Check(v)) {
+ return PyDec_FromUnicode(v, context);
+ }
+ else if (PyLong_Check(v)) {
+ return PyDec_FromLong(v, context);
+ }
+ else if (PyTuple_Check(v) || PyList_Check(v)) {
+ return PyDec_FromSequence(v, context);
+ }
+ else if (PyFloat_Check(v)) {
+ if (dec_addstatus(context, MPD_Float_operation)) {
+ return NULL;
+ }
+ return PyDec_FromFloat(v, context);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "conversion from %s to Decimal is not supported",
+ v->ob_type->tp_name);
+ return NULL;
+ }
+}
+
+static PyObject *
+dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"value", "context", NULL};
+ PyObject *v = NULL;
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
+ &v, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ return PyDecType_FromObjectExact(type, v, context);
+}
+
+static PyObject *
+ctx_create_decimal(PyObject *context, PyObject *args)
+{
+ PyObject *v = NULL;
+
+ if (!PyArg_ParseTuple(args, "|O", &v)) {
+ return NULL;
+ }
+
+ return PyDec_FromObject(v, context);
+}
+
+
+/******************************************************************************/
+/* Implicit conversions to Decimal */
+/******************************************************************************/
+
+/* Try to convert PyObject v to a new PyDecObject conv. If the conversion
+ fails, set conv to NULL (exception is set). If the conversion is not
+ implemented, set conv to Py_NotImplemented. */
+#define NOT_IMPL 0
+#define TYPE_ERR 1
+Py_LOCAL_INLINE(int)
+convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context)
+{
+
+ if (PyDec_Check(v)) {
+ *conv = v;
+ Py_INCREF(v);
+ return 1;
+ }
+ if (PyLong_Check(v)) {
+ *conv = PyDec_FromLongExact(v, context);
+ if (*conv == NULL) {
+ return 0;
+ }
+ return 1;
+ }
+
+ if (type_err) {
+ PyErr_Format(PyExc_TypeError,
+ "conversion from %s to Decimal is not supported",
+ v->ob_type->tp_name);
+ }
+ else {
+ Py_INCREF(Py_NotImplemented);
+ *conv = Py_NotImplemented;
+ }
+ return 0;
+}
+
+/* Return NotImplemented for unsupported types. */
+#define CONVERT_OP(a, v, context) \
+ if (!convert_op(NOT_IMPL, a, v, context)) { \
+ return *(a); \
+ }
+
+#define CONVERT_BINOP(a, b, v, w, context) \
+ if (!convert_op(NOT_IMPL, a, v, context)) { \
+ return *(a); \
+ } \
+ if (!convert_op(NOT_IMPL, b, w, context)) { \
+ Py_DECREF(*(a)); \
+ return *(b); \
+ }
+
+#define CONVERT_TERNOP(a, b, c, v, w, x, context) \
+ if (!convert_op(NOT_IMPL, a, v, context)) { \
+ return *(a); \
+ } \
+ if (!convert_op(NOT_IMPL, b, w, context)) { \
+ Py_DECREF(*(a)); \
+ return *(b); \
+ } \
+ if (!convert_op(NOT_IMPL, c, x, context)) { \
+ Py_DECREF(*(a)); \
+ Py_DECREF(*(b)); \
+ return *(c); \
+ }
+
+/* Raise TypeError for unsupported types. */
+#define CONVERT_OP_RAISE(a, v, context) \
+ if (!convert_op(TYPE_ERR, a, v, context)) { \
+ return NULL; \
+ }
+
+#define CONVERT_BINOP_RAISE(a, b, v, w, context) \
+ if (!convert_op(TYPE_ERR, a, v, context)) { \
+ return NULL; \
+ } \
+ if (!convert_op(TYPE_ERR, b, w, context)) { \
+ Py_DECREF(*(a)); \
+ return NULL; \
+ }
+
+#define CONVERT_TERNOP_RAISE(a, b, c, v, w, x, context) \
+ if (!convert_op(TYPE_ERR, a, v, context)) { \
+ return NULL; \
+ } \
+ if (!convert_op(TYPE_ERR, b, w, context)) { \
+ Py_DECREF(*(a)); \
+ return NULL; \
+ } \
+ if (!convert_op(TYPE_ERR, c, x, context)) { \
+ Py_DECREF(*(a)); \
+ Py_DECREF(*(b)); \
+ return NULL; \
+ }
+
+
+/******************************************************************************/
+/* Implicit conversions to Decimal for comparison */
+/******************************************************************************/
+
+/* Convert rationals for comparison */
+static PyObject *Rational = NULL;
+static PyObject *
+multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context)
+{
+ PyObject *result;
+ PyObject *tmp = NULL;
+ PyObject *denom = NULL;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+ mpd_ssize_t exp;
+ mpd_t *vv;
+
+ /* v is not special, r is a rational */
+ tmp = PyObject_GetAttrString(r, "denominator");
+ if (tmp == NULL) {
+ return NULL;
+ }
+ denom = PyDec_FromLongExact(tmp, context);
+ Py_DECREF(tmp);
+ if (denom == NULL) {
+ return NULL;
+ }
+
+ vv = mpd_qncopy(MPD(v));
+ if (vv == NULL) {
+ Py_DECREF(denom);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(denom);
+ mpd_del(vv);
+ return NULL;
+ }
+
+ mpd_maxcontext(&maxctx);
+ /* Prevent Overflow in the following multiplication. The result of
+ the multiplication is only used in mpd_qcmp, which can handle
+ values that are technically out of bounds, like (for 32-bit)
+ 99999999999999999999...99999999e+425000000. */
+ exp = vv->exp;
+ vv->exp = 0;
+ mpd_qmul(MPD(result), vv, MPD(denom), &maxctx, &status);
+ MPD(result)->exp = exp;
+
+ Py_DECREF(denom);
+ mpd_del(vv);
+ /* If any status has been accumulated during the multiplication,
+ the result is invalid. This is very unlikely, since even the
+ 32-bit version supports 425000000 digits. */
+ if (status) {
+ PyErr_SetString(PyExc_ValueError,
+ "exact conversion for comparison failed");
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+numerator_as_decimal(PyObject *r, PyObject *context)
+{
+ PyObject *tmp, *num;
+
+ tmp = PyObject_GetAttrString(r, "numerator");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ num = PyDec_FromLongExact(tmp, context);
+ Py_DECREF(tmp);
+ return num;
+}
+
+/* Convert v and w for comparison. v is a Decimal. If w is a Rational, both
+ v and w have to be transformed. Return 1 for success, with new references
+ to the converted objects in vcmp and wcmp. Return 0 for failure. In that
+ case wcmp is either NULL or Py_NotImplemented (new reference) and vcmp
+ is undefined. */
+static int
+convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w,
+ int op, PyObject *context)
+{
+ mpd_context_t *ctx = CTX(context);
+
+ *vcmp = v;
+
+ if (PyDec_Check(w)) {
+ Py_INCREF(w);
+ *wcmp = w;
+ }
+ else if (PyLong_Check(w)) {
+ *wcmp = PyDec_FromLongExact(w, context);
+ }
+ else if (PyFloat_Check(w)) {
+ if (op != Py_EQ && op != Py_NE &&
+ dec_addstatus(context, MPD_Float_operation)) {
+ *wcmp = NULL;
+ }
+ else {
+ ctx->status |= MPD_Float_operation;
+ *wcmp = PyDec_FromFloatExact(w, context);
+ }
+ }
+ else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) {
+ Py_complex c = PyComplex_AsCComplex(w);
+ if (c.real == -1.0 && PyErr_Occurred()) {
+ *wcmp = NULL;
+ }
+ else if (c.imag == 0.0) {
+ PyObject *tmp = PyFloat_FromDouble(c.real);
+ if (tmp == NULL) {
+ *wcmp = NULL;
+ }
+ else {
+ ctx->status |= MPD_Float_operation;
+ *wcmp = PyDec_FromFloatExact(tmp, context);
+ Py_DECREF(tmp);
+ }
+ }
+ else {
+ Py_INCREF(Py_NotImplemented);
+ *wcmp = Py_NotImplemented;
+ }
+ }
+ else if (PyObject_IsInstance(w, Rational)) {
+ *wcmp = numerator_as_decimal(w, context);
+ if (*wcmp && !mpd_isspecial(MPD(v))) {
+ *vcmp = multiply_by_denominator(v, w, context);
+ if (*vcmp == NULL) {
+ Py_CLEAR(*wcmp);
+ }
+ }
+ }
+ else {
+ Py_INCREF(Py_NotImplemented);
+ *wcmp = Py_NotImplemented;
+ }
+
+ if (*wcmp == NULL || *wcmp == Py_NotImplemented) {
+ return 0;
+ }
+ if (*vcmp == v) {
+ Py_INCREF(v);
+ }
+ return 1;
+}
+
+#define CONVERT_BINOP_CMP(vcmp, wcmp, v, w, op, ctx) \
+ if (!convert_op_cmp(vcmp, wcmp, v, w, op, ctx)) { \
+ return *(wcmp); \
+ } \
+
+
+/******************************************************************************/
+/* Conversions from decimal */
+/******************************************************************************/
+
+static PyObject *
+unicode_fromascii(const char *s, Py_ssize_t size)
+{
+ PyObject *res;
+
+ res = PyUnicode_New(size, 127);
+ if (res == NULL) {
+ return NULL;
+ }
+
+ memcpy(PyUnicode_1BYTE_DATA(res), s, size);
+ return res;
+}
+
+/* PyDecObject as a string. The default module context is only used for
+ the value of 'capitals'. */
+static PyObject *
+dec_str(PyObject *dec)
+{
+ PyObject *res, *context;
+ mpd_ssize_t size;
+ char *cp;
+
+ CURRENT_CONTEXT(context);
+ size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context));
+ if (size < 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ res = unicode_fromascii(cp, size);
+ mpd_free(cp);
+ return res;
+}
+
+/* Representation of a PyDecObject. */
+static PyObject *
+dec_repr(PyObject *dec)
+{
+ PyObject *res, *context;
+ char *cp;
+
+ CURRENT_CONTEXT(context);
+ cp = mpd_to_sci(MPD(dec), CtxCaps(context));
+ if (cp == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ res = PyUnicode_FromFormat("Decimal('%s')", cp);
+ mpd_free(cp);
+ return res;
+}
+
+/* Convert decimal_point or thousands_sep, which may be multibyte or in
+ the range [128, 255], to a UTF8 string. */
+static PyObject *
+dotsep_as_utf8(const char *s)
+{
+ PyObject *utf8;
+ PyObject *tmp;
+ wchar_t buf[2];
+ size_t n;
+
+ n = mbstowcs(buf, s, 2);
+ if (n != 1) { /* Issue #7442 */
+ PyErr_SetString(PyExc_ValueError,
+ "invalid decimal point or unsupported "
+ "combination of LC_CTYPE and LC_NUMERIC");
+ return NULL;
+ }
+ tmp = PyUnicode_FromWideChar(buf, n);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ utf8 = PyUnicode_AsUTF8String(tmp);
+ Py_DECREF(tmp);
+ return utf8;
+}
+
+/* Formatted representation of a PyDecObject. */
+static PyObject *
+dec_format(PyObject *dec, PyObject *args)
+{
+ PyObject *result = NULL;
+ PyObject *override = NULL;
+ PyObject *dot = NULL;
+ PyObject *sep = NULL;
+ PyObject *grouping = NULL;
+ PyObject *fmt = NULL;
+ PyObject *fmtarg;
+ PyObject *context;
+ mpd_spec_t spec;
+ char *decstring= NULL;
+ uint32_t status = 0;
+ size_t n;
+
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) {
+ return NULL;
+ }
+
+ if (PyUnicode_Check(fmtarg)) {
+ fmt = PyUnicode_AsUTF8String(fmtarg);
+ if (fmt == NULL) {
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "format arg must be str");
+ return NULL;
+ }
+
+ if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt),
+ CtxCaps(context))) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid format string");
+ goto finish;
+ }
+ if (override) {
+ /* Values for decimal_point, thousands_sep and grouping can
+ be explicitly specified in the override dict. These values
+ take precedence over the values obtained from localeconv()
+ in mpd_parse_fmt_str(). The feature is not documented and
+ is only used in test_decimal. */
+ if (!PyDict_Check(override)) {
+ PyErr_SetString(PyExc_TypeError,
+ "optional argument must be a dict");
+ goto finish;
+ }
+ if ((dot = PyDict_GetItemString(override, "decimal_point"))) {
+ if ((dot = PyUnicode_AsUTF8String(dot)) == NULL) {
+ goto finish;
+ }
+ spec.dot = PyBytes_AS_STRING(dot);
+ }
+ if ((sep = PyDict_GetItemString(override, "thousands_sep"))) {
+ if ((sep = PyUnicode_AsUTF8String(sep)) == NULL) {
+ goto finish;
+ }
+ spec.sep = PyBytes_AS_STRING(sep);
+ }
+ if ((grouping = PyDict_GetItemString(override, "grouping"))) {
+ if ((grouping = PyUnicode_AsUTF8String(grouping)) == NULL) {
+ goto finish;
+ }
+ spec.grouping = PyBytes_AS_STRING(grouping);
+ }
+ if (mpd_validate_lconv(&spec) < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid override dict");
+ goto finish;
+ }
+ }
+ else {
+ n = strlen(spec.dot);
+ if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) {
+ /* fix locale dependent non-ascii characters */
+ dot = dotsep_as_utf8(spec.dot);
+ if (dot == NULL) {
+ goto finish;
+ }
+ spec.dot = PyBytes_AS_STRING(dot);
+ }
+ n = strlen(spec.sep);
+ if (n > 1 || (n == 1 && !isascii((uchar)spec.sep[0]))) {
+ /* fix locale dependent non-ascii characters */
+ sep = dotsep_as_utf8(spec.sep);
+ if (sep == NULL) {
+ goto finish;
+ }
+ spec.sep = PyBytes_AS_STRING(sep);
+ }
+ }
+
+
+ decstring = mpd_qformat_spec(MPD(dec), &spec, CTX(context), &status);
+ if (decstring == NULL) {
+ dec_addstatus(context, status);
+ goto finish;
+ }
+ result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL);
+
+
+finish:
+ Py_XDECREF(grouping);
+ Py_XDECREF(sep);
+ Py_XDECREF(dot);
+ Py_XDECREF(fmt);
+ if (decstring) mpd_free(decstring);
+ return result;
+}
+
+/* Return a PyLongObject from a PyDecObject, using the specified rounding
+ * mode. The context precision is not observed. */
+static PyObject *
+dec_as_long(PyObject *dec, PyObject *context, int round)
+{
+ PyLongObject *pylong;
+ size_t maxsize, n;
+ Py_ssize_t i;
+ mpd_t *x;
+ mpd_context_t workctx;
+ uint32_t status = 0;
+
+ if (mpd_isspecial(MPD(dec))) {
+ if (mpd_isnan(MPD(dec))) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot convert NaN to integer");
+ }
+ else {
+ PyErr_SetString(PyExc_OverflowError,
+ "cannot convert Infinity to integer");
+ }
+ return NULL;
+ }
+
+ x = mpd_qnew();
+ if (x == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ workctx = *CTX(context);
+ workctx.round = round;
+ mpd_qround_to_int(x, MPD(dec), &workctx, &status);
+ if (dec_addstatus(context, status)) {
+ mpd_del(x);
+ return NULL;
+ }
+
+ maxsize = mpd_sizeinbase(x, PyLong_BASE);
+ if (maxsize > PY_SSIZE_T_MAX) {
+ mpd_del(x);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ pylong = _PyLong_New(maxsize);
+ if (pylong == NULL) {
+ mpd_del(x);
+ return NULL;
+ }
+
+ status = 0;
+#if PYLONG_BITS_IN_DIGIT == 30
+ n = mpd_qexport_u32(pylong->ob_digit, maxsize, PyLong_BASE, x, &status);
+#elif PYLONG_BITS_IN_DIGIT == 15
+ n = mpd_qexport_u16(pylong->ob_digit, maxsize, PyLong_BASE, x, &status);
+#else
+ #error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
+#endif
+ if (dec_addstatus(context, status)) {
+ Py_DECREF((PyObject *) pylong);
+ mpd_del(x);
+ return NULL;
+ }
+
+ i = n;
+ while ((i > 0) && (pylong->ob_digit[i-1] == 0)) {
+ i--;
+ }
+
+ Py_SIZE(pylong) = i;
+ if (mpd_isnegative(x) && !mpd_iszero(x)) {
+ Py_SIZE(pylong) = -i;
+ }
+
+ mpd_del(x);
+ return (PyObject *) pylong;
+}
+
+static PyObject *
+PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"rounding", "context", NULL};
+ PyObject *result;
+ PyObject *context;
+ uint32_t status = 0;
+ mpd_context_t workctx;
+ int round = -1;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
+ &round, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ workctx = *CTX(context);
+ if (round >= 0) {
+ if (!mpd_qsetround(&workctx, round)) {
+ return type_error_ptr(invalid_rounding_err);
+ }
+ }
+
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"rounding", "context", NULL};
+ PyObject *result;
+ PyObject *context;
+ uint32_t status = 0;
+ mpd_context_t workctx;
+ int round = -1;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
+ &round, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ workctx = *CTX(context);
+ if (round >= 0) {
+ if (!mpd_qsetround(&workctx, round)) {
+ return type_error_ptr(invalid_rounding_err);
+ }
+ }
+
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+PyDec_AsFloat(PyObject *dec)
+{
+ PyObject *f, *s;
+
+ s = dec_str(dec);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ f = PyFloat_FromString(s);
+ Py_DECREF(s);
+
+ return f;
+}
+
+static PyObject *
+PyDec_Round(PyObject *dec, PyObject *args)
+{
+ PyObject *result;
+ PyObject *x = NULL;
+ uint32_t status = 0;
+ PyObject *context;
+
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTuple(args, "|O", &x)) {
+ return NULL;
+ }
+
+ if (x) {
+ mpd_uint_t dq[1] = {1};
+ mpd_t q = {MPD_STATIC|MPD_CONST_DATA,0,1,1,1,dq};
+ mpd_ssize_t y;
+
+ if (!PyLong_Check(x)) {
+ PyErr_SetString(PyExc_TypeError,
+ "optional arg must be an integer");
+ return NULL;
+ }
+
+ y = PyLong_AsSsize_t(x);
+ if (y == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ q.exp = (y == MPD_SSIZE_MIN) ? MPD_SSIZE_MAX : -y;
+ mpd_qquantize(MPD(result), MPD(dec), &q, CTX(context), &status);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+ }
+ else {
+ return dec_as_long(dec, context, MPD_ROUND_HALF_EVEN);
+ }
+}
+
+PyObject *DecimalTuple = NULL;
+/* Return the DecimalTuple representation of a PyDecObject. */
+static PyObject *
+PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED)
+{
+ PyObject *result = NULL;
+ PyObject *sign = NULL;
+ PyObject *coeff = NULL;
+ PyObject *expt = NULL;
+ PyObject *tmp = NULL;
+ mpd_t *x = NULL;
+ char *intstring = NULL;
+ Py_ssize_t intlen, i;
+
+
+ x = mpd_qncopy(MPD(dec));
+ if (x == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec)));
+ if (sign == NULL) {
+ goto out;
+ }
+
+ if (mpd_isinfinite(x)) {
+ expt = PyUnicode_FromString("F");
+ if (expt == NULL) {
+ goto out;
+ }
+ /* decimal.py has non-compliant infinity payloads. */
+ coeff = Py_BuildValue("(i)", 0);
+ if (coeff == NULL) {
+ goto out;
+ }
+ }
+ else {
+ if (mpd_isnan(x)) {
+ expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N");
+ }
+ else {
+ expt = PyLong_FromSsize_t(MPD(dec)->exp);
+ }
+ if (expt == NULL) {
+ goto out;
+ }
+
+ /* coefficient is defined */
+ if (x->len > 0) {
+
+ /* make an integer */
+ x->exp = 0;
+ /* clear NaN and sign */
+ mpd_clear_flags(x);
+ intstring = mpd_to_sci(x, 1);
+ if (intstring == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ intlen = strlen(intstring);
+ coeff = PyTuple_New(intlen);
+ if (coeff == NULL) {
+ goto out;
+ }
+
+ for (i = 0; i < intlen; i++) {
+ tmp = PyLong_FromLong(intstring[i]-'0');
+ if (tmp == NULL) {
+ goto out;
+ }
+ PyTuple_SET_ITEM(coeff, i, tmp);
+ }
+ }
+ else {
+ coeff = PyTuple_New(0);
+ if (coeff == NULL) {
+ goto out;
+ }
+ }
+ }
+
+ result = PyObject_CallFunctionObjArgs(DecimalTuple,
+ sign, coeff, expt, NULL);
+
+out:
+ if (x) mpd_del(x);
+ if (intstring) mpd_free(intstring);
+ Py_XDECREF(sign);
+ Py_XDECREF(coeff);
+ Py_XDECREF(expt);
+ return result;
+}
+
+
+/******************************************************************************/
+/* Macros for converting mpdecimal functions to Decimal methods */
+/******************************************************************************/
+
+/* Unary number method that uses the default module context. */
+#define Dec_UnaryNumberMethod(MPDFUNC) \
+static PyObject * \
+nm_##MPDFUNC(PyObject *self) \
+{ \
+ PyObject *result; \
+ PyObject *context; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context); \
+ if ((result = dec_alloc()) == NULL) { \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Binary number method that uses default module context. */
+#define Dec_BinaryNumberMethod(MPDFUNC) \
+static PyObject * \
+nm_##MPDFUNC(PyObject *self, PyObject *other) \
+{ \
+ PyObject *a, *b; \
+ PyObject *result; \
+ PyObject *context; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context) ; \
+ CONVERT_BINOP(&a, &b, self, other, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Boolean function without a context arg. */
+#define Dec_BoolFunc(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *dummy UNUSED) \
+{ \
+ return MPDFUNC(MPD(self)) ? incr_true() : incr_false(); \
+}
+
+/* Boolean function with an optional context arg. */
+#define Dec_BoolFuncVA(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"context", NULL}; \
+ PyObject *context; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
+ &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ \
+ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \
+}
+
+/* Unary function with an optional context arg. */
+#define Dec_UnaryFuncVA(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"context", NULL}; \
+ PyObject *result; \
+ PyObject *context; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
+ &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Unary function with an optional context arg. The actual MPDFUNC
+ only takes a status parameter. */
+#define Dec_UnaryFuncVA_NO_CTX(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"context", NULL}; \
+ PyObject *result; \
+ PyObject *context; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \
+ &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(self), &status); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Binary function with an optional context arg. */
+#define Dec_BinaryFuncVA(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"other", "context", NULL}; \
+ PyObject *other, *context; \
+ PyObject *a, *b; \
+ PyObject *result; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \
+ &other, &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Binary function with an optional context arg. Actual MPDFUNC does
+ NOT take a context. The context is used to record InvalidOperation
+ if the second operand cannot be converted exactly. */
+#define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"other", "context", NULL}; \
+ PyObject *other, *context; \
+ PyObject *a, *b; \
+ PyObject *result; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \
+ &other, &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b)); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ \
+ return result; \
+}
+
+/* Ternary function with an optional context arg. */
+#define Dec_TernaryFuncVA(MPDFUNC) \
+static PyObject * \
+dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \
+{ \
+ static char *kwlist[] = {"other", "third", "context", NULL}; \
+ PyObject *other, *third, *context; \
+ PyObject *a, *b, *c; \
+ PyObject *result; \
+ uint32_t status = 0; \
+ \
+ CURRENT_CONTEXT(context); \
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, \
+ &other, &third, &context)) { \
+ return NULL; \
+ } \
+ CONTEXT_CHECK_VA(context); \
+ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ Py_DECREF(c); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ Py_DECREF(c); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+
+/**********************************************/
+/* Number methods */
+/**********************************************/
+
+Dec_UnaryNumberMethod(mpd_qminus)
+Dec_UnaryNumberMethod(mpd_qplus)
+Dec_UnaryNumberMethod(mpd_qabs)
+
+Dec_BinaryNumberMethod(mpd_qadd)
+Dec_BinaryNumberMethod(mpd_qsub)
+Dec_BinaryNumberMethod(mpd_qmul)
+Dec_BinaryNumberMethod(mpd_qdiv)
+Dec_BinaryNumberMethod(mpd_qrem)
+Dec_BinaryNumberMethod(mpd_qdivint)
+
+static PyObject *
+nm_dec_as_long(PyObject *dec)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ return dec_as_long(dec, context, MPD_ROUND_DOWN);
+}
+
+static int
+nm_nonzero(PyDecObject *v)
+{
+ return !mpd_iszero(v->dec);
+}
+
+static PyObject *
+nm_mpd_qdivmod(PyObject *v, PyObject *w)
+{
+ PyObject *a, *b;
+ PyObject *q, *r;
+ PyObject *context;
+ uint32_t status = 0;
+ PyObject *ret;
+
+ CURRENT_CONTEXT(context);
+ CONVERT_BINOP(&a, &b, v, w, context);
+
+ q = dec_alloc();
+ if (q == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return NULL;
+ }
+ r = dec_alloc();
+ if (r == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ Py_DECREF(q);
+ return NULL;
+ }
+
+ mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(r);
+ Py_DECREF(q);
+ return NULL;
+ }
+
+ ret = Py_BuildValue("(OO)", q, r);
+ Py_DECREF(r);
+ Py_DECREF(q);
+ return ret;
+}
+
+static mpd_uint_t data_zero[1] = {0};
+static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero};
+
+static PyObject *
+nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod)
+{
+ PyObject *a, *b, *c = NULL;
+ PyObject *result;
+ PyObject *context;
+ uint32_t status = 0;
+
+ CURRENT_CONTEXT(context);
+ CONVERT_BINOP(&a, &b, base, exp, context);
+
+ if (mod != Py_None) {
+ if (!convert_op(NOT_IMPL, &c, mod, context)) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return c;
+ }
+ }
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ Py_XDECREF(c);
+ return NULL;
+ }
+
+ if (c == NULL) {
+ mpd_qpow(MPD(result), MPD(a), MPD(b),
+ CTX(context), &status);
+ }
+ else {
+ mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c),
+ CTX(context), &status);
+ status = (status == MPD_Clamped) ? 0 : status;
+ /* remove ideal exponent for compatibility with decimal.py */
+ mpd_qquantize(MPD(result), MPD(result), &zero,
+ CTX(context), &status);
+ Py_DECREF(c);
+ }
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+
+/******************************************************************************/
+/* Decimal Methods */
+/******************************************************************************/
+
+/* Unary arithmetic functions, optional context arg */
+Dec_UnaryFuncVA(mpd_qexp)
+Dec_UnaryFuncVA(mpd_qln)
+Dec_UnaryFuncVA(mpd_qlog10)
+Dec_UnaryFuncVA(mpd_qnext_minus)
+Dec_UnaryFuncVA(mpd_qnext_plus)
+Dec_UnaryFuncVA(mpd_qreduce)
+Dec_UnaryFuncVA(mpd_qsqrt)
+
+/* Binary arithmetic functions, optional context arg */
+Dec_BinaryFuncVA(mpd_qcompare)
+Dec_BinaryFuncVA(mpd_qcompare_signal)
+Dec_BinaryFuncVA(mpd_qmax)
+Dec_BinaryFuncVA(mpd_qmax_mag)
+Dec_BinaryFuncVA(mpd_qmin)
+Dec_BinaryFuncVA(mpd_qmin_mag)
+Dec_BinaryFuncVA(mpd_qnext_toward)
+Dec_BinaryFuncVA(mpd_qrem_near)
+
+/* Ternary arithmetic functions, optional context arg */
+Dec_TernaryFuncVA(mpd_qfma)
+
+/* Boolean functions, no context arg */
+Dec_BoolFunc(mpd_iscanonical)
+Dec_BoolFunc(mpd_isfinite)
+Dec_BoolFunc(mpd_isinfinite)
+Dec_BoolFunc(mpd_isnan)
+Dec_BoolFunc(mpd_isqnan)
+Dec_BoolFunc(mpd_issnan)
+Dec_BoolFunc(mpd_issigned)
+Dec_BoolFunc(mpd_iszero)
+
+/* Boolean functions, optional context arg */
+Dec_BoolFuncVA(mpd_isnormal)
+Dec_BoolFuncVA(mpd_issubnormal)
+
+/* Unary functions, no context arg */
+static PyObject *
+dec_mpd_adjexp(PyObject *self, PyObject *dummy UNUSED)
+{
+ mpd_ssize_t retval;
+
+ if (mpd_isspecial(MPD(self))) {
+ retval = 0;
+ }
+ else {
+ retval = mpd_adjexp(MPD(self));
+ }
+
+ return PyLong_FromSsize_t(retval);
+}
+
+static PyObject *
+dec_canonical(PyObject *self, PyObject *dummy UNUSED)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *
+dec_conjugate(PyObject *self, PyObject *dummy UNUSED)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *
+dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED)
+{
+ PyObject *result;
+
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ _dec_settriple(result, MPD_POS, 10, 0);
+ return result;
+}
+
+/* Unary functions, optional context arg for conversion errors */
+Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_abs)
+Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_negate)
+
+/* Unary functions, optional context arg */
+Dec_UnaryFuncVA(mpd_qinvert)
+Dec_UnaryFuncVA(mpd_qlogb)
+
+static PyObject *
+dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"context", NULL};
+ PyObject *context;
+ const char *cp;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist,
+ &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ cp = mpd_class(MPD(self), CTX(context));
+ return PyUnicode_FromString(cp);
+}
+
+static PyObject *
+dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"context", NULL};
+ PyObject *result;
+ PyObject *context;
+ mpd_ssize_t size;
+ char *s;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist,
+ &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context));
+ if (size < 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ result = unicode_fromascii(s, size);
+ mpd_free(s);
+
+ return result;
+}
+
+/* Binary functions, optional context arg for conversion errors */
+Dec_BinaryFuncVA_NO_CTX(mpd_compare_total)
+Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag)
+
+static PyObject *
+dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"other", "context", NULL};
+ PyObject *other, *context;
+ PyObject *a, *b;
+ PyObject *result;
+ uint32_t status = 0;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
+ &other, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+ CONVERT_BINOP_RAISE(&a, &b, self, other, context);
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return NULL;
+ }
+
+ mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"other", "context", NULL};
+ PyObject *other, *context;
+ PyObject *a, *b;
+ PyObject *result;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
+ &other, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+ CONVERT_BINOP_RAISE(&a, &b, self, other, context);
+
+ result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false();
+ Py_DECREF(a);
+ Py_DECREF(b);
+
+ return result;
+}
+
+/* Binary functions, optional context arg */
+Dec_BinaryFuncVA(mpd_qand)
+Dec_BinaryFuncVA(mpd_qor)
+Dec_BinaryFuncVA(mpd_qxor)
+
+Dec_BinaryFuncVA(mpd_qrotate)
+Dec_BinaryFuncVA(mpd_qscaleb)
+Dec_BinaryFuncVA(mpd_qshift)
+
+static PyObject *
+dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"exp", "rounding", "context", NULL};
+ PyObject *w, *context;
+ PyObject *a, *b;
+ PyObject *result;
+ uint32_t status = 0;
+ mpd_context_t workctx;
+ int round = -1;
+
+ CURRENT_CONTEXT(context);
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist,
+ &w, &round, &context)) {
+ return NULL;
+ }
+ CONTEXT_CHECK_VA(context);
+
+ workctx = *CTX(context);
+ if (round >= 0) {
+ if (!mpd_qsetround(&workctx, round)) {
+ return type_error_ptr(invalid_rounding_err);
+ }
+ }
+
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context);
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return NULL;
+ }
+
+ mpd_qquantize(MPD(result), MPD(a), MPD(b), &workctx, &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Special methods */
+static PyObject *
+dec_richcompare(PyObject *v, PyObject *w, int op)
+{
+ PyObject *a;
+ PyObject *b;
+ PyObject *context;
+ uint32_t status = 0;
+ int a_issnan, b_issnan;
+ int r;
+
+ assert(PyDec_Check(v));
+
+ CURRENT_CONTEXT(context);
+ CONVERT_BINOP_CMP(&a, &b, v, w, op, context);
+
+ a_issnan = mpd_issnan(MPD(a));
+ b_issnan = mpd_issnan(MPD(b));
+
+ r = mpd_qcmp(MPD(a), MPD(b), &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (r == INT_MAX) {
+ /* sNaNs or op={le,ge,lt,gt} always signal. */
+ if (a_issnan || b_issnan || (op != Py_EQ && op != Py_NE)) {
+ if (dec_addstatus(context, status)) {
+ return NULL;
+ }
+ }
+ /* qNaN comparison with op={eq,ne} or comparison
+ * with InvalidOperation disabled. */
+ return (op == Py_NE) ? incr_true() : incr_false();
+ }
+
+ switch (op) {
+ case Py_EQ:
+ r = (r == 0);
+ break;
+ case Py_NE:
+ r = (r != 0);
+ break;
+ case Py_LE:
+ r = (r <= 0);
+ break;
+ case Py_GE:
+ r = (r >= 0);
+ break;
+ case Py_LT:
+ r = (r == -1);
+ break;
+ case Py_GT:
+ r = (r == 1);
+ break;
+ }
+
+ return PyBool_FromLong(r);
+}
+
+/* __ceil__ */
+static PyObject *
+dec_ceil(PyObject *self, PyObject *dummy UNUSED)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ return dec_as_long(self, context, MPD_ROUND_CEILING);
+}
+
+/* __complex__ */
+static PyObject *
+dec_complex(PyObject *self, PyObject *dummy UNUSED)
+{
+ PyObject *f;
+ double x;
+
+ f = PyDec_AsFloat(self);
+ if (f == NULL) {
+ return NULL;
+ }
+
+ x = PyFloat_AsDouble(f);
+ Py_DECREF(f);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ return PyComplex_FromDoubles(x, 0);
+}
+
+/* __copy__ and __deepcopy__ */
+static PyObject *
+dec_copy(PyObject *self, PyObject *dummy UNUSED)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+/* __floor__ */
+static PyObject *
+dec_floor(PyObject *self, PyObject *dummy UNUSED)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ return dec_as_long(self, context, MPD_ROUND_FLOOR);
+}
+
+/* Always uses the module context */
+static Py_hash_t
+dec_hash(PyObject *v)
+{
+#if defined(CONFIG_64) && _PyHASH_BITS == 61
+ /* 2**61 - 1 */
+ mpd_uint_t p_data[1] = {2305843009213693951ULL};
+ mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, p_data};
+ /* Inverse of 10 modulo p */
+ mpd_uint_t inv10_p_data[2] = {2075258708292324556ULL};
+ mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA,
+ 0, 19, 1, 1, inv10_p_data};
+#elif defined(CONFIG_32) && _PyHASH_BITS == 31
+ /* 2**31 - 1 */
+ mpd_uint_t p_data[2] = {147483647UL, 2};
+ mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 10, 2, 2, p_data};
+ /* Inverse of 10 modulo p */
+ mpd_uint_t inv10_p_data[2] = {503238553UL, 1};
+ mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA,
+ 0, 10, 2, 2, inv10_p_data};
+#else
+ #error "No valid combination of CONFIG_64, CONFIG_32 and _PyHASH_BITS"
+#endif
+ const Py_hash_t py_hash_inf = 314159;
+ const Py_hash_t py_hash_nan = 0;
+ mpd_uint_t ten_data[1] = {10};
+ mpd_t ten = {MPD_POS|MPD_STATIC|MPD_CONST_DATA,
+ 0, 2, 1, 1, ten_data};
+ Py_hash_t result;
+ mpd_t *exp_hash = NULL;
+ mpd_t *tmp = NULL;
+ mpd_ssize_t exp;
+ uint32_t status = 0;
+ mpd_context_t maxctx;
+ PyObject *context;
+
+
+ context = current_context();
+ if (context == NULL) {
+ return -1;
+ }
+
+ if (mpd_isspecial(MPD(v))) {
+ if (mpd_issnan(MPD(v))) {
+ PyErr_SetString(PyExc_TypeError,
+ "Cannot hash a signaling NaN value");
+ return -1;
+ }
+ else if (mpd_isnan(MPD(v))) {
+ return py_hash_nan;
+ }
+ else {
+ return py_hash_inf * mpd_arith_sign(MPD(v));
+ }
+ }
+
+ mpd_maxcontext(&maxctx);
+ exp_hash = mpd_qnew();
+ if (exp_hash == NULL) {
+ goto malloc_error;
+ }
+ tmp = mpd_qnew();
+ if (tmp == NULL) {
+ goto malloc_error;
+ }
+
+ /*
+ * exp(v): exponent of v
+ * int(v): coefficient of v
+ */
+ exp = MPD(v)->exp;
+ if (exp >= 0) {
+ /* 10**exp(v) % p */
+ mpd_qsset_ssize(tmp, exp, &maxctx, &status);
+ mpd_qpowmod(exp_hash, &ten, tmp, &p, &maxctx, &status);
+ }
+ else {
+ /* inv10_p**(-exp(v)) % p */
+ mpd_qsset_ssize(tmp, -exp, &maxctx, &status);
+ mpd_qpowmod(exp_hash, &inv10_p, tmp, &p, &maxctx, &status);
+ }
+
+ /* hash = (int(v) * exp_hash) % p */
+ if (!mpd_qcopy(tmp, MPD(v), &status)) {
+ goto malloc_error;
+ }
+ tmp->exp = 0;
+ mpd_set_positive(tmp);
+ mpd_qmul(tmp, tmp, exp_hash, &maxctx, &status);
+ mpd_qrem(tmp, tmp, &p, &maxctx, &status);
+
+ result = mpd_qget_ssize(tmp, &status);
+ result = mpd_ispositive(MPD(v)) ? result : -result;
+ result = (result == -1) ? -2 : result;
+
+ if (status != 0) {
+ status |= MPD_Invalid_operation;
+ if (dec_addstatus(context, status)) {
+ result = -1;
+ goto finish;
+ }
+ }
+
+
+finish:
+ if (exp_hash) mpd_del(exp_hash);
+ if (tmp) mpd_del(tmp);
+ return result;
+
+malloc_error:
+ PyErr_NoMemory();
+ result = -1;
+ goto finish;
+}
+
+/* __reduce__ */
+static PyObject *
+dec_reduce(PyObject *self, PyObject *dummy UNUSED)
+{
+ PyObject *result, *str;
+
+ str = dec_str(self);
+ if (str == NULL) {
+ return NULL;
+ }
+
+ result = Py_BuildValue("O(O)", Py_TYPE(self), str);
+ Py_DECREF(str);
+
+ return result;
+}
+
+/* __trunc__ */
+static PyObject *
+dec_trunc(PyObject *self, PyObject *dummy UNUSED)
+{
+ PyObject *context;
+
+ CURRENT_CONTEXT(context);
+ return dec_as_long(self, context, MPD_ROUND_DOWN);
+}
+
+/* real and imag */
+static PyObject *
+dec_real(PyObject *self, void *closure UNUSED)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *
+dec_imag(PyObject *self UNUSED, void *closure UNUSED)
+{
+ PyObject *result;
+
+ result = dec_alloc();
+ if (result == NULL) {
+ return NULL;
+ }
+
+ _dec_settriple(result, MPD_POS, 0, 0);
+ return result;
+}
+
+
+static PyGetSetDef dec_getsets [] =
+{
+ { "real", (getter)dec_real, NULL, NULL, NULL},
+ { "imag", (getter)dec_imag, NULL, NULL, NULL},
+ {NULL}
+};
+
+static PyNumberMethods dec_number_methods =
+{
+ (binaryfunc) nm_mpd_qadd,
+ (binaryfunc) nm_mpd_qsub,
+ (binaryfunc) nm_mpd_qmul,
+ (binaryfunc) nm_mpd_qrem,
+ (binaryfunc) nm_mpd_qdivmod,
+ (ternaryfunc) nm_mpd_qpow,
+ (unaryfunc) nm_mpd_qminus,
+ (unaryfunc) nm_mpd_qplus,
+ (unaryfunc) nm_mpd_qabs,
+ (inquiry) nm_nonzero,
+ (unaryfunc) 0, /* no bit-complement */
+ (binaryfunc) 0, /* no shiftl */
+ (binaryfunc) 0, /* no shiftr */
+ (binaryfunc) 0, /* no bit-and */
+ (binaryfunc) 0, /* no bit-xor */
+ (binaryfunc) 0, /* no bit-ior */
+ (unaryfunc) nm_dec_as_long,
+ 0, /* nb_reserved */
+ (unaryfunc) PyDec_AsFloat,
+ 0, /* binaryfunc nb_inplace_add; */
+ 0, /* binaryfunc nb_inplace_subtract; */
+ 0, /* binaryfunc nb_inplace_multiply; */
+ 0, /* binaryfunc nb_inplace_remainder; */
+ 0, /* ternaryfunc nb_inplace_power; */
+ 0, /* binaryfunc nb_inplace_lshift; */
+ 0, /* binaryfunc nb_inplace_rshift; */
+ 0, /* binaryfunc nb_inplace_and; */
+ 0, /* binaryfunc nb_inplace_xor; */
+ 0, /* binaryfunc nb_inplace_or; */
+ (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */
+ (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */
+ 0, /* binaryfunc nb_inplace_floor_divide; */
+ 0, /* binaryfunc nb_inplace_true_divide; */
+};
+
+static PyMethodDef dec_methods [] =
+{
+ /* Unary arithmetic functions, optional context arg */
+ { "exp", (PyCFunction)dec_mpd_qexp, METH_VARARGS|METH_KEYWORDS, doc_exp },
+ { "ln", (PyCFunction)dec_mpd_qln, METH_VARARGS|METH_KEYWORDS, doc_ln },
+ { "log10", (PyCFunction)dec_mpd_qlog10, METH_VARARGS|METH_KEYWORDS, doc_log10 },
+ { "next_minus", (PyCFunction)dec_mpd_qnext_minus, METH_VARARGS|METH_KEYWORDS, doc_next_minus },
+ { "next_plus", (PyCFunction)dec_mpd_qnext_plus, METH_VARARGS|METH_KEYWORDS, doc_next_plus },
+ { "normalize", (PyCFunction)dec_mpd_qreduce, METH_VARARGS|METH_KEYWORDS, doc_normalize },
+ { "to_integral", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral },
+ { "to_integral_exact", (PyCFunction)PyDec_ToIntegralExact, METH_VARARGS|METH_KEYWORDS, doc_to_integral_exact },
+ { "to_integral_value", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral_value },
+ { "sqrt", (PyCFunction)dec_mpd_qsqrt, METH_VARARGS|METH_KEYWORDS, doc_sqrt },
+
+ /* Binary arithmetic functions, optional context arg */
+ { "compare", (PyCFunction)dec_mpd_qcompare, METH_VARARGS|METH_KEYWORDS, doc_compare },
+ { "compare_signal", (PyCFunction)dec_mpd_qcompare_signal, METH_VARARGS|METH_KEYWORDS, doc_compare_signal },
+ { "max", (PyCFunction)dec_mpd_qmax, METH_VARARGS|METH_KEYWORDS, doc_max },
+ { "max_mag", (PyCFunction)dec_mpd_qmax_mag, METH_VARARGS|METH_KEYWORDS, doc_max_mag },
+ { "min", (PyCFunction)dec_mpd_qmin, METH_VARARGS|METH_KEYWORDS, doc_min },
+ { "min_mag", (PyCFunction)dec_mpd_qmin_mag, METH_VARARGS|METH_KEYWORDS, doc_min_mag },
+ { "next_toward", (PyCFunction)dec_mpd_qnext_toward, METH_VARARGS|METH_KEYWORDS, doc_next_toward },
+ { "quantize", (PyCFunction)dec_mpd_qquantize, METH_VARARGS|METH_KEYWORDS, doc_quantize },
+ { "remainder_near", (PyCFunction)dec_mpd_qrem_near, METH_VARARGS|METH_KEYWORDS, doc_remainder_near },
+
+ /* Ternary arithmetic functions, optional context arg */
+ { "fma", (PyCFunction)dec_mpd_qfma, METH_VARARGS|METH_KEYWORDS, doc_fma },
+
+ /* Boolean functions, no context arg */
+ { "is_canonical", dec_mpd_iscanonical, METH_NOARGS, doc_is_canonical },
+ { "is_finite", dec_mpd_isfinite, METH_NOARGS, doc_is_finite },
+ { "is_infinite", dec_mpd_isinfinite, METH_NOARGS, doc_is_infinite },
+ { "is_nan", dec_mpd_isnan, METH_NOARGS, doc_is_nan },
+ { "is_qnan", dec_mpd_isqnan, METH_NOARGS, doc_is_qnan },
+ { "is_snan", dec_mpd_issnan, METH_NOARGS, doc_is_snan },
+ { "is_signed", dec_mpd_issigned, METH_NOARGS, doc_is_signed },
+ { "is_zero", dec_mpd_iszero, METH_NOARGS, doc_is_zero },
+
+ /* Boolean functions, optional context arg */
+ { "is_normal", (PyCFunction)dec_mpd_isnormal, METH_VARARGS|METH_KEYWORDS, doc_is_normal },
+ { "is_subnormal", (PyCFunction)dec_mpd_issubnormal, METH_VARARGS|METH_KEYWORDS, doc_is_subnormal },
+
+ /* Unary functions, no context arg */
+ { "adjusted", dec_mpd_adjexp, METH_NOARGS, doc_adjusted },
+ { "canonical", dec_canonical, METH_NOARGS, doc_canonical },
+ { "conjugate", dec_conjugate, METH_NOARGS, doc_conjugate },
+ { "radix", dec_mpd_radix, METH_NOARGS, doc_radix },
+
+ /* Unary functions, optional context arg for conversion errors */
+ { "copy_abs", (PyCFunction)dec_mpd_qcopy_abs, METH_VARARGS|METH_KEYWORDS, doc_copy_abs },
+ { "copy_negate", (PyCFunction)dec_mpd_qcopy_negate, METH_VARARGS|METH_KEYWORDS, doc_copy_negate },
+
+ /* Unary functions, optional context arg */
+ { "logb", (PyCFunction)dec_mpd_qlogb, METH_VARARGS|METH_KEYWORDS, doc_logb },
+ { "logical_invert", (PyCFunction)dec_mpd_qinvert, METH_VARARGS|METH_KEYWORDS, doc_logical_invert },
+ { "number_class", (PyCFunction)dec_mpd_class, METH_VARARGS|METH_KEYWORDS, doc_number_class },
+ { "to_eng_string", (PyCFunction)dec_mpd_to_eng, METH_VARARGS|METH_KEYWORDS, doc_to_eng_string },
+
+ /* Binary functions, optional context arg for conversion errors */
+ { "compare_total", (PyCFunction)dec_mpd_compare_total, METH_VARARGS|METH_KEYWORDS, doc_compare_total },
+ { "compare_total_mag", (PyCFunction)dec_mpd_compare_total_mag, METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag },
+ { "copy_sign", (PyCFunction)dec_mpd_qcopy_sign, METH_VARARGS|METH_KEYWORDS, doc_copy_sign },
+ { "same_quantum", (PyCFunction)dec_mpd_same_quantum, METH_VARARGS|METH_KEYWORDS, doc_same_quantum },
+
+ /* Binary functions, optional context arg */
+ { "logical_and", (PyCFunction)dec_mpd_qand, METH_VARARGS|METH_KEYWORDS, doc_logical_and },
+ { "logical_or", (PyCFunction)dec_mpd_qor, METH_VARARGS|METH_KEYWORDS, doc_logical_or },
+ { "logical_xor", (PyCFunction)dec_mpd_qxor, METH_VARARGS|METH_KEYWORDS, doc_logical_xor },
+ { "rotate", (PyCFunction)dec_mpd_qrotate, METH_VARARGS|METH_KEYWORDS, doc_rotate },
+ { "scaleb", (PyCFunction)dec_mpd_qscaleb, METH_VARARGS|METH_KEYWORDS, doc_scaleb },
+ { "shift", (PyCFunction)dec_mpd_qshift, METH_VARARGS|METH_KEYWORDS, doc_shift },
+
+ /* Miscellaneous */
+ { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float },
+ { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple },
+
+ /* Special methods */
+ { "__copy__", dec_copy, METH_NOARGS, NULL },
+ { "__deepcopy__", dec_copy, METH_O, NULL },
+ { "__format__", dec_format, METH_VARARGS, NULL },
+ { "__reduce__", dec_reduce, METH_NOARGS, NULL },
+ { "__round__", PyDec_Round, METH_VARARGS, NULL },
+ { "__ceil__", dec_ceil, METH_NOARGS, NULL },
+ { "__floor__", dec_floor, METH_NOARGS, NULL },
+ { "__trunc__", dec_trunc, METH_NOARGS, NULL },
+ { "__complex__", dec_complex, METH_NOARGS, NULL },
+
+ { NULL, NULL, 1 }
+};
+
+static PyTypeObject PyDec_Type =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "decimal.Decimal", /* tp_name */
+ sizeof(PyDecObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) dec_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) 0, /* tp_getattr */
+ (setattrfunc) 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc) dec_repr, /* tp_repr */
+ &dec_number_methods, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc) dec_hash, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc) dec_str, /* tp_str */
+ (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */
+ (setattrofunc) 0, /* tp_setattro */
+ (PyBufferProcs *) 0, /* tp_as_buffer */
+ (Py_TPFLAGS_DEFAULT|
+ Py_TPFLAGS_BASETYPE), /* tp_flags */
+ doc_decimal, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ dec_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ dec_methods, /* tp_methods */
+ 0, /* tp_members */
+ dec_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ dec_new, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
+
+/******************************************************************************/
+/* Context Object, Part 2 */
+/******************************************************************************/
+
+
+/************************************************************************/
+/* Macros for converting mpdecimal functions to Context methods */
+/************************************************************************/
+
+/* Boolean context method. */
+#define DecCtx_BoolFunc(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *v) \
+{ \
+ PyObject *ret; \
+ PyObject *a; \
+ \
+ CONVERT_OP_RAISE(&a, v, context); \
+ \
+ ret = MPDFUNC(MPD(a), CTX(context)) ? incr_true() : incr_false(); \
+ Py_DECREF(a); \
+ return ret; \
+}
+
+/* Boolean context method. MPDFUNC does NOT use a context. */
+#define DecCtx_BoolFunc_NO_CTX(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *v) \
+{ \
+ PyObject *ret; \
+ PyObject *a; \
+ \
+ CONVERT_OP_RAISE(&a, v, context); \
+ \
+ ret = MPDFUNC(MPD(a)) ? incr_true() : incr_false(); \
+ Py_DECREF(a); \
+ return ret; \
+}
+
+/* Unary context method. */
+#define DecCtx_UnaryFunc(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *v) \
+{ \
+ PyObject *result, *a; \
+ uint32_t status = 0; \
+ \
+ CONVERT_OP_RAISE(&a, v, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), CTX(context), &status); \
+ Py_DECREF(a); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/* Binary context method. */
+#define DecCtx_BinaryFunc(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *args) \
+{ \
+ PyObject *v, *w; \
+ PyObject *a, *b; \
+ PyObject *result; \
+ uint32_t status = 0; \
+ \
+ if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \
+ return NULL; \
+ } \
+ \
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+/*
+ * Binary context method. The context is only used for conversion.
+ * The actual MPDFUNC does NOT take a context arg.
+ */
+#define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *args) \
+{ \
+ PyObject *v, *w; \
+ PyObject *a, *b; \
+ PyObject *result; \
+ \
+ if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \
+ return NULL; \
+ } \
+ \
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b)); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ \
+ return result; \
+}
+
+/* Ternary context method. */
+#define DecCtx_TernaryFunc(MPDFUNC) \
+static PyObject * \
+ctx_##MPDFUNC(PyObject *context, PyObject *args) \
+{ \
+ PyObject *v, *w, *x; \
+ PyObject *a, *b, *c; \
+ PyObject *result; \
+ uint32_t status = 0; \
+ \
+ if (!PyArg_ParseTuple(args, "OOO", &v, &w, &x)) { \
+ return NULL; \
+ } \
+ \
+ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \
+ \
+ if ((result = dec_alloc()) == NULL) { \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ Py_DECREF(c); \
+ return NULL; \
+ } \
+ \
+ MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \
+ Py_DECREF(a); \
+ Py_DECREF(b); \
+ Py_DECREF(c); \
+ if (dec_addstatus(context, status)) { \
+ Py_DECREF(result); \
+ return NULL; \
+ } \
+ \
+ return result; \
+}
+
+
+/* Unary arithmetic functions */
+DecCtx_UnaryFunc(mpd_qabs)
+DecCtx_UnaryFunc(mpd_qexp)
+DecCtx_UnaryFunc(mpd_qln)
+DecCtx_UnaryFunc(mpd_qlog10)
+DecCtx_UnaryFunc(mpd_qminus)
+DecCtx_UnaryFunc(mpd_qnext_minus)
+DecCtx_UnaryFunc(mpd_qnext_plus)
+DecCtx_UnaryFunc(mpd_qplus)
+DecCtx_UnaryFunc(mpd_qreduce)
+DecCtx_UnaryFunc(mpd_qround_to_int)
+DecCtx_UnaryFunc(mpd_qround_to_intx)
+DecCtx_UnaryFunc(mpd_qsqrt)
+
+/* Binary arithmetic functions */
+DecCtx_BinaryFunc(mpd_qadd)
+DecCtx_BinaryFunc(mpd_qcompare)
+DecCtx_BinaryFunc(mpd_qcompare_signal)
+DecCtx_BinaryFunc(mpd_qdiv)
+DecCtx_BinaryFunc(mpd_qdivint)
+DecCtx_BinaryFunc(mpd_qmax)
+DecCtx_BinaryFunc(mpd_qmax_mag)
+DecCtx_BinaryFunc(mpd_qmin)
+DecCtx_BinaryFunc(mpd_qmin_mag)
+DecCtx_BinaryFunc(mpd_qmul)
+DecCtx_BinaryFunc(mpd_qnext_toward)
+DecCtx_BinaryFunc(mpd_qquantize)
+DecCtx_BinaryFunc(mpd_qrem)
+DecCtx_BinaryFunc(mpd_qrem_near)
+DecCtx_BinaryFunc(mpd_qsub)
+
+static PyObject *
+ctx_mpd_qdivmod(PyObject *context, PyObject *args)
+{
+ PyObject *v, *w;
+ PyObject *a, *b;
+ PyObject *q, *r;
+ uint32_t status = 0;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "OO", &v, &w)) {
+ return NULL;
+ }
+
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context);
+
+ q = dec_alloc();
+ if (q == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return NULL;
+ }
+ r = dec_alloc();
+ if (r == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ Py_DECREF(q);
+ return NULL;
+ }
+
+ mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(r);
+ Py_DECREF(q);
+ return NULL;
+ }
+
+ ret = Py_BuildValue("(OO)", q, r);
+ Py_DECREF(r);
+ Py_DECREF(q);
+ return ret;
+}
+
+/* Binary or ternary arithmetic functions */
+static PyObject *
+ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"a", "b", "modulo", NULL};
+ PyObject *base, *exp, *mod = NULL;
+ PyObject *a, *b, *c = NULL;
+ PyObject *result;
+ uint32_t status = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist,
+ &base, &exp, &mod)) {
+ return NULL;
+ }
+
+ CONVERT_BINOP_RAISE(&a, &b, base, exp, context);
+
+ if (mod != NULL) {
+ if (!convert_op(TYPE_ERR, &c, mod, context)) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return c;
+ }
+ }
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ Py_XDECREF(c);
+ return NULL;
+ }
+
+ if (c == NULL) {
+ mpd_qpow(MPD(result), MPD(a), MPD(b),
+ CTX(context), &status);
+ }
+ else {
+ mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c),
+ CTX(context), &status);
+ status = (status == MPD_Clamped) ? 0 : status;
+ /* remove ideal exponent for compatibility with decimal.py */
+ mpd_qquantize(MPD(result), MPD(result), &zero,
+ CTX(context), &status);
+ Py_DECREF(c);
+ }
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Ternary arithmetic functions */
+DecCtx_TernaryFunc(mpd_qfma)
+
+/* No argument */
+static PyObject *
+ctx_mpd_radix(PyObject *context, PyObject *dummy)
+{
+ return dec_mpd_radix(context, dummy);
+}
+
+/* Boolean functions: single decimal argument */
+DecCtx_BoolFunc(mpd_isnormal)
+DecCtx_BoolFunc(mpd_issubnormal)
+DecCtx_BoolFunc_NO_CTX(mpd_isfinite)
+DecCtx_BoolFunc_NO_CTX(mpd_isinfinite)
+DecCtx_BoolFunc_NO_CTX(mpd_isnan)
+DecCtx_BoolFunc_NO_CTX(mpd_isqnan)
+DecCtx_BoolFunc_NO_CTX(mpd_issigned)
+DecCtx_BoolFunc_NO_CTX(mpd_issnan)
+DecCtx_BoolFunc_NO_CTX(mpd_iszero)
+
+static PyObject *
+ctx_iscanonical(PyObject *context UNUSED, PyObject *v)
+{
+ if (!PyDec_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Decimal");
+ return NULL;
+ }
+
+ return mpd_iscanonical(MPD(v)) ? incr_true() : incr_false();
+}
+
+/* Functions with a single decimal argument */
+static PyObject *
+PyDecContext_Apply(PyObject *context, PyObject *v)
+{
+ PyObject *result, *a;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ result = dec_apply(a, context);
+ Py_DECREF(a);
+ return result;
+}
+
+static PyObject *
+ctx_canonical(PyObject *context UNUSED, PyObject *v)
+{
+ if (!PyDec_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be a Decimal");
+ return NULL;
+ }
+
+ Py_INCREF(v);
+ return v;
+}
+
+static PyObject *
+ctx_mpd_qcopy_abs(PyObject *context, PyObject *v)
+{
+ PyObject *result, *a;
+ uint32_t status = 0;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ return NULL;
+ }
+
+ mpd_qcopy_abs(MPD(result), MPD(a), &status);
+ Py_DECREF(a);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+ctx_copy_decimal(PyObject *context, PyObject *v)
+{
+ PyObject *result;
+
+ CONVERT_OP_RAISE(&result, v, context);
+ return result;
+}
+
+static PyObject *
+ctx_mpd_qcopy_negate(PyObject *context, PyObject *v)
+{
+ PyObject *result, *a;
+ uint32_t status = 0;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ return NULL;
+ }
+
+ mpd_qcopy_negate(MPD(result), MPD(a), &status);
+ Py_DECREF(a);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+DecCtx_UnaryFunc(mpd_qlogb)
+DecCtx_UnaryFunc(mpd_qinvert)
+
+static PyObject *
+ctx_mpd_class(PyObject *context, PyObject *v)
+{
+ PyObject *a;
+ const char *cp;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ cp = mpd_class(MPD(a), CTX(context));
+ Py_DECREF(a);
+
+ return PyUnicode_FromString(cp);
+}
+
+static PyObject *
+ctx_mpd_to_sci(PyObject *context, PyObject *v)
+{
+ PyObject *result;
+ PyObject *a;
+ mpd_ssize_t size;
+ char *s;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ size = mpd_to_sci_size(&s, MPD(a), CtxCaps(context));
+ Py_DECREF(a);
+ if (size < 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ result = unicode_fromascii(s, size);
+ mpd_free(s);
+
+ return result;
+}
+
+static PyObject *
+ctx_mpd_to_eng(PyObject *context, PyObject *v)
+{
+ PyObject *result;
+ PyObject *a;
+ mpd_ssize_t size;
+ char *s;
+
+ CONVERT_OP_RAISE(&a, v, context);
+
+ size = mpd_to_eng_size(&s, MPD(a), CtxCaps(context));
+ Py_DECREF(a);
+ if (size < 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ result = unicode_fromascii(s, size);
+ mpd_free(s);
+
+ return result;
+}
+
+/* Functions with two decimal arguments */
+DecCtx_BinaryFunc_NO_CTX(mpd_compare_total)
+DecCtx_BinaryFunc_NO_CTX(mpd_compare_total_mag)
+
+static PyObject *
+ctx_mpd_qcopy_sign(PyObject *context, PyObject *args)
+{
+ PyObject *v, *w;
+ PyObject *a, *b;
+ PyObject *result;
+ uint32_t status = 0;
+
+ if (!PyArg_ParseTuple(args, "OO", &v, &w)) {
+ return NULL;
+ }
+
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context);
+
+ result = dec_alloc();
+ if (result == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(b);
+ return NULL;
+ }
+
+ mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (dec_addstatus(context, status)) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+DecCtx_BinaryFunc(mpd_qand)
+DecCtx_BinaryFunc(mpd_qor)
+DecCtx_BinaryFunc(mpd_qxor)
+
+DecCtx_BinaryFunc(mpd_qrotate)
+DecCtx_BinaryFunc(mpd_qscaleb)
+DecCtx_BinaryFunc(mpd_qshift)
+
+static PyObject *
+ctx_mpd_same_quantum(PyObject *context, PyObject *args)
+{
+ PyObject *v, *w;
+ PyObject *a, *b;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "OO", &v, &w)) {
+ return NULL;
+ }
+
+ CONVERT_BINOP_RAISE(&a, &b, v, w, context);
+
+ result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false();
+ Py_DECREF(a);
+ Py_DECREF(b);
+
+ return result;
+}
+
+
+static PyMethodDef context_methods [] =
+{
+ /* Unary arithmetic functions */
+ { "abs", ctx_mpd_qabs, METH_O, doc_ctx_abs },
+ { "exp", ctx_mpd_qexp, METH_O, doc_ctx_exp },
+ { "ln", ctx_mpd_qln, METH_O, doc_ctx_ln },
+ { "log10", ctx_mpd_qlog10, METH_O, doc_ctx_log10 },
+ { "minus", ctx_mpd_qminus, METH_O, doc_ctx_minus },
+ { "next_minus", ctx_mpd_qnext_minus, METH_O, doc_ctx_next_minus },
+ { "next_plus", ctx_mpd_qnext_plus, METH_O, doc_ctx_next_plus },
+ { "normalize", ctx_mpd_qreduce, METH_O, doc_ctx_normalize },
+ { "plus", ctx_mpd_qplus, METH_O, doc_ctx_plus },
+ { "to_integral", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral },
+ { "to_integral_exact", ctx_mpd_qround_to_intx, METH_O, doc_ctx_to_integral_exact },
+ { "to_integral_value", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral_value },
+ { "sqrt", ctx_mpd_qsqrt, METH_O, doc_ctx_sqrt },
+
+ /* Binary arithmetic functions */
+ { "add", ctx_mpd_qadd, METH_VARARGS, doc_ctx_add },
+ { "compare", ctx_mpd_qcompare, METH_VARARGS, doc_ctx_compare },
+ { "compare_signal", ctx_mpd_qcompare_signal, METH_VARARGS, doc_ctx_compare_signal },
+ { "divide", ctx_mpd_qdiv, METH_VARARGS, doc_ctx_divide },
+ { "divide_int", ctx_mpd_qdivint, METH_VARARGS, doc_ctx_divide_int },
+ { "divmod", ctx_mpd_qdivmod, METH_VARARGS, doc_ctx_divmod },
+ { "max", ctx_mpd_qmax, METH_VARARGS, doc_ctx_max },
+ { "max_mag", ctx_mpd_qmax_mag, METH_VARARGS, doc_ctx_max_mag },
+ { "min", ctx_mpd_qmin, METH_VARARGS, doc_ctx_min },
+ { "min_mag", ctx_mpd_qmin_mag, METH_VARARGS, doc_ctx_min_mag },
+ { "multiply", ctx_mpd_qmul, METH_VARARGS, doc_ctx_multiply },
+ { "next_toward", ctx_mpd_qnext_toward, METH_VARARGS, doc_ctx_next_toward },
+ { "quantize", ctx_mpd_qquantize, METH_VARARGS, doc_ctx_quantize },
+ { "remainder", ctx_mpd_qrem, METH_VARARGS, doc_ctx_remainder },
+ { "remainder_near", ctx_mpd_qrem_near, METH_VARARGS, doc_ctx_remainder_near },
+ { "subtract", ctx_mpd_qsub, METH_VARARGS, doc_ctx_subtract },
+
+ /* Binary or ternary arithmetic functions */
+ { "power", (PyCFunction)ctx_mpd_qpow, METH_VARARGS|METH_KEYWORDS, doc_ctx_power },
+
+ /* Ternary arithmetic functions */
+ { "fma", ctx_mpd_qfma, METH_VARARGS, doc_ctx_fma },
+
+ /* No argument */
+ { "Etiny", context_getetiny, METH_NOARGS, doc_ctx_Etiny },
+ { "Etop", context_getetop, METH_NOARGS, doc_ctx_Etop },
+ { "radix", ctx_mpd_radix, METH_NOARGS, doc_ctx_radix },
+
+ /* Boolean functions */
+ { "is_canonical", ctx_iscanonical, METH_O, doc_ctx_is_canonical },
+ { "is_finite", ctx_mpd_isfinite, METH_O, doc_ctx_is_finite },
+ { "is_infinite", ctx_mpd_isinfinite, METH_O, doc_ctx_is_infinite },
+ { "is_nan", ctx_mpd_isnan, METH_O, doc_ctx_is_nan },
+ { "is_normal", ctx_mpd_isnormal, METH_O, doc_ctx_is_normal },
+ { "is_qnan", ctx_mpd_isqnan, METH_O, doc_ctx_is_qnan },
+ { "is_signed", ctx_mpd_issigned, METH_O, doc_ctx_is_signed },
+ { "is_snan", ctx_mpd_issnan, METH_O, doc_ctx_is_snan },
+ { "is_subnormal", ctx_mpd_issubnormal, METH_O, doc_ctx_is_subnormal },
+ { "is_zero", ctx_mpd_iszero, METH_O, doc_ctx_is_zero },
+
+ /* Functions with a single decimal argument */
+ { "_apply", PyDecContext_Apply, METH_O, NULL }, /* alias for apply */
+#ifdef EXTRA_FUNCTIONALITY
+ { "apply", PyDecContext_Apply, METH_O, doc_ctx_apply },
+#endif
+ { "canonical", ctx_canonical, METH_O, doc_ctx_canonical },
+ { "copy_abs", ctx_mpd_qcopy_abs, METH_O, doc_ctx_copy_abs },
+ { "copy_decimal", ctx_copy_decimal, METH_O, doc_ctx_copy_decimal },
+ { "copy_negate", ctx_mpd_qcopy_negate, METH_O, doc_ctx_copy_negate },
+ { "logb", ctx_mpd_qlogb, METH_O, doc_ctx_logb },
+ { "logical_invert", ctx_mpd_qinvert, METH_O, doc_ctx_logical_invert },
+ { "number_class", ctx_mpd_class, METH_O, doc_ctx_number_class },
+ { "to_sci_string", ctx_mpd_to_sci, METH_O, doc_ctx_to_sci_string },
+ { "to_eng_string", ctx_mpd_to_eng, METH_O, doc_ctx_to_eng_string },
+
+ /* Functions with two decimal arguments */
+ { "compare_total", ctx_mpd_compare_total, METH_VARARGS, doc_ctx_compare_total },
+ { "compare_total_mag", ctx_mpd_compare_total_mag, METH_VARARGS, doc_ctx_compare_total_mag },
+ { "copy_sign", ctx_mpd_qcopy_sign, METH_VARARGS, doc_ctx_copy_sign },
+ { "logical_and", ctx_mpd_qand, METH_VARARGS, doc_ctx_logical_and },
+ { "logical_or", ctx_mpd_qor, METH_VARARGS, doc_ctx_logical_or },
+ { "logical_xor", ctx_mpd_qxor, METH_VARARGS, doc_ctx_logical_xor },
+ { "rotate", ctx_mpd_qrotate, METH_VARARGS, doc_ctx_rotate },
+ { "same_quantum", ctx_mpd_same_quantum, METH_VARARGS, doc_ctx_same_quantum },
+ { "scaleb", ctx_mpd_qscaleb, METH_VARARGS, doc_ctx_scaleb },
+ { "shift", ctx_mpd_qshift, METH_VARARGS, doc_ctx_shift },
+
+ /* Set context values */
+ { "clear_flags", context_clear_flags, METH_NOARGS, doc_ctx_clear_flags },
+ { "clear_traps", context_clear_traps, METH_NOARGS, doc_ctx_clear_traps },
+
+#ifdef CONFIG_32
+ /* Unsafe set functions with relaxed range checks */
+ { "_unsafe_setprec", context_unsafe_setprec, METH_O, NULL },
+ { "_unsafe_setemin", context_unsafe_setemin, METH_O, NULL },
+ { "_unsafe_setemax", context_unsafe_setemax, METH_O, NULL },
+#endif
+
+ /* Miscellaneous */
+ { "__copy__", (PyCFunction)context_copy, METH_NOARGS, NULL },
+ { "__reduce__", context_reduce, METH_NOARGS, NULL },
+ { "copy", (PyCFunction)context_copy, METH_NOARGS, doc_ctx_copy },
+ { "create_decimal", ctx_create_decimal, METH_VARARGS, doc_ctx_create_decimal },
+ { "create_decimal_from_float", ctx_from_float, METH_O, doc_ctx_create_decimal_from_float },
+
+ { NULL, NULL, 1 }
+};
+
+static PyTypeObject PyDecContext_Type =
+{
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "decimal.Context", /* tp_name */
+ sizeof(PyDecContextObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor) context_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) 0, /* tp_getattr */
+ (setattrfunc) 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc) context_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc) 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc) context_repr, /* tp_str */
+ (getattrofunc) context_getattr, /* tp_getattro */
+ (setattrofunc) context_setattr, /* tp_setattro */
+ (PyBufferProcs *) 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ doc_context, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ context_methods, /* tp_methods */
+ 0, /* tp_members */
+ context_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ context_init, /* tp_init */
+ 0, /* tp_alloc */
+ context_new, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
+
+static PyMethodDef _decimal_methods [] =
+{
+ { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext},
+ { "setcontext", (PyCFunction)PyDec_SetCurrentContext, METH_O, doc_setcontext},
+ { "localcontext", (PyCFunction)ctxmanager_new, METH_VARARGS, doc_localcontext},
+#ifdef EXTRA_FUNCTIONALITY
+ { "IEEEContext", (PyCFunction)ieee_context, METH_O, doc_ieee_context},
+#endif
+ { NULL, NULL, 1, NULL }
+};
+
+static struct PyModuleDef _decimal_module = {
+ PyModuleDef_HEAD_INIT,
+ "decimal",
+ doc__decimal,
+ -1,
+ _decimal_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct ssize_constmap { const char *name; mpd_ssize_t val; };
+static struct ssize_constmap ssize_constants [] = {
+ {"MAX_PREC", MPD_MAX_PREC},
+ {"MAX_EMAX", MPD_MAX_EMAX},
+ {"MIN_EMIN", MPD_MIN_EMIN},
+ {"MIN_ETINY", MPD_MIN_ETINY},
+ {NULL}
+};
+
+struct int_constmap { const char *name; int val; };
+static struct int_constmap int_constants [] = {
+ /* int constants */
+#ifdef EXTRA_FUNCTIONALITY
+ {"DECIMAL32", MPD_DECIMAL32},
+ {"DECIMAL64", MPD_DECIMAL64},
+ {"DECIMAL128", MPD_DECIMAL128},
+ {"IEEE_CONTEXT_MAX_BITS", MPD_IEEE_CONTEXT_MAX_BITS},
+#endif
+ {"ROUND_CEILING", MPD_ROUND_CEILING},
+ {"ROUND_FLOOR", MPD_ROUND_FLOOR},
+ {"ROUND_UP", MPD_ROUND_UP},
+ {"ROUND_DOWN", MPD_ROUND_DOWN},
+ {"ROUND_HALF_UP", MPD_ROUND_HALF_UP},
+ {"ROUND_HALF_DOWN", MPD_ROUND_HALF_DOWN},
+ {"ROUND_HALF_EVEN", MPD_ROUND_HALF_EVEN},
+ {"ROUND_05UP", MPD_ROUND_05UP},
+#ifdef EXTRA_FUNCTIONALITY
+ {"ROUND_TRUNC", MPD_ROUND_TRUNC},
+ /* int condition flags */
+ {"DecClamped", MPD_Clamped},
+ {"DecConversionSyntax", MPD_Conversion_syntax},
+ {"DecDivisionByZero", MPD_Division_by_zero},
+ {"DecDivisionImpossible", MPD_Division_impossible},
+ {"DecDivisionUndefined", MPD_Division_undefined},
+ {"DecFpuError", MPD_Fpu_error},
+ {"DecInexact", MPD_Inexact},
+ {"DecInvalidContext", MPD_Invalid_context},
+ {"DecInvalidOperation", MPD_Invalid_operation},
+ {"DecIEEEInvalidOperation", MPD_IEEE_Invalid_operation},
+ {"DecMallocError", MPD_Malloc_error},
+ {"DecFloatOperation", MPD_Float_operation},
+ {"DecOverflow", MPD_Overflow},
+ {"DecRounded", MPD_Rounded},
+ {"DecSubnormal", MPD_Subnormal},
+ {"DecUnderflow", MPD_Underflow},
+ {"DecErrors", MPD_Errors},
+ {"DecTraps", MPD_Traps},
+#endif
+ {NULL}
+};
+
+
+#define CHECK_INT(expr) \
+ do { if ((expr) < 0) goto error; } while (0)
+#define ASSIGN_PTR(result, expr) \
+ do { result = (expr); if (result == NULL) goto error; } while (0)
+#define CHECK_PTR(expr) \
+ do { if ((expr) == NULL) goto error; } while (0)
+
+PyMODINIT_FUNC
+PyInit__decimal(void)
+{
+ PyObject *m = NULL;
+ PyObject *numbers = NULL;
+ PyObject *Number = NULL;
+ PyObject *collections = NULL;
+ PyObject *MutableMapping = NULL;
+ PyObject *obj = NULL;
+ DecCondMap *cm;
+ struct ssize_constmap *ssize_cm;
+ struct int_constmap *int_cm;
+ int i;
+
+
+ /* Init libmpdec */
+ mpd_traphandler = dec_traphandler;
+ mpd_mallocfunc = PyMem_Malloc;
+ mpd_reallocfunc = PyMem_Realloc;
+ mpd_callocfunc = mpd_callocfunc_em;
+ mpd_free = PyMem_Free;
+ mpd_setminalloc(4);
+
+
+ /* Init types */
+ PyDec_Type.tp_base = &PyBaseObject_Type;
+ PyDecContext_Type.tp_base = &PyBaseObject_Type;
+ PyDecContextManager_Type.tp_base = &PyBaseObject_Type;
+ PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type;
+
+ CHECK_INT(PyType_Ready(&PyDec_Type));
+ CHECK_INT(PyType_Ready(&PyDecContext_Type));
+ CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type));
+ CHECK_INT(PyType_Ready(&PyDecContextManager_Type));
+
+ ASSIGN_PTR(obj, PyUnicode_FromString("decimal"));
+ CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj));
+ CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict,
+ "__module__", obj));
+ Py_CLEAR(obj);
+
+
+ /* Numeric abstract base classes */
+ ASSIGN_PTR(numbers, PyImport_ImportModule("numbers"));
+ ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number"));
+ /* Register Decimal with the Number abstract base class */
+ ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)",
+ (PyObject *)&PyDec_Type));
+ Py_CLEAR(obj);
+ /* Rational is a global variable used for fraction comparisons. */
+ ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational"));
+ /* Done with numbers, Number */
+ Py_CLEAR(numbers);
+ Py_CLEAR(Number);
+
+ /* DecimalTuple */
+ ASSIGN_PTR(collections, PyImport_ImportModule("collections"));
+ ASSIGN_PTR(DecimalTuple, PyObject_CallMethod(collections,
+ "namedtuple", "(ss)", "DecimalTuple",
+ "sign digits exponent"));
+ /* MutableMapping */
+ ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections,
+ "MutableMapping"));
+ /* Create SignalDict type */
+ ASSIGN_PTR(PyDecSignalDict_Type,
+ (PyTypeObject *)PyObject_CallFunction(
+ (PyObject *)&PyType_Type, "s(OO){}",
+ "SignalDict", &PyDecSignalDictMixin_Type,
+ MutableMapping));
+
+ /* Done with collections, MutableMapping */
+ Py_CLEAR(collections);
+ Py_CLEAR(MutableMapping);
+
+
+ /* Create the module */
+ ASSIGN_PTR(m, PyModule_Create(&_decimal_module));
+
+
+ /* Add types to the module */
+ Py_INCREF(&PyDec_Type);
+ CHECK_INT(PyModule_AddObject(m, "Decimal", (PyObject *)&PyDec_Type));
+ Py_INCREF(&PyDecContext_Type);
+ CHECK_INT(PyModule_AddObject(m, "Context",
+ (PyObject *)&PyDecContext_Type));
+ Py_INCREF(DecimalTuple);
+ CHECK_INT(PyModule_AddObject(m, "DecimalTuple", DecimalTuple));
+
+
+ /* Create top level exception */
+ ASSIGN_PTR(DecimalException, PyErr_NewException(
+ "decimal.DecimalException",
+ PyExc_ArithmeticError, NULL));
+ Py_INCREF(DecimalException);
+ CHECK_INT(PyModule_AddObject(m, "DecimalException", DecimalException));
+
+ /* Create signal tuple */
+ ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN));
+
+ /* Add exceptions that correspond to IEEE signals */
+ for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) {
+ ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
+ DecimalException, NULL));
+
+ /* add to module */
+ Py_INCREF(cm->ex);
+ CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex));
+
+ /* add to signal tuple */
+ Py_INCREF(cm->ex);
+ PyTuple_SET_ITEM(SignalTuple, i, cm->ex);
+ }
+
+ /*
+ * Unfortunately, InvalidOperation is a signal that comprises
+ * several conditions, including InvalidOperation! Naming the
+ * signal IEEEInvalidOperation would prevent the confusion.
+ */
+ cond_map[0].ex = signal_map[0].ex;
+
+ /* Add remaining exceptions, inherit from InvalidOperation */
+ for (cm = cond_map+1; cm->name != NULL; cm++) {
+ ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname,
+ signal_map[0].ex, NULL));
+ Py_INCREF(cm->ex);
+ CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex));
+ }
+
+
+ /* Init default context template first */
+ ASSIGN_PTR(default_context_template,
+ PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL));
+ Py_INCREF(default_context_template);
+ CHECK_INT(PyModule_AddObject(m, "DefaultContext",
+ default_context_template));
+
+#ifdef WITHOUT_THREADS
+ /* Init module context */
+ ASSIGN_PTR(module_context,
+ PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL));
+ Py_INCREF(Py_False);
+ CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_False));
+#else
+ ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__"));
+ Py_INCREF(Py_True);
+ CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_True));
+#endif
+
+ /* Init basic context template */
+ ASSIGN_PTR(basic_context_template,
+ PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL));
+ init_basic_context(basic_context_template);
+ Py_INCREF(basic_context_template);
+ CHECK_INT(PyModule_AddObject(m, "BasicContext",
+ basic_context_template));
+
+ /* Init extended context template */
+ ASSIGN_PTR(extended_context_template,
+ PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL));
+ init_extended_context(extended_context_template);
+ Py_INCREF(extended_context_template);
+ CHECK_INT(PyModule_AddObject(m, "ExtendedContext",
+ extended_context_template));
+
+
+ /* Init mpd_ssize_t constants */
+ for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) {
+ ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val));
+ CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj));
+ }
+
+ /* Init int constants */
+ for (int_cm = int_constants; int_cm->name != NULL; int_cm++) {
+ CHECK_INT(PyModule_AddIntConstant(m, int_cm->name,
+ int_cm->val));
+ }
+
+ /* Add specification version number */
+ CHECK_INT(PyModule_AddStringConstant(m, "__version__", " 1.70"));
+
+
+ return m;
+
+
+error:
+ Py_XDECREF(obj); /* GCOV_NOT_REACHED */
+ Py_XDECREF(numbers); /* GCOV_NOT_REACHED */
+ Py_XDECREF(Number); /* GCOV_NOT_REACHED */
+ Py_XDECREF(Rational); /* GCOV_NOT_REACHED */
+ Py_XDECREF(collections); /* GCOV_NOT_REACHED */
+ Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */
+ Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */
+ Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */
+#ifdef WITHOUT_THREADS
+ Py_XDECREF(module_context); /* GCOV_NOT_REACHED */
+#else
+ Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */
+ Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */
+#endif
+ Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */
+ Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */
+ Py_XDECREF(m); /* GCOV_NOT_REACHED */
+
+ return NULL; /* GCOV_NOT_REACHED */
+}
+
+
diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h
new file mode 100644
index 0000000..cf150c7
--- /dev/null
+++ b/Modules/_decimal/docstrings.h
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2001-2012 Python Software Foundation. All Rights Reserved.
+ * Modified and extended by Stefan Krah.
+ */
+
+
+#ifndef DOCSTRINGS_H
+#define DOCSTRINGS_H
+
+
+#include "pymacro.h"
+
+
+/******************************************************************************/
+/* Module */
+/******************************************************************************/
+
+
+PyDoc_STRVAR(doc__decimal,
+"C decimal arithmetic module");
+
+PyDoc_STRVAR(doc_getcontext,"\n\
+getcontext() - Get the current default context.\n\
+\n");
+
+PyDoc_STRVAR(doc_setcontext,"\n\
+setcontext(c) - Set a new default context.\n\
+\n");
+
+PyDoc_STRVAR(doc_localcontext,"\n\
+localcontext(c) - Return a context manager that will set the default context\n\
+to a copy of c on entry to the with-statement and restore the previous default\n\
+context when exiting the with-statement. If no context is specified, a copy of\n\
+the current default context is used.\n\
+\n");
+
+#ifdef EXTRA_FUNCTIONALITY
+PyDoc_STRVAR(doc_ieee_context,"\n\
+IEEEContext(bits) - Return a context object initialized to the proper values for\n\
+one of the IEEE interchange formats. The argument must be a multiple of 32 and\n\
+less than IEEE_CONTEXT_MAX_BITS. For the most common values, the constants\n\
+DECIMAL32, DECIMAL64 and DECIMAL128 are provided.\n\
+\n");
+#endif
+
+
+/******************************************************************************/
+/* Decimal Object and Methods */
+/******************************************************************************/
+
+PyDoc_STRVAR(doc_decimal,"\n\
+Decimal([value[, context]]): Construct a new Decimal object from value.\n\
+\n\
+value can be an integer, string, tuple, or another Decimal object.\n\
+If no value is given, return Decimal('0'). The context does not affect\n\
+the conversion and is only passed to determine if the InvalidOperation\n\
+trap is active.\n\
+\n");
+
+PyDoc_STRVAR(doc_adjusted,"\n\
+adjusted() - Return the adjusted exponent of the number.\n\
+\n\
+Defined as exp + digits - 1.\n\
+\n");
+
+PyDoc_STRVAR(doc_as_tuple,"\n\
+as_tuple() - Return a tuple representation of the number.\n\
+\n");
+
+PyDoc_STRVAR(doc_canonical,"\n\
+canonical() - Return the canonical encoding of the argument. Currently,\n\
+the encoding of a Decimal instance is always canonical, so this operation\n\
+returns its argument unchanged.\n\
+\n");
+
+PyDoc_STRVAR(doc_compare,"\n\
+compare(other[, context]) - Compare self to other. Return a decimal value:\n\
+\n\
+ a or b is a NaN ==> Decimal('NaN')\n\
+ a < b ==> Decimal('-1')\n\
+ a == b ==> Decimal('0')\n\
+ a > b ==> Decimal('1')\n\
+\n");
+
+PyDoc_STRVAR(doc_compare_signal,"\n\
+compare_signal(other[, context]) - Identical to compare, except that\n\
+all NaNs signal.\n\
+\n");
+
+PyDoc_STRVAR(doc_compare_total,"\n\
+compare_total(other) - Compare two operands using their abstract representation\n\
+rather than their numerical value. Similar to the compare() method, but the\n\
+result gives a total ordering on Decimal instances. Two Decimal instances with\n\
+the same numeric value but different representations compare unequal in this\n\
+ordering:\n\
+\n\
+ >>> Decimal('12.0').compare_total(Decimal('12'))\n\
+ Decimal('-1')\n\
+\n\
+Quiet and signaling NaNs are also included in the total ordering. The result\n\
+of this function is Decimal('0') if both operands have the same representation,\n\
+Decimal('-1') if the first operand is lower in the total order than the second,\n\
+and Decimal('1') if the first operand is higher in the total order than the\n\
+second operand. See the specification for details of the total order.\n\
+\n");
+
+PyDoc_STRVAR(doc_compare_total_mag,"\n\
+compare_total_mag(other) - Compare two operands using their abstract\n\
+representation rather than their value as in compare_total(), but\n\
+ignoring the sign of each operand. x.compare_total_mag(y) is\n\
+equivalent to x.copy_abs().compare_total(y.copy_abs()).\n\
+\n");
+
+PyDoc_STRVAR(doc_conjugate,"\n\
+conjugate() - Return self.\n\
+\n");
+
+PyDoc_STRVAR(doc_copy_abs,"\n\
+copy_abs() - Return the absolute value of the argument. This operation\n\
+is unaffected by the context and is quiet: no flags are changed and no\n\
+rounding is performed.\n\
+\n");
+
+PyDoc_STRVAR(doc_copy_negate,"\n\
+copy_negate() - Return the negation of the argument. This operation is\n\
+unaffected by the context and is quiet: no flags are changed and no\n\
+rounding is performed.\n\
+\n");
+
+PyDoc_STRVAR(doc_copy_sign,"\n\
+copy_sign(other) - Return a copy of the first operand with the sign set\n\
+to be the same as the sign of the second operand. For example:\n\
+\n\
+ >>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\
+ Decimal('-2.3')\n\
+\n\
+This operation is unaffected by the context and is quiet: no flags are\n\
+changed and no rounding is performed.\n\
+\n");
+
+PyDoc_STRVAR(doc_exp,"\n\
+exp([context]) - Return the value of the (natural) exponential function e**x\n\
+at the given number. The function always uses the ROUND_HALF_EVEN mode and\n\
+the result is correctly rounded.\n\
+\n");
+
+PyDoc_STRVAR(doc_from_float,"\n\
+from_float(f) - Class method that converts a float to a decimal number, exactly.\n\
+Since 0.1 is not exactly representable in binary floating point,\n\
+Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\
+\n\
+ >>> Decimal.from_float(0.1)\n\
+ Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\
+ >>> Decimal.from_float(float('nan'))\n\
+ Decimal('NaN')\n\
+ >>> Decimal.from_float(float('inf'))\n\
+ Decimal('Infinity')\n\
+ >>> Decimal.from_float(float('-inf'))\n\
+ Decimal('-Infinity')\n\
+\n\
+\n");
+
+PyDoc_STRVAR(doc_fma,"\n\
+fma(other, third[, context]) - Fused multiply-add. Return self*other+third\n\
+with no rounding of the intermediate product self*other.\n\
+\n\
+ >>> Decimal(2).fma(3, 5)\n\
+ Decimal('11')\n\
+\n\
+\n");
+
+PyDoc_STRVAR(doc_is_canonical,"\n\
+is_canonical() - Return True if the argument is canonical and False otherwise.\n\
+Currently, a Decimal instance is always canonical, so this operation always\n\
+returns True.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_finite,"\n\
+is_finite() - Return True if the argument is a finite number, and False if the\n\
+argument is infinite or a NaN.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_infinite,"\n\
+is_infinite() - Return True if the argument is either positive or negative\n\
+infinity and False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_nan,"\n\
+is_nan() - Return True if the argument is a (quiet or signaling) NaN and\n\
+False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_normal,"\n\
+is_normal([context]) - Return True if the argument is a normal finite non-zero\n\
+number with an adjusted exponent greater than or equal to Emin. Return False\n\
+if the argument is zero, subnormal, infinite or a NaN.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_qnan,"\n\
+is_qnan() - Return True if the argument is a quiet NaN, and False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_signed,"\n\
+is_signed() - Return True if the argument has a negative sign and\n\
+False otherwise. Note that both zeros and NaNs can carry signs.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_snan,"\n\
+is_snan() - Return True if the argument is a signaling NaN and False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_subnormal,"\n\
+is_subnormal([context]) - Return True if the argument is subnormal, and False\n\
+otherwise. A number is subnormal if it is non-zero, finite, and has an\n\
+adjusted exponent less than Emin.\n\
+\n");
+
+PyDoc_STRVAR(doc_is_zero,"\n\
+is_zero() - Return True if the argument is a (positive or negative) zero and\n\
+False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ln,"\n\
+ln([context]) - Return the natural (base e) logarithm of the operand.\n\
+The function always uses the ROUND_HALF_EVEN mode and the result is\n\
+correctly rounded.\n\
+\n");
+
+PyDoc_STRVAR(doc_log10,"\n\
+log10([context]) - Return the base ten logarithm of the operand.\n\
+The function always uses the ROUND_HALF_EVEN mode and the result is\n\
+correctly rounded.\n\
+\n");
+
+PyDoc_STRVAR(doc_logb,"\n\
+logb([context]) - For a non-zero number, return the adjusted exponent\n\
+of the operand as a Decimal instance. If the operand is a zero, then\n\
+Decimal('-Infinity') is returned and the DivisionByZero condition is\n\
+raised. If the operand is an infinity then Decimal('Infinity') is returned.\n\
+\n");
+
+PyDoc_STRVAR(doc_logical_and,"\n\
+logical_and(other[, context]) - Return the digit-wise and of the two\n\
+(logical) operands.\n\
+\n");
+
+PyDoc_STRVAR(doc_logical_invert,"\n\
+logical_invert([context]) - Return the digit-wise inversion of the\n\
+(logical) operand.\n\
+\n");
+
+PyDoc_STRVAR(doc_logical_or,"\n\
+logical_or(other[, context]) - Return the digit-wise or of the two\n\
+(logical) operands.\n\
+\n");
+
+PyDoc_STRVAR(doc_logical_xor,"\n\
+logical_xor(other[, context]) - Return the digit-wise exclusive or of the\n\
+two (logical) operands.\n\
+\n");
+
+PyDoc_STRVAR(doc_max,"\n\
+max(other[, context]) - Maximum of self and other. If one operand is a quiet\n\
+NaN and the other is numeric, the numeric operand is returned.\n\
+\n");
+
+PyDoc_STRVAR(doc_max_mag,"\n\
+max_mag(other[, context]) - Similar to the max() method, but the comparison is\n\
+done using the absolute values of the operands.\n\
+\n");
+
+PyDoc_STRVAR(doc_min,"\n\
+min(other[, context]) - Minimum of self and other. If one operand is a quiet\n\
+NaN and the other is numeric, the numeric operand is returned.\n\
+\n");
+
+PyDoc_STRVAR(doc_min_mag,"\n\
+min_mag(other[, context]) - Similar to the min() method, but the comparison is\n\
+done using the absolute values of the operands.\n\
+\n");
+
+PyDoc_STRVAR(doc_next_minus,"\n\
+next_minus([context]) - Return the largest number representable in the given\n\
+context (or in the current default context if no context is given) that is\n\
+smaller than the given operand.\n\
+\n");
+
+PyDoc_STRVAR(doc_next_plus,"\n\
+next_plus([context]) - Return the smallest number representable in the given\n\
+context (or in the current default context if no context is given) that is\n\
+larger than the given operand.\n\
+\n");
+
+PyDoc_STRVAR(doc_next_toward,"\n\
+next_toward(other[, context]) - If the two operands are unequal, return the\n\
+number closest to the first operand in the direction of the second operand.\n\
+If both operands are numerically equal, return a copy of the first operand\n\
+with the sign set to be the same as the sign of the second operand.\n\
+\n");
+
+PyDoc_STRVAR(doc_normalize,"\n\
+normalize([context]) - Normalize the number by stripping the rightmost trailing\n\
+zeros and converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\
+for producing canonical values for members of an equivalence class. For example,\n\
+Decimal('32.100') and Decimal('0.321000e+2') both normalize to the equivalent\n\
+value Decimal('32.1').\n\
+\n");
+
+PyDoc_STRVAR(doc_number_class,"\n\
+number_class([context]) - Return a string describing the class of the operand.\n\
+The returned value is one of the following ten strings:\n\
+\n\
+ * '-Infinity', indicating that the operand is negative infinity.\n\
+ * '-Normal', indicating that the operand is a negative normal number.\n\
+ * '-Subnormal', indicating that the operand is negative and subnormal.\n\
+ * '-Zero', indicating that the operand is a negative zero.\n\
+ * '+Zero', indicating that the operand is a positive zero.\n\
+ * '+Subnormal', indicating that the operand is positive and subnormal.\n\
+ * '+Normal', indicating that the operand is a positive normal number.\n\
+ * '+Infinity', indicating that the operand is positive infinity.\n\
+ * 'NaN', indicating that the operand is a quiet NaN (Not a Number).\n\
+ * 'sNaN', indicating that the operand is a signaling NaN.\n\
+\n\
+\n");
+
+PyDoc_STRVAR(doc_quantize,"\n\
+quantize(exp[, rounding[, context]]) - Return a value equal to the first\n\
+operand after rounding and having the exponent of the second operand.\n\
+\n\
+ >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\
+ Decimal('1.414')\n\
+\n\
+Unlike other operations, if the length of the coefficient after the quantize\n\
+operation would be greater than precision, then an InvalidOperation is signaled.\n\
+This guarantees that, unless there is an error condition, the quantized exponent\n\
+is always equal to that of the right-hand operand.\n\
+\n\
+Also unlike other operations, quantize never signals Underflow, even if the\n\
+result is subnormal and inexact.\n\
+\n\
+If the exponent of the second operand is larger than that of the first, then\n\
+rounding may be necessary. In this case, the rounding mode is determined by the\n\
+rounding argument if given, else by the given context argument; if neither\n\
+argument is given, the rounding mode of the current thread's context is used.\n\
+\n");
+
+PyDoc_STRVAR(doc_radix,"\n\
+radix() - Return Decimal(10), the radix (base) in which the Decimal class does\n\
+all its arithmetic. Included for compatibility with the specification.\n\
+\n");
+
+PyDoc_STRVAR(doc_remainder_near,"\n\
+remainder_near(other[, context]) - Compute the modulo as either a positive\n\
+or negative value depending on which is closest to zero. For instance,\n\
+Decimal(10).remainder_near(6) returns Decimal('-2'), which is closer to zero\n\
+than Decimal('4').\n\
+\n\
+If both are equally close, the one chosen will have the same sign as self.\n\
+\n");
+
+PyDoc_STRVAR(doc_rotate,"\n\
+rotate(other[, context]) - Return the result of rotating the digits of the\n\
+first operand by an amount specified by the second operand. The second operand\n\
+must be an integer in the range -precision through precision. The absolute\n\
+value of the second operand gives the number of places to rotate. If the second\n\
+operand is positive then rotation is to the left; otherwise rotation is to the\n\
+right. The coefficient of the first operand is padded on the left with zeros to\n\
+length precision if necessary. The sign and exponent of the first operand are\n\
+unchanged.\n\
+\n");
+
+PyDoc_STRVAR(doc_same_quantum,"\n\
+same_quantum(other[, context]) - Test whether self and other have the\n\
+same exponent or whether both are NaN.\n\
+\n");
+
+PyDoc_STRVAR(doc_scaleb,"\n\
+scaleb(other[, context]) - Return the first operand with the exponent adjusted\n\
+the second. Equivalently, return the first operand multiplied by 10**other.\n\
+The second operand must be an integer.\n\
+\n");
+
+PyDoc_STRVAR(doc_shift,"\n\
+shift(other[, context]) - Return the result of shifting the digits of\n\
+the first operand by an amount specified by the second operand. The second\n\
+operand must be an integer in the range -precision through precision. The\n\
+absolute value of the second operand gives the number of places to shift.\n\
+If the second operand is positive, then the shift is to the left; otherwise\n\
+the shift is to the right. Digits shifted into the coefficient are zeros.\n\
+The sign and exponent of the first operand are unchanged.\n\
+\n");
+
+PyDoc_STRVAR(doc_sqrt,"\n\
+sqrt([context]) - Return the square root of the argument to full precision.\n\
+The result is correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\
+\n");
+
+PyDoc_STRVAR(doc_to_eng_string,"\n\
+to_eng_string([context]) - Convert to an engineering-type string.\n\
+Engineering notation has an exponent which is a multiple of 3, so\n\
+there are up to 3 digits left of the decimal place. For example,\n\
+Decimal('123E+1') is converted to Decimal('1.23E+3')\n\
+\n");
+
+PyDoc_STRVAR(doc_to_integral,"\n\
+to_integral([rounding[, context]]) - Identical to the to_integral_value()\n\
+method. The to_integral name has been kept for compatibility with older\n\
+versions.\n\
+\n");
+
+PyDoc_STRVAR(doc_to_integral_exact,"\n\
+to_integral_exact([rounding[, context]]) - Round to the nearest integer,\n\
+signaling Inexact or Rounded as appropriate if rounding occurs. The rounding\n\
+mode is determined by the rounding parameter if given, else by the given\n\
+context. If neither parameter is given, then the rounding mode of the current\n\
+default context is used.\n\
+\n");
+
+PyDoc_STRVAR(doc_to_integral_value,"\n\
+to_integral_value([rounding[, context]]) - Round to the nearest integer without\n\
+signaling Inexact or Rounded. The rounding mode is determined by the rounding\n\
+parameter if given, else by the given context. If neither parameter is given,\n\
+then the rounding mode of the current default context is used.\n\
+\n");
+
+
+/******************************************************************************/
+/* Context Object and Methods */
+/******************************************************************************/
+
+PyDoc_STRVAR(doc_context,"\n\
+The context affects almost all operations and controls rounding,\n\
+Over/Underflow, raising of exceptions and much more. A new context\n\
+can be constructed as follows:\n\
+\n\
+ >>> c = Context(prec=28, Emin=-425000000, Emax=425000000,\n\
+ ... rounding=ROUND_HALF_EVEN, capitals=1, clamp=1,\n\
+ ... traps=[InvalidOperation, DivisionByZero, Overflow],\n\
+ ... flags=[])\n\
+ >>>\n\
+\n\
+\n");
+
+#ifdef EXTRA_FUNCTIONALITY
+PyDoc_STRVAR(doc_ctx_apply,"\n\
+apply(x) - Apply self to Decimal x.\n\
+\n");
+#endif
+
+PyDoc_STRVAR(doc_ctx_clear_flags,"\n\
+clear_flags() - Reset all flags to False.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_clear_traps,"\n\
+clear_traps() - Set all traps to False.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_copy,"\n\
+copy() - Return a duplicate of the context with all flags cleared.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_copy_decimal,"\n\
+copy_decimal(x) - Return a copy of Decimal x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_create_decimal,"\n\
+create_decimal(x) - Create a new Decimal instance from x, using self as the\n\
+context. Unlike the Decimal constructor, this function observes the context\n\
+limits.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_create_decimal_from_float,"\n\
+create_decimal_from_float(f) - Create a new Decimal instance from float f.\n\
+Unlike the Decimal.from_float() class method, this function observes the\n\
+context limits.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_Etiny,"\n\
+Etiny() - Return a value equal to Emin - prec + 1, which is the minimum\n\
+exponent value for subnormal results. When underflow occurs, the exponent\n\
+is set to Etiny.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_Etop,"\n\
+Etop() - Return a value equal to Emax - prec + 1. This is the maximum exponent\n\
+if the _clamp field of the context is set to 1 (IEEE clamp mode). Etop() must\n\
+not be negative.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_abs,"\n\
+abs(x) - Return the absolute value of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_add,"\n\
+add(x, y) - Return the sum of x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_canonical,"\n\
+canonical(x) - Return a new instance of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_compare,"\n\
+compare(x, y) - Compare x and y numerically.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_compare_signal,"\n\
+compare_signal(x, y) - Compare x and y numerically. All NaNs signal.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_compare_total,"\n\
+compare_total(x, y) - Compare x and y using their abstract representation.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_compare_total_mag,"\n\
+compare_total_mag(x, y) - Compare x and y using their abstract representation,\n\
+ignoring sign.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_copy_abs,"\n\
+copy_abs(x) - Return a copy of x with the sign set to 0.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_copy_negate,"\n\
+copy_negate(x) - Return a copy of x with the sign inverted.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_copy_sign,"\n\
+copy_sign(x, y) - Copy the sign from y to x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_divide,"\n\
+divide(x, y) - Return x divided by y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_divide_int,"\n\
+divide_int(x, y) - Return x divided by y, truncated to an integer.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_divmod,"\n\
+divmod(x, y) - Return quotient and remainder of the division x / y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_exp,"\n\
+exp(x) - Return e ** x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_fma,"\n\
+fma(x, y, z) - Return x multiplied by y, plus z.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_canonical,"\n\
+is_canonical(x) - Return True if x is canonical, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_finite,"\n\
+is_finite(x) - Return True if x is finite, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_infinite,"\n\
+is_infinite(x) - Return True if x is infinite, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_nan,"\n\
+is_nan(x) - Return True if x is a qNaN or sNaN, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_normal,"\n\
+is_normal(x) - Return True if x is a normal number, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_qnan,"\n\
+is_qnan(x) - Return True if x is a quiet NaN, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_signed,"\n\
+is_signed(x) - Return True if x is negative, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_snan,"\n\
+is_snan() - Return True if x is a signaling NaN, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_subnormal,"\n\
+is_subnormal(x) - Return True if x is subnormal, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_is_zero,"\n\
+is_zero(x) - Return True if x is a zero, False otherwise.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_ln,"\n\
+ln(x) - Return the natural (base e) logarithm of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_log10,"\n\
+log10(x) - Return the base 10 logarithm of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_logb,"\n\
+logb(x) - Return the exponent of the magnitude of the operand's MSD.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_logical_and,"\n\
+logical_and(x, y) - Digit-wise and of x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_logical_invert,"\n\
+logical_invert(x) - Invert all digits of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_logical_or,"\n\
+logical_or(x, y) - Digit-wise or of x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_logical_xor,"\n\
+logical_xor(x, y) - Digit-wise xor of x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_max,"\n\
+max(x, y) - Compare the values numerically and return the maximum.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_max_mag,"\n\
+max_mag(x, y) - Compare the values numerically with their sign ignored.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_min,"\n\
+min(x, y) - Compare the values numerically and return the minimum.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_min_mag,"\n\
+min_mag(x, y) - Compare the values numerically with their sign ignored.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_minus,"\n\
+minus(x) - Minus corresponds to the unary prefix minus operator in Python,\n\
+but applies the context to the result.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_multiply,"\n\
+multiply(x, y) - Return the product of x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_next_minus,"\n\
+next_minus(x) - Return the largest representable number smaller than x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_next_plus,"\n\
+next_plus(x) - Return the smallest representable number larger than x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_next_toward,"\n\
+next_toward(x) - Return the number closest to x, in the direction towards y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_normalize,"\n\
+normalize(x) - Reduce x to its simplest form. Alias for reduce(x).\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_number_class,"\n\
+number_class(x) - Return an indication of the class of x.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_plus,"\n\
+plus(x) - Plus corresponds to the unary prefix plus operator in Python,\n\
+but applies the context to the result.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_power,"\n\
+power(x, y) - Compute x**y. If x is negative, then y must be integral.\n\
+The result will be inexact unless y is integral and the result is finite\n\
+and can be expressed exactly in 'precision' digits. In the Python version\n\
+the result is always correctly rounded, in the C version the result is\n\
+almost always correctly rounded.\n\
+\n\
+power(x, y, m) - Compute (x**y) % m. The following restrictions hold:\n\
+\n\
+ * all three arguments must be integral\n\
+ * y must be nonnegative\n\
+ * at least one of x or y must be nonzero\n\
+ * m must be nonzero and less than 10**prec in absolute value\n\
+\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_quantize,"\n\
+quantize(x, y) - Return a value equal to x (rounded), having the exponent of y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_radix,"\n\
+radix() - Return 10.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_remainder,"\n\
+remainder(x, y) - Return the remainder from integer division. The sign of\n\
+the result, if non-zero, is the same as that of the original dividend.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_remainder_near,"\n\
+remainder_near(x, y) - Return x - y * n, where n is the integer nearest the\n\
+exact value of x / y (if the result is 0 then its sign will be the sign of x).\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_rotate,"\n\
+rotate(x, y) - Return a copy of x, rotated by y places.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_same_quantum,"\n\
+same_quantum(x, y) - Return True if the two operands have the same exponent.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_scaleb,"\n\
+scaleb(x, y) - Return the first operand after adding the second value\n\
+to its exp.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_shift,"\n\
+shift(x, y) - Return a copy of x, shifted by y places.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_sqrt,"\n\
+sqrt(x) - Square root of a non-negative number to context precision.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_subtract,"\n\
+subtract(x, y) - Return the difference between x and y.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_to_eng_string,"\n\
+to_eng_string(x) - Convert a number to a string, using engineering notation.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_to_integral,"\n\
+to_integral(x) - Identical to to_integral_value(x).\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_to_integral_exact,"\n\
+to_integral_exact(x) - Round to an integer. Signal if the result is\n\
+rounded or inexact.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_to_integral_value,"\n\
+to_integral_value(x) - Round to an integer.\n\
+\n");
+
+PyDoc_STRVAR(doc_ctx_to_sci_string,"\n\
+to_sci_string(x) - Convert a number to a string using scientific notation.\n\
+\n");
+
+
+#endif /* DOCSTRINGS_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/README.txt b/Modules/_decimal/libmpdec/README.txt
new file mode 100644
index 0000000..ad8f88c
--- /dev/null
+++ b/Modules/_decimal/libmpdec/README.txt
@@ -0,0 +1,90 @@
+
+
+libmpdec
+========
+
+libmpdec is a fast C/C++ library for correctly-rounded arbitrary precision
+decimal floating point arithmetic. It is a complete implementation of
+Mike Cowlishaw/IBM's General Decimal Arithmetic Specification.
+
+
+Files required for the Python _decimal module
+=============================================
+
+ Core files for small and medium precision arithmetic
+ ----------------------------------------------------
+
+ basearith.{c,h} -> Core arithmetic in base 10**9 or 10**19.
+ bits.h -> Portable detection of least/most significant one-bit.
+ constants.{c,h} -> Constants that are used in multiple files.
+ context.c -> Context functions.
+ io.{c,h} -> Conversions between mpd_t and ASCII strings,
+ mpd_t formatting (allows UTF-8 fill character).
+ memory.{c,h} -> Allocation handlers with overflow detection
+ and functions for switching between static
+ and dynamic mpd_t.
+ mpdecimal.{c,h} -> All (quiet) functions of the specification.
+ typearith.h -> Fast primitives for double word multiplication,
+ division etc.
+
+ Visual Studio only:
+ ~~~~~~~~~~~~~~~~~~~
+ vccompat.h -> snprintf <==> sprintf_s and similar things.
+ vcstdint.h -> stdint.h (included in VS 2010 but not in VS 2008).
+ vcdiv64.asm -> Double word division used in typearith.h. VS 2008 does
+ not allow inline asm for x64. Also, it does not provide
+ an intrinsic for double word division.
+
+ Files for bignum arithmetic:
+ ----------------------------
+
+ The following files implement the Fast Number Theoretic Transform
+ used for multiplying coefficients with more than 1024 words (see
+ mpdecimal.c: _mpd_fntmul()).
+
+ umodarith.h -> Fast low level routines for unsigned modular arithmetic.
+ numbertheory.{c,h} -> Routines for setting up the Number Theoretic Transform.
+ difradix2.{c,h} -> Decimation in frequency transform, used as the
+ "base case" by the following three files:
+
+ fnt.{c,h} -> Transform arrays up to 4096 words.
+ sixstep.{c,h} -> Transform larger arrays of length 2**n.
+ fourstep.{c,h} -> Transform larger arrays of length 3 * 2**n.
+
+ convolute.{c,h} -> Fast convolution using one of the three transform
+ functions.
+ transpose.{c,h} -> Transpositions needed for the sixstep algorithm.
+ crt.{c,h} -> Chinese Remainder Theorem: use information from three
+ transforms modulo three different primes to get the
+ final result.
+
+
+Pointers to literature, proofs and more
+=======================================
+
+ literature/
+ -----------
+
+ REFERENCES.txt -> List of relevant papers.
+ bignum.txt -> Explanation of the Fast Number Theoretic Transform (FNT).
+ fnt.py -> Verify constants used in the FNT; Python demo for the
+ O(N**2) discrete transform.
+
+ matrix-transform.txt -> Proof for the Matrix Fourier Transform used in
+ fourstep.c.
+ six-step.txt -> Show that the algorithm used in sixstep.c is
+ a variant of the Matrix Fourier Transform.
+ mulmod-64.txt -> Proof for the mulmod64 algorithm from
+ umodarith.h.
+ mulmod-ppro.txt -> Proof for the x87 FPU modular multiplication
+ from umodarith.h.
+ umodarith.lisp -> ACL2 proofs for many functions from umodarith.h.
+
+
+Library Author
+==============
+
+ Stefan Krah <skrah@bytereef.org>
+
+
+
diff --git a/Modules/_decimal/libmpdec/basearith.c b/Modules/_decimal/libmpdec/basearith.c
new file mode 100644
index 0000000..e9d5024
--- /dev/null
+++ b/Modules/_decimal/libmpdec/basearith.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "constants.h"
+#include "memory.h"
+#include "typearith.h"
+#include "basearith.h"
+
+
+/*********************************************************************/
+/* Calculations in base MPD_RADIX */
+/*********************************************************************/
+
+
+/*
+ * Knuth, TAOCP, Volume 2, 4.3.1:
+ * w := sum of u (len m) and v (len n)
+ * n > 0 and m >= n
+ * The calling function has to handle a possible final carry.
+ */
+mpd_uint_t
+_mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n)
+{
+ mpd_uint_t s;
+ mpd_uint_t carry = 0;
+ mpd_size_t i;
+
+ assert(n > 0 && m >= n);
+
+ /* add n members of u and v */
+ for (i = 0; i < n; i++) {
+ s = u[i] + (v[i] + carry);
+ carry = (s < u[i]) | (s >= MPD_RADIX);
+ w[i] = carry ? s-MPD_RADIX : s;
+ }
+ /* if there is a carry, propagate it */
+ for (; carry && i < m; i++) {
+ s = u[i] + carry;
+ carry = (s == MPD_RADIX);
+ w[i] = carry ? 0 : s;
+ }
+ /* copy the rest of u */
+ for (; i < m; i++) {
+ w[i] = u[i];
+ }
+
+ return carry;
+}
+
+/*
+ * Add the contents of u to w. Carries are propagated further. The caller
+ * has to make sure that w is big enough.
+ */
+void
+_mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n)
+{
+ mpd_uint_t s;
+ mpd_uint_t carry = 0;
+ mpd_size_t i;
+
+ if (n == 0) return;
+
+ /* add n members of u to w */
+ for (i = 0; i < n; i++) {
+ s = w[i] + (u[i] + carry);
+ carry = (s < w[i]) | (s >= MPD_RADIX);
+ w[i] = carry ? s-MPD_RADIX : s;
+ }
+ /* if there is a carry, propagate it */
+ for (; carry; i++) {
+ s = w[i] + carry;
+ carry = (s == MPD_RADIX);
+ w[i] = carry ? 0 : s;
+ }
+}
+
+/*
+ * Add v to w (len m). The calling function has to handle a possible
+ * final carry. Assumption: m > 0.
+ */
+mpd_uint_t
+_mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v)
+{
+ mpd_uint_t s;
+ mpd_uint_t carry;
+ mpd_size_t i;
+
+ assert(m > 0);
+
+ /* add v to w */
+ s = w[0] + v;
+ carry = (s < v) | (s >= MPD_RADIX);
+ w[0] = carry ? s-MPD_RADIX : s;
+
+ /* if there is a carry, propagate it */
+ for (i = 1; carry && i < m; i++) {
+ s = w[i] + carry;
+ carry = (s == MPD_RADIX);
+ w[i] = carry ? 0 : s;
+ }
+
+ return carry;
+}
+
+/* Increment u. The calling function has to handle a possible carry. */
+mpd_uint_t
+_mpd_baseincr(mpd_uint_t *u, mpd_size_t n)
+{
+ mpd_uint_t s;
+ mpd_uint_t carry = 1;
+ mpd_size_t i;
+
+ assert(n > 0);
+
+ /* if there is a carry, propagate it */
+ for (i = 0; carry && i < n; i++) {
+ s = u[i] + carry;
+ carry = (s == MPD_RADIX);
+ u[i] = carry ? 0 : s;
+ }
+
+ return carry;
+}
+
+/*
+ * Knuth, TAOCP, Volume 2, 4.3.1:
+ * w := difference of u (len m) and v (len n).
+ * number in u >= number in v;
+ */
+void
+_mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n)
+{
+ mpd_uint_t d;
+ mpd_uint_t borrow = 0;
+ mpd_size_t i;
+
+ assert(m > 0 && n > 0);
+
+ /* subtract n members of v from u */
+ for (i = 0; i < n; i++) {
+ d = u[i] - (v[i] + borrow);
+ borrow = (u[i] < d);
+ w[i] = borrow ? d + MPD_RADIX : d;
+ }
+ /* if there is a borrow, propagate it */
+ for (; borrow && i < m; i++) {
+ d = u[i] - borrow;
+ borrow = (u[i] == 0);
+ w[i] = borrow ? MPD_RADIX-1 : d;
+ }
+ /* copy the rest of u */
+ for (; i < m; i++) {
+ w[i] = u[i];
+ }
+}
+
+/*
+ * Subtract the contents of u from w. w is larger than u. Borrows are
+ * propagated further, but eventually w can absorb the final borrow.
+ */
+void
+_mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n)
+{
+ mpd_uint_t d;
+ mpd_uint_t borrow = 0;
+ mpd_size_t i;
+
+ if (n == 0) return;
+
+ /* subtract n members of u from w */
+ for (i = 0; i < n; i++) {
+ d = w[i] - (u[i] + borrow);
+ borrow = (w[i] < d);
+ w[i] = borrow ? d + MPD_RADIX : d;
+ }
+ /* if there is a borrow, propagate it */
+ for (; borrow; i++) {
+ d = w[i] - borrow;
+ borrow = (w[i] == 0);
+ w[i] = borrow ? MPD_RADIX-1 : d;
+ }
+}
+
+/* w := product of u (len n) and v (single word) */
+void
+_mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t carry = 0;
+ mpd_size_t i;
+
+ assert(n > 0);
+
+ for (i=0; i < n; i++) {
+
+ _mpd_mul_words(&hi, &lo, u[i], v);
+ lo = carry + lo;
+ if (lo < carry) hi++;
+
+ _mpd_div_words_r(&carry, &w[i], hi, lo);
+ }
+ w[i] = carry;
+}
+
+/*
+ * Knuth, TAOCP, Volume 2, 4.3.1:
+ * w := product of u (len m) and v (len n)
+ * w must be initialized to zero
+ */
+void
+_mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t carry;
+ mpd_size_t i, j;
+
+ assert(m > 0 && n > 0);
+
+ for (j=0; j < n; j++) {
+ carry = 0;
+ for (i=0; i < m; i++) {
+
+ _mpd_mul_words(&hi, &lo, u[i], v[j]);
+ lo = w[i+j] + lo;
+ if (lo < w[i+j]) hi++;
+ lo = carry + lo;
+ if (lo < carry) hi++;
+
+ _mpd_div_words_r(&carry, &w[i+j], hi, lo);
+ }
+ w[j+m] = carry;
+ }
+}
+
+/*
+ * Knuth, TAOCP Volume 2, 4.3.1, exercise 16:
+ * w := quotient of u (len n) divided by a single word v
+ */
+mpd_uint_t
+_mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t rem = 0;
+ mpd_size_t i;
+
+ assert(n > 0);
+
+ for (i=n-1; i != MPD_SIZE_MAX; i--) {
+
+ _mpd_mul_words(&hi, &lo, rem, MPD_RADIX);
+ lo = u[i] + lo;
+ if (lo < u[i]) hi++;
+
+ _mpd_div_words(&w[i], &rem, hi, lo, v);
+ }
+
+ return rem;
+}
+
+/*
+ * Knuth, TAOCP Volume 2, 4.3.1:
+ * q, r := quotient and remainder of uconst (len nplusm)
+ * divided by vconst (len n)
+ * nplusm >= n
+ *
+ * If r is not NULL, r will contain the remainder. If r is NULL, the
+ * return value indicates if there is a remainder: 1 for true, 0 for
+ * false. A return value of -1 indicates an error.
+ */
+int
+_mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r,
+ const mpd_uint_t *uconst, const mpd_uint_t *vconst,
+ mpd_size_t nplusm, mpd_size_t n)
+{
+ mpd_uint_t ustatic[MPD_MINALLOC_MAX];
+ mpd_uint_t vstatic[MPD_MINALLOC_MAX];
+ mpd_uint_t *u = ustatic;
+ mpd_uint_t *v = vstatic;
+ mpd_uint_t d, qhat, rhat, w2[2];
+ mpd_uint_t hi, lo, x;
+ mpd_uint_t carry;
+ mpd_size_t i, j, m;
+ int retval = 0;
+
+ assert(n > 1 && nplusm >= n);
+ m = sub_size_t(nplusm, n);
+
+ /* D1: normalize */
+ d = MPD_RADIX / (vconst[n-1] + 1);
+
+ if (nplusm >= MPD_MINALLOC_MAX) {
+ if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) {
+ return -1;
+ }
+ }
+ if (n >= MPD_MINALLOC_MAX) {
+ if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) {
+ mpd_free(u);
+ return -1;
+ }
+ }
+
+ _mpd_shortmul(u, uconst, nplusm, d);
+ _mpd_shortmul(v, vconst, n, d);
+
+ /* D2: loop */
+ for (j=m; j != MPD_SIZE_MAX; j--) {
+
+ /* D3: calculate qhat and rhat */
+ rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]);
+ qhat = w2[1] * MPD_RADIX + w2[0];
+
+ while (1) {
+ if (qhat < MPD_RADIX) {
+ _mpd_singlemul(w2, qhat, v[n-2]);
+ if (w2[1] <= rhat) {
+ if (w2[1] != rhat || w2[0] <= u[j+n-2]) {
+ break;
+ }
+ }
+ }
+ qhat -= 1;
+ rhat += v[n-1];
+ if (rhat < v[n-1] || rhat >= MPD_RADIX) {
+ break;
+ }
+ }
+ /* D4: multiply and subtract */
+ carry = 0;
+ for (i=0; i <= n; i++) {
+
+ _mpd_mul_words(&hi, &lo, qhat, v[i]);
+
+ lo = carry + lo;
+ if (lo < carry) hi++;
+
+ _mpd_div_words_r(&hi, &lo, hi, lo);
+
+ x = u[i+j] - lo;
+ carry = (u[i+j] < x);
+ u[i+j] = carry ? x+MPD_RADIX : x;
+ carry += hi;
+ }
+ q[j] = qhat;
+ /* D5: test remainder */
+ if (carry) {
+ q[j] -= 1;
+ /* D6: add back */
+ (void)_mpd_baseadd(u+j, u+j, v, n+1, n);
+ }
+ }
+
+ /* D8: unnormalize */
+ if (r != NULL) {
+ _mpd_shortdiv(r, u, n, d);
+ /* we are not interested in the return value here */
+ retval = 0;
+ }
+ else {
+ retval = !_mpd_isallzero(u, n);
+ }
+
+
+if (u != ustatic) mpd_free(u);
+if (v != vstatic) mpd_free(v);
+return retval;
+}
+
+/*
+ * Left shift of src by 'shift' digits; src may equal dest.
+ *
+ * dest := area of n mpd_uint_t with space for srcdigits+shift digits.
+ * src := coefficient with length m.
+ *
+ * The case splits in the function are non-obvious. The following
+ * equations might help:
+ *
+ * Let msdigits denote the number of digits in the most significant
+ * word of src. Then 1 <= msdigits <= rdigits.
+ *
+ * 1) shift = q * rdigits + r
+ * 2) srcdigits = qsrc * rdigits + msdigits
+ * 3) destdigits = shift + srcdigits
+ * = q * rdigits + r + qsrc * rdigits + msdigits
+ * = q * rdigits + (qsrc * rdigits + (r + msdigits))
+ *
+ * The result has q zero words, followed by the coefficient that
+ * is left-shifted by r. The case r == 0 is trivial. For r > 0, it
+ * is important to keep in mind that we always read m source words,
+ * but write m+1 destination words if r + msdigits > rdigits, m words
+ * otherwise.
+ */
+void
+_mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m,
+ mpd_size_t shift)
+{
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+ /* spurious uninitialized warnings */
+ mpd_uint_t l=l, lprev=lprev, h=h;
+#else
+ mpd_uint_t l, lprev, h;
+#endif
+ mpd_uint_t q, r;
+ mpd_uint_t ph;
+
+ assert(m > 0 && n >= m);
+
+ _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);
+
+ if (r != 0) {
+
+ ph = mpd_pow10[r];
+
+ --m; --n;
+ _mpd_divmod_pow10(&h, &lprev, src[m--], MPD_RDIGITS-r);
+ if (h != 0) { /* r + msdigits > rdigits <==> h != 0 */
+ dest[n--] = h;
+ }
+ /* write m-1 shifted words */
+ for (; m != MPD_SIZE_MAX; m--,n--) {
+ _mpd_divmod_pow10(&h, &l, src[m], MPD_RDIGITS-r);
+ dest[n] = ph * lprev + h;
+ lprev = l;
+ }
+ /* write least significant word */
+ dest[q] = ph * lprev;
+ }
+ else {
+ while (--m != MPD_SIZE_MAX) {
+ dest[m+q] = src[m];
+ }
+ }
+
+ mpd_uint_zero(dest, q);
+}
+
+/*
+ * Right shift of src by 'shift' digits; src may equal dest.
+ * Assumption: srcdigits-shift > 0.
+ *
+ * dest := area with space for srcdigits-shift digits.
+ * src := coefficient with length 'slen'.
+ *
+ * The case splits in the function rely on the following equations:
+ *
+ * Let msdigits denote the number of digits in the most significant
+ * word of src. Then 1 <= msdigits <= rdigits.
+ *
+ * 1) shift = q * rdigits + r
+ * 2) srcdigits = qsrc * rdigits + msdigits
+ * 3) destdigits = srcdigits - shift
+ * = qsrc * rdigits + msdigits - (q * rdigits + r)
+ * = (qsrc - q) * rdigits + msdigits - r
+ *
+ * Since destdigits > 0 and 1 <= msdigits <= rdigits:
+ *
+ * 4) qsrc >= q
+ * 5) qsrc == q ==> msdigits > r
+ *
+ * The result has slen-q words if msdigits > r, slen-q-1 words otherwise.
+ */
+mpd_uint_t
+_mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen,
+ mpd_size_t shift)
+{
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+ /* spurious uninitialized warnings */
+ mpd_uint_t l=l, h=h, hprev=hprev; /* low, high, previous high */
+#else
+ mpd_uint_t l, h, hprev; /* low, high, previous high */
+#endif
+ mpd_uint_t rnd, rest; /* rounding digit, rest */
+ mpd_uint_t q, r;
+ mpd_size_t i, j;
+ mpd_uint_t ph;
+
+ assert(slen > 0);
+
+ _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);
+
+ rnd = rest = 0;
+ if (r != 0) {
+
+ ph = mpd_pow10[MPD_RDIGITS-r];
+
+ _mpd_divmod_pow10(&hprev, &rest, src[q], r);
+ _mpd_divmod_pow10(&rnd, &rest, rest, r-1);
+
+ if (rest == 0 && q > 0) {
+ rest = !_mpd_isallzero(src, q);
+ }
+ /* write slen-q-1 words */
+ for (j=0,i=q+1; i<slen; i++,j++) {
+ _mpd_divmod_pow10(&h, &l, src[i], r);
+ dest[j] = ph * l + hprev;
+ hprev = h;
+ }
+ /* write most significant word */
+ if (hprev != 0) { /* always the case if slen==q-1 */
+ dest[j] = hprev;
+ }
+ }
+ else {
+ if (q > 0) {
+ _mpd_divmod_pow10(&rnd, &rest, src[q-1], MPD_RDIGITS-1);
+ /* is there any non-zero digit below rnd? */
+ if (rest == 0) rest = !_mpd_isallzero(src, q-1);
+ }
+ for (j = 0; j < slen-q; j++) {
+ dest[j] = src[q+j];
+ }
+ }
+
+ /* 0-4 ==> rnd+rest < 0.5 */
+ /* 5 ==> rnd+rest == 0.5 */
+ /* 6-9 ==> rnd+rest > 0.5 */
+ return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd;
+}
+
+
+/*********************************************************************/
+/* Calculations in base b */
+/*********************************************************************/
+
+/*
+ * Add v to w (len m). The calling function has to handle a possible
+ * final carry. Assumption: m > 0.
+ */
+mpd_uint_t
+_mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b)
+{
+ mpd_uint_t s;
+ mpd_uint_t carry;
+ mpd_size_t i;
+
+ assert(m > 0);
+
+ /* add v to w */
+ s = w[0] + v;
+ carry = (s < v) | (s >= b);
+ w[0] = carry ? s-b : s;
+
+ /* if there is a carry, propagate it */
+ for (i = 1; carry && i < m; i++) {
+ s = w[i] + carry;
+ carry = (s == b);
+ w[i] = carry ? 0 : s;
+ }
+
+ return carry;
+}
+
+/* w := product of u (len n) and v (single word) */
+void
+_mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v, mpd_uint_t b)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t carry = 0;
+ mpd_size_t i;
+
+ assert(n > 0);
+
+ for (i=0; i < n; i++) {
+
+ _mpd_mul_words(&hi, &lo, u[i], v);
+ lo = carry + lo;
+ if (lo < carry) hi++;
+
+ _mpd_div_words(&carry, &w[i], hi, lo, b);
+ }
+ w[i] = carry;
+}
+
+/*
+ * Knuth, TAOCP Volume 2, 4.3.1, exercise 16:
+ * w := quotient of u (len n) divided by a single word v
+ */
+mpd_uint_t
+_mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v, mpd_uint_t b)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t rem = 0;
+ mpd_size_t i;
+
+ assert(n > 0);
+
+ for (i=n-1; i != MPD_SIZE_MAX; i--) {
+
+ _mpd_mul_words(&hi, &lo, rem, b);
+ lo = u[i] + lo;
+ if (lo < u[i]) hi++;
+
+ _mpd_div_words(&w[i], &rem, hi, lo, v);
+ }
+
+ return rem;
+}
+
+
+
diff --git a/Modules/_decimal/libmpdec/basearith.h b/Modules/_decimal/libmpdec/basearith.h
new file mode 100644
index 0000000..94de862
--- /dev/null
+++ b/Modules/_decimal/libmpdec/basearith.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef BASEARITH_H
+#define BASEARITH_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include "typearith.h"
+
+
+mpd_uint_t _mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n);
+void _mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n);
+mpd_uint_t _mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v);
+mpd_uint_t _mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v,
+ mpd_uint_t b);
+mpd_uint_t _mpd_baseincr(mpd_uint_t *u, mpd_size_t n);
+void _mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n);
+void _mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n);
+void _mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t m, mpd_size_t n);
+void _mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v);
+void _mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v, mpd_uint_t b);
+mpd_uint_t _mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v);
+mpd_uint_t _mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n,
+ mpd_uint_t v, mpd_uint_t b);
+int _mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, const mpd_uint_t *uconst,
+ const mpd_uint_t *vconst, mpd_size_t nplusm, mpd_size_t n);
+void _mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n,
+ mpd_size_t m, mpd_size_t shift);
+mpd_uint_t _mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen,
+ mpd_size_t shift);
+
+
+
+#ifdef CONFIG_64
+extern const mpd_uint_t mprime_rdx;
+
+/*
+ * Algorithm from: Division by Invariant Integers using Multiplication,
+ * T. Granlund and P. L. Montgomery, Proceedings of the SIGPLAN '94
+ * Conference on Programming Language Design and Implementation.
+ *
+ * http://gmplib.org/~tege/divcnst-pldi94.pdf
+ *
+ * Variables from the paper and their translations (See section 8):
+ *
+ * N := 64
+ * d := MPD_RADIX
+ * l := 64
+ * m' := floor((2**(64+64) - 1)/MPD_RADIX) - 2**64
+ *
+ * Since N-l == 0:
+ *
+ * dnorm := d
+ * n2 := hi
+ * n10 := lo
+ *
+ * ACL2 proof: mpd-div-words-r-correct
+ */
+static inline void
+_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo)
+{
+ mpd_uint_t n_adj, h, l, t;
+ mpd_uint_t n1_neg;
+
+ /* n1_neg = if lo >= 2**63 then MPD_UINT_MAX else 0 */
+ n1_neg = (lo & (1ULL<<63)) ? MPD_UINT_MAX : 0;
+ /* n_adj = if lo >= 2**63 then lo+MPD_RADIX else lo */
+ n_adj = lo + (n1_neg & MPD_RADIX);
+
+ /* (h, l) = if lo >= 2**63 then m'*(hi+1) else m'*hi */
+ _mpd_mul_words(&h, &l, mprime_rdx, hi-n1_neg);
+ l = l + n_adj;
+ if (l < n_adj) h++;
+ t = h + hi;
+ /* At this point t == qest, with q == qest or q == qest+1:
+ * 1) 0 <= 2**64*hi + lo - qest*MPD_RADIX < 2*MPD_RADIX
+ */
+
+ /* t = 2**64-1 - qest = 2**64 - (qest+1) */
+ t = MPD_UINT_MAX - t;
+
+ /* (h, l) = 2**64*MPD_RADIX - (qest+1)*MPD_RADIX */
+ _mpd_mul_words(&h, &l, t, MPD_RADIX);
+ l = l + lo;
+ if (l < lo) h++;
+ h += hi;
+ h -= MPD_RADIX;
+ /* (h, l) = 2**64*hi + lo - (qest+1)*MPD_RADIX (mod 2**128)
+ * Case q == qest+1:
+ * a) h == 0, l == r
+ * b) q := h - t == qest+1
+ * c) r := l
+ * Case q == qest:
+ * a) h == MPD_UINT_MAX, l == 2**64-(MPD_RADIX-r)
+ * b) q := h - t == qest
+ * c) r := l + MPD_RADIX = r
+ */
+
+ *q = (h - t);
+ *r = l + (MPD_RADIX & h);
+}
+#else
+static inline void
+_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo)
+{
+ _mpd_div_words(q, r, hi, lo, MPD_RADIX);
+}
+#endif
+
+
+/* Multiply two single base MPD_RADIX words, store result in array w[2]. */
+static inline void
+_mpd_singlemul(mpd_uint_t w[2], mpd_uint_t u, mpd_uint_t v)
+{
+ mpd_uint_t hi, lo;
+
+ _mpd_mul_words(&hi, &lo, u, v);
+ _mpd_div_words_r(&w[1], &w[0], hi, lo);
+}
+
+/* Multiply u (len 2) and v (len m, 1 <= m <= 2). */
+static inline void
+_mpd_mul_2_le2(mpd_uint_t w[4], mpd_uint_t u[2], mpd_uint_t v[2], mpd_ssize_t m)
+{
+ mpd_uint_t hi, lo;
+
+ _mpd_mul_words(&hi, &lo, u[0], v[0]);
+ _mpd_div_words_r(&w[1], &w[0], hi, lo);
+
+ _mpd_mul_words(&hi, &lo, u[1], v[0]);
+ lo = w[1] + lo;
+ if (lo < w[1]) hi++;
+ _mpd_div_words_r(&w[2], &w[1], hi, lo);
+ if (m == 1) return;
+
+ _mpd_mul_words(&hi, &lo, u[0], v[1]);
+ lo = w[1] + lo;
+ if (lo < w[1]) hi++;
+ _mpd_div_words_r(&w[3], &w[1], hi, lo);
+
+ _mpd_mul_words(&hi, &lo, u[1], v[1]);
+ lo = w[2] + lo;
+ if (lo < w[2]) hi++;
+ lo = w[3] + lo;
+ if (lo < w[3]) hi++;
+ _mpd_div_words_r(&w[3], &w[2], hi, lo);
+}
+
+
+/*
+ * Test if all words from data[len-1] to data[0] are zero. If len is 0, nothing
+ * is tested and the coefficient is regarded as "all zero".
+ */
+static inline int
+_mpd_isallzero(const mpd_uint_t *data, mpd_ssize_t len)
+{
+ while (--len >= 0) {
+ if (data[len] != 0) return 0;
+ }
+ return 1;
+}
+
+/*
+ * Test if all full words from data[len-1] to data[0] are MPD_RADIX-1
+ * (all nines). Return true if len == 0.
+ */
+static inline int
+_mpd_isallnine(const mpd_uint_t *data, mpd_ssize_t len)
+{
+ while (--len >= 0) {
+ if (data[len] != MPD_RADIX-1) return 0;
+ }
+ return 1;
+}
+
+
+#endif /* BASEARITH_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/bits.h b/Modules/_decimal/libmpdec/bits.h
new file mode 100644
index 0000000..949ec94
--- /dev/null
+++ b/Modules/_decimal/libmpdec/bits.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef BITS_H
+#define BITS_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+/* Check if n is a power of 2. */
+static inline int
+ispower2(mpd_size_t n)
+{
+ return n != 0 && (n & (n-1)) == 0;
+}
+
+#if defined(ANSI)
+/*
+ * Return the most significant bit position of n from 0 to 31 (63).
+ * Assumptions: n != 0.
+ */
+static inline int
+mpd_bsr(mpd_size_t n)
+{
+ int pos = 0;
+ mpd_size_t tmp;
+
+#ifdef CONFIG_64
+ tmp = n >> 32;
+ if (tmp != 0) { n = tmp; pos += 32; }
+#endif
+ tmp = n >> 16;
+ if (tmp != 0) { n = tmp; pos += 16; }
+ tmp = n >> 8;
+ if (tmp != 0) { n = tmp; pos += 8; }
+ tmp = n >> 4;
+ if (tmp != 0) { n = tmp; pos += 4; }
+ tmp = n >> 2;
+ if (tmp != 0) { n = tmp; pos += 2; }
+ tmp = n >> 1;
+ if (tmp != 0) { n = tmp; pos += 1; }
+
+ return pos + (int)n - 1;
+}
+
+/*
+ * Return the least significant bit position of n from 0 to 31 (63).
+ * Assumptions: n != 0.
+ */
+static inline int
+mpd_bsf(mpd_size_t n)
+{
+ int pos;
+
+#ifdef CONFIG_64
+ pos = 63;
+ if (n & 0x00000000FFFFFFFFULL) { pos -= 32; } else { n >>= 32; }
+ if (n & 0x000000000000FFFFULL) { pos -= 16; } else { n >>= 16; }
+ if (n & 0x00000000000000FFULL) { pos -= 8; } else { n >>= 8; }
+ if (n & 0x000000000000000FULL) { pos -= 4; } else { n >>= 4; }
+ if (n & 0x0000000000000003ULL) { pos -= 2; } else { n >>= 2; }
+ if (n & 0x0000000000000001ULL) { pos -= 1; }
+#else
+ pos = 31;
+ if (n & 0x000000000000FFFFUL) { pos -= 16; } else { n >>= 16; }
+ if (n & 0x00000000000000FFUL) { pos -= 8; } else { n >>= 8; }
+ if (n & 0x000000000000000FUL) { pos -= 4; } else { n >>= 4; }
+ if (n & 0x0000000000000003UL) { pos -= 2; } else { n >>= 2; }
+ if (n & 0x0000000000000001UL) { pos -= 1; }
+#endif
+ return pos;
+}
+/* END ANSI */
+
+#elif defined(ASM)
+/*
+ * Bit scan reverse. Assumptions: a != 0.
+ */
+static inline int
+mpd_bsr(mpd_size_t a)
+{
+ mpd_size_t retval;
+
+ __asm__ (
+#ifdef CONFIG_64
+ "bsrq %1, %0\n\t"
+#else
+ "bsr %1, %0\n\t"
+#endif
+ :"=r" (retval)
+ :"r" (a)
+ :"cc"
+ );
+
+ return (int)retval;
+}
+
+/*
+ * Bit scan forward. Assumptions: a != 0.
+ */
+static inline int
+mpd_bsf(mpd_size_t a)
+{
+ mpd_size_t retval;
+
+ __asm__ (
+#ifdef CONFIG_64
+ "bsfq %1, %0\n\t"
+#else
+ "bsf %1, %0\n\t"
+#endif
+ :"=r" (retval)
+ :"r" (a)
+ :"cc"
+ );
+
+ return (int)retval;
+}
+/* END ASM */
+
+#elif defined(MASM)
+#include <intrin.h>
+/*
+ * Bit scan reverse. Assumptions: a != 0.
+ */
+static inline int __cdecl
+mpd_bsr(mpd_size_t a)
+{
+ unsigned long retval;
+
+#ifdef CONFIG_64
+ _BitScanReverse64(&retval, a);
+#else
+ _BitScanReverse(&retval, a);
+#endif
+
+ return (int)retval;
+}
+
+/*
+ * Bit scan forward. Assumptions: a != 0.
+ */
+static inline int __cdecl
+mpd_bsf(mpd_size_t a)
+{
+ unsigned long retval;
+
+#ifdef CONFIG_64
+ _BitScanForward64(&retval, a);
+#else
+ _BitScanForward(&retval, a);
+#endif
+
+ return (int)retval;
+}
+/* END MASM (_MSC_VER) */
+#else
+ #error "missing preprocessor definitions"
+#endif /* BSR/BSF */
+
+
+#endif /* BITS_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/constants.c b/Modules/_decimal/libmpdec/constants.c
new file mode 100644
index 0000000..92f5891
--- /dev/null
+++ b/Modules/_decimal/libmpdec/constants.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include "constants.h"
+
+
+#if defined(CONFIG_64)
+
+ /* number-theory.c */
+ const mpd_uint_t mpd_moduli[3] = {
+ 18446744069414584321ULL, 18446744056529682433ULL, 18446742974197923841ULL
+ };
+ const mpd_uint_t mpd_roots[3] = {7ULL, 10ULL, 19ULL};
+
+ /* crt.c */
+ const mpd_uint_t INV_P1_MOD_P2 = 18446744055098026669ULL;
+ const mpd_uint_t INV_P1P2_MOD_P3 = 287064143708160ULL;
+ const mpd_uint_t LH_P1P2 = 18446744052234715137ULL; /* (P1*P2) % 2^64 */
+ const mpd_uint_t UH_P1P2 = 18446744052234715141ULL; /* (P1*P2) / 2^64 */
+
+ /* transpose.c */
+ const mpd_size_t mpd_bits[64] = {
+ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
+ 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
+ 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824,
+ 2147483648ULL, 4294967296ULL, 8589934592ULL, 17179869184ULL, 34359738368ULL,
+ 68719476736ULL, 137438953472ULL, 274877906944ULL, 549755813888ULL,
+ 1099511627776ULL, 2199023255552ULL, 4398046511104, 8796093022208ULL,
+ 17592186044416ULL, 35184372088832ULL, 70368744177664ULL, 140737488355328ULL,
+ 281474976710656ULL, 562949953421312ULL, 1125899906842624ULL,
+ 2251799813685248ULL, 4503599627370496ULL, 9007199254740992ULL,
+ 18014398509481984ULL, 36028797018963968ULL, 72057594037927936ULL,
+ 144115188075855872ULL, 288230376151711744ULL, 576460752303423488ULL,
+ 1152921504606846976ULL, 2305843009213693952ULL, 4611686018427387904ULL,
+ 9223372036854775808ULL
+ };
+
+ /* mpdecimal.c */
+ const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = {
+ 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,
+ 10000000000ULL,100000000000ULL,1000000000000ULL,10000000000000ULL,
+ 100000000000000ULL,1000000000000000ULL,10000000000000000ULL,
+ 100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL
+ };
+
+ /* magic number for constant division by MPD_RADIX */
+ const mpd_uint_t mprime_rdx = 15581492618384294730ULL;
+
+#elif defined(CONFIG_32)
+
+ /* number-theory.c */
+ const mpd_uint_t mpd_moduli[3] = {2113929217UL, 2013265921UL, 1811939329UL};
+ const mpd_uint_t mpd_roots[3] = {5UL, 31UL, 13UL};
+
+ /* PentiumPro modular multiplication: These constants have to be loaded as
+ * 80 bit long doubles, which are not supported by certain compilers. */
+ const uint32_t mpd_invmoduli[3][3] = {
+ {4293885170U, 2181570688U, 16352U}, /* ((long double) 1 / 2113929217UL) */
+ {1698898177U, 2290649223U, 16352U}, /* ((long double) 1 / 2013265921UL) */
+ {2716021846U, 2545165803U, 16352U} /* ((long double) 1 / 1811939329UL) */
+ };
+
+ const float MPD_TWO63 = 9223372036854775808.0; /* 2^63 */
+
+ /* crt.c */
+ const mpd_uint_t INV_P1_MOD_P2 = 2013265901UL;
+ const mpd_uint_t INV_P1P2_MOD_P3 = 54UL;
+ const mpd_uint_t LH_P1P2 = 4127195137UL; /* (P1*P2) % 2^32 */
+ const mpd_uint_t UH_P1P2 = 990904320UL; /* (P1*P2) / 2^32 */
+
+ /* transpose.c */
+ const mpd_size_t mpd_bits[32] = {
+ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
+ 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
+ 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824,
+ 2147483648UL
+ };
+
+ /* mpdecimal.c */
+ const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = {
+ 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000
+ };
+
+#else
+ #error "CONFIG_64 or CONFIG_32 must be defined."
+#endif
+
+const char *mpd_round_string[MPD_ROUND_GUARD] = {
+ "ROUND_UP", /* round away from 0 */
+ "ROUND_DOWN", /* round toward 0 (truncate) */
+ "ROUND_CEILING", /* round toward +infinity */
+ "ROUND_FLOOR", /* round toward -infinity */
+ "ROUND_HALF_UP", /* 0.5 is rounded up */
+ "ROUND_HALF_DOWN", /* 0.5 is rounded down */
+ "ROUND_HALF_EVEN", /* 0.5 is rounded to even */
+ "ROUND_05UP", /* round zero or five away from 0 */
+ "ROUND_TRUNC", /* truncate, but set infinity */
+};
+
+const char *mpd_clamp_string[MPD_CLAMP_GUARD] = {
+ "CLAMP_DEFAULT",
+ "CLAMP_IEEE_754"
+};
+
+
diff --git a/Modules/_decimal/libmpdec/constants.h b/Modules/_decimal/libmpdec/constants.h
new file mode 100644
index 0000000..2d63d7e
--- /dev/null
+++ b/Modules/_decimal/libmpdec/constants.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+
+#include "mpdecimal.h"
+
+
+/* choice of optimized functions */
+#if defined(CONFIG_64)
+/* x64 */
+ #define MULMOD(a, b) x64_mulmod(a, b, umod)
+ #define MULMOD2C(a0, a1, w) x64_mulmod2c(a0, a1, w, umod)
+ #define MULMOD2(a0, b0, a1, b1) x64_mulmod2(a0, b0, a1, b1, umod)
+ #define POWMOD(base, exp) x64_powmod(base, exp, umod)
+ #define SETMODULUS(modnum) std_setmodulus(modnum, &umod)
+ #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod)
+#elif defined(PPRO)
+/* PentiumPro (or later) gcc inline asm */
+ #define MULMOD(a, b) ppro_mulmod(a, b, &dmod, dinvmod)
+ #define MULMOD2C(a0, a1, w) ppro_mulmod2c(a0, a1, w, &dmod, dinvmod)
+ #define MULMOD2(a0, b0, a1, b1) ppro_mulmod2(a0, b0, a1, b1, &dmod, dinvmod)
+ #define POWMOD(base, exp) ppro_powmod(base, exp, &dmod, dinvmod)
+ #define SETMODULUS(modnum) ppro_setmodulus(modnum, &umod, &dmod, dinvmod)
+ #define SIZE3_NTT(x0, x1, x2, w3table) ppro_size3_ntt(x0, x1, x2, w3table, umod, &dmod, dinvmod)
+#else
+ /* ANSI C99 */
+ #define MULMOD(a, b) std_mulmod(a, b, umod)
+ #define MULMOD2C(a0, a1, w) std_mulmod2c(a0, a1, w, umod)
+ #define MULMOD2(a0, b0, a1, b1) std_mulmod2(a0, b0, a1, b1, umod)
+ #define POWMOD(base, exp) std_powmod(base, exp, umod)
+ #define SETMODULUS(modnum) std_setmodulus(modnum, &umod)
+ #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod)
+#endif
+
+/* PentiumPro (or later) gcc inline asm */
+extern const float MPD_TWO63;
+extern const uint32_t mpd_invmoduli[3][3];
+
+enum {P1, P2, P3};
+
+extern const mpd_uint_t mpd_moduli[];
+extern const mpd_uint_t mpd_roots[];
+extern const mpd_size_t mpd_bits[];
+extern const mpd_uint_t mpd_pow10[];
+
+extern const mpd_uint_t INV_P1_MOD_P2;
+extern const mpd_uint_t INV_P1P2_MOD_P3;
+extern const mpd_uint_t LH_P1P2;
+extern const mpd_uint_t UH_P1P2;
+
+
+#endif /* CONSTANTS_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/context.c b/Modules/_decimal/libmpdec/context.c
new file mode 100644
index 0000000..dc77a32
--- /dev/null
+++ b/Modules/_decimal/libmpdec/context.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+
+void
+mpd_dflt_traphandler(mpd_context_t *ctx UNUSED)
+{
+ raise(SIGFPE);
+}
+
+void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler;
+
+
+/* Set guaranteed minimum number of coefficient words. The function may
+ be used once at program start. Setting MPD_MINALLOC to out-of-bounds
+ values is a catastrophic error, so in that case the function exits rather
+ than relying on the user to check a return value. */
+void
+mpd_setminalloc(mpd_ssize_t n)
+{
+ static int minalloc_is_set = 0;
+
+ if (minalloc_is_set) {
+ mpd_err_warn("mpd_setminalloc: ignoring request to set "
+ "MPD_MINALLOC a second time\n");
+ return;
+ }
+ if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) {
+ mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */
+ }
+ MPD_MINALLOC = n;
+ minalloc_is_set = 1;
+}
+
+void
+mpd_init(mpd_context_t *ctx, mpd_ssize_t prec)
+{
+ mpd_ssize_t ideal_minalloc;
+
+ mpd_defaultcontext(ctx);
+
+ if (!mpd_qsetprec(ctx, prec)) {
+ mpd_addstatus_raise(ctx, MPD_Invalid_context);
+ return;
+ }
+
+ ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS);
+ if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN;
+ if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX;
+
+ mpd_setminalloc(ideal_minalloc);
+}
+
+void
+mpd_maxcontext(mpd_context_t *ctx)
+{
+ ctx->prec=MPD_MAX_PREC;
+ ctx->emax=MPD_MAX_EMAX;
+ ctx->emin=MPD_MIN_EMIN;
+ ctx->round=MPD_ROUND_HALF_EVEN;
+ ctx->traps=MPD_Traps;
+ ctx->status=0;
+ ctx->newtrap=0;
+ ctx->clamp=0;
+ ctx->allcr=1;
+}
+
+void
+mpd_defaultcontext(mpd_context_t *ctx)
+{
+ ctx->prec=2*MPD_RDIGITS;
+ ctx->emax=MPD_MAX_EMAX;
+ ctx->emin=MPD_MIN_EMIN;
+ ctx->round=MPD_ROUND_HALF_UP;
+ ctx->traps=MPD_Traps;
+ ctx->status=0;
+ ctx->newtrap=0;
+ ctx->clamp=0;
+ ctx->allcr=1;
+}
+
+void
+mpd_basiccontext(mpd_context_t *ctx)
+{
+ ctx->prec=9;
+ ctx->emax=MPD_MAX_EMAX;
+ ctx->emin=MPD_MIN_EMIN;
+ ctx->round=MPD_ROUND_HALF_UP;
+ ctx->traps=MPD_Traps|MPD_Clamped;
+ ctx->status=0;
+ ctx->newtrap=0;
+ ctx->clamp=0;
+ ctx->allcr=1;
+}
+
+int
+mpd_ieee_context(mpd_context_t *ctx, int bits)
+{
+ if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) {
+ return -1;
+ }
+
+ ctx->prec = 9 * (bits/32) - 2;
+ ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3));
+ ctx->emin = 1 - ctx->emax;
+ ctx->round=MPD_ROUND_HALF_EVEN;
+ ctx->traps=0;
+ ctx->status=0;
+ ctx->newtrap=0;
+ ctx->clamp=1;
+ ctx->allcr=1;
+
+ return 0;
+}
+
+mpd_ssize_t
+mpd_getprec(const mpd_context_t *ctx)
+{
+ return ctx->prec;
+}
+
+mpd_ssize_t
+mpd_getemax(const mpd_context_t *ctx)
+{
+ return ctx->emax;
+}
+
+mpd_ssize_t
+mpd_getemin(const mpd_context_t *ctx)
+{
+ return ctx->emin;
+}
+
+int
+mpd_getround(const mpd_context_t *ctx)
+{
+ return ctx->round;
+}
+
+uint32_t
+mpd_gettraps(const mpd_context_t *ctx)
+{
+ return ctx->traps;
+}
+
+uint32_t
+mpd_getstatus(const mpd_context_t *ctx)
+{
+ return ctx->status;
+}
+
+int
+mpd_getclamp(const mpd_context_t *ctx)
+{
+ return ctx->clamp;
+}
+
+int
+mpd_getcr(const mpd_context_t *ctx)
+{
+ return ctx->allcr;
+}
+
+
+int
+mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec)
+{
+ if (prec <= 0 || prec > MPD_MAX_PREC) {
+ return 0;
+ }
+ ctx->prec = prec;
+ return 1;
+}
+
+int
+mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax)
+{
+ if (emax < 0 || emax > MPD_MAX_EMAX) {
+ return 0;
+ }
+ ctx->emax = emax;
+ return 1;
+}
+
+int
+mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin)
+{
+ if (emin > 0 || emin < MPD_MIN_EMIN) {
+ return 0;
+ }
+ ctx->emin = emin;
+ return 1;
+}
+
+int
+mpd_qsetround(mpd_context_t *ctx, int round)
+{
+ if (!(0 <= round && round < MPD_ROUND_GUARD)) {
+ return 0;
+ }
+ ctx->round = round;
+ return 1;
+}
+
+int
+mpd_qsettraps(mpd_context_t *ctx, uint32_t traps)
+{
+ if (traps > MPD_Max_status) {
+ return 0;
+ }
+ ctx->traps = traps;
+ return 1;
+}
+
+int
+mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags)
+{
+ if (flags > MPD_Max_status) {
+ return 0;
+ }
+ ctx->status = flags;
+ return 1;
+}
+
+int
+mpd_qsetclamp(mpd_context_t *ctx, int c)
+{
+ if (c != 0 && c != 1) {
+ return 0;
+ }
+ ctx->clamp = c;
+ return 1;
+}
+
+int
+mpd_qsetcr(mpd_context_t *ctx, int c)
+{
+ if (c != 0 && c != 1) {
+ return 0;
+ }
+ ctx->allcr = c;
+ return 1;
+}
+
+
+void
+mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags)
+{
+ ctx->status |= flags;
+ if (flags&ctx->traps) {
+ ctx->newtrap = (flags&ctx->traps);
+ mpd_traphandler(ctx);
+ }
+}
+
+
diff --git a/Modules/_decimal/libmpdec/convolute.c b/Modules/_decimal/libmpdec/convolute.c
new file mode 100644
index 0000000..b5fe131
--- /dev/null
+++ b/Modules/_decimal/libmpdec/convolute.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include "bits.h"
+#include "constants.h"
+#include "fnt.h"
+#include "fourstep.h"
+#include "numbertheory.h"
+#include "sixstep.h"
+#include "umodarith.h"
+#include "convolute.h"
+
+
+/* Bignum: Fast convolution using the Number Theoretic Transform. Used for
+ the multiplication of very large coefficients. */
+
+
+/* Convolute the data in c1 and c2. Result is in c1. */
+int
+fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum)
+{
+ int (*fnt)(mpd_uint_t *, mpd_size_t, int);
+ int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int);
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t n_inv, umod;
+ mpd_size_t i;
+
+
+ SETMODULUS(modnum);
+ n_inv = POWMOD(n, (umod-2));
+
+ if (ispower2(n)) {
+ if (n > SIX_STEP_THRESHOLD) {
+ fnt = six_step_fnt;
+ inv_fnt = inv_six_step_fnt;
+ }
+ else {
+ fnt = std_fnt;
+ inv_fnt = std_inv_fnt;
+ }
+ }
+ else {
+ fnt = four_step_fnt;
+ inv_fnt = inv_four_step_fnt;
+ }
+
+ if (!fnt(c1, n, modnum)) {
+ return 0;
+ }
+ if (!fnt(c2, n, modnum)) {
+ return 0;
+ }
+ for (i = 0; i < n-1; i += 2) {
+ mpd_uint_t x0 = c1[i];
+ mpd_uint_t y0 = c2[i];
+ mpd_uint_t x1 = c1[i+1];
+ mpd_uint_t y1 = c2[i+1];
+ MULMOD2(&x0, y0, &x1, y1);
+ c1[i] = x0;
+ c1[i+1] = x1;
+ }
+
+ if (!inv_fnt(c1, n, modnum)) {
+ return 0;
+ }
+ for (i = 0; i < n-3; i += 4) {
+ mpd_uint_t x0 = c1[i];
+ mpd_uint_t x1 = c1[i+1];
+ mpd_uint_t x2 = c1[i+2];
+ mpd_uint_t x3 = c1[i+3];
+ MULMOD2C(&x0, &x1, n_inv);
+ MULMOD2C(&x2, &x3, n_inv);
+ c1[i] = x0;
+ c1[i+1] = x1;
+ c1[i+2] = x2;
+ c1[i+3] = x3;
+ }
+
+ return 1;
+}
+
+/* Autoconvolute the data in c1. Result is in c1. */
+int
+fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum)
+{
+ int (*fnt)(mpd_uint_t *, mpd_size_t, int);
+ int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int);
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t n_inv, umod;
+ mpd_size_t i;
+
+
+ SETMODULUS(modnum);
+ n_inv = POWMOD(n, (umod-2));
+
+ if (ispower2(n)) {
+ if (n > SIX_STEP_THRESHOLD) {
+ fnt = six_step_fnt;
+ inv_fnt = inv_six_step_fnt;
+ }
+ else {
+ fnt = std_fnt;
+ inv_fnt = std_inv_fnt;
+ }
+ }
+ else {
+ fnt = four_step_fnt;
+ inv_fnt = inv_four_step_fnt;
+ }
+
+ if (!fnt(c1, n, modnum)) {
+ return 0;
+ }
+ for (i = 0; i < n-1; i += 2) {
+ mpd_uint_t x0 = c1[i];
+ mpd_uint_t x1 = c1[i+1];
+ MULMOD2(&x0, x0, &x1, x1);
+ c1[i] = x0;
+ c1[i+1] = x1;
+ }
+
+ if (!inv_fnt(c1, n, modnum)) {
+ return 0;
+ }
+ for (i = 0; i < n-3; i += 4) {
+ mpd_uint_t x0 = c1[i];
+ mpd_uint_t x1 = c1[i+1];
+ mpd_uint_t x2 = c1[i+2];
+ mpd_uint_t x3 = c1[i+3];
+ MULMOD2C(&x0, &x1, n_inv);
+ MULMOD2C(&x2, &x3, n_inv);
+ c1[i] = x0;
+ c1[i+1] = x1;
+ c1[i+2] = x2;
+ c1[i+3] = x3;
+ }
+
+ return 1;
+}
+
+
diff --git a/Modules/_decimal/libmpdec/convolute.h b/Modules/_decimal/libmpdec/convolute.h
new file mode 100644
index 0000000..2f8d6d8
--- /dev/null
+++ b/Modules/_decimal/libmpdec/convolute.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef CONVOLUTE_H
+#define CONVOLUTE_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+#define SIX_STEP_THRESHOLD 4096
+
+
+int fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum);
+int fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum);
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/crt.c b/Modules/_decimal/libmpdec/crt.c
new file mode 100644
index 0000000..c71c4ee
--- /dev/null
+++ b/Modules/_decimal/libmpdec/crt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <assert.h>
+#include "numbertheory.h"
+#include "umodarith.h"
+#include "crt.h"
+
+
+/* Bignum: Chinese Remainder Theorem, extends the maximum transform length. */
+
+
+/* Multiply P1P2 by v, store result in w. */
+static inline void
+_crt_mulP1P2_3(mpd_uint_t w[3], mpd_uint_t v)
+{
+ mpd_uint_t hi1, hi2, lo;
+
+ _mpd_mul_words(&hi1, &lo, LH_P1P2, v);
+ w[0] = lo;
+
+ _mpd_mul_words(&hi2, &lo, UH_P1P2, v);
+ lo = hi1 + lo;
+ if (lo < hi1) hi2++;
+
+ w[1] = lo;
+ w[2] = hi2;
+}
+
+/* Add 3 words from v to w. The result is known to fit in w. */
+static inline void
+_crt_add3(mpd_uint_t w[3], mpd_uint_t v[3])
+{
+ mpd_uint_t carry;
+ mpd_uint_t s;
+
+ s = w[0] + v[0];
+ carry = (s < w[0]);
+ w[0] = s;
+
+ s = w[1] + (v[1] + carry);
+ carry = (s < w[1]);
+ w[1] = s;
+
+ w[2] = w[2] + (v[2] + carry);
+}
+
+/* Divide 3 words in u by v, store result in w, return remainder. */
+static inline mpd_uint_t
+_crt_div3(mpd_uint_t *w, const mpd_uint_t *u, mpd_uint_t v)
+{
+ mpd_uint_t r1 = u[2];
+ mpd_uint_t r2;
+
+ if (r1 < v) {
+ w[2] = 0;
+ }
+ else {
+ _mpd_div_word(&w[2], &r1, u[2], v); /* GCOV_NOT_REACHED */
+ }
+
+ _mpd_div_words(&w[1], &r2, r1, u[1], v);
+ _mpd_div_words(&w[0], &r1, r2, u[0], v);
+
+ return r1;
+}
+
+
+/*
+ * Chinese Remainder Theorem:
+ * Algorithm from Joerg Arndt, "Matters Computational",
+ * Chapter 37.4.1 [http://www.jjj.de/fxt/]
+ *
+ * See also Knuth, TAOCP, Volume 2, 4.3.2, exercise 7.
+ */
+
+/*
+ * CRT with carry: x1, x2, x3 contain numbers modulo p1, p2, p3. For each
+ * triple of members of the arrays, find the unique z modulo p1*p2*p3, with
+ * zmax = p1*p2*p3 - 1.
+ *
+ * In each iteration of the loop, split z into result[i] = z % MPD_RADIX
+ * and carry = z / MPD_RADIX. Let N be the size of carry[] and cmax the
+ * maximum carry.
+ *
+ * Limits for the 32-bit build:
+ *
+ * N = 2**96
+ * cmax = 7711435591312380274
+ *
+ * Limits for the 64 bit build:
+ *
+ * N = 2**192
+ * cmax = 627710135393475385904124401220046371710
+ *
+ * The following statements hold for both versions:
+ *
+ * 1) cmax + zmax < N, so the addition does not overflow.
+ *
+ * 2) (cmax + zmax) / MPD_RADIX == cmax.
+ *
+ * 3) If c <= cmax, then c_next = (c + zmax) / MPD_RADIX <= cmax.
+ */
+void
+crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t rsize)
+{
+ mpd_uint_t p1 = mpd_moduli[P1];
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t a1, a2, a3;
+ mpd_uint_t s;
+ mpd_uint_t z[3], t[3];
+ mpd_uint_t carry[3] = {0,0,0};
+ mpd_uint_t hi, lo;
+ mpd_size_t i;
+
+ for (i = 0; i < rsize; i++) {
+
+ a1 = x1[i];
+ a2 = x2[i];
+ a3 = x3[i];
+
+ SETMODULUS(P2);
+ s = ext_submod(a2, a1, umod);
+ s = MULMOD(s, INV_P1_MOD_P2);
+
+ _mpd_mul_words(&hi, &lo, s, p1);
+ lo = lo + a1;
+ if (lo < a1) hi++;
+
+ SETMODULUS(P3);
+ s = dw_submod(a3, hi, lo, umod);
+ s = MULMOD(s, INV_P1P2_MOD_P3);
+
+ z[0] = lo;
+ z[1] = hi;
+ z[2] = 0;
+
+ _crt_mulP1P2_3(t, s);
+ _crt_add3(z, t);
+ _crt_add3(carry, z);
+
+ x1[i] = _crt_div3(carry, carry, MPD_RADIX);
+ }
+
+ assert(carry[0] == 0 && carry[1] == 0 && carry[2] == 0);
+}
+
+
diff --git a/Modules/_decimal/libmpdec/crt.h b/Modules/_decimal/libmpdec/crt.h
new file mode 100644
index 0000000..0e03e5d
--- /dev/null
+++ b/Modules/_decimal/libmpdec/crt.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef CRT_H
+#define CRT_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+void crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t nmemb);
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/difradix2.c b/Modules/_decimal/libmpdec/difradix2.c
new file mode 100644
index 0000000..4ebb0b5
--- /dev/null
+++ b/Modules/_decimal/libmpdec/difradix2.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <assert.h>
+#include "bits.h"
+#include "numbertheory.h"
+#include "umodarith.h"
+#include "difradix2.h"
+
+
+/* Bignum: The actual transform routine (decimation in frequency). */
+
+
+/*
+ * Generate index pairs (x, bitreverse(x)) and carry out the permutation.
+ * n must be a power of two.
+ * Algorithm due to Brent/Lehmann, see Joerg Arndt, "Matters Computational",
+ * Chapter 1.14.4. [http://www.jjj.de/fxt/]
+ */
+static inline void
+bitreverse_permute(mpd_uint_t a[], mpd_size_t n)
+{
+ mpd_size_t x = 0;
+ mpd_size_t r = 0;
+ mpd_uint_t t;
+
+ do { /* Invariant: r = bitreverse(x) */
+ if (r > x) {
+ t = a[x];
+ a[x] = a[r];
+ a[r] = t;
+ }
+ /* Flip trailing consecutive 1 bits and the first zero bit
+ * that absorbs a possible carry. */
+ x += 1;
+ /* Mirror the operation on r: Flip n_trailing_zeros(x)+1
+ high bits of r. */
+ r ^= (n - (n >> (mpd_bsf(x)+1)));
+ /* The loop invariant is preserved. */
+ } while (x < n);
+}
+
+
+/* Fast Number Theoretic Transform, decimation in frequency. */
+void
+fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams)
+{
+ mpd_uint_t *wtable = tparams->wtable;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t u0, u1, v0, v1;
+ mpd_uint_t w, w0, w1, wstep;
+ mpd_size_t m, mhalf;
+ mpd_size_t j, r;
+
+
+ assert(ispower2(n));
+ assert(n >= 4);
+
+ SETMODULUS(tparams->modnum);
+
+ /* m == n */
+ mhalf = n / 2;
+ for (j = 0; j < mhalf; j += 2) {
+
+ w0 = wtable[j];
+ w1 = wtable[j+1];
+
+ u0 = a[j];
+ v0 = a[j+mhalf];
+
+ u1 = a[j+1];
+ v1 = a[j+1+mhalf];
+
+ a[j] = addmod(u0, v0, umod);
+ v0 = submod(u0, v0, umod);
+
+ a[j+1] = addmod(u1, v1, umod);
+ v1 = submod(u1, v1, umod);
+
+ MULMOD2(&v0, w0, &v1, w1);
+
+ a[j+mhalf] = v0;
+ a[j+1+mhalf] = v1;
+
+ }
+
+ wstep = 2;
+ for (m = n/2; m >= 2; m>>=1, wstep<<=1) {
+
+ mhalf = m / 2;
+
+ /* j == 0 */
+ for (r = 0; r < n; r += 2*m) {
+
+ u0 = a[r];
+ v0 = a[r+mhalf];
+
+ u1 = a[m+r];
+ v1 = a[m+r+mhalf];
+
+ a[r] = addmod(u0, v0, umod);
+ v0 = submod(u0, v0, umod);
+
+ a[m+r] = addmod(u1, v1, umod);
+ v1 = submod(u1, v1, umod);
+
+ a[r+mhalf] = v0;
+ a[m+r+mhalf] = v1;
+ }
+
+ for (j = 1; j < mhalf; j++) {
+
+ w = wtable[j*wstep];
+
+ for (r = 0; r < n; r += 2*m) {
+
+ u0 = a[r+j];
+ v0 = a[r+j+mhalf];
+
+ u1 = a[m+r+j];
+ v1 = a[m+r+j+mhalf];
+
+ a[r+j] = addmod(u0, v0, umod);
+ v0 = submod(u0, v0, umod);
+
+ a[m+r+j] = addmod(u1, v1, umod);
+ v1 = submod(u1, v1, umod);
+
+ MULMOD2C(&v0, &v1, w);
+
+ a[r+j+mhalf] = v0;
+ a[m+r+j+mhalf] = v1;
+ }
+
+ }
+
+ }
+
+ bitreverse_permute(a, n);
+}
+
+
diff --git a/Modules/_decimal/libmpdec/difradix2.h b/Modules/_decimal/libmpdec/difradix2.h
new file mode 100644
index 0000000..759442a
--- /dev/null
+++ b/Modules/_decimal/libmpdec/difradix2.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef DIF_RADIX2_H
+#define DIF_RADIX2_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include "numbertheory.h"
+
+
+void fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams);
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/fnt.c b/Modules/_decimal/libmpdec/fnt.c
new file mode 100644
index 0000000..9311653
--- /dev/null
+++ b/Modules/_decimal/libmpdec/fnt.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bits.h"
+#include "difradix2.h"
+#include "numbertheory.h"
+#include "fnt.h"
+
+
+/* Bignum: Fast transform for medium-sized coefficients. */
+
+
+/* forward transform, sign = -1 */
+int
+std_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ struct fnt_params *tparams;
+
+ assert(ispower2(n));
+ assert(n >= 4);
+ assert(n <= 3*MPD_MAXTRANSFORM_2N);
+
+ if ((tparams = _mpd_init_fnt_params(n, -1, modnum)) == NULL) {
+ return 0;
+ }
+ fnt_dif2(a, n, tparams);
+
+ mpd_free(tparams);
+ return 1;
+}
+
+/* reverse transform, sign = 1 */
+int
+std_inv_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ struct fnt_params *tparams;
+
+ assert(ispower2(n));
+ assert(n >= 4);
+ assert(n <= 3*MPD_MAXTRANSFORM_2N);
+
+ if ((tparams = _mpd_init_fnt_params(n, 1, modnum)) == NULL) {
+ return 0;
+ }
+ fnt_dif2(a, n, tparams);
+
+ mpd_free(tparams);
+ return 1;
+}
+
+
+
diff --git a/Modules/_decimal/libmpdec/fnt.h b/Modules/_decimal/libmpdec/fnt.h
new file mode 100644
index 0000000..2d701b6
--- /dev/null
+++ b/Modules/_decimal/libmpdec/fnt.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef FNT_H
+#define FNT_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+int std_fnt(mpd_uint_t a[], mpd_size_t n, int modnum);
+int std_inv_fnt(mpd_uint_t a[], mpd_size_t n, int modnum);
+
+
+#endif
+
diff --git a/Modules/_decimal/libmpdec/fourstep.c b/Modules/_decimal/libmpdec/fourstep.c
new file mode 100644
index 0000000..91a1b27
--- /dev/null
+++ b/Modules/_decimal/libmpdec/fourstep.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <assert.h>
+#include "numbertheory.h"
+#include "sixstep.h"
+#include "transpose.h"
+#include "umodarith.h"
+#include "fourstep.h"
+
+
+/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the
+ form 3 * 2**n (See literature/matrix-transform.txt). */
+
+
+#ifndef PPRO
+static inline void
+std_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3,
+ mpd_uint_t w3table[3], mpd_uint_t umod)
+{
+ mpd_uint_t r1, r2;
+ mpd_uint_t w;
+ mpd_uint_t s, tmp;
+
+
+ /* k = 0 -> w = 1 */
+ s = *x1;
+ s = addmod(s, *x2, umod);
+ s = addmod(s, *x3, umod);
+
+ r1 = s;
+
+ /* k = 1 */
+ s = *x1;
+
+ w = w3table[1];
+ tmp = MULMOD(*x2, w);
+ s = addmod(s, tmp, umod);
+
+ w = w3table[2];
+ tmp = MULMOD(*x3, w);
+ s = addmod(s, tmp, umod);
+
+ r2 = s;
+
+ /* k = 2 */
+ s = *x1;
+
+ w = w3table[2];
+ tmp = MULMOD(*x2, w);
+ s = addmod(s, tmp, umod);
+
+ w = w3table[1];
+ tmp = MULMOD(*x3, w);
+ s = addmod(s, tmp, umod);
+
+ *x3 = s;
+ *x2 = r2;
+ *x1 = r1;
+}
+#else /* PPRO */
+static inline void
+ppro_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_uint_t w3table[3],
+ mpd_uint_t umod, double *dmod, uint32_t dinvmod[3])
+{
+ mpd_uint_t r1, r2;
+ mpd_uint_t w;
+ mpd_uint_t s, tmp;
+
+
+ /* k = 0 -> w = 1 */
+ s = *x1;
+ s = addmod(s, *x2, umod);
+ s = addmod(s, *x3, umod);
+
+ r1 = s;
+
+ /* k = 1 */
+ s = *x1;
+
+ w = w3table[1];
+ tmp = ppro_mulmod(*x2, w, dmod, dinvmod);
+ s = addmod(s, tmp, umod);
+
+ w = w3table[2];
+ tmp = ppro_mulmod(*x3, w, dmod, dinvmod);
+ s = addmod(s, tmp, umod);
+
+ r2 = s;
+
+ /* k = 2 */
+ s = *x1;
+
+ w = w3table[2];
+ tmp = ppro_mulmod(*x2, w, dmod, dinvmod);
+ s = addmod(s, tmp, umod);
+
+ w = w3table[1];
+ tmp = ppro_mulmod(*x3, w, dmod, dinvmod);
+ s = addmod(s, tmp, umod);
+
+ *x3 = s;
+ *x2 = r2;
+ *x1 = r1;
+}
+#endif
+
+
+/* forward transform, sign = -1; transform length = 3 * 2**n */
+int
+four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ mpd_size_t R = 3; /* number of rows */
+ mpd_size_t C = n / 3; /* number of columns */
+ mpd_uint_t w3table[3];
+ mpd_uint_t kernel, w0, w1, wstep;
+ mpd_uint_t *s, *p0, *p1, *p2;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_size_t i, k;
+
+
+ assert(n >= 48);
+ assert(n <= 3*MPD_MAXTRANSFORM_2N);
+
+
+ /* Length R transform on the columns. */
+ SETMODULUS(modnum);
+ _mpd_init_w3table(w3table, -1, modnum);
+ for (p0=a, p1=p0+C, p2=p0+2*C; p0<a+C; p0++,p1++,p2++) {
+
+ SIZE3_NTT(p0, p1, p2, w3table);
+ }
+
+ /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */
+ kernel = _mpd_getkernel(n, -1, modnum);
+ for (i = 1; i < R; i++) {
+ w0 = 1; /* r**(i*0): initial value for k=0 */
+ w1 = POWMOD(kernel, i); /* r**(i*1): initial value for k=1 */
+ wstep = MULMOD(w1, w1); /* r**(2*i) */
+ for (k = 0; k < C-1; k += 2) {
+ mpd_uint_t x0 = a[i*C+k];
+ mpd_uint_t x1 = a[i*C+k+1];
+ MULMOD2(&x0, w0, &x1, w1);
+ MULMOD2C(&w0, &w1, wstep); /* r**(i*(k+2)) = r**(i*k) * r**(2*i) */
+ a[i*C+k] = x0;
+ a[i*C+k+1] = x1;
+ }
+ }
+
+ /* Length C transform on the rows. */
+ for (s = a; s < a+n; s += C) {
+ if (!six_step_fnt(s, C, modnum)) {
+ return 0;
+ }
+ }
+
+#if 0 /* An unordered transform is sufficient for convolution. */
+ /* Transpose the matrix. */
+ transpose_3xpow2(a, R, C);
+#endif
+
+ return 1;
+}
+
+/* backward transform, sign = 1; transform length = 3 * 2**n */
+int
+inv_four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ mpd_size_t R = 3; /* number of rows */
+ mpd_size_t C = n / 3; /* number of columns */
+ mpd_uint_t w3table[3];
+ mpd_uint_t kernel, w0, w1, wstep;
+ mpd_uint_t *s, *p0, *p1, *p2;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_size_t i, k;
+
+
+ assert(n >= 48);
+ assert(n <= 3*MPD_MAXTRANSFORM_2N);
+
+
+#if 0 /* An unordered transform is sufficient for convolution. */
+ /* Transpose the matrix, producing an R*C matrix. */
+ transpose_3xpow2(a, C, R);
+#endif
+
+ /* Length C transform on the rows. */
+ for (s = a; s < a+n; s += C) {
+ if (!inv_six_step_fnt(s, C, modnum)) {
+ return 0;
+ }
+ }
+
+ /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */
+ SETMODULUS(modnum);
+ kernel = _mpd_getkernel(n, 1, modnum);
+ for (i = 1; i < R; i++) {
+ w0 = 1;
+ w1 = POWMOD(kernel, i);
+ wstep = MULMOD(w1, w1);
+ for (k = 0; k < C; k += 2) {
+ mpd_uint_t x0 = a[i*C+k];
+ mpd_uint_t x1 = a[i*C+k+1];
+ MULMOD2(&x0, w0, &x1, w1);
+ MULMOD2C(&w0, &w1, wstep);
+ a[i*C+k] = x0;
+ a[i*C+k+1] = x1;
+ }
+ }
+
+ /* Length R transform on the columns. */
+ _mpd_init_w3table(w3table, 1, modnum);
+ for (p0=a, p1=p0+C, p2=p0+2*C; p0<a+C; p0++,p1++,p2++) {
+
+ SIZE3_NTT(p0, p1, p2, w3table);
+ }
+
+ return 1;
+}
+
+
diff --git a/Modules/_decimal/libmpdec/fourstep.h b/Modules/_decimal/libmpdec/fourstep.h
new file mode 100644
index 0000000..61d9d6a
--- /dev/null
+++ b/Modules/_decimal/libmpdec/fourstep.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef FOUR_STEP_H
+#define FOUR_STEP_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+int four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+int inv_four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c
new file mode 100644
index 0000000..d736919
--- /dev/null
+++ b/Modules/_decimal/libmpdec/io.c
@@ -0,0 +1,1575 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <locale.h>
+#include "bits.h"
+#include "constants.h"
+#include "memory.h"
+#include "typearith.h"
+#include "io.h"
+
+
+/* This file contains functions for decimal <-> string conversions, including
+ PEP-3101 formatting for numeric types. */
+
+
+/*
+ * Work around the behavior of tolower() and strcasecmp() in certain
+ * locales. For example, in tr_TR.utf8:
+ *
+ * tolower((unsigned char)'I') == 'I'
+ *
+ * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1
+ */
+static inline int
+_mpd_strneq(const char *s, const char *l, const char *u, size_t n)
+{
+ while (--n != SIZE_MAX) {
+ if (*s != *l && *s != *u) {
+ return 0;
+ }
+ s++; u++; l++;
+ }
+
+ return 1;
+}
+
+static mpd_ssize_t
+strtoexp(const char *s)
+{
+ char *end;
+ mpd_ssize_t retval;
+
+ errno = 0;
+ retval = mpd_strtossize(s, &end, 10);
+ if (errno == 0 && !(*s != '\0' && *end == '\0'))
+ errno = EINVAL;
+
+ return retval;
+}
+
+/*
+ * Scan 'len' words. The most significant word contains 'r' digits,
+ * the remaining words are full words. Skip dpoint. The string 's' must
+ * consist of digits and an optional single decimal point at 'dpoint'.
+ */
+static void
+string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r,
+ size_t len)
+{
+ int j;
+
+ if (r > 0) {
+ data[--len] = 0;
+ for (j = 0; j < r; j++, s++) {
+ if (s == dpoint) s++;
+ data[len] = 10 * data[len] + (*s - '0');
+ }
+ }
+
+ while (--len != SIZE_MAX) {
+ data[len] = 0;
+ for (j = 0; j < MPD_RDIGITS; j++, s++) {
+ if (s == dpoint) s++;
+ data[len] = 10 * data[len] + (*s - '0');
+ }
+ }
+}
+
+/*
+ * Partially verify a numeric string of the form:
+ *
+ * [cdigits][.][cdigits][eE][+-][edigits]
+ *
+ * If successful, return a pointer to the location of the first
+ * relevant coefficient digit. This digit is either non-zero or
+ * part of one of the following patterns:
+ *
+ * ["0\x00", "0.\x00", "0.E", "0.e", "0E", "0e"]
+ *
+ * The locations of a single optional dot or indicator are stored
+ * in 'dpoint' and 'exp'.
+ *
+ * The end of the string is stored in 'end'. If an indicator [eE]
+ * occurs without trailing [edigits], the condition is caught
+ * later by strtoexp().
+ */
+static const char *
+scan_dpoint_exp(const char *s, const char **dpoint, const char **exp,
+ const char **end)
+{
+ const char *coeff = NULL;
+
+ *dpoint = NULL;
+ *exp = NULL;
+ for (; *s != '\0'; s++) {
+ switch (*s) {
+ case '.':
+ if (*dpoint != NULL || *exp != NULL)
+ return NULL;
+ *dpoint = s;
+ break;
+ case 'E': case 'e':
+ if (*exp != NULL)
+ return NULL;
+ *exp = s;
+ if (*(s+1) == '+' || *(s+1) == '-')
+ s++;
+ break;
+ default:
+ if (!isdigit((uchar)*s))
+ return NULL;
+ if (coeff == NULL && *exp == NULL) {
+ if (*s == '0') {
+ if (!isdigit((uchar)*(s+1)))
+ if (!(*(s+1) == '.' &&
+ isdigit((uchar)*(s+2))))
+ coeff = s;
+ }
+ else {
+ coeff = s;
+ }
+ }
+ break;
+
+ }
+ }
+
+ *end = s;
+ return coeff;
+}
+
+/* scan the payload of a NaN */
+static const char *
+scan_payload(const char *s, const char **end)
+{
+ const char *coeff;
+
+ while (*s == '0')
+ s++;
+ coeff = s;
+
+ while (isdigit((uchar)*s))
+ s++;
+ *end = s;
+
+ return (*s == '\0') ? coeff : NULL;
+}
+
+/* convert a character string to a decimal */
+void
+mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_ssize_t q, r, len;
+ const char *coeff, *end;
+ const char *dpoint = NULL, *exp = NULL;
+ size_t digits;
+ uint8_t sign = MPD_POS;
+
+ mpd_set_flags(dec, 0);
+ dec->len = 0;
+ dec->exp = 0;
+
+ /* sign */
+ if (*s == '+') {
+ s++;
+ }
+ else if (*s == '-') {
+ mpd_set_negative(dec);
+ sign = MPD_NEG;
+ s++;
+ }
+
+ if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */
+ s += 3;
+ mpd_setspecial(dec, sign, MPD_NAN);
+ if (*s == '\0')
+ return;
+ /* validate payload: digits only */
+ if ((coeff = scan_payload(s, &end)) == NULL)
+ goto conversion_error;
+ /* payload consists entirely of zeros */
+ if (*coeff == '\0')
+ return;
+ digits = end - coeff;
+ /* prec >= 1, clamp is 0 or 1 */
+ if (digits > (size_t)(ctx->prec-ctx->clamp))
+ goto conversion_error;
+ } /* sNaN */
+ else if (_mpd_strneq(s, "snan", "SNAN", 4)) {
+ s += 4;
+ mpd_setspecial(dec, sign, MPD_SNAN);
+ if (*s == '\0')
+ return;
+ /* validate payload: digits only */
+ if ((coeff = scan_payload(s, &end)) == NULL)
+ goto conversion_error;
+ /* payload consists entirely of zeros */
+ if (*coeff == '\0')
+ return;
+ digits = end - coeff;
+ if (digits > (size_t)(ctx->prec-ctx->clamp))
+ goto conversion_error;
+ }
+ else if (_mpd_strneq(s, "inf", "INF", 3)) {
+ s += 3;
+ if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) {
+ /* numeric-value: infinity */
+ mpd_setspecial(dec, sign, MPD_INF);
+ return;
+ }
+ goto conversion_error;
+ }
+ else {
+ /* scan for start of coefficient, decimal point, indicator, end */
+ if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL)
+ goto conversion_error;
+
+ /* numeric-value: [exponent-part] */
+ if (exp) {
+ /* exponent-part */
+ end = exp; exp++;
+ dec->exp = strtoexp(exp);
+ if (errno) {
+ if (!(errno == ERANGE &&
+ (dec->exp == MPD_SSIZE_MAX ||
+ dec->exp == MPD_SSIZE_MIN)))
+ goto conversion_error;
+ }
+ }
+
+ digits = end - coeff;
+ if (dpoint) {
+ size_t fracdigits = end-dpoint-1;
+ if (dpoint > coeff) digits--;
+
+ if (fracdigits > MPD_MAX_PREC) {
+ goto conversion_error;
+ }
+ if (dec->exp < MPD_SSIZE_MIN+(mpd_ssize_t)fracdigits) {
+ dec->exp = MPD_SSIZE_MIN;
+ }
+ else {
+ dec->exp -= (mpd_ssize_t)fracdigits;
+ }
+ }
+ if (digits > MPD_MAX_PREC) {
+ goto conversion_error;
+ }
+ if (dec->exp > MPD_EXP_INF) {
+ dec->exp = MPD_EXP_INF;
+ }
+ if (dec->exp == MPD_SSIZE_MIN) {
+ dec->exp = MPD_SSIZE_MIN+1;
+ }
+ }
+
+ _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS);
+
+ len = (r == 0) ? q : q+1;
+ if (len == 0) {
+ goto conversion_error; /* GCOV_NOT_REACHED */
+ }
+ if (!mpd_qresize(dec, len, status)) {
+ mpd_seterror(dec, MPD_Malloc_error, status);
+ return;
+ }
+ dec->len = len;
+
+ string_to_coeff(dec->data, coeff, dpoint, (int)r, len);
+
+ mpd_setdigits(dec);
+ mpd_qfinalize(dec, ctx, status);
+ return;
+
+conversion_error:
+ /* standard wants a positive NaN */
+ mpd_seterror(dec, MPD_Conversion_syntax, status);
+}
+
+/* Print word x with n decimal digits to string s. dot is either NULL
+ or the location of a decimal point. */
+#define EXTRACT_DIGIT(s, x, d, dot) \
+ if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d
+static inline char *
+word_to_string(char *s, mpd_uint_t x, int n, char *dot)
+{
+ switch(n) {
+#ifdef CONFIG_64
+ case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */
+ case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot);
+ case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot);
+ case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot);
+ case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot);
+ case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot);
+ case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot);
+ case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot);
+ case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot);
+ case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot);
+#endif
+ case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot);
+ case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot);
+ case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot);
+ case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot);
+ case 6: EXTRACT_DIGIT(s, x, 100000UL, dot);
+ case 5: EXTRACT_DIGIT(s, x, 10000UL, dot);
+ case 4: EXTRACT_DIGIT(s, x, 1000UL, dot);
+ case 3: EXTRACT_DIGIT(s, x, 100UL, dot);
+ case 2: EXTRACT_DIGIT(s, x, 10UL, dot);
+ default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x;
+ }
+
+ *s = '\0';
+ return s;
+}
+
+/* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */
+static inline char *
+exp_to_string(char *s, mpd_ssize_t x)
+{
+ char sign = '+';
+
+ if (x < 0) {
+ sign = '-';
+ x = -x;
+ }
+ *s++ = sign;
+
+ return word_to_string(s, x, mpd_word_digits(x), NULL);
+}
+
+/* Print the coefficient of dec to string s. len(dec) > 0. */
+static inline char *
+coeff_to_string(char *s, const mpd_t *dec)
+{
+ mpd_uint_t x;
+ mpd_ssize_t i;
+
+ /* most significant word */
+ x = mpd_msword(dec);
+ s = word_to_string(s, x, mpd_word_digits(x), NULL);
+
+ /* remaining full words */
+ for (i=dec->len-2; i >= 0; --i) {
+ x = dec->data[i];
+ s = word_to_string(s, x, MPD_RDIGITS, NULL);
+ }
+
+ return s;
+}
+
+/* Print the coefficient of dec to string s. len(dec) > 0. dot is either
+ NULL or a pointer to the location of a decimal point. */
+static inline char *
+coeff_to_string_dot(char *s, char *dot, const mpd_t *dec)
+{
+ mpd_uint_t x;
+ mpd_ssize_t i;
+
+ /* most significant word */
+ x = mpd_msword(dec);
+ s = word_to_string(s, x, mpd_word_digits(x), dot);
+
+ /* remaining full words */
+ for (i=dec->len-2; i >= 0; --i) {
+ x = dec->data[i];
+ s = word_to_string(s, x, MPD_RDIGITS, dot);
+ }
+
+ return s;
+}
+
+/* Format type */
+#define MPD_FMT_LOWER 0x00000000
+#define MPD_FMT_UPPER 0x00000001
+#define MPD_FMT_TOSCI 0x00000002
+#define MPD_FMT_TOENG 0x00000004
+#define MPD_FMT_EXP 0x00000008
+#define MPD_FMT_FIXED 0x00000010
+#define MPD_FMT_PERCENT 0x00000020
+#define MPD_FMT_SIGN_SPACE 0x00000040
+#define MPD_FMT_SIGN_PLUS 0x00000080
+
+/* Default place of the decimal point for MPD_FMT_TOSCI, MPD_FMT_EXP */
+#define MPD_DEFAULT_DOTPLACE 1
+
+/*
+ * Set *result to the string representation of a decimal. Return the length
+ * of *result, not including the terminating '\0' character.
+ *
+ * Formatting is done according to 'flags'. A return value of -1 with *result
+ * set to NULL indicates MPD_Malloc_error.
+ *
+ * 'dplace' is the default place of the decimal point. It is always set to
+ * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP.
+ */
+static mpd_ssize_t
+_mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace)
+{
+ char *decstring = NULL, *cp = NULL;
+ mpd_ssize_t ldigits;
+ mpd_ssize_t mem = 0, k;
+
+ if (mpd_isspecial(dec)) {
+
+ mem = sizeof "-Infinity";
+ if (mpd_isnan(dec) && dec->len > 0) {
+ /* diagnostic code */
+ mem += dec->digits;
+ }
+ cp = decstring = mpd_alloc(mem, sizeof *decstring);
+ if (cp == NULL) {
+ *result = NULL;
+ return -1;
+ }
+
+ if (mpd_isnegative(dec)) {
+ *cp++ = '-';
+ }
+ else if (flags&MPD_FMT_SIGN_SPACE) {
+ *cp++ = ' ';
+ }
+ else if (flags&MPD_FMT_SIGN_PLUS) {
+ *cp++ = '+';
+ }
+
+ if (mpd_isnan(dec)) {
+ if (mpd_isqnan(dec)) {
+ strcpy(cp, "NaN");
+ cp += 3;
+ }
+ else {
+ strcpy(cp, "sNaN");
+ cp += 4;
+ }
+ if (dec->len > 0) { /* diagnostic code */
+ cp = coeff_to_string(cp, dec);
+ }
+ }
+ else if (mpd_isinfinite(dec)) {
+ strcpy(cp, "Infinity");
+ cp += 8;
+ }
+ else { /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+ }
+ else {
+ assert(dec->len > 0);
+
+ /*
+ * For easier manipulation of the decimal point's location
+ * and the exponent that is finally printed, the number is
+ * rescaled to a virtual representation with exp = 0. Here
+ * ldigits denotes the number of decimal digits to the left
+ * of the decimal point and remains constant once initialized.
+ *
+ * dplace is the location of the decimal point relative to
+ * the start of the coefficient. Note that 3) always holds
+ * when dplace is shifted.
+ *
+ * 1) ldigits := dec->digits - dec->exp
+ * 2) dplace := ldigits (initially)
+ * 3) exp := ldigits - dplace (initially exp = 0)
+ *
+ * 0.00000_.____._____000000.
+ * ^ ^ ^ ^
+ * | | | |
+ * | | | `- dplace >= digits
+ * | | `- dplace in the middle of the coefficient
+ * | ` dplace = 1 (after the first coefficient digit)
+ * `- dplace <= 0
+ */
+
+ ldigits = dec->digits + dec->exp;
+
+ if (flags&MPD_FMT_EXP) {
+ ;
+ }
+ else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) {
+ /* MPD_FMT_FIXED: always use fixed point notation.
+ * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range,
+ * override exponent notation. */
+ dplace = ldigits;
+ }
+ else if (flags&MPD_FMT_TOENG) {
+ if (mpd_iszero(dec)) {
+ /* If the exponent is divisible by three,
+ * dplace = 1. Otherwise, move dplace one
+ * or two places to the left. */
+ dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3);
+ }
+ else { /* ldigits-1 is the adjusted exponent, which
+ * should be divisible by three. If not, move
+ * dplace one or two places to the right. */
+ dplace += mod_mpd_ssize_t(ldigits-1, 3);
+ }
+ }
+
+ /*
+ * Basic space requirements:
+ *
+ * [-][.][coeffdigits][E][-][expdigits+1][%]['\0']
+ *
+ * If the decimal point lies outside of the coefficient digits,
+ * space is adjusted accordingly.
+ */
+ if (dplace <= 0) {
+ mem = -dplace + dec->digits + 2;
+ }
+ else if (dplace >= dec->digits) {
+ mem = dplace;
+ }
+ else {
+ mem = dec->digits;
+ }
+ mem += (MPD_EXPDIGITS+1+6);
+
+ cp = decstring = mpd_alloc(mem, sizeof *decstring);
+ if (cp == NULL) {
+ *result = NULL;
+ return -1;
+ }
+
+
+ if (mpd_isnegative(dec)) {
+ *cp++ = '-';
+ }
+ else if (flags&MPD_FMT_SIGN_SPACE) {
+ *cp++ = ' ';
+ }
+ else if (flags&MPD_FMT_SIGN_PLUS) {
+ *cp++ = '+';
+ }
+
+ if (dplace <= 0) {
+ /* space: -dplace+dec->digits+2 */
+ *cp++ = '0';
+ *cp++ = '.';
+ for (k = 0; k < -dplace; k++) {
+ *cp++ = '0';
+ }
+ cp = coeff_to_string(cp, dec);
+ }
+ else if (dplace >= dec->digits) {
+ /* space: dplace */
+ cp = coeff_to_string(cp, dec);
+ for (k = 0; k < dplace-dec->digits; k++) {
+ *cp++ = '0';
+ }
+ }
+ else {
+ /* space: dec->digits+1 */
+ cp = coeff_to_string_dot(cp, cp+dplace, dec);
+ }
+
+ /*
+ * Conditions for printing an exponent:
+ *
+ * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace
+ * MPD_FMT_FIXED: never (ldigits == dplace)
+ * MPD_FMT_EXP: always
+ */
+ if (ldigits != dplace || flags&MPD_FMT_EXP) {
+ /* space: expdigits+2 */
+ *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e';
+ cp = exp_to_string(cp, ldigits-dplace);
+ }
+
+ if (flags&MPD_FMT_PERCENT) {
+ *cp++ = '%';
+ }
+ }
+
+ assert(cp < decstring+mem);
+ assert(cp-decstring < MPD_SSIZE_MAX);
+
+ *cp = '\0';
+ *result = decstring;
+ return (mpd_ssize_t)(cp-decstring);
+}
+
+char *
+mpd_to_sci(const mpd_t *dec, int fmt)
+{
+ char *res;
+ int flags = MPD_FMT_TOSCI;
+
+ flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
+ (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE);
+ return res;
+}
+
+char *
+mpd_to_eng(const mpd_t *dec, int fmt)
+{
+ char *res;
+ int flags = MPD_FMT_TOENG;
+
+ flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
+ (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE);
+ return res;
+}
+
+mpd_ssize_t
+mpd_to_sci_size(char **res, const mpd_t *dec, int fmt)
+{
+ int flags = MPD_FMT_TOSCI;
+
+ flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
+ return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE);
+}
+
+mpd_ssize_t
+mpd_to_eng_size(char **res, const mpd_t *dec, int fmt)
+{
+ int flags = MPD_FMT_TOENG;
+
+ flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
+ return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE);
+}
+
+/* Copy a single UTF-8 char to dest. See: The Unicode Standard, version 5.2,
+ chapter 3.9: Well-formed UTF-8 byte sequences. */
+static int
+_mpd_copy_utf8(char dest[5], const char *s)
+{
+ const uchar *cp = (const uchar *)s;
+ uchar lb, ub;
+ int count, i;
+
+
+ if (*cp == 0) {
+ /* empty string */
+ dest[0] = '\0';
+ return 0;
+ }
+ else if (*cp <= 0x7f) {
+ /* ascii */
+ dest[0] = *cp;
+ dest[1] = '\0';
+ return 1;
+ }
+ else if (0xc2 <= *cp && *cp <= 0xdf) {
+ lb = 0x80; ub = 0xbf;
+ count = 2;
+ }
+ else if (*cp == 0xe0) {
+ lb = 0xa0; ub = 0xbf;
+ count = 3;
+ }
+ else if (*cp <= 0xec) {
+ lb = 0x80; ub = 0xbf;
+ count = 3;
+ }
+ else if (*cp == 0xed) {
+ lb = 0x80; ub = 0x9f;
+ count = 3;
+ }
+ else if (*cp <= 0xef) {
+ lb = 0x80; ub = 0xbf;
+ count = 3;
+ }
+ else if (*cp == 0xf0) {
+ lb = 0x90; ub = 0xbf;
+ count = 4;
+ }
+ else if (*cp <= 0xf3) {
+ lb = 0x80; ub = 0xbf;
+ count = 4;
+ }
+ else if (*cp == 0xf4) {
+ lb = 0x80; ub = 0x8f;
+ count = 4;
+ }
+ else {
+ /* invalid */
+ goto error;
+ }
+
+ dest[0] = *cp++;
+ if (*cp < lb || ub < *cp) {
+ goto error;
+ }
+ dest[1] = *cp++;
+ for (i = 2; i < count; i++) {
+ if (*cp < 0x80 || 0xbf < *cp) {
+ goto error;
+ }
+ dest[i] = *cp++;
+ }
+ dest[i] = '\0';
+
+ return count;
+
+error:
+ dest[0] = '\0';
+ return -1;
+}
+
+int
+mpd_validate_lconv(mpd_spec_t *spec)
+{
+ size_t n;
+#if CHAR_MAX == SCHAR_MAX
+ const char *cp = spec->grouping;
+ while (*cp != '\0') {
+ if (*cp++ < 0) {
+ return -1;
+ }
+ }
+#endif
+ n = strlen(spec->dot);
+ if (n == 0 || n > 4) {
+ return -1;
+ }
+ if (strlen(spec->sep) > 4) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps)
+{
+ char *cp = (char *)fmt;
+ int have_align = 0, n;
+
+ /* defaults */
+ spec->min_width = 0;
+ spec->prec = -1;
+ spec->type = caps ? 'G' : 'g';
+ spec->align = '>';
+ spec->sign = '-';
+ spec->dot = "";
+ spec->sep = "";
+ spec->grouping = "";
+
+
+ /* presume that the first character is a UTF-8 fill character */
+ if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) {
+ return 0;
+ }
+
+ /* alignment directive, prefixed by a fill character */
+ if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' ||
+ *(cp+n) == '=' || *(cp+n) == '^')) {
+ cp += n;
+ spec->align = *cp++;
+ have_align = 1;
+ } /* alignment directive */
+ else {
+ /* default fill character */
+ spec->fill[0] = ' ';
+ spec->fill[1] = '\0';
+ if (*cp == '<' || *cp == '>' ||
+ *cp == '=' || *cp == '^') {
+ spec->align = *cp++;
+ have_align = 1;
+ }
+ }
+
+ /* sign formatting */
+ if (*cp == '+' || *cp == '-' || *cp == ' ') {
+ spec->sign = *cp++;
+ }
+
+ /* zero padding */
+ if (*cp == '0') {
+ /* zero padding implies alignment, which should not be
+ * specified twice. */
+ if (have_align) {
+ return 0;
+ }
+ spec->align = 'z';
+ spec->fill[0] = *cp++;
+ spec->fill[1] = '\0';
+ }
+
+ /* minimum width */
+ if (isdigit((uchar)*cp)) {
+ if (*cp == '0') {
+ return 0;
+ }
+ errno = 0;
+ spec->min_width = mpd_strtossize(cp, &cp, 10);
+ if (errno == ERANGE || errno == EINVAL) {
+ return 0;
+ }
+ }
+
+ /* thousands separator */
+ if (*cp == ',') {
+ spec->dot = ".";
+ spec->sep = ",";
+ spec->grouping = "\003\003";
+ cp++;
+ }
+
+ /* fraction digits or significant digits */
+ if (*cp == '.') {
+ cp++;
+ if (!isdigit((uchar)*cp)) {
+ return 0;
+ }
+ errno = 0;
+ spec->prec = mpd_strtossize(cp, &cp, 10);
+ if (errno == ERANGE || errno == EINVAL) {
+ return 0;
+ }
+ }
+
+ /* type */
+ if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' ||
+ *cp == 'G' || *cp == 'g' || *cp == '%') {
+ spec->type = *cp++;
+ }
+ else if (*cp == 'N' || *cp == 'n') {
+ /* locale specific conversion */
+ struct lconv *lc;
+ /* separator has already been specified */
+ if (*spec->sep) {
+ return 0;
+ }
+ spec->type = *cp++;
+ spec->type = (spec->type == 'N') ? 'G' : 'g';
+ lc = localeconv();
+ spec->dot = lc->decimal_point;
+ spec->sep = lc->thousands_sep;
+ spec->grouping = lc->grouping;
+ if (mpd_validate_lconv(spec) < 0) {
+ return 0; /* GCOV_NOT_REACHED */
+ }
+ }
+
+ /* check correctness */
+ if (*cp != '\0') {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * The following functions assume that spec->min_width <= MPD_MAX_PREC, which
+ * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a
+ * four-byte separator after each digit, nbytes in the following struct
+ * cannot overflow.
+ */
+
+/* Multibyte string */
+typedef struct {
+ mpd_ssize_t nbytes; /* length in bytes */
+ mpd_ssize_t nchars; /* length in chars */
+ mpd_ssize_t cur; /* current write index */
+ char *data;
+} mpd_mbstr_t;
+
+static inline void
+_mpd_bcopy(char *dest, const char *src, mpd_ssize_t n)
+{
+ while (--n >= 0) {
+ dest[n] = src[n];
+ }
+}
+
+static inline void
+_mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
+{
+ dest->nbytes += n;
+ dest->nchars += (n > 0 ? 1 : 0);
+ dest->cur -= n;
+
+ if (dest->data != NULL) {
+ _mpd_bcopy(dest->data+dest->cur, src, n);
+ }
+}
+
+static inline void
+_mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
+{
+ dest->nbytes += n;
+ dest->nchars += n;
+ dest->cur -= n;
+
+ if (dest->data != NULL) {
+ _mpd_bcopy(dest->data+dest->cur, src, n);
+ }
+}
+
+static inline void
+_mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n)
+{
+ dest->nbytes += n;
+ dest->nchars += n;
+ dest->cur -= n;
+
+ if (dest->data != NULL) {
+ char *cp = dest->data + dest->cur;
+ while (--n >= 0) {
+ cp[n] = '0';
+ }
+ }
+}
+
+/*
+ * Copy a numeric string to dest->data, adding separators in the integer
+ * part according to spec->grouping. If leading zero padding is enabled
+ * and the result is smaller than spec->min_width, continue adding zeros
+ * and separators until the minimum width is reached.
+ *
+ * The final length of dest->data is stored in dest->nbytes. The number
+ * of UTF-8 characters is stored in dest->nchars.
+ *
+ * First run (dest->data == NULL): determine the length of the result
+ * string and store it in dest->nbytes.
+ *
+ * Second run (write to dest->data): data is written in chunks and in
+ * reverse order, starting with the rest of the numeric string.
+ */
+static void
+_mpd_add_sep_dot(mpd_mbstr_t *dest,
+ const char *sign, /* location of optional sign */
+ const char *src, mpd_ssize_t n_src, /* integer part and length */
+ const char *dot, /* location of optional decimal point */
+ const char *rest, mpd_ssize_t n_rest, /* remaining part and length */
+ const mpd_spec_t *spec)
+{
+ mpd_ssize_t n_sep, n_sign, consume;
+ const char *g;
+ int pad = 0;
+
+ n_sign = sign ? 1 : 0;
+ n_sep = (mpd_ssize_t)strlen(spec->sep);
+ /* Initial write index: set to location of '\0' in the output string.
+ * Irrelevant for the first run. */
+ dest->cur = dest->nbytes;
+ dest->nbytes = dest->nchars = 0;
+
+ _mbstr_copy_ascii(dest, rest, n_rest);
+
+ if (dot) {
+ _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot));
+ }
+
+ g = spec->grouping;
+ consume = *g;
+ while (1) {
+ /* If the group length is 0 or CHAR_MAX or greater than the
+ * number of source bytes, consume all remaining bytes. */
+ if (*g == 0 || *g == CHAR_MAX || consume > n_src) {
+ consume = n_src;
+ }
+ n_src -= consume;
+ if (pad) {
+ _mbstr_copy_pad(dest, consume);
+ }
+ else {
+ _mbstr_copy_ascii(dest, src+n_src, consume);
+ }
+
+ if (n_src == 0) {
+ /* Either the real source of intpart digits or the virtual
+ * source of padding zeros is exhausted. */
+ if (spec->align == 'z' &&
+ dest->nchars + n_sign < spec->min_width) {
+ /* Zero padding is set and length < min_width:
+ * Generate n_src additional characters. */
+ n_src = spec->min_width - (dest->nchars + n_sign);
+ /* Next iteration:
+ * case *g == 0 || *g == CHAR_MAX:
+ * consume all padding characters
+ * case consume < g*:
+ * fill remainder of current group
+ * case consume == g*
+ * copying is a no-op */
+ consume = *g - consume;
+ /* Switch on virtual source of zeros. */
+ pad = 1;
+ continue;
+ }
+ break;
+ }
+
+ if (n_sep > 0) {
+ /* If padding is switched on, separators are counted
+ * as padding characters. This rule does not apply if
+ * the separator would be the first character of the
+ * result string. */
+ if (pad && n_src > 1) n_src -= 1;
+ _mbstr_copy_char(dest, spec->sep, n_sep);
+ }
+
+ /* If non-NUL, use the next value for grouping. */
+ if (*g && *(g+1)) g++;
+ consume = *g;
+ }
+
+ if (sign) {
+ _mbstr_copy_ascii(dest, sign, 1);
+ }
+
+ if (dest->data) {
+ dest->data[dest->nbytes] = '\0';
+ }
+}
+
+/*
+ * Convert a numeric-string to its locale-specific appearance.
+ * The string must have one of these forms:
+ *
+ * 1) [sign] digits [exponent-part]
+ * 2) [sign] digits '.' [digits] [exponent-part]
+ *
+ * Not allowed, since _mpd_to_string() never returns this form:
+ *
+ * 3) [sign] '.' digits [exponent-part]
+ *
+ * Input: result->data := original numeric string (ASCII)
+ * result->bytes := strlen(result->data)
+ * result->nchars := strlen(result->data)
+ *
+ * Output: result->data := modified or original string
+ * result->bytes := strlen(result->data)
+ * result->nchars := number of characters (possibly UTF-8)
+ */
+static int
+_mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status)
+{
+ const char *sign = NULL, *intpart = NULL, *dot = NULL;
+ const char *rest, *dp;
+ char *decstring;
+ mpd_ssize_t n_int, n_rest;
+
+ /* original numeric string */
+ dp = result->data;
+
+ /* sign */
+ if (*dp == '+' || *dp == '-' || *dp == ' ') {
+ sign = dp++;
+ }
+ /* integer part */
+ assert(isdigit((uchar)*dp));
+ intpart = dp++;
+ while (isdigit((uchar)*dp)) {
+ dp++;
+ }
+ n_int = (mpd_ssize_t)(dp-intpart);
+ /* decimal point */
+ if (*dp == '.') {
+ dp++; dot = spec->dot;
+ }
+ /* rest */
+ rest = dp;
+ n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data);
+
+ if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) {
+ /* _mpd_add_sep_dot() would not change anything */
+ return 1;
+ }
+
+ /* Determine the size of the new decimal string after inserting the
+ * decimal point, optional separators and optional padding. */
+ decstring = result->data;
+ result->data = NULL;
+ _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
+ rest, n_rest, spec);
+
+ result->data = mpd_alloc(result->nbytes+1, 1);
+ if (result->data == NULL) {
+ *status |= MPD_Malloc_error;
+ mpd_free(decstring);
+ return 0;
+ }
+
+ /* Perform actual writes. */
+ _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
+ rest, n_rest, spec);
+
+ mpd_free(decstring);
+ return 1;
+}
+
+/* Add padding to the formatted string if necessary. */
+static int
+_mpd_add_pad(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status)
+{
+ if (result->nchars < spec->min_width) {
+ mpd_ssize_t add_chars, add_bytes;
+ size_t lpad = 0, rpad = 0;
+ size_t n_fill, len, i, j;
+ char align = spec->align;
+ uint8_t err = 0;
+ char *cp;
+
+ n_fill = strlen(spec->fill);
+ add_chars = (spec->min_width - result->nchars);
+ /* max value: MPD_MAX_PREC * 4 */
+ add_bytes = add_chars * (mpd_ssize_t)n_fill;
+
+ cp = result->data = mpd_realloc(result->data,
+ result->nbytes+add_bytes+1,
+ sizeof *result->data, &err);
+ if (err) {
+ *status |= MPD_Malloc_error;
+ mpd_free(result->data);
+ return 0;
+ }
+
+ if (align == 'z') {
+ align = '=';
+ }
+
+ if (align == '<') {
+ rpad = add_chars;
+ }
+ else if (align == '>' || align == '=') {
+ lpad = add_chars;
+ }
+ else { /* align == '^' */
+ lpad = add_chars/2;
+ rpad = add_chars-lpad;
+ }
+
+ len = result->nbytes;
+ if (align == '=' && (*cp == '-' || *cp == '+' || *cp == ' ')) {
+ /* leave sign in the leading position */
+ cp++; len--;
+ }
+
+ memmove(cp+n_fill*lpad, cp, len);
+ for (i = 0; i < lpad; i++) {
+ for (j = 0; j < n_fill; j++) {
+ cp[i*n_fill+j] = spec->fill[j];
+ }
+ }
+ cp += (n_fill*lpad + len);
+ for (i = 0; i < rpad; i++) {
+ for (j = 0; j < n_fill; j++) {
+ cp[i*n_fill+j] = spec->fill[j];
+ }
+ }
+
+ result->nbytes += add_bytes;
+ result->nchars += add_chars;
+ result->data[result->nbytes] = '\0';
+ }
+
+ return 1;
+}
+
+/* Round a number to prec digits. The adjusted exponent stays the same
+ or increases by one if rounding up crosses a power of ten boundary.
+ If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation
+ is set and the result is NaN. */
+static inline void
+_mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_ssize_t exp = a->exp + a->digits - prec;
+
+ if (prec <= 0) {
+ mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */
+ return; /* GCOV_NOT_REACHED */
+ }
+ if (mpd_isspecial(a) || mpd_iszero(a)) {
+ mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */
+ return; /* GCOV_NOT_REACHED */
+ }
+
+ mpd_qrescale_fmt(result, a, exp, ctx, status);
+ if (result->digits > prec) {
+ mpd_qrescale_fmt(result, result, exp+1, ctx, status);
+ }
+}
+
+/*
+ * Return the string representation of an mpd_t, formatted according to 'spec'.
+ * The format specification is assumed to be valid. Memory errors are indicated
+ * as usual. This function is quiet.
+ */
+char *
+mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_uint_t dt[MPD_MINALLOC_MAX];
+ mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
+ mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE;
+ mpd_mbstr_t result;
+ mpd_spec_t stackspec;
+ char type = spec->type;
+ int flags = 0;
+
+
+ if (spec->min_width > MPD_MAX_PREC) {
+ *status |= MPD_Invalid_operation;
+ return NULL;
+ }
+
+ if (isupper((uchar)type)) {
+ type = tolower((uchar)type);
+ flags |= MPD_FMT_UPPER;
+ }
+ if (spec->sign == ' ') {
+ flags |= MPD_FMT_SIGN_SPACE;
+ }
+ else if (spec->sign == '+') {
+ flags |= MPD_FMT_SIGN_PLUS;
+ }
+
+ if (mpd_isspecial(dec)) {
+ if (spec->align == 'z') {
+ stackspec = *spec;
+ stackspec.fill[0] = ' ';
+ stackspec.fill[1] = '\0';
+ stackspec.align = '>';
+ spec = &stackspec;
+ }
+ }
+ else {
+ uint32_t workstatus = 0;
+ mpd_ssize_t prec;
+
+ switch (type) {
+ case 'g': flags |= MPD_FMT_TOSCI; break;
+ case 'e': flags |= MPD_FMT_EXP; break;
+ case '%': flags |= MPD_FMT_PERCENT;
+ if (!mpd_qcopy(&tmp, dec, status)) {
+ return NULL;
+ }
+ tmp.exp += 2;
+ dec = &tmp;
+ type = 'f'; /* fall through */
+ case 'f': flags |= MPD_FMT_FIXED; break;
+ default: abort(); /* debug: GCOV_NOT_REACHED */
+ }
+
+ if (spec->prec >= 0) {
+ if (spec->prec > MPD_MAX_PREC) {
+ *status |= MPD_Invalid_operation;
+ goto error;
+ }
+
+ switch (type) {
+ case 'g':
+ prec = (spec->prec == 0) ? 1 : spec->prec;
+ if (dec->digits > prec) {
+ _mpd_round(&tmp, dec, prec, ctx,
+ &workstatus);
+ dec = &tmp;
+ }
+ break;
+ case 'e':
+ if (mpd_iszero(dec)) {
+ dplace = 1-spec->prec;
+ }
+ else {
+ _mpd_round(&tmp, dec, spec->prec+1, ctx,
+ &workstatus);
+ dec = &tmp;
+ }
+ break;
+ case 'f':
+ mpd_qrescale(&tmp, dec, -spec->prec, ctx,
+ &workstatus);
+ dec = &tmp;
+ break;
+ }
+ }
+
+ if (type == 'f') {
+ if (mpd_iszero(dec) && dec->exp > 0) {
+ mpd_qrescale(&tmp, dec, 0, ctx, &workstatus);
+ dec = &tmp;
+ }
+ }
+
+ if (workstatus&MPD_Errors) {
+ *status |= (workstatus&MPD_Errors);
+ goto error;
+ }
+ }
+
+ /*
+ * At this point, for all scaled or non-scaled decimals:
+ * 1) 1 <= digits <= MAX_PREC+1
+ * 2) adjexp(scaled) = adjexp(orig) [+1]
+ * 3) case 'g': MIN_ETINY <= exp <= MAX_EMAX+1
+ * case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1
+ * case 'f': MIN_ETINY <= exp <= MAX_EMAX+1
+ * 4) max memory alloc in _mpd_to_string:
+ * case 'g': MAX_PREC+36
+ * case 'e': MAX_PREC+36
+ * case 'f': 2*MPD_MAX_PREC+30
+ */
+ result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace);
+ result.nchars = result.nbytes;
+ if (result.nbytes < 0) {
+ *status |= MPD_Malloc_error;
+ goto error;
+ }
+
+ if (*spec->dot != '\0' && !mpd_isspecial(dec)) {
+ if (result.nchars > MPD_MAX_PREC+36) {
+ /* Since a group length of one is not explicitly
+ * disallowed, ensure that it is always possible to
+ * insert a four byte separator after each digit. */
+ *status |= MPD_Invalid_operation;
+ mpd_free(result.data);
+ goto error;
+ }
+ if (!_mpd_apply_lconv(&result, spec, status)) {
+ goto error;
+ }
+ }
+
+ if (spec->min_width) {
+ if (!_mpd_add_pad(&result, spec, status)) {
+ goto error;
+ }
+ }
+
+ mpd_del(&tmp);
+ return result.data;
+
+error:
+ mpd_del(&tmp);
+ return NULL;
+}
+
+char *
+mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_spec_t spec;
+
+ if (!mpd_parse_fmt_str(&spec, fmt, 1)) {
+ *status |= MPD_Invalid_operation;
+ return NULL;
+ }
+
+ return mpd_qformat_spec(dec, &spec, ctx, status);
+}
+
+/*
+ * The specification has a *condition* called Invalid_operation and an
+ * IEEE *signal* called Invalid_operation. The former corresponds to
+ * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation.
+ * MPD_IEEE_Invalid_operation comprises the following conditions:
+ *
+ * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined,
+ * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation,
+ * MPD_Malloc_error]
+ *
+ * In the following functions, 'flag' denotes the condition, 'signal'
+ * denotes the IEEE signal.
+ */
+
+static const char *mpd_flag_string[MPD_NUM_FLAGS] = {
+ "Clamped",
+ "Conversion_syntax",
+ "Division_by_zero",
+ "Division_impossible",
+ "Division_undefined",
+ "Fpu_error",
+ "Inexact",
+ "Invalid_context",
+ "Invalid_operation",
+ "Malloc_error",
+ "Not_implemented",
+ "Overflow",
+ "Rounded",
+ "Subnormal",
+ "Underflow",
+};
+
+static const char *mpd_signal_string[MPD_NUM_FLAGS] = {
+ "Clamped",
+ "IEEE_Invalid_operation",
+ "Division_by_zero",
+ "IEEE_Invalid_operation",
+ "IEEE_Invalid_operation",
+ "IEEE_Invalid_operation",
+ "Inexact",
+ "IEEE_Invalid_operation",
+ "IEEE_Invalid_operation",
+ "IEEE_Invalid_operation",
+ "Not_implemented",
+ "Overflow",
+ "Rounded",
+ "Subnormal",
+ "Underflow",
+};
+
+/* print conditions to buffer, separated by spaces */
+int
+mpd_snprint_flags(char *dest, int nmemb, uint32_t flags)
+{
+ char *cp;
+ int n, j;
+
+ assert(nmemb >= MPD_MAX_FLAG_STRING);
+
+ *dest = '\0'; cp = dest;
+ for (j = 0; j < MPD_NUM_FLAGS; j++) {
+ if (flags & (1U<<j)) {
+ n = snprintf(cp, nmemb, "%s ", mpd_flag_string[j]);
+ if (n < 0 || n >= nmemb) return -1;
+ cp += n; nmemb -= n;
+ }
+ }
+
+ if (cp != dest) {
+ *(--cp) = '\0';
+ }
+
+ return (int)(cp-dest);
+}
+
+/* print conditions to buffer, in list form */
+int
+mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[])
+{
+ char *cp;
+ int n, j;
+
+ assert(nmemb >= MPD_MAX_FLAG_LIST);
+ if (flag_string == NULL) {
+ flag_string = mpd_flag_string;
+ }
+
+ *dest = '[';
+ *(dest+1) = '\0';
+ cp = dest+1;
+ --nmemb;
+
+ for (j = 0; j < MPD_NUM_FLAGS; j++) {
+ if (flags & (1U<<j)) {
+ n = snprintf(cp, nmemb, "%s, ", flag_string[j]);
+ if (n < 0 || n >= nmemb) return -1;
+ cp += n; nmemb -= n;
+ }
+ }
+
+ /* erase the last ", " */
+ if (cp != dest+1) {
+ cp -= 2;
+ }
+
+ *cp++ = ']';
+ *cp = '\0';
+
+ return (int)(cp-dest); /* strlen, without NUL terminator */
+}
+
+/* print signals to buffer, in list form */
+int
+mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[])
+{
+ char *cp;
+ int n, j;
+ int ieee_invalid_done = 0;
+
+ assert(nmemb >= MPD_MAX_SIGNAL_LIST);
+ if (signal_string == NULL) {
+ signal_string = mpd_signal_string;
+ }
+
+ *dest = '[';
+ *(dest+1) = '\0';
+ cp = dest+1;
+ --nmemb;
+
+ for (j = 0; j < MPD_NUM_FLAGS; j++) {
+ uint32_t f = flags & (1U<<j);
+ if (f) {
+ if (f&MPD_IEEE_Invalid_operation) {
+ if (ieee_invalid_done) {
+ continue;
+ }
+ ieee_invalid_done = 1;
+ }
+ n = snprintf(cp, nmemb, "%s, ", signal_string[j]);
+ if (n < 0 || n >= nmemb) return -1;
+ cp += n; nmemb -= n;
+ }
+ }
+
+ /* erase the last ", " */
+ if (cp != dest+1) {
+ cp -= 2;
+ }
+
+ *cp++ = ']';
+ *cp = '\0';
+
+ return (int)(cp-dest); /* strlen, without NUL terminator */
+}
+
+/* The following two functions are mainly intended for debugging. */
+void
+mpd_fprint(FILE *file, const mpd_t *dec)
+{
+ char *decstring;
+
+ decstring = mpd_to_sci(dec, 1);
+ if (decstring != NULL) {
+ fprintf(file, "%s\n", decstring);
+ mpd_free(decstring);
+ }
+ else {
+ fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */
+ }
+}
+
+void
+mpd_print(const mpd_t *dec)
+{
+ char *decstring;
+
+ decstring = mpd_to_sci(dec, 1);
+ if (decstring != NULL) {
+ printf("%s\n", decstring);
+ mpd_free(decstring);
+ }
+ else {
+ fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */
+ }
+}
+
+
diff --git a/Modules/_decimal/libmpdec/io.h b/Modules/_decimal/libmpdec/io.h
new file mode 100644
index 0000000..3dfce73
--- /dev/null
+++ b/Modules/_decimal/libmpdec/io.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef IO_H
+#define IO_H
+
+
+#include <errno.h>
+#include "mpdecimal.h"
+
+
+#if SIZE_MAX == MPD_SIZE_MAX
+ #define mpd_strtossize _mpd_strtossize
+#else
+static inline mpd_ssize_t
+mpd_strtossize(const char *s, char **end, int base)
+{
+ int64_t retval;
+
+ errno = 0;
+ retval = _mpd_strtossize(s, end, base);
+ if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) {
+ errno = ERANGE;
+ }
+ if (errno == ERANGE) {
+ return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX;
+ }
+
+ return (mpd_ssize_t)retval;
+}
+#endif
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/literature/REFERENCES.txt b/Modules/_decimal/libmpdec/literature/REFERENCES.txt
new file mode 100644
index 0000000..9ed5782
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/REFERENCES.txt
@@ -0,0 +1,51 @@
+
+
+This document contains links to the literature used in the process of
+creating the library. The list is probably not complete.
+
+
+Mike Cowlishaw: General Decimal Arithmetic Specification
+http://speleotrove.com/decimal/decarith.html
+
+
+Jean-Michel Muller: On the definition of ulp (x)
+lara.inist.fr/bitstream/2332/518/1/LIP-RR2005-09.pdf
+
+
+T. E. Hull, A. Abrham: Properly rounded variable precision square root
+http://portal.acm.org/citation.cfm?id=214413
+
+
+T. E. Hull, A. Abrham: Variable precision exponential function
+http://portal.acm.org/citation.cfm?id=6498
+
+
+Roman E. Maeder: Storage allocation for the Karatsuba integer multiplication
+algorithm. http://www.springerlink.com/content/w15058mj6v59t565/
+
+
+J. M. Pollard: The fast Fourier transform in a finite field
+http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html
+
+
+David H. Bailey: FFTs in External or Hierarchical Memory
+http://crd.lbl.gov/~dhbailey/dhbpapers/
+
+
+W. Morven Gentleman: Matrix Multiplication and Fast Fourier Transforms
+http://www.alcatel-lucent.com/bstj/vol47-1968/articles/bstj47-6-1099.pdf
+
+
+Mikko Tommila: Apfloat documentation
+http://www.apfloat.org/apfloat/2.41/apfloat.pdf
+
+
+Joerg Arndt: "Matters Computational"
+http://www.jjj.de/fxt/
+
+
+Karl Hasselstrom: Fast Division of Large Integers
+www.treskal.com/kalle/exjobb/original-report.pdf
+
+
+
diff --git a/Modules/_decimal/libmpdec/literature/bignum.txt b/Modules/_decimal/libmpdec/literature/bignum.txt
new file mode 100644
index 0000000..8a8731d
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/bignum.txt
@@ -0,0 +1,83 @@
+
+
+Bignum support (Fast Number Theoretic Transform or FNT):
+========================================================
+
+Bignum arithmetic in libmpdec uses the scheme for fast convolution
+of integer sequences from:
+
+J. M. Pollard: The fast Fourier transform in a finite field
+http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html
+
+
+The transform in a finite field can be used for convolution in the same
+way as the Fourier Transform. The main advantages of the Number Theoretic
+Transform are that it is both exact and very memory efficient.
+
+
+Convolution in pseudo-code:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ fnt_convolute(a, b):
+ x = fnt(a) # forward transform of a
+ y = fnt(b) # forward transform of b
+ z = pairwise multiply x[i] and y[i]
+ result = inv_fnt(z) # backward transform of z.
+
+
+Extending the maximum transform length (Chinese Remainder Theorem):
+-------------------------------------------------------------------
+
+The maximum transform length is quite limited when using a single
+prime field. However, it is possible to use multiple primes and
+recover the result using the Chinese Remainder Theorem.
+
+
+Multiplication in pseudo-code:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ _mpd_fntmul(u, v):
+ c1 = fnt_convolute(u, v, P1) # convolute modulo prime1
+ c2 = fnt_convolute(u, v, P2) # convolute modulo prime2
+ c3 = fnt_convolute(u, v, P3) # convolute modulo prime3
+ result = crt3(c1, c2, c3) # Chinese Remainder Theorem
+
+
+Optimized transform functions:
+------------------------------
+
+There are three different fnt() functions:
+
+ std_fnt: "standard" decimation in frequency transform for array lengths
+ of 2**n. Performs well up to 1024 words.
+
+ sixstep: Cache-friendly algorithm for array lengths of 2**n. Outperforms
+ std_fnt for large arrays.
+
+ fourstep: Algorithm for array lengths of 3 * 2**n. Also cache friendly
+ in large parts.
+
+
+List of bignum-only files:
+--------------------------
+
+Functions from these files are only used in _mpd_fntmul().
+
+ umodarith.h -> fast low level routines for unsigned modular arithmetic
+ numbertheory.c -> routines for setting up the FNT
+ difradix2.c -> decimation in frequency transform, used as the
+ "base case" by the following three files:
+
+ fnt.c -> standard transform for smaller arrays
+ sixstep.c -> transform large arrays of length 2**n
+ fourstep.c -> transform arrays of length 3 * 2**n
+
+ convolute.c -> do the actual fast convolution, using one of
+ the three transform functions.
+ transpose.c -> transpositions needed for the sixstep algorithm.
+ crt.c -> Chinese Remainder Theorem: use information from three
+ transforms modulo three different primes to get the
+ final result.
+
+
+
diff --git a/Modules/_decimal/libmpdec/literature/fnt.py b/Modules/_decimal/libmpdec/literature/fnt.py
new file mode 100644
index 0000000..bf93745
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/fnt.py
@@ -0,0 +1,208 @@
+#
+# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+
+######################################################################
+# This file lists and checks some of the constants and limits used #
+# in libmpdec's Number Theoretic Transform. At the end of the file #
+# there is an example function for the plain DFT transform. #
+######################################################################
+
+
+#
+# Number theoretic transforms are done in subfields of F(p). P[i]
+# are the primes, D[i] = P[i] - 1 are highly composite and w[i]
+# are the respective primitive roots of F(p).
+#
+# The strategy is to convolute two coefficients modulo all three
+# primes, then use the Chinese Remainder Theorem on the three
+# result arrays to recover the result in the usual base RADIX
+# form.
+#
+
+# ======================================================================
+# Primitive roots
+# ======================================================================
+
+#
+# Verify primitive roots:
+#
+# For a prime field, r is a primitive root if and only if for all prime
+# factors f of p-1, r**((p-1)/f) =/= 1 (mod p).
+#
+def prod(F, E):
+ """Check that the factorization of P-1 is correct. F is the list of
+ factors of P-1, E lists the number of occurrences of each factor."""
+ x = 1
+ for y, z in zip(F, E):
+ x *= y**z
+ return x
+
+def is_primitive_root(r, p, factors, exponents):
+ """Check if r is a primitive root of F(p)."""
+ if p != prod(factors, exponents) + 1:
+ return False
+ for f in factors:
+ q, control = divmod(p-1, f)
+ if control != 0:
+ return False
+ if pow(r, q, p) == 1:
+ return False
+ return True
+
+
+# =================================================================
+# Constants and limits for the 64-bit version
+# =================================================================
+
+RADIX = 10**19
+
+# Primes P1, P2 and P3:
+P = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1]
+
+# P-1, highly composite. The transform length d is variable and
+# must divide D = P-1. Since all D are divisible by 3 * 2**32,
+# transform lengths can be 2**n or 3 * 2**n (where n <= 32).
+D = [2**32 * 3 * (5 * 17 * 257 * 65537),
+ 2**34 * 3**2 * (7 * 11 * 31 * 151 * 331),
+ 2**40 * 3**2 * (5 * 7 * 13 * 17 * 241)]
+
+# Prime factors of P-1 and their exponents:
+F = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)]
+E = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)]
+
+# Maximum transform length for 2**n. Above that only 3 * 2**31
+# or 3 * 2**32 are possible.
+MPD_MAXTRANSFORM_2N = 2**32
+
+
+# Limits in the terminology of Pollard's paper:
+m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.
+M1 = M2 = RADIX-1 # Maximum value per single word.
+L = m2 * M1 * M2
+P[0] * P[1] * P[2] > 2 * L
+
+
+# Primitive roots of F(P1), F(P2) and F(P3):
+w = [7, 10, 19]
+
+# The primitive roots are correct:
+for i in range(3):
+ if not is_primitive_root(w[i], P[i], F[i], E[i]):
+ print("FAIL")
+
+
+# =================================================================
+# Constants and limits for the 32-bit version
+# =================================================================
+
+RADIX = 10**9
+
+# Primes P1, P2 and P3:
+P = [2113929217, 2013265921, 1811939329]
+
+# P-1, highly composite. All D = P-1 are divisible by 3 * 2**25,
+# allowing for transform lengths up to 3 * 2**25 words.
+D = [2**25 * 3**2 * 7,
+ 2**27 * 3 * 5,
+ 2**26 * 3**3]
+
+# Prime factors of P-1 and their exponents:
+F = [(2,3,7), (2,3,5), (2,3)]
+E = [(25,2,1), (27,1,1), (26,3)]
+
+# Maximum transform length for 2**n. Above that only 3 * 2**24 or
+# 3 * 2**25 are possible.
+MPD_MAXTRANSFORM_2N = 2**25
+
+
+# Limits in the terminology of Pollard's paper:
+m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array.
+M1 = M2 = RADIX-1 # Maximum value per single word.
+L = m2 * M1 * M2
+P[0] * P[1] * P[2] > 2 * L
+
+
+# Primitive roots of F(P1), F(P2) and F(P3):
+w = [5, 31, 13]
+
+# The primitive roots are correct:
+for i in range(3):
+ if not is_primitive_root(w[i], P[i], F[i], E[i]):
+ print("FAIL")
+
+
+# ======================================================================
+# Example transform using a single prime
+# ======================================================================
+
+def ntt(lst, dir):
+ """Perform a transform on the elements of lst. len(lst) must
+ be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT."""
+ p = 2113929217 # prime
+ d = len(lst) # transform length
+ d_prime = pow(d, (p-2), p) # inverse of d
+ xi = (p-1)//d
+ w = 5 # primitive root of F(p)
+ r = pow(w, xi, p) # primitive root of the subfield
+ r_prime = pow(w, (p-1-xi), p) # inverse of r
+ if dir == 1: # forward transform
+ a = lst # input array
+ A = [0] * d # transformed values
+ for i in range(d):
+ s = 0
+ for j in range(d):
+ s += a[j] * pow(r, i*j, p)
+ A[i] = s % p
+ return A
+ elif dir == -1: # backward transform
+ A = lst # input array
+ a = [0] * d # transformed values
+ for j in range(d):
+ s = 0
+ for i in range(d):
+ s += A[i] * pow(r_prime, i*j, p)
+ a[j] = (d_prime * s) % p
+ return a
+
+def ntt_convolute(a, b):
+ """convolute arrays a and b."""
+ assert(len(a) == len(b))
+ x = ntt(a, 1)
+ y = ntt(b, 1)
+ for i in range(len(a)):
+ y[i] = y[i] * x[i]
+ r = ntt(y, -1)
+ return r
+
+
+# Example: Two arrays representing 21 and 81 in little-endian:
+a = [1, 2, 0, 0]
+b = [1, 8, 0, 0]
+
+assert(ntt_convolute(a, b) == [1, 10, 16, 0])
+assert(21 * 81 == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3))
diff --git a/Modules/_decimal/libmpdec/literature/matrix-transform.txt b/Modules/_decimal/libmpdec/literature/matrix-transform.txt
new file mode 100644
index 0000000..ff62198
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/matrix-transform.txt
@@ -0,0 +1,256 @@
+
+
+(* Copyright (c) 2011 Stefan Krah. All rights reserved. *)
+
+
+The Matrix Fourier Transform:
+=============================
+
+In libmpdec, the Matrix Fourier Transform [1] is called four-step transform
+after a variant that appears in [2]. The algorithm requires that the input
+array can be viewed as an R*C matrix.
+
+All operations are done modulo p. For readability, the proofs drop all
+instances of (mod p).
+
+
+Algorithm four-step (forward transform):
+----------------------------------------
+
+ a := input array
+ d := len(a) = R * C
+ p := prime
+ w := primitive root of unity of the prime field
+ r := w**((p-1)/d)
+ A := output array
+
+ 1) Apply a length R FNT to each column.
+
+ 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m).
+
+ 3) Apply a length C FNT to each row.
+
+ 4) Transpose the matrix.
+
+
+Proof (forward transform):
+--------------------------
+
+ The algorithm can be derived starting from the regular definition of
+ the finite-field transform of length d:
+
+ d-1
+ ,----
+ \
+ A[k] = | a[l] * r**(k * l)
+ /
+ `----
+ l = 0
+
+
+ The sum can be rearranged into the sum of the sums of columns:
+
+ C-1 R-1
+ ,---- ,----
+ \ \
+ = | | a[i * C + j] * r**(k * (i * C + j))
+ / /
+ `---- `----
+ j = 0 i = 0
+
+
+ Extracting a constant from the inner sum:
+
+ C-1 R-1
+ ,---- ,----
+ \ \
+ = | r**k*j * | a[i * C + j] * r**(k * i * C)
+ / /
+ `---- `----
+ j = 0 i = 0
+
+
+ Without any loss of generality, let k = n * R + m,
+ where n < C and m < R:
+
+ C-1 R-1
+ ,---- ,----
+ \ \
+ A[n*R+m] = | r**(R*n*j) * r**(m*j) * | a[i*C+j] * r**(R*C*n*i) * r**(C*m*i)
+ / /
+ `---- `----
+ j = 0 i = 0
+
+
+ Since r = w ** ((p-1) / (R*C)):
+
+ a) r**(R*C*n*i) = w**((p-1)*n*i) = 1
+
+ b) r**(C*m*i) = w**((p-1) / R) ** (m*i) = r_R ** (m*i)
+
+ c) r**(R*n*j) = w**((p-1) / C) ** (n*j) = r_C ** (n*j)
+
+ r_R := root of the subfield of length R.
+ r_C := root of the subfield of length C.
+
+
+ C-1 R-1
+ ,---- ,----
+ \ \
+ A[n*R+m] = | r_C**(n*j) * [ r**(m*j) * | a[i*C+j] * r_R**(m*i) ]
+ / ^ /
+ `---- | `---- 1) transform the columns
+ j = 0 | i = 0
+ ^ |
+ | `-- 2) multiply
+ |
+ `-- 3) transform the rows
+
+
+ Note that the entire RHS is a function of n and m and that the results
+ for each pair (n, m) are stored in Fortran order.
+
+ Let the term in square brackets be f(m, j). Step 1) and 2) precalculate
+ the term for all (m, j). After that, the original matrix is now a lookup
+ table with the mth element in the jth column at location m * C + j.
+
+ Let the complete RHS be g(m, n). Step 3) does an in-place transform of
+ length n on all rows. After that, the original matrix is now a lookup
+ table with the mth element in the nth column at location m * C + n.
+
+ But each (m, n) pair should be written to location n * R + m. Therefore,
+ step 4) transposes the result of step 3).
+
+
+
+Algorithm four-step (inverse transform):
+----------------------------------------
+
+ A := input array
+ d := len(A) = R * C
+ p := prime
+ d' := d**(p-2) # inverse of d
+ w := primitive root of unity of the prime field
+ r := w**((p-1)/d) # root of the subfield
+ r' := w**((p-1) - (p-1)/d) # inverse of r
+ a := output array
+
+ 0) View the matrix as a C*R matrix.
+
+ 1) Transpose the matrix, producing an R*C matrix.
+
+ 2) Apply a length C FNT to each row.
+
+ 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n).
+
+ 4) Apply a length R FNT to each column.
+
+
+Proof (inverse transform):
+--------------------------
+
+ The algorithm can be derived starting from the regular definition of
+ the finite-field inverse transform of length d:
+
+ d-1
+ ,----
+ \
+ a[k] = d' * | A[l] * r' ** (k * l)
+ /
+ `----
+ l = 0
+
+
+ The sum can be rearranged into the sum of the sums of columns. Note
+ that at this stage we still have a C*R matrix, so C denotes the number
+ of rows:
+
+ R-1 C-1
+ ,---- ,----
+ \ \
+ = d' * | | a[j * R + i] * r' ** (k * (j * R + i))
+ / /
+ `---- `----
+ i = 0 j = 0
+
+
+ Extracting a constant from the inner sum:
+
+ R-1 C-1
+ ,---- ,----
+ \ \
+ = d' * | r' ** (k*i) * | a[j * R + i] * r' ** (k * j * R)
+ / /
+ `---- `----
+ i = 0 j = 0
+
+
+ Without any loss of generality, let k = m * C + n,
+ where m < R and n < C:
+
+ R-1 C-1
+ ,---- ,----
+ \ \
+ A[m*C+n] = d' * | r' ** (C*m*i) * r' ** (n*i) * | a[j*R+i] * r' ** (R*C*m*j) * r' ** (R*n*j)
+ / /
+ `---- `----
+ i = 0 j = 0
+
+
+ Since r' = w**((p-1) - (p-1)/d) and d = R*C:
+
+ a) r' ** (R*C*m*j) = w**((p-1)*R*C*m*j - (p-1)*m*j) = 1
+
+ b) r' ** (C*m*i) = w**((p-1)*C - (p-1)/R) ** (m*i) = r_R' ** (m*i)
+
+ c) r' ** (R*n*j) = r_C' ** (n*j)
+
+ d) d' = d**(p-2) = (R*C) ** (p-2) = R**(p-2) * C**(p-2) = R' * C'
+
+ r_R' := inverse of the root of the subfield of length R.
+ r_C' := inverse of the root of the subfield of length C.
+ R' := inverse of R
+ C' := inverse of C
+
+
+ R-1 C-1
+ ,---- ,---- 2) transform the rows of a^T
+ \ \
+ A[m*C+n] = R' * | r_R' ** (m*i) * [ r' ** (n*i) * C' * | a[j*R+i] * r_C' ** (n*j) ]
+ / ^ / ^
+ `---- | `---- |
+ i = 0 | j = 0 |
+ ^ | `-- 1) Transpose input matrix
+ | `-- 3) multiply to address elements by
+ | i * C + j
+ `-- 3) transform the columns
+
+
+
+ Note that the entire RHS is a function of m and n and that the results
+ for each pair (m, n) are stored in C order.
+
+ Let the term in square brackets be f(n, i). Without step 1), the sum
+ would perform a length C transform on the columns of the input matrix.
+ This is a) inefficient and b) the results are needed in C order, so
+ step 1) exchanges rows and columns.
+
+ Step 2) and 3) precalculate f(n, i) for all (n, i). After that, the
+ original matrix is now a lookup table with the ith element in the nth
+ column at location i * C + n.
+
+ Let the complete RHS be g(m, n). Step 4) does an in-place transform of
+ length m on all columns. After that, the original matrix is now a lookup
+ table with the mth element in the nth column at location m * C + n,
+ which means that all A[k] = A[m * C + n] are in the correct order.
+
+
+--
+
+ [1] Joerg Arndt: "Matters Computational"
+ http://www.jjj.de/fxt/
+ [2] David H. Bailey: FFTs in External or Hierarchical Memory
+ http://crd.lbl.gov/~dhbailey/dhbpapers/
+
+
+
diff --git a/Modules/_decimal/libmpdec/literature/mulmod-64.txt b/Modules/_decimal/libmpdec/literature/mulmod-64.txt
new file mode 100644
index 0000000..93bf22e
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/mulmod-64.txt
@@ -0,0 +1,127 @@
+
+
+(* Copyright (c) 2011 Stefan Krah. All rights reserved. *)
+
+
+==========================================================================
+ Calculate (a * b) % p using special primes
+==========================================================================
+
+A description of the algorithm can be found in the apfloat manual by
+Tommila [1].
+
+
+Definitions:
+------------
+
+In the whole document, "==" stands for "is congruent with".
+
+Result of a * b in terms of high/low words:
+
+ (1) hi * 2**64 + lo = a * b
+
+Special primes:
+
+ (2) p = 2**64 - z + 1, where z = 2**n
+
+Single step modular reduction:
+
+ (3) R(hi, lo) = hi * z - hi + lo
+
+
+Strategy:
+---------
+
+ a) Set (hi, lo) to the result of a * b.
+
+ b) Set (hi', lo') to the result of R(hi, lo).
+
+ c) Repeat step b) until 0 <= hi' * 2**64 + lo' < 2*p.
+
+ d) If the result is less than p, return lo'. Otherwise return lo' - p.
+
+
+The reduction step b) preserves congruence:
+-------------------------------------------
+
+ hi * 2**64 + lo == hi * z - hi + lo (mod p)
+
+ Proof:
+ ~~~~~~
+
+ hi * 2**64 + lo = (2**64 - z + 1) * hi + z * hi - hi + lo
+
+ = p * hi + z * hi - hi + lo
+
+ == z * hi - hi + lo (mod p)
+
+
+Maximum numbers of step b):
+---------------------------
+
+# To avoid unneccessary formalism, define:
+
+def R(hi, lo, z):
+ return divmod(hi * z - hi + lo, 2**64)
+
+# For simplicity, assume hi=2**64-1, lo=2**64-1 after the
+# initial multiplication a * b. This is of course impossible
+# but certainly covers all cases.
+
+# Then, for p1:
+hi=2**64-1; lo=2**64-1; z=2**32
+p1 = 2**64 - z + 1
+
+hi, lo = R(hi, lo, z) # First reduction
+hi, lo = R(hi, lo, z) # Second reduction
+hi * 2**64 + lo < 2 * p1 # True
+
+# For p2:
+hi=2**64-1; lo=2**64-1; z=2**34
+p2 = 2**64 - z + 1
+
+hi, lo = R(hi, lo, z) # First reduction
+hi, lo = R(hi, lo, z) # Second reduction
+hi, lo = R(hi, lo, z) # Third reduction
+hi * 2**64 + lo < 2 * p2 # True
+
+# For p3:
+hi=2**64-1; lo=2**64-1; z=2**40
+p3 = 2**64 - z + 1
+
+hi, lo = R(hi, lo, z) # First reduction
+hi, lo = R(hi, lo, z) # Second reduction
+hi, lo = R(hi, lo, z) # Third reduction
+hi * 2**64 + lo < 2 * p3 # True
+
+
+Step d) preserves congruence and yields a result < p:
+-----------------------------------------------------
+
+ Case hi = 0:
+
+ Case lo < p: trivial.
+
+ Case lo >= p:
+
+ lo == lo - p (mod p) # result is congruent
+
+ p <= lo < 2*p -> 0 <= lo - p < p # result is in the correct range
+
+ Case hi = 1:
+
+ p < 2**64 /\ 2**64 + lo < 2*p -> lo < p # lo is always less than p
+
+ 2**64 + lo == 2**64 + (lo - p) (mod p) # result is congruent
+
+ = lo - p # exactly the same value as the previous RHS
+ # in uint64_t arithmetic.
+
+ p < 2**64 + lo < 2*p -> 0 < 2**64 + (lo - p) < p # correct range
+
+
+
+[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf
+
+
+
diff --git a/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt
new file mode 100644
index 0000000..43e6e4e
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt
@@ -0,0 +1,269 @@
+
+
+(* Copyright (c) 2011 Stefan Krah. All rights reserved. *)
+
+
+========================================================================
+ Calculate (a * b) % p using the 80-bit x87 FPU
+========================================================================
+
+A description of the algorithm can be found in the apfloat manual by
+Tommila [1].
+
+The proof follows an argument made by Granlund/Montgomery in [2].
+
+
+Definitions and assumptions:
+----------------------------
+
+The 80-bit extended precision format uses 64 bits for the significand:
+
+ (1) F = 64
+
+The modulus is prime and less than 2**31:
+
+ (2) 2 <= p < 2**31
+
+The factors are less than p:
+
+ (3) 0 <= a < p
+ (4) 0 <= b < p
+
+The product a * b is less than 2**62 and is thus exact in 64 bits:
+
+ (5) n = a * b
+
+The product can be represented in terms of quotient and remainder:
+
+ (6) n = q * p + r
+
+Using (3), (4) and the fact that p is prime, the remainder is always
+greater than zero:
+
+ (7) 0 <= q < p /\ 1 <= r < p
+
+
+Strategy:
+---------
+
+Precalculate the 80-bit long double inverse of p, with a maximum
+relative error of 2**(1-F):
+
+ (8) pinv = (long double)1.0 / p
+
+Calculate an estimate for q = floor(n/p). The multiplication has another
+maximum relative error of 2**(1-F):
+
+ (9) qest = n * pinv
+
+If we can show that q < qest < q+1, then trunc(qest) = q. It is then
+easy to recover the remainder r. The complete algorithm is:
+
+ a) Set the control word to 64-bit precision and truncation mode.
+
+ b) n = a * b # Calculate exact product.
+
+ c) qest = n * pinv # Calculate estimate for the quotient.
+
+ d) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient.
+
+ f) r = n - q * p # Calculate remainder.
+
+
+Proof for q < qest < q+1:
+-------------------------
+
+Using the cumulative error, the error bounds for qest are:
+
+ n n * (1 + 2**(1-F))**2
+ (9) --------------------- <= qest <= ---------------------
+ p * (1 + 2**(1-F))**2 p
+
+
+ Lemma 1:
+ --------
+ n q * p + r
+ (10) q < --------------------- = ---------------------
+ p * (1 + 2**(1-F))**2 p * (1 + 2**(1-F))**2
+
+
+ Proof:
+ ~~~~~~
+
+ (I) q * p * (1 + 2**(1-F))**2 < q * p + r
+
+ (II) q * p * 2**(2-F) + q * p * 2**(2-2*F) < r
+
+ Using (1) and (7), it is sufficient to show that:
+
+ (III) q * p * 2**(-62) + q * p * 2**(-126) < 1 <= r
+
+ (III) can easily be verified by substituting the largest possible
+ values p = 2**31-1 and q = 2**31-2.
+
+ The critical cases occur when r = 1, n = m * p + 1. These cases
+ can be exhaustively verified with a test program.
+
+
+ Lemma 2:
+ --------
+
+ n * (1 + 2**(1-F))**2 (q * p + r) * (1 + 2**(1-F))**2
+ (11) --------------------- = ------------------------------- < q + 1
+ p p
+
+ Proof:
+ ~~~~~~
+
+ (I) (q * p + r) + (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < q * p + p
+
+ (II) (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < p - r
+
+ Using (1) and (7), it is sufficient to show that:
+
+ (III) (q * p + r) * 2**(-62) + (q * p + r) * 2**(-126) < 1 <= p - r
+
+ (III) can easily be verified by substituting the largest possible
+ values p = 2**31-1, q = 2**31-2 and r = 2**31-2.
+
+ The critical cases occur when r = (p - 1), n = m * p - 1. These cases
+ can be exhaustively verified with a test program.
+
+
+[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf
+[2] http://gmplib.org/~tege/divcnst-pldi94.pdf
+ [Section 7: "Use of floating point"]
+
+
+
+(* Coq proof for (10) and (11) *)
+
+Require Import ZArith.
+Require Import QArith.
+Require Import Qpower.
+Require Import Qabs.
+Require Import Psatz.
+
+Open Scope Q_scope.
+
+
+Ltac qreduce T :=
+ rewrite <- (Qred_correct (T)); simpl (Qred (T)).
+
+Theorem Qlt_move_right :
+ forall x y z:Q, x + z < y <-> x < y - z.
+Proof.
+ intros.
+ split.
+ intros.
+ psatzl Q.
+ intros.
+ psatzl Q.
+Qed.
+
+Theorem Qlt_mult_by_z :
+ forall x y z:Q, 0 < z -> (x < y <-> x * z < y * z).
+Proof.
+ intros.
+ split.
+ intros.
+ apply Qmult_lt_compat_r. trivial. trivial.
+ intros.
+ rewrite <- (Qdiv_mult_l x z). rewrite <- (Qdiv_mult_l y z).
+ apply Qmult_lt_compat_r.
+ apply Qlt_shift_inv_l.
+ trivial. psatzl Q. trivial. psatzl Q. psatzl Q.
+Qed.
+
+Theorem Qle_mult_quad :
+ forall (a b c d:Q),
+ 0 <= a -> a <= c ->
+ 0 <= b -> b <= d ->
+ a * b <= c * d.
+ intros.
+ psatz Q.
+Qed.
+
+
+Theorem q_lt_qest:
+ forall (p q r:Q),
+ (0 < p) -> (p <= (2#1)^31 - 1) ->
+ (0 <= q) -> (q <= p - 1) ->
+ (1 <= r) -> (r <= p - 1) ->
+ q < (q * p + r) / (p * (1 + (2#1)^(-63))^2).
+Proof.
+ intros.
+ rewrite Qlt_mult_by_z with (z := (p * (1 + (2#1)^(-63))^2)).
+
+ unfold Qdiv.
+ rewrite <- Qmult_assoc.
+ rewrite (Qmult_comm (/ (p * (1 + (2 # 1) ^ (-63)) ^ 2)) (p * (1 + (2 # 1) ^ (-63)) ^ 2)).
+ rewrite Qmult_inv_r.
+ rewrite Qmult_1_r.
+
+ assert (q * (p * (1 + (2 # 1) ^ (-63)) ^ 2) == q * p + (q * p) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))).
+ qreduce ((1 + (2 # 1) ^ (-63)) ^ 2).
+ qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)).
+ ring_simplify.
+ reflexivity.
+ rewrite H5.
+
+ rewrite Qplus_comm.
+ rewrite Qlt_move_right.
+ ring_simplify (q * p + r - q * p).
+ qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)).
+
+ apply Qlt_le_trans with (y := 1).
+ rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617).
+ ring_simplify.
+
+ apply Qle_lt_trans with (y := ((2 # 1) ^ 31 - (2#1)) * ((2 # 1) ^ 31 - 1)).
+ apply Qle_mult_quad.
+ assumption. psatzl Q. psatzl Q. psatzl Q. psatzl Q. psatzl Q. assumption. psatzl Q. psatzl Q.
+Qed.
+
+Theorem qest_lt_qplus1:
+ forall (p q r:Q),
+ (0 < p) -> (p <= (2#1)^31 - 1) ->
+ (0 <= q) -> (q <= p - 1) ->
+ (1 <= r) -> (r <= p - 1) ->
+ ((q * p + r) * (1 + (2#1)^(-63))^2) / p < q + 1.
+Proof.
+ intros.
+ rewrite Qlt_mult_by_z with (z := p).
+
+ unfold Qdiv.
+ rewrite <- Qmult_assoc.
+ rewrite (Qmult_comm (/ p) p).
+ rewrite Qmult_inv_r.
+ rewrite Qmult_1_r.
+
+ assert ((q * p + r) * (1 + (2 # 1) ^ (-63)) ^ 2 == q * p + r + (q * p + r) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))).
+ qreduce ((1 + (2 # 1) ^ (-63)) ^ 2).
+ qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)).
+ ring_simplify. reflexivity.
+ rewrite H5.
+
+ rewrite <- Qplus_assoc. rewrite <- Qplus_comm. rewrite Qlt_move_right.
+ ring_simplify ((q + 1) * p - q * p).
+
+ rewrite <- Qplus_comm. rewrite Qlt_move_right.
+
+ apply Qlt_le_trans with (y := 1).
+ qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)).
+
+ rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617).
+ ring_simplify.
+
+ ring_simplify in H0.
+ apply Qle_lt_trans with (y := (2147483646 # 1) * (2147483647 # 1) + (2147483646 # 1)).
+
+ apply Qplus_le_compat.
+ apply Qle_mult_quad.
+ assumption. psatzl Q. auto with qarith. assumption. psatzl Q.
+ auto with qarith. auto with qarith.
+ psatzl Q. psatzl Q. assumption.
+Qed.
+
+
+
diff --git a/Modules/_decimal/libmpdec/literature/six-step.txt b/Modules/_decimal/libmpdec/literature/six-step.txt
new file mode 100644
index 0000000..759147f
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/six-step.txt
@@ -0,0 +1,63 @@
+
+
+(* Copyright (c) 2011 Stefan Krah. All rights reserved. *)
+
+
+The Six Step Transform:
+=======================
+
+In libmpdec, the six-step transform is the Matrix Fourier Transform (See
+matrix-transform.txt) in disguise. It is called six-step transform after
+a variant that appears in [1]. The algorithm requires that the input
+array can be viewed as an R*C matrix.
+
+
+Algorithm six-step (forward transform):
+---------------------------------------
+
+ 1a) Transpose the matrix.
+
+ 1b) Apply a length R FNT to each row.
+
+ 1c) Transpose the matrix.
+
+ 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m).
+
+ 3) Apply a length C FNT to each row.
+
+ 4) Transpose the matrix.
+
+Note that steps 1a) - 1c) are exactly equivalent to step 1) of the Matrix
+Fourier Transform. For large R, it is faster to transpose twice and do
+a transform on the rows than to perform a column transpose directly.
+
+
+
+Algorithm six-step (inverse transform):
+---------------------------------------
+
+ 0) View the matrix as a C*R matrix.
+
+ 1) Transpose the matrix, producing an R*C matrix.
+
+ 2) Apply a length C FNT to each row.
+
+ 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n).
+
+ 4a) Transpose the matrix.
+
+ 4b) Apply a length R FNT to each row.
+
+ 4c) Transpose the matrix.
+
+Again, steps 4a) - 4c) are equivalent to step 4) of the Matrix Fourier
+Transform.
+
+
+
+--
+
+ [1] David H. Bailey: FFTs in External or Hierarchical Memory
+ http://crd.lbl.gov/~dhbailey/dhbpapers/
+
+
diff --git a/Modules/_decimal/libmpdec/literature/umodarith.lisp b/Modules/_decimal/libmpdec/literature/umodarith.lisp
new file mode 100644
index 0000000..60a14a4
--- /dev/null
+++ b/Modules/_decimal/libmpdec/literature/umodarith.lisp
@@ -0,0 +1,692 @@
+;
+; Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; 1. Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+; SUCH DAMAGE.
+;
+
+
+(in-package "ACL2")
+
+(include-book "arithmetic/top-with-meta" :dir :system)
+(include-book "arithmetic-2/floor-mod/floor-mod" :dir :system)
+
+
+;; =====================================================================
+;; Proofs for several functions in umodarith.h
+;; =====================================================================
+
+
+
+;; =====================================================================
+;; Helper theorems
+;; =====================================================================
+
+(defthm elim-mod-m<x<2*m
+ (implies (and (<= m x)
+ (< x (* 2 m))
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ (+ x (- m)))))
+
+(defthm modaux-1a
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod (- x) m)
+ (+ (- x) m))))
+
+(defthm modaux-1b
+ (implies (and (< (- x) m) (< x 0) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ (+ x m)))
+ :hints (("Goal" :use ((:instance modaux-1a
+ (x (- x)))))))
+
+(defthm modaux-1c
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (rationalp x) (rationalp m))
+ (equal (mod x m)
+ x)))
+
+(defthm modaux-2a
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (< (mod (+ b x) m) b))
+ (equal (mod (+ (- m) b x) m)
+ (+ (- m) b (mod x m)))))
+
+(defthm modaux-2b
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (< (mod (+ b x) m) b))
+ (equal (mod (+ b x) m)
+ (+ (- m) b (mod x m))))
+ :hints (("Goal" :use (modaux-2a))))
+
+(defthm linear-mod-1
+ (implies (and (< x m) (< b m)
+ (natp x) (natp b)
+ (rationalp m))
+ (equal (< x (mod (+ (- b) x) m))
+ (< x b)))
+ :hints (("Goal" :use ((:instance modaux-1a
+ (x (+ b (- x))))))))
+
+(defthm linear-mod-2
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b)
+ (natp m))
+ (equal (< (mod x m)
+ (mod (+ (- b) x) m))
+ (< (mod x m) b))))
+
+(defthm linear-mod-3
+ (implies (and (< x m) (< b m)
+ (natp x) (natp b)
+ (rationalp m))
+ (equal (<= b (mod (+ b x) m))
+ (< (+ b x) m)))
+ :hints (("Goal" :use ((:instance elim-mod-m<x<2*m
+ (x (+ b x)))))))
+
+(defthm modaux-2c
+ (implies (and (< 0 b) (< b m)
+ (natp x) (natp b) (natp m)
+ (<= b (mod (+ b x) m)))
+ (equal (mod (+ b x) m)
+ (+ b (mod x m))))
+ :hints (("Subgoal *1/8''" :use (linear-mod-3))))
+
+(defthmd modaux-2d
+ (implies (and (< x m) (< 0 x) (< 0 m)
+ (< (- m) b) (< b 0) (rationalp m)
+ (<= x (mod (+ b x) m))
+ (rationalp x) (rationalp b))
+ (equal (+ (- m) (mod (+ b x) m))
+ (+ b x)))
+ :hints (("Goal" :cases ((<= 0 (+ b x))))
+ ("Subgoal 2'" :use ((:instance modaux-1b
+ (x (+ b x)))))))
+
+(defthm mod-m-b
+ (implies (and (< 0 x) (< 0 b) (< 0 m)
+ (< x b) (< b m)
+ (natp x) (natp b) (natp m))
+ (equal (mod (+ (mod (- x) m) b) m)
+ (mod (- x) b))))
+
+
+;; =====================================================================
+;; addmod, submod
+;; =====================================================================
+
+(defun addmod (a b m base)
+ (let* ((s (mod (+ a b) base))
+ (s (if (< s a) (mod (- s m) base) s))
+ (s (if (>= s m) (mod (- s m) base) s)))
+ s))
+
+(defthmd addmod-correct
+ (implies (and (< 0 m) (< m base)
+ (< a m) (<= b m)
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (addmod a b m base)
+ (mod (+ a b) m)))
+ :hints (("Goal" :cases ((<= base (+ a b))))
+ ("Subgoal 2.1'" :use ((:instance elim-mod-m<x<2*m
+ (x (+ a b)))))))
+
+(defun submod (a b m base)
+ (let* ((d (mod (- a b) base))
+ (d (if (< a d) (mod (+ d m) base) d)))
+ d))
+
+(defthmd submod-aux1
+ (implies (and (< a (mod (+ a (- b)) base))
+ (< 0 base) (< a base) (<= b base)
+ (natp base) (natp a) (natp b))
+ (< a b))
+ :rule-classes :forward-chaining)
+
+(defthmd submod-aux2
+ (implies (and (<= (mod (+ a (- b)) base) a)
+ (< 0 base) (< a base) (< b base)
+ (natp base) (natp a) (natp b))
+ (<= b a))
+ :rule-classes :forward-chaining)
+
+(defthmd submod-correct
+ (implies (and (< 0 m) (< m base)
+ (< a m) (<= b m)
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (submod a b m base)
+ (mod (- a b) m)))
+ :hints (("Goal" :cases ((<= base (+ a b))))
+ ("Subgoal 2.2" :use ((:instance submod-aux1)))
+ ("Subgoal 2.2'''" :cases ((and (< 0 (+ a (- b) m))
+ (< (+ a (- b) m) m))))
+ ("Subgoal 2.1" :use ((:instance submod-aux2)))
+ ("Subgoal 1.2" :use ((:instance submod-aux1)))
+ ("Subgoal 1.1" :use ((:instance submod-aux2)))))
+
+
+(defun submod-2 (a b m base)
+ (let* ((d (mod (- a b) base))
+ (d (if (< a b) (mod (+ d m) base) d)))
+ d))
+
+(defthm submod-2-correct
+ (implies (and (< 0 m) (< m base)
+ (< a m) (<= b m)
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (submod-2 a b m base)
+ (mod (- a b) m)))
+ :hints (("Subgoal 2'" :cases ((and (< 0 (+ a (- b) m))
+ (< (+ a (- b) m) m))))))
+
+
+;; =========================================================================
+;; ext-submod is correct
+;; =========================================================================
+
+; a < 2*m, b < 2*m
+(defun ext-submod (a b m base)
+ (let* ((a (if (>= a m) (- a m) a))
+ (b (if (>= b m) (- b m) b))
+ (d (mod (- a b) base))
+ (d (if (< a b) (mod (+ d m) base) d)))
+ d))
+
+; a < 2*m, b < 2*m
+(defun ext-submod-2 (a b m base)
+ (let* ((a (mod a m))
+ (b (mod b m))
+ (d (mod (- a b) base))
+ (d (if (< a b) (mod (+ d m) base) d)))
+ d))
+
+(defthmd ext-submod-ext-submod-2-equal
+ (implies (and (< 0 m) (< m base)
+ (< a (* 2 m)) (< b (* 2 m))
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (ext-submod a b m base)
+ (ext-submod-2 a b m base))))
+
+(defthmd ext-submod-2-correct
+ (implies (and (< 0 m) (< m base)
+ (< a (* 2 m)) (< b (* 2 m))
+ (natp m) (natp base)
+ (natp a) (natp b))
+ (equal (ext-submod-2 a b m base)
+ (mod (- a b) m))))
+
+
+;; =========================================================================
+;; dw-reduce is correct
+;; =========================================================================
+
+(defun dw-reduce (hi lo m base)
+ (let* ((r1 (mod hi m))
+ (r2 (mod (+ (* r1 base) lo) m)))
+ r2))
+
+(defthmd dw-reduce-correct
+ (implies (and (< 0 m) (< m base)
+ (< hi base) (< lo base)
+ (natp m) (natp base)
+ (natp hi) (natp lo))
+ (equal (dw-reduce hi lo m base)
+ (mod (+ (* hi base) lo) m))))
+
+(defthmd <=-multiply-both-sides-by-z
+ (implies (and (rationalp x) (rationalp y)
+ (< 0 z) (rationalp z))
+ (equal (<= x y)
+ (<= (* z x) (* z y)))))
+
+(defthmd dw-reduce-aux1
+ (implies (and (< 0 m) (< m base)
+ (natp m) (natp base)
+ (< lo base) (natp lo)
+ (< x m) (natp x))
+ (< (+ lo (* base x)) (* base m)))
+ :hints (("Goal" :cases ((<= (+ x 1) m)))
+ ("Subgoal 1''" :cases ((<= (* base (+ x 1)) (* base m))))
+ ("subgoal 1.2" :use ((:instance <=-multiply-both-sides-by-z
+ (x (+ 1 x))
+ (y m)
+ (z base))))))
+
+(defthm dw-reduce-aux2
+ (implies (and (< x (* base m))
+ (< 0 m) (< m base)
+ (natp m) (natp base) (natp x))
+ (< (floor x m) base)))
+
+;; This is the necessary condition for using _mpd_div_words().
+(defthmd dw-reduce-second-quotient-fits-in-single-word
+ (implies (and (< 0 m) (< m base)
+ (< hi base) (< lo base)
+ (natp m) (natp base)
+ (natp hi) (natp lo)
+ (equal r1 (mod hi m)))
+ (< (floor (+ (* r1 base) lo) m)
+ base))
+ :hints (("Goal" :cases ((< r1 m)))
+ ("Subgoal 1''" :cases ((< (+ lo (* base (mod hi m))) (* base m))))
+ ("Subgoal 1.2" :use ((:instance dw-reduce-aux1
+ (x (mod hi m)))))))
+
+
+;; =========================================================================
+;; dw-submod is correct
+;; =========================================================================
+
+(defun dw-submod (a hi lo m base)
+ (let* ((r (dw-reduce hi lo m base))
+ (d (mod (- a r) base))
+ (d (if (< a r) (mod (+ d m) base) d)))
+ d))
+
+(defthmd dw-submod-aux1
+ (implies (and (natp a) (< 0 m) (natp m)
+ (natp x) (equal r (mod x m)))
+ (equal (mod (- a x) m)
+ (mod (- a r) m))))
+
+(defthmd dw-submod-correct
+ (implies (and (< 0 m) (< m base)
+ (natp a) (< a m)
+ (< hi base) (< lo base)
+ (natp m) (natp base)
+ (natp hi) (natp lo))
+ (equal (dw-submod a hi lo m base)
+ (mod (- a (+ (* base hi) lo)) m)))
+ :hints (("Goal" :in-theory (disable dw-reduce)
+ :use ((:instance dw-submod-aux1
+ (x (+ lo (* base hi)))
+ (r (dw-reduce hi lo m base)))
+ (:instance dw-reduce-correct)))))
+
+
+;; =========================================================================
+;; ANSI C arithmetic for uint64_t
+;; =========================================================================
+
+(defun add (a b)
+ (mod (+ a b)
+ (expt 2 64)))
+
+(defun sub (a b)
+ (mod (- a b)
+ (expt 2 64)))
+
+(defun << (w n)
+ (mod (* w (expt 2 n))
+ (expt 2 64)))
+
+(defun >> (w n)
+ (floor w (expt 2 n)))
+
+;; join upper and lower half of a double word, yielding a 128 bit number
+(defun join (hi lo)
+ (+ (* (expt 2 64) hi) lo))
+
+
+;; =============================================================================
+;; Fast modular reduction
+;; =============================================================================
+
+;; These are the three primes used in the Number Theoretic Transform.
+;; A fast modular reduction scheme exists for all of them.
+(defmacro p1 ()
+ (+ (expt 2 64) (- (expt 2 32)) 1))
+
+(defmacro p2 ()
+ (+ (expt 2 64) (- (expt 2 34)) 1))
+
+(defmacro p3 ()
+ (+ (expt 2 64) (- (expt 2 40)) 1))
+
+
+;; reduce the double word number hi*2**64 + lo (mod p1)
+(defun simple-mod-reduce-p1 (hi lo)
+ (+ (* (expt 2 32) hi) (- hi) lo))
+
+;; reduce the double word number hi*2**64 + lo (mod p2)
+(defun simple-mod-reduce-p2 (hi lo)
+ (+ (* (expt 2 34) hi) (- hi) lo))
+
+;; reduce the double word number hi*2**64 + lo (mod p3)
+(defun simple-mod-reduce-p3 (hi lo)
+ (+ (* (expt 2 40) hi) (- hi) lo))
+
+
+; ----------------------------------------------------------
+; The modular reductions given above are correct
+; ----------------------------------------------------------
+
+(defthmd congruence-p1-aux
+ (equal (* (expt 2 64) hi)
+ (+ (* (p1) hi)
+ (* (expt 2 32) hi)
+ (- hi))))
+
+(defthmd congruence-p2-aux
+ (equal (* (expt 2 64) hi)
+ (+ (* (p2) hi)
+ (* (expt 2 34) hi)
+ (- hi))))
+
+(defthmd congruence-p3-aux
+ (equal (* (expt 2 64) hi)
+ (+ (* (p3) hi)
+ (* (expt 2 40) hi)
+ (- hi))))
+
+(defthmd mod-augment
+ (implies (and (rationalp x)
+ (rationalp y)
+ (rationalp m))
+ (equal (mod (+ x y) m)
+ (mod (+ x (mod y m)) m))))
+
+(defthmd simple-mod-reduce-p1-congruent
+ (implies (and (integerp hi)
+ (integerp lo))
+ (equal (mod (simple-mod-reduce-p1 hi lo) (p1))
+ (mod (join hi lo) (p1))))
+ :hints (("Goal''" :use ((:instance congruence-p1-aux)
+ (:instance mod-augment
+ (m (p1))
+ (x (+ (- hi) lo (* (expt 2 32) hi)))
+ (y (* (p1) hi)))))))
+
+(defthmd simple-mod-reduce-p2-congruent
+ (implies (and (integerp hi)
+ (integerp lo))
+ (equal (mod (simple-mod-reduce-p2 hi lo) (p2))
+ (mod (join hi lo) (p2))))
+ :hints (("Goal''" :use ((:instance congruence-p2-aux)
+ (:instance mod-augment
+ (m (p2))
+ (x (+ (- hi) lo (* (expt 2 34) hi)))
+ (y (* (p2) hi)))))))
+
+(defthmd simple-mod-reduce-p3-congruent
+ (implies (and (integerp hi)
+ (integerp lo))
+ (equal (mod (simple-mod-reduce-p3 hi lo) (p3))
+ (mod (join hi lo) (p3))))
+ :hints (("Goal''" :use ((:instance congruence-p3-aux)
+ (:instance mod-augment
+ (m (p3))
+ (x (+ (- hi) lo (* (expt 2 40) hi)))
+ (y (* (p3) hi)))))))
+
+
+; ---------------------------------------------------------------------
+; We need a number less than 2*p, so that we can use the trick from
+; elim-mod-m<x<2*m for the final reduction.
+; For p1, two modular reductions are sufficient, for p2 and p3 three.
+; ---------------------------------------------------------------------
+
+;; p1: the first reduction is less than 2**96
+(defthmd simple-mod-reduce-p1-<-2**96
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p1 hi lo)
+ (expt 2 96))))
+
+;; p1: the second reduction is less than 2*p1
+(defthmd simple-mod-reduce-p1-<-2*p1
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 96))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p1 hi lo)
+ (* 2 (p1)))))
+
+
+;; p2: the first reduction is less than 2**98
+(defthmd simple-mod-reduce-p2-<-2**98
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (expt 2 98))))
+
+;; p2: the second reduction is less than 2**69
+(defthmd simple-mod-reduce-p2-<-2*69
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 98))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (expt 2 69))))
+
+;; p3: the third reduction is less than 2*p2
+(defthmd simple-mod-reduce-p2-<-2*p2
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 69))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p2 hi lo)
+ (* 2 (p2)))))
+
+
+;; p3: the first reduction is less than 2**104
+(defthmd simple-mod-reduce-p3-<-2**104
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (expt 2 104))))
+
+;; p3: the second reduction is less than 2**81
+(defthmd simple-mod-reduce-p3-<-2**81
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 104))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (expt 2 81))))
+
+;; p3: the third reduction is less than 2*p3
+(defthmd simple-mod-reduce-p3-<-2*p3
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (< (join hi lo) (expt 2 81))
+ (natp hi) (natp lo))
+ (< (simple-mod-reduce-p3 hi lo)
+ (* 2 (p3)))))
+
+
+; -------------------------------------------------------------------------
+; The simple modular reductions, adapted for compiler friendly C
+; -------------------------------------------------------------------------
+
+(defun mod-reduce-p1 (hi lo)
+ (let* ((y hi)
+ (x y)
+ (hi (>> hi 32))
+ (x (sub lo x))
+ (hi (if (> x lo) (+ hi -1) hi))
+ (y (<< y 32))
+ (lo (add y x))
+ (hi (if (< lo y) (+ hi 1) hi)))
+ (+ (* hi (expt 2 64)) lo)))
+
+(defun mod-reduce-p2 (hi lo)
+ (let* ((y hi)
+ (x y)
+ (hi (>> hi 30))
+ (x (sub lo x))
+ (hi (if (> x lo) (+ hi -1) hi))
+ (y (<< y 34))
+ (lo (add y x))
+ (hi (if (< lo y) (+ hi 1) hi)))
+ (+ (* hi (expt 2 64)) lo)))
+
+(defun mod-reduce-p3 (hi lo)
+ (let* ((y hi)
+ (x y)
+ (hi (>> hi 24))
+ (x (sub lo x))
+ (hi (if (> x lo) (+ hi -1) hi))
+ (y (<< y 40))
+ (lo (add y x))
+ (hi (if (< lo y) (+ hi 1) hi)))
+ (+ (* hi (expt 2 64)) lo)))
+
+
+; -------------------------------------------------------------------------
+; The compiler friendly versions are equal to the simple versions
+; -------------------------------------------------------------------------
+
+(defthm mod-reduce-aux1
+ (implies (and (<= 0 a) (natp a) (natp m)
+ (< (- m) b) (<= b 0)
+ (integerp b)
+ (< (mod (+ b a) m)
+ (mod a m)))
+ (equal (mod (+ b a) m)
+ (+ b (mod a m))))
+ :hints (("Subgoal 2" :use ((:instance modaux-1b
+ (x (+ a b)))))))
+
+(defthm mod-reduce-aux2
+ (implies (and (<= 0 a) (natp a) (natp m)
+ (< b m) (natp b)
+ (< (mod (+ b a) m)
+ (mod a m)))
+ (equal (+ m (mod (+ b a) m))
+ (+ b (mod a m)))))
+
+
+(defthm mod-reduce-aux3
+ (implies (and (< 0 a) (natp a) (natp m)
+ (< (- m) b) (< b 0)
+ (integerp b)
+ (<= (mod a m)
+ (mod (+ b a) m)))
+ (equal (+ (- m) (mod (+ b a) m))
+ (+ b (mod a m))))
+ :hints (("Subgoal 1.2'" :use ((:instance modaux-1b
+ (x b))))
+ ("Subgoal 1''" :use ((:instance modaux-2d
+ (x I))))))
+
+
+(defthm mod-reduce-aux4
+ (implies (and (< 0 a) (natp a) (natp m)
+ (< b m) (natp b)
+ (<= (mod a m)
+ (mod (+ b a) m)))
+ (equal (mod (+ b a) m)
+ (+ b (mod a m)))))
+
+
+(defthm mod-reduce-p1==simple-mod-reduce-p1
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (equal (mod-reduce-p1 hi lo)
+ (simple-mod-reduce-p1 hi lo)))
+ :hints (("Goal" :in-theory (disable expt)
+ :cases ((< 0 hi)))
+ ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 32) hi)))))
+ ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 32) hi)))))
+ ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 32) hi)))))
+ ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 32) hi)))))))
+
+
+(defthm mod-reduce-p2==simple-mod-reduce-p2
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (equal (mod-reduce-p2 hi lo)
+ (simple-mod-reduce-p2 hi lo)))
+ :hints (("Goal" :cases ((< 0 hi)))
+ ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 34) hi)))))
+ ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 34) hi)))))
+ ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 34) hi)))))
+ ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 34) hi)))))))
+
+
+(defthm mod-reduce-p3==simple-mod-reduce-p3
+ (implies (and (< hi (expt 2 64))
+ (< lo (expt 2 64))
+ (natp hi) (natp lo))
+ (equal (mod-reduce-p3 hi lo)
+ (simple-mod-reduce-p3 hi lo)))
+ :hints (("Goal" :cases ((< 0 hi)))
+ ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 40) hi)))))
+ ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 40) hi)))))
+ ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 40) hi)))))
+ ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4
+ (m (expt 2 64))
+ (b (+ (- HI) LO))
+ (a (* (expt 2 40) hi)))))))
+
+
+
diff --git a/Modules/_decimal/libmpdec/memory.c b/Modules/_decimal/libmpdec/memory.c
new file mode 100644
index 0000000..037ba35
--- /dev/null
+++ b/Modules/_decimal/libmpdec/memory.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "typearith.h"
+#include "memory.h"
+
+
+/* Guaranteed minimum allocation for a coefficient. May be changed once
+ at program start using mpd_setminalloc(). */
+mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN;
+
+/* Custom allocation and free functions */
+void *(* mpd_mallocfunc)(size_t size) = malloc;
+void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc;
+void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc;
+void (* mpd_free)(void *ptr) = free;
+
+
+/* emulate calloc if it is not available */
+void *
+mpd_callocfunc_em(size_t nmemb, size_t size)
+{
+ void *ptr;
+ size_t req;
+ mpd_size_t overflow;
+
+#if MPD_SIZE_MAX < SIZE_MAX
+ /* full_coverage test only */
+ if (nmemb > MPD_SIZE_MAX || size > MPD_SIZE_MAX) {
+ return NULL;
+ }
+#endif
+
+ req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size,
+ &overflow);
+ if (overflow) {
+ return NULL;
+ }
+
+ ptr = mpd_mallocfunc(req);
+ if (ptr == NULL) {
+ return NULL;
+ }
+ /* used on uint32_t or uint64_t */
+ memset(ptr, 0, req);
+
+ return ptr;
+}
+
+
+/* malloc with overflow checking */
+void *
+mpd_alloc(mpd_size_t nmemb, mpd_size_t size)
+{
+ mpd_size_t req, overflow;
+
+ req = mul_size_t_overflow(nmemb, size, &overflow);
+ if (overflow) {
+ return NULL;
+ }
+
+ return mpd_mallocfunc(req);
+}
+
+/* calloc with overflow checking */
+void *
+mpd_calloc(mpd_size_t nmemb, mpd_size_t size)
+{
+ mpd_size_t overflow;
+
+ (void)mul_size_t_overflow(nmemb, size, &overflow);
+ if (overflow) {
+ return NULL;
+ }
+
+ return mpd_callocfunc(nmemb, size);
+}
+
+/* realloc with overflow checking */
+void *
+mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err)
+{
+ void *new;
+ mpd_size_t req, overflow;
+
+ req = mul_size_t_overflow(nmemb, size, &overflow);
+ if (overflow) {
+ *err = 1;
+ return ptr;
+ }
+
+ new = mpd_reallocfunc(ptr, req);
+ if (new == NULL) {
+ *err = 1;
+ return ptr;
+ }
+
+ return new;
+}
+
+/* struct hack malloc with overflow checking */
+void *
+mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size)
+{
+ mpd_size_t req, overflow;
+
+ req = mul_size_t_overflow(nmemb, size, &overflow);
+ if (overflow) {
+ return NULL;
+ }
+
+ req = add_size_t_overflow(req, struct_size, &overflow);
+ if (overflow) {
+ return NULL;
+ }
+
+ return mpd_mallocfunc(req);
+}
+
+
+/* Allocate a new decimal with a coefficient of length 'nwords'. In case
+ of an error the return value is NULL. */
+mpd_t *
+mpd_qnew_size(mpd_ssize_t nwords)
+{
+ mpd_t *result;
+
+ nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords;
+
+ result = mpd_alloc(1, sizeof *result);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->data = mpd_alloc(nwords, sizeof *result->data);
+ if (result->data == NULL) {
+ mpd_free(result);
+ return NULL;
+ }
+
+ result->flags = 0;
+ result->exp = 0;
+ result->digits = 0;
+ result->len = 0;
+ result->alloc = nwords;
+
+ return result;
+}
+
+/* Allocate a new decimal with a coefficient of length MPD_MINALLOC.
+ In case of an error the return value is NULL. */
+mpd_t *
+mpd_qnew(void)
+{
+ return mpd_qnew_size(MPD_MINALLOC);
+}
+
+/* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error.
+ Raises on error. */
+mpd_t *
+mpd_new(mpd_context_t *ctx)
+{
+ mpd_t *result;
+
+ result = mpd_qnew();
+ if (result == NULL) {
+ mpd_addstatus_raise(ctx, MPD_Malloc_error);
+ }
+ return result;
+}
+
+/*
+ * Input: 'result' is a static mpd_t with a static coefficient.
+ * Assumption: 'nwords' >= result->alloc.
+ *
+ * Resize the static coefficient to a larger dynamic one and copy the
+ * existing data. If successful, the value of 'result' is unchanged.
+ * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error.
+ */
+int
+mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
+{
+ mpd_uint_t *p = result->data;
+
+ assert(nwords >= result->alloc);
+
+ result->data = mpd_alloc(nwords, sizeof *result->data);
+ if (result->data == NULL) {
+ result->data = p;
+ mpd_set_qnan(result);
+ mpd_set_positive(result);
+ result->exp = result->digits = result->len = 0;
+ *status |= MPD_Malloc_error;
+ return 0;
+ }
+
+ memcpy(result->data, p, result->len * (sizeof *result->data));
+ result->alloc = nwords;
+ mpd_set_dynamic_data(result);
+ return 1;
+}
+
+/*
+ * Input: 'result' is a static mpd_t with a static coefficient.
+ *
+ * Convert the coefficient to a dynamic one that is initialized to zero. If
+ * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error.
+ */
+int
+mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
+{
+ mpd_uint_t *p = result->data;
+
+ result->data = mpd_calloc(nwords, sizeof *result->data);
+ if (result->data == NULL) {
+ result->data = p;
+ mpd_set_qnan(result);
+ mpd_set_positive(result);
+ result->exp = result->digits = result->len = 0;
+ *status |= MPD_Malloc_error;
+ return 0;
+ }
+
+ result->alloc = nwords;
+ mpd_set_dynamic_data(result);
+
+ return 1;
+}
+
+/*
+ * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient.
+ * Resize the coefficient to length 'nwords':
+ * Case nwords > result->alloc:
+ * If realloc is successful:
+ * 'result' has a larger coefficient but the same value. Return 1.
+ * Otherwise:
+ * Set 'result' to NaN, update status with MPD_Malloc_error and return 0.
+ * Case nwords < result->alloc:
+ * If realloc is successful:
+ * 'result' has a smaller coefficient. result->len is undefined. Return 1.
+ * Otherwise (unlikely):
+ * 'result' is unchanged. Reuse the now oversized coefficient. Return 1.
+ */
+int
+mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
+{
+ uint8_t err = 0;
+
+ result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err);
+ if (!err) {
+ result->alloc = nwords;
+ }
+ else if (nwords > result->alloc) {
+ mpd_set_qnan(result);
+ mpd_set_positive(result);
+ result->exp = result->digits = result->len = 0;
+ *status |= MPD_Malloc_error;
+ return 0;
+ }
+
+ return 1;
+}
+
+
diff --git a/Modules/_decimal/libmpdec/memory.h b/Modules/_decimal/libmpdec/memory.h
new file mode 100644
index 0000000..b3a4a56
--- /dev/null
+++ b/Modules/_decimal/libmpdec/memory.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef MEMORY_H
+#define MEMORY_H
+
+
+#include "mpdecimal.h"
+
+
+int mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+int mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+int mpd_realloc_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+
+
+#endif
+
+
+
diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c
new file mode 100644
index 0000000..c70ef41
--- /dev/null
+++ b/Modules/_decimal/libmpdec/mpdecimal.c
@@ -0,0 +1,7596 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include "basearith.h"
+#include "bits.h"
+#include "convolute.h"
+#include "crt.h"
+#include "errno.h"
+#include "memory.h"
+#include "typearith.h"
+#include "umodarith.h"
+
+#ifdef PPRO
+ #if defined(_MSC_VER)
+ #include <float.h>
+ #pragma fenv_access(on)
+ #elif !defined(__OpenBSD__) && !defined(__NetBSD__)
+ /* C99 */
+ #include <fenv.h>
+ #pragma STDC FENV_ACCESS ON
+ #endif
+#endif
+
+#if defined(__x86_64__) && defined(__GLIBC__) && !defined(__INTEL_COMPILER)
+ #define USE_80BIT_LONG_DOUBLE
+#endif
+
+#if defined(_MSC_VER)
+ #define ALWAYS_INLINE __forceinline
+#elif defined(LEGACY_COMPILER)
+ #define ALWAYS_INLINE
+ #undef inline
+ #define inline
+#else
+ #ifdef TEST_COVERAGE
+ #define ALWAYS_INLINE
+ #else
+ #define ALWAYS_INLINE inline __attribute__ ((always_inline))
+ #endif
+#endif
+
+
+#define MPD_NEWTONDIV_CUTOFF 1024L
+
+#define MPD_NEW_STATIC(name, flags, exp, digits, len) \
+ mpd_uint_t name##_data[MPD_MINALLOC_MAX]; \
+ mpd_t name = {flags|MPD_STATIC|MPD_STATIC_DATA, exp, digits, \
+ len, MPD_MINALLOC_MAX, name##_data}
+
+#define MPD_NEW_CONST(name, flags, exp, digits, len, alloc, initval) \
+ mpd_uint_t name##_data[alloc] = {initval}; \
+ mpd_t name = {flags|MPD_STATIC|MPD_CONST_DATA, exp, digits, \
+ len, alloc, name##_data}
+
+#define MPD_NEW_SHARED(name, a) \
+ mpd_t name = {(a->flags&~MPD_DATAFLAGS)|MPD_STATIC|MPD_SHARED_DATA, \
+ a->exp, a->digits, a->len, a->alloc, a->data}
+
+
+static mpd_uint_t data_one[1] = {1};
+static mpd_uint_t data_zero[1] = {0};
+static const mpd_t one = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_one};
+static const mpd_t minus_one = {MPD_NEG|MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1,
+ data_one};
+static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero};
+
+static inline void _mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx,
+ uint32_t *status);
+static void _settriple(mpd_t *result, uint8_t sign, mpd_uint_t a,
+ mpd_ssize_t exp);
+static inline mpd_ssize_t _mpd_real_size(mpd_uint_t *data, mpd_ssize_t size);
+
+static void _mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status);
+static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status);
+static void _mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a,
+ const mpd_t *b, uint32_t *status);
+static inline void _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp,
+ uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status);
+
+mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n);
+
+
+/******************************************************************************/
+/* Performance critical inline functions */
+/******************************************************************************/
+
+#ifdef CONFIG_64
+/* Digits in a word, primarily useful for the most significant word. */
+ALWAYS_INLINE int
+mpd_word_digits(mpd_uint_t word)
+{
+ if (word < mpd_pow10[9]) {
+ if (word < mpd_pow10[4]) {
+ if (word < mpd_pow10[2]) {
+ return (word < mpd_pow10[1]) ? 1 : 2;
+ }
+ return (word < mpd_pow10[3]) ? 3 : 4;
+ }
+ if (word < mpd_pow10[6]) {
+ return (word < mpd_pow10[5]) ? 5 : 6;
+ }
+ if (word < mpd_pow10[8]) {
+ return (word < mpd_pow10[7]) ? 7 : 8;
+ }
+ return 9;
+ }
+ if (word < mpd_pow10[14]) {
+ if (word < mpd_pow10[11]) {
+ return (word < mpd_pow10[10]) ? 10 : 11;
+ }
+ if (word < mpd_pow10[13]) {
+ return (word < mpd_pow10[12]) ? 12 : 13;
+ }
+ return 14;
+ }
+ if (word < mpd_pow10[18]) {
+ if (word < mpd_pow10[16]) {
+ return (word < mpd_pow10[15]) ? 15 : 16;
+ }
+ return (word < mpd_pow10[17]) ? 17 : 18;
+ }
+
+ return (word < mpd_pow10[19]) ? 19 : 20;
+}
+#else
+ALWAYS_INLINE int
+mpd_word_digits(mpd_uint_t word)
+{
+ if (word < mpd_pow10[4]) {
+ if (word < mpd_pow10[2]) {
+ return (word < mpd_pow10[1]) ? 1 : 2;
+ }
+ return (word < mpd_pow10[3]) ? 3 : 4;
+ }
+ if (word < mpd_pow10[6]) {
+ return (word < mpd_pow10[5]) ? 5 : 6;
+ }
+ if (word < mpd_pow10[8]) {
+ return (word < mpd_pow10[7]) ? 7 : 8;
+ }
+
+ return (word < mpd_pow10[9]) ? 9 : 10;
+}
+#endif
+
+
+/* Adjusted exponent */
+ALWAYS_INLINE mpd_ssize_t
+mpd_adjexp(const mpd_t *dec)
+{
+ return (dec->exp + dec->digits) - 1;
+}
+
+/* Etiny */
+ALWAYS_INLINE mpd_ssize_t
+mpd_etiny(const mpd_context_t *ctx)
+{
+ return ctx->emin - (ctx->prec - 1);
+}
+
+/* Etop: used for folding down in IEEE clamping */
+ALWAYS_INLINE mpd_ssize_t
+mpd_etop(const mpd_context_t *ctx)
+{
+ return ctx->emax - (ctx->prec - 1);
+}
+
+/* Most significant word */
+ALWAYS_INLINE mpd_uint_t
+mpd_msword(const mpd_t *dec)
+{
+ assert(dec->len > 0);
+ return dec->data[dec->len-1];
+}
+
+/* Most significant digit of a word */
+inline mpd_uint_t
+mpd_msd(mpd_uint_t word)
+{
+ int n;
+
+ n = mpd_word_digits(word);
+ return word / mpd_pow10[n-1];
+}
+
+/* Least significant digit of a word */
+ALWAYS_INLINE mpd_uint_t
+mpd_lsd(mpd_uint_t word)
+{
+ return word % 10;
+}
+
+/* Coefficient size needed to store 'digits' */
+ALWAYS_INLINE mpd_ssize_t
+mpd_digits_to_size(mpd_ssize_t digits)
+{
+ mpd_ssize_t q, r;
+
+ _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
+ return (r == 0) ? q : q+1;
+}
+
+/* Number of digits in the exponent. Not defined for MPD_SSIZE_MIN. */
+inline int
+mpd_exp_digits(mpd_ssize_t exp)
+{
+ exp = (exp < 0) ? -exp : exp;
+ return mpd_word_digits(exp);
+}
+
+/* Canonical */
+ALWAYS_INLINE int
+mpd_iscanonical(const mpd_t *dec UNUSED)
+{
+ return 1;
+}
+
+/* Finite */
+ALWAYS_INLINE int
+mpd_isfinite(const mpd_t *dec)
+{
+ return !(dec->flags & MPD_SPECIAL);
+}
+
+/* Infinite */
+ALWAYS_INLINE int
+mpd_isinfinite(const mpd_t *dec)
+{
+ return dec->flags & MPD_INF;
+}
+
+/* NaN */
+ALWAYS_INLINE int
+mpd_isnan(const mpd_t *dec)
+{
+ return dec->flags & (MPD_NAN|MPD_SNAN);
+}
+
+/* Negative */
+ALWAYS_INLINE int
+mpd_isnegative(const mpd_t *dec)
+{
+ return dec->flags & MPD_NEG;
+}
+
+/* Positive */
+ALWAYS_INLINE int
+mpd_ispositive(const mpd_t *dec)
+{
+ return !(dec->flags & MPD_NEG);
+}
+
+/* qNaN */
+ALWAYS_INLINE int
+mpd_isqnan(const mpd_t *dec)
+{
+ return dec->flags & MPD_NAN;
+}
+
+/* Signed */
+ALWAYS_INLINE int
+mpd_issigned(const mpd_t *dec)
+{
+ return dec->flags & MPD_NEG;
+}
+
+/* sNaN */
+ALWAYS_INLINE int
+mpd_issnan(const mpd_t *dec)
+{
+ return dec->flags & MPD_SNAN;
+}
+
+/* Special */
+ALWAYS_INLINE int
+mpd_isspecial(const mpd_t *dec)
+{
+ return dec->flags & MPD_SPECIAL;
+}
+
+/* Zero */
+ALWAYS_INLINE int
+mpd_iszero(const mpd_t *dec)
+{
+ return !mpd_isspecial(dec) && mpd_msword(dec) == 0;
+}
+
+/* Test for zero when specials have been ruled out already */
+ALWAYS_INLINE int
+mpd_iszerocoeff(const mpd_t *dec)
+{
+ return mpd_msword(dec) == 0;
+}
+
+/* Normal */
+inline int
+mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx)
+{
+ if (mpd_isspecial(dec)) return 0;
+ if (mpd_iszerocoeff(dec)) return 0;
+
+ return mpd_adjexp(dec) >= ctx->emin;
+}
+
+/* Subnormal */
+inline int
+mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx)
+{
+ if (mpd_isspecial(dec)) return 0;
+ if (mpd_iszerocoeff(dec)) return 0;
+
+ return mpd_adjexp(dec) < ctx->emin;
+}
+
+/* Odd word */
+ALWAYS_INLINE int
+mpd_isoddword(mpd_uint_t word)
+{
+ return word & 1;
+}
+
+/* Odd coefficient */
+ALWAYS_INLINE int
+mpd_isoddcoeff(const mpd_t *dec)
+{
+ return mpd_isoddword(dec->data[0]);
+}
+
+/* 0 if dec is positive, 1 if dec is negative */
+ALWAYS_INLINE uint8_t
+mpd_sign(const mpd_t *dec)
+{
+ return dec->flags & MPD_NEG;
+}
+
+/* 1 if dec is positive, -1 if dec is negative */
+ALWAYS_INLINE int
+mpd_arith_sign(const mpd_t *dec)
+{
+ return 1 - 2 * mpd_isnegative(dec);
+}
+
+/* Radix */
+ALWAYS_INLINE long
+mpd_radix(void)
+{
+ return 10;
+}
+
+/* Dynamic decimal */
+ALWAYS_INLINE int
+mpd_isdynamic(mpd_t *dec)
+{
+ return !(dec->flags & MPD_STATIC);
+}
+
+/* Static decimal */
+ALWAYS_INLINE int
+mpd_isstatic(mpd_t *dec)
+{
+ return dec->flags & MPD_STATIC;
+}
+
+/* Data of decimal is dynamic */
+ALWAYS_INLINE int
+mpd_isdynamic_data(mpd_t *dec)
+{
+ return !(dec->flags & MPD_DATAFLAGS);
+}
+
+/* Data of decimal is static */
+ALWAYS_INLINE int
+mpd_isstatic_data(mpd_t *dec)
+{
+ return dec->flags & MPD_STATIC_DATA;
+}
+
+/* Data of decimal is shared */
+ALWAYS_INLINE int
+mpd_isshared_data(mpd_t *dec)
+{
+ return dec->flags & MPD_SHARED_DATA;
+}
+
+/* Data of decimal is const */
+ALWAYS_INLINE int
+mpd_isconst_data(mpd_t *dec)
+{
+ return dec->flags & MPD_CONST_DATA;
+}
+
+
+/******************************************************************************/
+/* Inline memory handling */
+/******************************************************************************/
+
+/* Fill destination with zeros */
+ALWAYS_INLINE void
+mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len)
+{
+ mpd_size_t i;
+
+ for (i = 0; i < len; i++) {
+ dest[i] = 0;
+ }
+}
+
+/* Free a decimal */
+ALWAYS_INLINE void
+mpd_del(mpd_t *dec)
+{
+ if (mpd_isdynamic_data(dec)) {
+ mpd_free(dec->data);
+ }
+ if (mpd_isdynamic(dec)) {
+ mpd_free(dec);
+ }
+}
+
+/*
+ * Resize the coefficient. Existing data up to 'nwords' is left untouched.
+ * Return 1 on success, 0 otherwise.
+ *
+ * Input invariants:
+ * 1) MPD_MINALLOC <= result->alloc.
+ * 2) 0 <= result->len <= result->alloc.
+ *
+ * Case nwords > result->alloc:
+ * Case realloc success:
+ * The value of 'result' does not change. Return 1.
+ * Case realloc failure:
+ * 'result' is NaN, status is updated with MPD_Malloc_error. Return 0.
+ *
+ * Case nwords < result->alloc:
+ * Case is_static_data or nwords < MPD_MINALLOC or realloc failure [1]:
+ * 'result' is unchanged. Return 1.
+ * Case realloc success:
+ * The value of result is undefined (expected). Return 1.
+ *
+ * Case nwords == result->alloc:
+ * 'result' is unchanged. Return 1.
+ *
+ * [1] In that case the old (now oversized) area is still valid.
+ */
+ALWAYS_INLINE int
+mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
+{
+ assert(!mpd_isconst_data(result)); /* illegal operation for a const */
+ assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
+
+ if (mpd_isstatic_data(result)) {
+ if (nwords > result->alloc) {
+ return mpd_switch_to_dyn(result, nwords, status);
+ }
+ }
+ else if (nwords != result->alloc && nwords >= MPD_MINALLOC) {
+ return mpd_realloc_dyn(result, nwords, status);
+ }
+
+ return 1;
+}
+
+/* Same as mpd_qresize, but the complete coefficient (including the old
+ * memory area!) is initialized to zero. */
+ALWAYS_INLINE int
+mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
+{
+ assert(!mpd_isconst_data(result)); /* illegal operation for a const */
+ assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
+
+ if (mpd_isstatic_data(result)) {
+ if (nwords > result->alloc) {
+ return mpd_switch_to_dyn_zero(result, nwords, status);
+ }
+ }
+ else if (nwords != result->alloc && nwords >= MPD_MINALLOC) {
+ if (!mpd_realloc_dyn(result, nwords, status)) {
+ return 0;
+ }
+ }
+
+ mpd_uint_zero(result->data, nwords);
+
+ return 1;
+}
+
+/*
+ * Reduce memory size for the coefficient to MPD_MINALLOC. In theory,
+ * realloc may fail even when reducing the memory size. But in that case
+ * the old memory area is always big enough, so checking for MPD_Malloc_error
+ * is not imperative.
+ */
+ALWAYS_INLINE void
+mpd_minalloc(mpd_t *result)
+{
+ assert(!mpd_isconst_data(result)); /* illegal operation for a const */
+ assert(!mpd_isshared_data(result)); /* illegal operation for a shared */
+
+ if (!mpd_isstatic_data(result) && result->alloc > MPD_MINALLOC) {
+ uint8_t err = 0;
+ result->data = mpd_realloc(result->data, MPD_MINALLOC,
+ sizeof *result->data, &err);
+ if (!err) {
+ result->alloc = MPD_MINALLOC;
+ }
+ }
+}
+
+int
+mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
+{
+ uint32_t status = 0;
+ if (!mpd_qresize(result, nwords, &status)) {
+ mpd_addstatus_raise(ctx, status);
+ return 0;
+ }
+ return 1;
+}
+
+int
+mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx)
+{
+ uint32_t status = 0;
+ if (!mpd_qresize_zero(result, nwords, &status)) {
+ mpd_addstatus_raise(ctx, status);
+ return 0;
+ }
+ return 1;
+}
+
+
+/******************************************************************************/
+/* Set attributes of a decimal */
+/******************************************************************************/
+
+/* Set digits. Assumption: result->len is initialized and > 0. */
+inline void
+mpd_setdigits(mpd_t *result)
+{
+ mpd_ssize_t wdigits = mpd_word_digits(mpd_msword(result));
+ result->digits = wdigits + (result->len-1) * MPD_RDIGITS;
+}
+
+/* Set sign */
+ALWAYS_INLINE void
+mpd_set_sign(mpd_t *result, uint8_t sign)
+{
+ result->flags &= ~MPD_NEG;
+ result->flags |= sign;
+}
+
+/* Copy sign from another decimal */
+ALWAYS_INLINE void
+mpd_signcpy(mpd_t *result, mpd_t *a)
+{
+ uint8_t sign = a->flags&MPD_NEG;
+
+ result->flags &= ~MPD_NEG;
+ result->flags |= sign;
+}
+
+/* Set infinity */
+ALWAYS_INLINE void
+mpd_set_infinity(mpd_t *result)
+{
+ result->flags &= ~MPD_SPECIAL;
+ result->flags |= MPD_INF;
+}
+
+/* Set qNaN */
+ALWAYS_INLINE void
+mpd_set_qnan(mpd_t *result)
+{
+ result->flags &= ~MPD_SPECIAL;
+ result->flags |= MPD_NAN;
+}
+
+/* Set sNaN */
+ALWAYS_INLINE void
+mpd_set_snan(mpd_t *result)
+{
+ result->flags &= ~MPD_SPECIAL;
+ result->flags |= MPD_SNAN;
+}
+
+/* Set to negative */
+ALWAYS_INLINE void
+mpd_set_negative(mpd_t *result)
+{
+ result->flags |= MPD_NEG;
+}
+
+/* Set to positive */
+ALWAYS_INLINE void
+mpd_set_positive(mpd_t *result)
+{
+ result->flags &= ~MPD_NEG;
+}
+
+/* Set to dynamic */
+ALWAYS_INLINE void
+mpd_set_dynamic(mpd_t *result)
+{
+ result->flags &= ~MPD_STATIC;
+}
+
+/* Set to static */
+ALWAYS_INLINE void
+mpd_set_static(mpd_t *result)
+{
+ result->flags |= MPD_STATIC;
+}
+
+/* Set data to dynamic */
+ALWAYS_INLINE void
+mpd_set_dynamic_data(mpd_t *result)
+{
+ result->flags &= ~MPD_DATAFLAGS;
+}
+
+/* Set data to static */
+ALWAYS_INLINE void
+mpd_set_static_data(mpd_t *result)
+{
+ result->flags &= ~MPD_DATAFLAGS;
+ result->flags |= MPD_STATIC_DATA;
+}
+
+/* Set data to shared */
+ALWAYS_INLINE void
+mpd_set_shared_data(mpd_t *result)
+{
+ result->flags &= ~MPD_DATAFLAGS;
+ result->flags |= MPD_SHARED_DATA;
+}
+
+/* Set data to const */
+ALWAYS_INLINE void
+mpd_set_const_data(mpd_t *result)
+{
+ result->flags &= ~MPD_DATAFLAGS;
+ result->flags |= MPD_CONST_DATA;
+}
+
+/* Clear flags, preserving memory attributes. */
+ALWAYS_INLINE void
+mpd_clear_flags(mpd_t *result)
+{
+ result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
+}
+
+/* Set flags, preserving memory attributes. */
+ALWAYS_INLINE void
+mpd_set_flags(mpd_t *result, uint8_t flags)
+{
+ result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
+ result->flags |= flags;
+}
+
+/* Copy flags, preserving memory attributes of result. */
+ALWAYS_INLINE void
+mpd_copy_flags(mpd_t *result, const mpd_t *a)
+{
+ uint8_t aflags = a->flags;
+ result->flags &= (MPD_STATIC|MPD_DATAFLAGS);
+ result->flags |= (aflags & ~(MPD_STATIC|MPD_DATAFLAGS));
+}
+
+/* Initialize a workcontext from ctx. Set traps, flags and newtrap to 0. */
+static inline void
+mpd_workcontext(mpd_context_t *workctx, const mpd_context_t *ctx)
+{
+ workctx->prec = ctx->prec;
+ workctx->emax = ctx->emax;
+ workctx->emin = ctx->emin;
+ workctx->round = ctx->round;
+ workctx->traps = 0;
+ workctx->status = 0;
+ workctx->newtrap = 0;
+ workctx->clamp = ctx->clamp;
+ workctx->allcr = ctx->allcr;
+}
+
+
+/******************************************************************************/
+/* Getting and setting parts of decimals */
+/******************************************************************************/
+
+/* Flip the sign of a decimal */
+static inline void
+_mpd_negate(mpd_t *dec)
+{
+ dec->flags ^= MPD_NEG;
+}
+
+/* Set coefficient to zero */
+void
+mpd_zerocoeff(mpd_t *result)
+{
+ mpd_minalloc(result);
+ result->digits = 1;
+ result->len = 1;
+ result->data[0] = 0;
+}
+
+/* Set the coefficient to all nines. */
+void
+mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_ssize_t len, r;
+
+ _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
+ len = (r == 0) ? len : len+1;
+
+ if (!mpd_qresize(result, len, status)) {
+ return;
+ }
+
+ result->len = len;
+ result->digits = ctx->prec;
+
+ --len;
+ if (r > 0) {
+ result->data[len--] = mpd_pow10[r]-1;
+ }
+ for (; len >= 0; --len) {
+ result->data[len] = MPD_RADIX-1;
+ }
+}
+
+/*
+ * Cut off the most significant digits so that the rest fits in ctx->prec.
+ * Cannot fail.
+ */
+static void
+_mpd_cap(mpd_t *result, const mpd_context_t *ctx)
+{
+ uint32_t dummy;
+ mpd_ssize_t len, r;
+
+ if (result->len > 0 && result->digits > ctx->prec) {
+ _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS);
+ len = (r == 0) ? len : len+1;
+
+ if (r != 0) {
+ result->data[len-1] %= mpd_pow10[r];
+ }
+
+ len = _mpd_real_size(result->data, len);
+ /* resize to fewer words cannot fail */
+ mpd_qresize(result, len, &dummy);
+ result->len = len;
+ mpd_setdigits(result);
+ }
+ if (mpd_iszero(result)) {
+ _settriple(result, mpd_sign(result), 0, result->exp);
+ }
+}
+
+/*
+ * Cut off the most significant digits of a NaN payload so that the rest
+ * fits in ctx->prec - ctx->clamp. Cannot fail.
+ */
+static void
+_mpd_fix_nan(mpd_t *result, const mpd_context_t *ctx)
+{
+ uint32_t dummy;
+ mpd_ssize_t prec;
+ mpd_ssize_t len, r;
+
+ prec = ctx->prec - ctx->clamp;
+ if (result->len > 0 && result->digits > prec) {
+ if (prec == 0) {
+ mpd_minalloc(result);
+ result->len = result->digits = 0;
+ }
+ else {
+ _mpd_idiv_word(&len, &r, prec, MPD_RDIGITS);
+ len = (r == 0) ? len : len+1;
+
+ if (r != 0) {
+ result->data[len-1] %= mpd_pow10[r];
+ }
+
+ len = _mpd_real_size(result->data, len);
+ /* resize to fewer words cannot fail */
+ mpd_qresize(result, len, &dummy);
+ result->len = len;
+ mpd_setdigits(result);
+ if (mpd_iszerocoeff(result)) {
+ /* NaN0 is not a valid representation */
+ result->len = result->digits = 0;
+ }
+ }
+ }
+}
+
+/*
+ * Get n most significant digits from a decimal, where 0 < n <= MPD_UINT_DIGITS.
+ * Assumes MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for 32 and 64 bit
+ * machines.
+ *
+ * The result of the operation will be in lo. If the operation is impossible,
+ * hi will be nonzero. This is used to indicate an error.
+ */
+static inline void
+_mpd_get_msdigits(mpd_uint_t *hi, mpd_uint_t *lo, const mpd_t *dec,
+ unsigned int n)
+{
+ mpd_uint_t r, tmp;
+
+ assert(0 < n && n <= MPD_RDIGITS+1);
+
+ _mpd_div_word(&tmp, &r, dec->digits, MPD_RDIGITS);
+ r = (r == 0) ? MPD_RDIGITS : r; /* digits in the most significant word */
+
+ *hi = 0;
+ *lo = dec->data[dec->len-1];
+ if (n <= r) {
+ *lo /= mpd_pow10[r-n];
+ }
+ else if (dec->len > 1) {
+ /* at this point 1 <= r < n <= MPD_RDIGITS+1 */
+ _mpd_mul_words(hi, lo, *lo, mpd_pow10[n-r]);
+ tmp = dec->data[dec->len-2] / mpd_pow10[MPD_RDIGITS-(n-r)];
+ *lo = *lo + tmp;
+ if (*lo < tmp) (*hi)++;
+ }
+}
+
+
+/******************************************************************************/
+/* Gathering information about a decimal */
+/******************************************************************************/
+
+/* The real size of the coefficient without leading zero words. */
+static inline mpd_ssize_t
+_mpd_real_size(mpd_uint_t *data, mpd_ssize_t size)
+{
+ while (size > 1 && data[size-1] == 0) {
+ size--;
+ }
+
+ return size;
+}
+
+/* Return number of trailing zeros. No errors are possible. */
+mpd_ssize_t
+mpd_trail_zeros(const mpd_t *dec)
+{
+ mpd_uint_t word;
+ mpd_ssize_t i, tz = 0;
+
+ for (i=0; i < dec->len; ++i) {
+ if (dec->data[i] != 0) {
+ word = dec->data[i];
+ tz = i * MPD_RDIGITS;
+ while (word % 10 == 0) {
+ word /= 10;
+ tz++;
+ }
+ break;
+ }
+ }
+
+ return tz;
+}
+
+/* Integer: Undefined for specials */
+static int
+_mpd_isint(const mpd_t *dec)
+{
+ mpd_ssize_t tz;
+
+ if (mpd_iszerocoeff(dec)) {
+ return 1;
+ }
+
+ tz = mpd_trail_zeros(dec);
+ return (dec->exp + tz >= 0);
+}
+
+/* Integer */
+int
+mpd_isinteger(const mpd_t *dec)
+{
+ if (mpd_isspecial(dec)) {
+ return 0;
+ }
+ return _mpd_isint(dec);
+}
+
+/* Word is a power of 10 */
+static int
+mpd_word_ispow10(mpd_uint_t word)
+{
+ int n;
+
+ n = mpd_word_digits(word);
+ if (word == mpd_pow10[n-1]) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Coefficient is a power of 10 */
+static int
+mpd_coeff_ispow10(const mpd_t *dec)
+{
+ if (mpd_word_ispow10(mpd_msword(dec))) {
+ if (_mpd_isallzero(dec->data, dec->len-1)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* All digits of a word are nines */
+static int
+mpd_word_isallnine(mpd_uint_t word)
+{
+ int n;
+
+ n = mpd_word_digits(word);
+ if (word == mpd_pow10[n]-1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* All digits of the coefficient are nines */
+static int
+mpd_coeff_isallnine(const mpd_t *dec)
+{
+ if (mpd_word_isallnine(mpd_msword(dec))) {
+ if (_mpd_isallnine(dec->data, dec->len-1)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Odd decimal: Undefined for non-integers! */
+int
+mpd_isodd(const mpd_t *dec)
+{
+ mpd_uint_t q, r;
+ assert(mpd_isinteger(dec));
+ if (mpd_iszerocoeff(dec)) return 0;
+ if (dec->exp < 0) {
+ _mpd_div_word(&q, &r, -dec->exp, MPD_RDIGITS);
+ q = dec->data[q] / mpd_pow10[r];
+ return mpd_isoddword(q);
+ }
+ return dec->exp == 0 && mpd_isoddword(dec->data[0]);
+}
+
+/* Even: Undefined for non-integers! */
+int
+mpd_iseven(const mpd_t *dec)
+{
+ return !mpd_isodd(dec);
+}
+
+/******************************************************************************/
+/* Getting and setting decimals */
+/******************************************************************************/
+
+/* Internal function: Set a static decimal from a triple, no error checking. */
+static void
+_ssettriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
+{
+ mpd_set_flags(result, sign);
+ result->exp = exp;
+ _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
+ result->len = (result->data[1] == 0) ? 1 : 2;
+ mpd_setdigits(result);
+}
+
+/* Internal function: Set a decimal from a triple, no error checking. */
+static void
+_settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp)
+{
+ mpd_minalloc(result);
+ mpd_set_flags(result, sign);
+ result->exp = exp;
+ _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX);
+ result->len = (result->data[1] == 0) ? 1 : 2;
+ mpd_setdigits(result);
+}
+
+/* Set a special number from a triple */
+void
+mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type)
+{
+ mpd_minalloc(result);
+ result->flags &= ~(MPD_NEG|MPD_SPECIAL);
+ result->flags |= (sign|type);
+ result->exp = result->digits = result->len = 0;
+}
+
+/* Set result of NaN with an error status */
+void
+mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status)
+{
+ mpd_minalloc(result);
+ mpd_set_qnan(result);
+ mpd_set_positive(result);
+ result->exp = result->digits = result->len = 0;
+ *status |= flags;
+}
+
+/* quietly set a static decimal from an mpd_ssize_t */
+void
+mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_uint_t u;
+ uint8_t sign = MPD_POS;
+
+ if (a < 0) {
+ if (a == MPD_SSIZE_MIN) {
+ u = (mpd_uint_t)MPD_SSIZE_MAX +
+ (-(MPD_SSIZE_MIN+MPD_SSIZE_MAX));
+ }
+ else {
+ u = -a;
+ }
+ sign = MPD_NEG;
+ }
+ else {
+ u = a;
+ }
+ _ssettriple(result, sign, u, 0);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* quietly set a static decimal from an mpd_uint_t */
+void
+mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ _ssettriple(result, MPD_POS, a, 0);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* quietly set a static decimal from an int32_t */
+void
+mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qsset_ssize(result, a, ctx, status);
+}
+
+/* quietly set a static decimal from a uint32_t */
+void
+mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qsset_uint(result, a, ctx, status);
+}
+
+#ifdef CONFIG_64
+/* quietly set a static decimal from an int64_t */
+void
+mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qsset_ssize(result, a, ctx, status);
+}
+
+/* quietly set a static decimal from a uint64_t */
+void
+mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qsset_uint(result, a, ctx, status);
+}
+#endif
+
+/* quietly set a decimal from an mpd_ssize_t */
+void
+mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_minalloc(result);
+ mpd_qsset_ssize(result, a, ctx, status);
+}
+
+/* quietly set a decimal from an mpd_uint_t */
+void
+mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ _settriple(result, MPD_POS, a, 0);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* quietly set a decimal from an int32_t */
+void
+mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qset_ssize(result, a, ctx, status);
+}
+
+/* quietly set a decimal from a uint32_t */
+void
+mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_qset_uint(result, a, ctx, status);
+}
+
+#if defined(CONFIG_32) && !defined(LEGACY_COMPILER)
+/* set a decimal from a uint64_t */
+static void
+_c32setu64(mpd_t *result, uint64_t u, uint8_t sign, uint32_t *status)
+{
+ mpd_uint_t w[3];
+ uint64_t q;
+ int i, len;
+
+ len = 0;
+ do {
+ q = u / MPD_RADIX;
+ w[len] = (mpd_uint_t)(u - q * MPD_RADIX);
+ u = q; len++;
+ } while (u != 0);
+
+ if (!mpd_qresize(result, len, status)) {
+ return;
+ }
+ for (i = 0; i < len; i++) {
+ result->data[i] = w[i];
+ }
+
+ mpd_set_sign(result, sign);
+ result->exp = 0;
+ result->len = len;
+ mpd_setdigits(result);
+}
+
+static void
+_c32_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ _c32setu64(result, a, MPD_POS, status);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* set a decimal from an int64_t */
+static void
+_c32_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ uint64_t u;
+ uint8_t sign = MPD_POS;
+
+ if (a < 0) {
+ if (a == INT64_MIN) {
+ u = (uint64_t)INT64_MAX + (-(INT64_MIN+INT64_MAX));
+ }
+ else {
+ u = -a;
+ }
+ sign = MPD_NEG;
+ }
+ else {
+ u = a;
+ }
+ _c32setu64(result, u, sign, status);
+ mpd_qfinalize(result, ctx, status);
+}
+#endif /* CONFIG_32 && !LEGACY_COMPILER */
+
+#ifndef LEGACY_COMPILER
+/* quietly set a decimal from an int64_t */
+void
+mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+#ifdef CONFIG_64
+ mpd_qset_ssize(result, a, ctx, status);
+#else
+ _c32_qset_i64(result, a, ctx, status);
+#endif
+}
+
+/* quietly set a decimal from a uint64_t */
+void
+mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+#ifdef CONFIG_64
+ mpd_qset_uint(result, a, ctx, status);
+#else
+ _c32_qset_u64(result, a, ctx, status);
+#endif
+}
+#endif /* !LEGACY_COMPILER */
+
+
+/*
+ * Quietly get an mpd_uint_t from a decimal. Assumes
+ * MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for
+ * 32 and 64 bit machines.
+ *
+ * If the operation is impossible, MPD_Invalid_operation is set.
+ */
+static mpd_uint_t
+_mpd_qget_uint(int use_sign, const mpd_t *a, uint32_t *status)
+{
+ mpd_t tmp;
+ mpd_uint_t tmp_data[2];
+ mpd_uint_t lo, hi;
+
+ if (mpd_isspecial(a)) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+ if (mpd_iszero(a)) {
+ return 0;
+ }
+ if (use_sign && mpd_isnegative(a)) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+
+ if (a->digits+a->exp > MPD_RDIGITS+1) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+
+ if (a->exp < 0) {
+ if (!_mpd_isint(a)) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+ /* At this point a->digits+a->exp <= MPD_RDIGITS+1,
+ * so the shift fits. */
+ tmp.data = tmp_data;
+ tmp.flags = MPD_STATIC|MPD_CONST_DATA;
+ mpd_qsshiftr(&tmp, a, -a->exp);
+ tmp.exp = 0;
+ a = &tmp;
+ }
+
+ _mpd_get_msdigits(&hi, &lo, a, MPD_RDIGITS+1);
+ if (hi) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+
+ if (a->exp > 0) {
+ _mpd_mul_words(&hi, &lo, lo, mpd_pow10[a->exp]);
+ if (hi) {
+ *status |= MPD_Invalid_operation;
+ return MPD_UINT_MAX;
+ }
+ }
+
+ return lo;
+}
+
+/*
+ * Sets Invalid_operation for:
+ * - specials
+ * - negative numbers (except negative zero)
+ * - non-integers
+ * - overflow
+ */
+mpd_uint_t
+mpd_qget_uint(const mpd_t *a, uint32_t *status)
+{
+ return _mpd_qget_uint(1, a, status);
+}
+
+/* Same as above, but gets the absolute value, i.e. the sign is ignored. */
+mpd_uint_t
+mpd_qabs_uint(const mpd_t *a, uint32_t *status)
+{
+ return _mpd_qget_uint(0, a, status);
+}
+
+/* quietly get an mpd_ssize_t from a decimal */
+mpd_ssize_t
+mpd_qget_ssize(const mpd_t *a, uint32_t *status)
+{
+ mpd_uint_t u;
+ int isneg;
+
+ u = mpd_qabs_uint(a, status);
+ if (*status&MPD_Invalid_operation) {
+ return MPD_SSIZE_MAX;
+ }
+
+ isneg = mpd_isnegative(a);
+ if (u <= MPD_SSIZE_MAX) {
+ return isneg ? -((mpd_ssize_t)u) : (mpd_ssize_t)u;
+ }
+ else if (isneg && u-1 == MPD_SSIZE_MAX) {
+ return MPD_SSIZE_MIN;
+ }
+
+ *status |= MPD_Invalid_operation;
+ return MPD_SSIZE_MAX;
+}
+
+#ifdef CONFIG_64
+/* quietly get a uint64_t from a decimal */
+uint64_t
+mpd_qget_u64(const mpd_t *a, uint32_t *status)
+{
+ return mpd_qget_uint(a, status);
+}
+
+/* quietly get an int64_t from a decimal */
+int64_t
+mpd_qget_i64(const mpd_t *a, uint32_t *status)
+{
+ return mpd_qget_ssize(a, status);
+}
+#else
+/* quietly get a uint32_t from a decimal */
+uint32_t
+mpd_qget_u32(const mpd_t *a, uint32_t *status)
+{
+ return mpd_qget_uint(a, status);
+}
+
+/* quietly get an int32_t from a decimal */
+int32_t
+mpd_qget_i32(const mpd_t *a, uint32_t *status)
+{
+ return mpd_qget_ssize(a, status);
+}
+#endif
+
+
+/******************************************************************************/
+/* Filtering input of functions, finalizing output of functions */
+/******************************************************************************/
+
+/*
+ * Check if the operand is NaN, copy to result and return 1 if this is
+ * the case. Copying can fail since NaNs are allowed to have a payload that
+ * does not fit in MPD_MINALLOC.
+ */
+int
+mpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isnan(a)) {
+ *status |= mpd_issnan(a) ? MPD_Invalid_operation : 0;
+ mpd_qcopy(result, a, status);
+ mpd_set_qnan(result);
+ _mpd_fix_nan(result, ctx);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Check if either operand is NaN, copy to result and return 1 if this
+ * is the case. Copying can fail since NaNs are allowed to have a payload
+ * that does not fit in MPD_MINALLOC.
+ */
+int
+mpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if ((a->flags|b->flags)&(MPD_NAN|MPD_SNAN)) {
+ const mpd_t *choice = b;
+ if (mpd_issnan(a)) {
+ choice = a;
+ *status |= MPD_Invalid_operation;
+ }
+ else if (mpd_issnan(b)) {
+ *status |= MPD_Invalid_operation;
+ }
+ else if (mpd_isqnan(a)) {
+ choice = a;
+ }
+ mpd_qcopy(result, choice, status);
+ mpd_set_qnan(result);
+ _mpd_fix_nan(result, ctx);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Check if one of the operands is NaN, copy to result and return 1 if this
+ * is the case. Copying can fail since NaNs are allowed to have a payload
+ * that does not fit in MPD_MINALLOC.
+ */
+static int
+mpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if ((a->flags|b->flags|c->flags)&(MPD_NAN|MPD_SNAN)) {
+ const mpd_t *choice = c;
+ if (mpd_issnan(a)) {
+ choice = a;
+ *status |= MPD_Invalid_operation;
+ }
+ else if (mpd_issnan(b)) {
+ choice = b;
+ *status |= MPD_Invalid_operation;
+ }
+ else if (mpd_issnan(c)) {
+ *status |= MPD_Invalid_operation;
+ }
+ else if (mpd_isqnan(a)) {
+ choice = a;
+ }
+ else if (mpd_isqnan(b)) {
+ choice = b;
+ }
+ mpd_qcopy(result, choice, status);
+ mpd_set_qnan(result);
+ _mpd_fix_nan(result, ctx);
+ return 1;
+ }
+ return 0;
+}
+
+/* Check if rounding digit 'rnd' leads to an increment. */
+static inline int
+_mpd_rnd_incr(const mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx)
+{
+ int ld;
+
+ switch (ctx->round) {
+ case MPD_ROUND_DOWN: case MPD_ROUND_TRUNC:
+ return 0;
+ case MPD_ROUND_HALF_UP:
+ return (rnd >= 5);
+ case MPD_ROUND_HALF_EVEN:
+ return (rnd > 5) || ((rnd == 5) && mpd_isoddcoeff(dec));
+ case MPD_ROUND_CEILING:
+ return !(rnd == 0 || mpd_isnegative(dec));
+ case MPD_ROUND_FLOOR:
+ return !(rnd == 0 || mpd_ispositive(dec));
+ case MPD_ROUND_HALF_DOWN:
+ return (rnd > 5);
+ case MPD_ROUND_UP:
+ return !(rnd == 0);
+ case MPD_ROUND_05UP:
+ ld = (int)mpd_lsd(dec->data[0]);
+ return (!(rnd == 0) && (ld == 0 || ld == 5));
+ default:
+ /* Without a valid context, further results will be undefined. */
+ return 0; /* GCOV_NOT_REACHED */
+ }
+}
+
+/*
+ * Apply rounding to a decimal that has been right-shifted into a full
+ * precision decimal. If an increment leads to an overflow of the precision,
+ * adjust the coefficient and the exponent and check the new exponent for
+ * overflow.
+ */
+static inline void
+_mpd_apply_round(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (_mpd_rnd_incr(dec, rnd, ctx)) {
+ /* We have a number with exactly ctx->prec digits. The increment
+ * can only lead to an overflow if the decimal is all nines. In
+ * that case, the result is a power of ten with prec+1 digits.
+ *
+ * If the precision is a multiple of MPD_RDIGITS, this situation is
+ * detected by _mpd_baseincr returning a carry.
+ * If the precision is not a multiple of MPD_RDIGITS, we have to
+ * check if the result has one digit too many.
+ */
+ mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
+ if (carry) {
+ dec->data[dec->len-1] = mpd_pow10[MPD_RDIGITS-1];
+ dec->exp += 1;
+ _mpd_check_exp(dec, ctx, status);
+ return;
+ }
+ mpd_setdigits(dec);
+ if (dec->digits > ctx->prec) {
+ mpd_qshiftr_inplace(dec, 1);
+ dec->exp += 1;
+ dec->digits = ctx->prec;
+ _mpd_check_exp(dec, ctx, status);
+ }
+ }
+}
+
+/*
+ * Apply rounding to a decimal. Allow overflow of the precision.
+ */
+static inline void
+_mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (_mpd_rnd_incr(dec, rnd, ctx)) {
+ mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
+ if (carry) {
+ if (!mpd_qresize(dec, dec->len+1, status)) {
+ return;
+ }
+ dec->data[dec->len] = 1;
+ dec->len += 1;
+ }
+ mpd_setdigits(dec);
+ }
+}
+
+/*
+ * Apply rounding to a decimal that has been right-shifted into a decimal
+ * with full precision or less. Return failure if an increment would
+ * overflow the precision.
+ */
+static inline int
+_mpd_apply_round_fit(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (_mpd_rnd_incr(dec, rnd, ctx)) {
+ mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len);
+ if (carry) {
+ if (!mpd_qresize(dec, dec->len+1, status)) {
+ return 0;
+ }
+ dec->data[dec->len] = 1;
+ dec->len += 1;
+ }
+ mpd_setdigits(dec);
+ if (dec->digits > ctx->prec) {
+ mpd_seterror(dec, MPD_Invalid_operation, status);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Check a normal number for overflow, underflow, clamping. If the operand
+ is modified, it will be zero, special or (sub)normal with a coefficient
+ that fits into the current context precision. */
+static inline void
+_mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_ssize_t adjexp, etiny, shift;
+ int rnd;
+
+ adjexp = mpd_adjexp(dec);
+ if (adjexp > ctx->emax) {
+
+ if (mpd_iszerocoeff(dec)) {
+ dec->exp = ctx->emax;
+ if (ctx->clamp) {
+ dec->exp -= (ctx->prec-1);
+ }
+ mpd_zerocoeff(dec);
+ *status |= MPD_Clamped;
+ return;
+ }
+
+ switch (ctx->round) {
+ case MPD_ROUND_HALF_UP: case MPD_ROUND_HALF_EVEN:
+ case MPD_ROUND_HALF_DOWN: case MPD_ROUND_UP:
+ case MPD_ROUND_TRUNC:
+ mpd_setspecial(dec, mpd_sign(dec), MPD_INF);
+ break;
+ case MPD_ROUND_DOWN: case MPD_ROUND_05UP:
+ mpd_qmaxcoeff(dec, ctx, status);
+ dec->exp = ctx->emax - ctx->prec + 1;
+ break;
+ case MPD_ROUND_CEILING:
+ if (mpd_isnegative(dec)) {
+ mpd_qmaxcoeff(dec, ctx, status);
+ dec->exp = ctx->emax - ctx->prec + 1;
+ }
+ else {
+ mpd_setspecial(dec, MPD_POS, MPD_INF);
+ }
+ break;
+ case MPD_ROUND_FLOOR:
+ if (mpd_ispositive(dec)) {
+ mpd_qmaxcoeff(dec, ctx, status);
+ dec->exp = ctx->emax - ctx->prec + 1;
+ }
+ else {
+ mpd_setspecial(dec, MPD_NEG, MPD_INF);
+ }
+ break;
+ default: /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+
+ *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
+
+ } /* fold down */
+ else if (ctx->clamp && dec->exp > mpd_etop(ctx)) {
+ /* At this point adjexp=exp+digits-1 <= emax and exp > etop=emax-prec+1:
+ * (1) shift = exp -emax+prec-1 > 0
+ * (2) digits+shift = exp+digits-1 - emax + prec <= prec */
+ shift = dec->exp - mpd_etop(ctx);
+ if (!mpd_qshiftl(dec, dec, shift, status)) {
+ return;
+ }
+ dec->exp -= shift;
+ *status |= MPD_Clamped;
+ if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) {
+ /* Underflow is impossible, since exp < etiny=emin-prec+1
+ * and exp > etop=emax-prec+1 would imply emax < emin. */
+ *status |= MPD_Subnormal;
+ }
+ }
+ else if (adjexp < ctx->emin) {
+
+ etiny = mpd_etiny(ctx);
+
+ if (mpd_iszerocoeff(dec)) {
+ if (dec->exp < etiny) {
+ dec->exp = etiny;
+ mpd_zerocoeff(dec);
+ *status |= MPD_Clamped;
+ }
+ return;
+ }
+
+ *status |= MPD_Subnormal;
+ if (dec->exp < etiny) {
+ /* At this point adjexp=exp+digits-1 < emin and exp < etiny=emin-prec+1:
+ * (1) shift = emin-prec+1 - exp > 0
+ * (2) digits-shift = exp+digits-1 - emin + prec < prec */
+ shift = etiny - dec->exp;
+ rnd = (int)mpd_qshiftr_inplace(dec, shift);
+ dec->exp = etiny;
+ /* We always have a spare digit in case of an increment. */
+ _mpd_apply_round_excess(dec, rnd, ctx, status);
+ *status |= MPD_Rounded;
+ if (rnd) {
+ *status |= (MPD_Inexact|MPD_Underflow);
+ if (mpd_iszerocoeff(dec)) {
+ mpd_zerocoeff(dec);
+ *status |= MPD_Clamped;
+ }
+ }
+ }
+ /* Case exp >= etiny=emin-prec+1:
+ * (1) adjexp=exp+digits-1 < emin
+ * (2) digits < emin-exp+1 <= prec */
+ }
+}
+
+/* Transcendental functions do not always set Underflow reliably,
+ * since they only use as much precision as is necessary for correct
+ * rounding. If a result like 1.0000000000e-101 is finalized, there
+ * is no rounding digit that would trigger Underflow. But we can
+ * assume Inexact, so a short check suffices. */
+static inline void
+mpd_check_underflow(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
+{
+ if (mpd_adjexp(dec) < ctx->emin && !mpd_iszero(dec) &&
+ dec->exp < mpd_etiny(ctx)) {
+ *status |= MPD_Underflow;
+ }
+}
+
+/* Check if a normal number must be rounded after the exponent has been checked. */
+static inline void
+_mpd_check_round(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_uint_t rnd;
+ mpd_ssize_t shift;
+
+ /* must handle specials: _mpd_check_exp() can produce infinities or NaNs */
+ if (mpd_isspecial(dec)) {
+ return;
+ }
+
+ if (dec->digits > ctx->prec) {
+ shift = dec->digits - ctx->prec;
+ rnd = mpd_qshiftr_inplace(dec, shift);
+ dec->exp += shift;
+ _mpd_apply_round(dec, rnd, ctx, status);
+ *status |= MPD_Rounded;
+ if (rnd) {
+ *status |= MPD_Inexact;
+ }
+ }
+}
+
+/* Finalize all operations. */
+void
+mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status)
+{
+ if (mpd_isspecial(result)) {
+ if (mpd_isnan(result)) {
+ _mpd_fix_nan(result, ctx);
+ }
+ return;
+ }
+
+ _mpd_check_exp(result, ctx, status);
+ _mpd_check_round(result, ctx, status);
+}
+
+
+/******************************************************************************/
+/* Copying */
+/******************************************************************************/
+
+/* Internal function: Copy a decimal, share data with src: USE WITH CARE! */
+static inline void
+_mpd_copy_shared(mpd_t *dest, const mpd_t *src)
+{
+ dest->flags = src->flags;
+ dest->exp = src->exp;
+ dest->digits = src->digits;
+ dest->len = src->len;
+ dest->alloc = src->alloc;
+ dest->data = src->data;
+
+ mpd_set_shared_data(dest);
+}
+
+/*
+ * Copy a decimal. In case of an error, status is set to MPD_Malloc_error.
+ */
+int
+mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status)
+{
+ if (result == a) return 1;
+
+ if (!mpd_qresize(result, a->len, status)) {
+ return 0;
+ }
+
+ mpd_copy_flags(result, a);
+ result->exp = a->exp;
+ result->digits = a->digits;
+ result->len = a->len;
+ memcpy(result->data, a->data, a->len * (sizeof *result->data));
+
+ return 1;
+}
+
+/*
+ * Copy to a decimal with a static buffer. The caller has to make sure that
+ * the buffer is big enough. Cannot fail.
+ */
+static void
+mpd_qcopy_static(mpd_t *result, const mpd_t *a)
+{
+ if (result == a) return;
+
+ memcpy(result->data, a->data, a->len * (sizeof *result->data));
+
+ mpd_copy_flags(result, a);
+ result->exp = a->exp;
+ result->digits = a->digits;
+ result->len = a->len;
+}
+
+/*
+ * Return a newly allocated copy of the operand. In case of an error,
+ * status is set to MPD_Malloc_error and the return value is NULL.
+ */
+mpd_t *
+mpd_qncopy(const mpd_t *a)
+{
+ mpd_t *result;
+
+ if ((result = mpd_qnew_size(a->len)) == NULL) {
+ return NULL;
+ }
+ memcpy(result->data, a->data, a->len * (sizeof *result->data));
+ mpd_copy_flags(result, a);
+ result->exp = a->exp;
+ result->digits = a->digits;
+ result->len = a->len;
+
+ return result;
+}
+
+/*
+ * Copy a decimal and set the sign to positive. In case of an error, the
+ * status is set to MPD_Malloc_error.
+ */
+int
+mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status)
+{
+ if (!mpd_qcopy(result, a, status)) {
+ return 0;
+ }
+ mpd_set_positive(result);
+ return 1;
+}
+
+/*
+ * Copy a decimal and negate the sign. In case of an error, the
+ * status is set to MPD_Malloc_error.
+ */
+int
+mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status)
+{
+ if (!mpd_qcopy(result, a, status)) {
+ return 0;
+ }
+ _mpd_negate(result);
+ return 1;
+}
+
+/*
+ * Copy a decimal, setting the sign of the first operand to the sign of the
+ * second operand. In case of an error, the status is set to MPD_Malloc_error.
+ */
+int
+mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
+{
+ uint8_t sign_b = mpd_sign(b); /* result may equal b! */
+
+ if (!mpd_qcopy(result, a, status)) {
+ return 0;
+ }
+ mpd_set_sign(result, sign_b);
+ return 1;
+}
+
+
+/******************************************************************************/
+/* Comparisons */
+/******************************************************************************/
+
+/*
+ * For all functions that compare two operands and return an int the usual
+ * convention applies to the return value:
+ *
+ * -1 if op1 < op2
+ * 0 if op1 == op2
+ * 1 if op1 > op2
+ *
+ * INT_MAX for error
+ */
+
+
+/* Convenience macro. If a and b are not equal, return from the calling
+ * function with the correct comparison value. */
+#define CMP_EQUAL_OR_RETURN(a, b) \
+ if (a != b) { \
+ if (a < b) { \
+ return -1; \
+ } \
+ return 1; \
+ }
+
+/*
+ * Compare the data of big and small. This function does the equivalent
+ * of first shifting small to the left and then comparing the data of
+ * big and small, except that no allocation for the left shift is needed.
+ */
+static int
+_mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m,
+ mpd_size_t shift)
+{
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+ /* spurious uninitialized warnings */
+ mpd_uint_t l=l, lprev=lprev, h=h;
+#else
+ mpd_uint_t l, lprev, h;
+#endif
+ mpd_uint_t q, r;
+ mpd_uint_t ph, x;
+
+ assert(m > 0 && n >= m && shift > 0);
+
+ _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS);
+
+ if (r != 0) {
+
+ ph = mpd_pow10[r];
+
+ --m; --n;
+ _mpd_divmod_pow10(&h, &lprev, small[m--], MPD_RDIGITS-r);
+ if (h != 0) {
+ CMP_EQUAL_OR_RETURN(big[n], h)
+ --n;
+ }
+ for (; m != MPD_SIZE_MAX; m--,n--) {
+ _mpd_divmod_pow10(&h, &l, small[m], MPD_RDIGITS-r);
+ x = ph * lprev + h;
+ CMP_EQUAL_OR_RETURN(big[n], x)
+ lprev = l;
+ }
+ x = ph * lprev;
+ CMP_EQUAL_OR_RETURN(big[q], x)
+ }
+ else {
+ while (--m != MPD_SIZE_MAX) {
+ CMP_EQUAL_OR_RETURN(big[m+q], small[m])
+ }
+ }
+
+ return !_mpd_isallzero(big, q);
+}
+
+/* Compare two decimals with the same adjusted exponent. */
+static int
+_mpd_cmp_same_adjexp(const mpd_t *a, const mpd_t *b)
+{
+ mpd_ssize_t shift, i;
+
+ if (a->exp != b->exp) {
+ /* Cannot wrap: a->exp + a->digits = b->exp + b->digits, so
+ * a->exp - b->exp = b->digits - a->digits. */
+ shift = a->exp - b->exp;
+ if (shift > 0) {
+ return -1 * _mpd_basecmp(b->data, a->data, b->len, a->len, shift);
+ }
+ else {
+ return _mpd_basecmp(a->data, b->data, a->len, b->len, -shift);
+ }
+ }
+
+ /*
+ * At this point adjexp(a) == adjexp(b) and a->exp == b->exp,
+ * so a->digits == b->digits, therefore a->len == b->len.
+ */
+ for (i = a->len-1; i >= 0; --i) {
+ CMP_EQUAL_OR_RETURN(a->data[i], b->data[i])
+ }
+
+ return 0;
+}
+
+/* Compare two numerical values. */
+static int
+_mpd_cmp(const mpd_t *a, const mpd_t *b)
+{
+ mpd_ssize_t adjexp_a, adjexp_b;
+
+ /* equal pointers */
+ if (a == b) {
+ return 0;
+ }
+
+ /* infinities */
+ if (mpd_isinfinite(a)) {
+ if (mpd_isinfinite(b)) {
+ return mpd_isnegative(b) - mpd_isnegative(a);
+ }
+ return mpd_arith_sign(a);
+ }
+ if (mpd_isinfinite(b)) {
+ return -mpd_arith_sign(b);
+ }
+
+ /* zeros */
+ if (mpd_iszerocoeff(a)) {
+ if (mpd_iszerocoeff(b)) {
+ return 0;
+ }
+ return -mpd_arith_sign(b);
+ }
+ if (mpd_iszerocoeff(b)) {
+ return mpd_arith_sign(a);
+ }
+
+ /* different signs */
+ if (mpd_sign(a) != mpd_sign(b)) {
+ return mpd_sign(b) - mpd_sign(a);
+ }
+
+ /* different adjusted exponents */
+ adjexp_a = mpd_adjexp(a);
+ adjexp_b = mpd_adjexp(b);
+ if (adjexp_a != adjexp_b) {
+ if (adjexp_a < adjexp_b) {
+ return -1 * mpd_arith_sign(a);
+ }
+ return mpd_arith_sign(a);
+ }
+
+ /* same adjusted exponents */
+ return _mpd_cmp_same_adjexp(a, b) * mpd_arith_sign(a);
+}
+
+/* Compare the absolutes of two numerical values. */
+static int
+_mpd_cmp_abs(const mpd_t *a, const mpd_t *b)
+{
+ mpd_ssize_t adjexp_a, adjexp_b;
+
+ /* equal pointers */
+ if (a == b) {
+ return 0;
+ }
+
+ /* infinities */
+ if (mpd_isinfinite(a)) {
+ if (mpd_isinfinite(b)) {
+ return 0;
+ }
+ return 1;
+ }
+ if (mpd_isinfinite(b)) {
+ return -1;
+ }
+
+ /* zeros */
+ if (mpd_iszerocoeff(a)) {
+ if (mpd_iszerocoeff(b)) {
+ return 0;
+ }
+ return -1;
+ }
+ if (mpd_iszerocoeff(b)) {
+ return 1;
+ }
+
+ /* different adjusted exponents */
+ adjexp_a = mpd_adjexp(a);
+ adjexp_b = mpd_adjexp(b);
+ if (adjexp_a != adjexp_b) {
+ if (adjexp_a < adjexp_b) {
+ return -1;
+ }
+ return 1;
+ }
+
+ /* same adjusted exponents */
+ return _mpd_cmp_same_adjexp(a, b);
+}
+
+/* Compare two values and return an integer result. */
+int
+mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status)
+{
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_isnan(a) || mpd_isnan(b)) {
+ *status |= MPD_Invalid_operation;
+ return INT_MAX;
+ }
+ }
+
+ return _mpd_cmp(a, b);
+}
+
+/*
+ * Compare a and b, convert the the usual integer result to a decimal and
+ * store it in 'result'. For convenience, the integer result of the comparison
+ * is returned. Comparisons involving NaNs return NaN/INT_MAX.
+ */
+int
+mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return INT_MAX;
+ }
+ }
+
+ c = _mpd_cmp(a, b);
+ _settriple(result, (c < 0), (c != 0), 0);
+ return c;
+}
+
+/* Same as mpd_compare(), but signal for all NaNs, i.e. also for quiet NaNs. */
+int
+mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ *status |= MPD_Invalid_operation;
+ return INT_MAX;
+ }
+ }
+
+ c = _mpd_cmp(a, b);
+ _settriple(result, (c < 0), (c != 0), 0);
+ return c;
+}
+
+/* Compare the operands using a total order. */
+int
+mpd_cmp_total(const mpd_t *a, const mpd_t *b)
+{
+ mpd_t aa, bb;
+ int nan_a, nan_b;
+ int c;
+
+ if (mpd_sign(a) != mpd_sign(b)) {
+ return mpd_sign(b) - mpd_sign(a);
+ }
+
+
+ if (mpd_isnan(a)) {
+ c = 1;
+ if (mpd_isnan(b)) {
+ nan_a = (mpd_isqnan(a)) ? 1 : 0;
+ nan_b = (mpd_isqnan(b)) ? 1 : 0;
+ if (nan_b == nan_a) {
+ if (a->len > 0 && b->len > 0) {
+ _mpd_copy_shared(&aa, a);
+ _mpd_copy_shared(&bb, b);
+ aa.exp = bb.exp = 0;
+ /* compare payload */
+ c = _mpd_cmp_abs(&aa, &bb);
+ }
+ else {
+ c = (a->len > 0) - (b->len > 0);
+ }
+ }
+ else {
+ c = nan_a - nan_b;
+ }
+ }
+ }
+ else if (mpd_isnan(b)) {
+ c = -1;
+ }
+ else {
+ c = _mpd_cmp_abs(a, b);
+ if (c == 0 && a->exp != b->exp) {
+ c = (a->exp < b->exp) ? -1 : 1;
+ }
+ }
+
+ return c * mpd_arith_sign(a);
+}
+
+/*
+ * Compare a and b according to a total order, convert the usual integer result
+ * to a decimal and store it in 'result'. For convenience, the integer result
+ * of the comparison is returned.
+ */
+int
+mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b)
+{
+ int c;
+
+ c = mpd_cmp_total(a, b);
+ _settriple(result, (c < 0), (c != 0), 0);
+ return c;
+}
+
+/* Compare the magnitude of the operands using a total order. */
+int
+mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b)
+{
+ mpd_t aa, bb;
+
+ _mpd_copy_shared(&aa, a);
+ _mpd_copy_shared(&bb, b);
+
+ mpd_set_positive(&aa);
+ mpd_set_positive(&bb);
+
+ return mpd_cmp_total(&aa, &bb);
+}
+
+/*
+ * Compare the magnitude of a and b according to a total order, convert the
+ * the usual integer result to a decimal and store it in 'result'.
+ * For convenience, the integer result of the comparison is returned.
+ */
+int
+mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b)
+{
+ int c;
+
+ c = mpd_cmp_total_mag(a, b);
+ _settriple(result, (c < 0), (c != 0), 0);
+ return c;
+}
+
+/* Determine an ordering for operands that are numerically equal. */
+static inline int
+_mpd_cmp_numequal(const mpd_t *a, const mpd_t *b)
+{
+ int sign_a, sign_b;
+ int c;
+
+ sign_a = mpd_sign(a);
+ sign_b = mpd_sign(b);
+ if (sign_a != sign_b) {
+ c = sign_b - sign_a;
+ }
+ else {
+ c = (a->exp < b->exp) ? -1 : 1;
+ c *= mpd_arith_sign(a);
+ }
+
+ return c;
+}
+
+
+/******************************************************************************/
+/* Shifting the coefficient */
+/******************************************************************************/
+
+/*
+ * Shift the coefficient of the operand to the left, no check for specials.
+ * Both operands may be the same pointer. If the result length has to be
+ * increased, mpd_qresize() might fail with MPD_Malloc_error.
+ */
+int
+mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
+{
+ mpd_ssize_t size;
+
+ assert(n >= 0);
+
+ if (mpd_iszerocoeff(a) || n == 0) {
+ return mpd_qcopy(result, a, status);
+ }
+
+ size = mpd_digits_to_size(a->digits+n);
+ if (!mpd_qresize(result, size, status)) {
+ return 0; /* result is NaN */
+ }
+
+ _mpd_baseshiftl(result->data, a->data, size, a->len, n);
+
+ mpd_copy_flags(result, a);
+ result->len = size;
+ result->exp = a->exp;
+ result->digits = a->digits+n;
+
+ return 1;
+}
+
+/* Determine the rounding indicator if all digits of the coefficient are shifted
+ * out of the picture. */
+static mpd_uint_t
+_mpd_get_rnd(const mpd_uint_t *data, mpd_ssize_t len, int use_msd)
+{
+ mpd_uint_t rnd = 0, rest = 0, word;
+
+ word = data[len-1];
+ /* special treatment for the most significant digit if shift == digits */
+ if (use_msd) {
+ _mpd_divmod_pow10(&rnd, &rest, word, mpd_word_digits(word)-1);
+ if (len > 1 && rest == 0) {
+ rest = !_mpd_isallzero(data, len-1);
+ }
+ }
+ else {
+ rest = !_mpd_isallzero(data, len);
+ }
+
+ return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd;
+}
+
+/*
+ * Same as mpd_qshiftr(), but 'result' is a static array. It is the
+ * caller's responsibility to make sure that the array is big enough.
+ * The function cannot fail.
+ */
+mpd_uint_t
+mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n)
+{
+ mpd_uint_t rnd;
+ mpd_ssize_t size;
+
+ assert(n >= 0);
+
+ if (mpd_iszerocoeff(a) || n == 0) {
+ mpd_qcopy_static(result, a);
+ return 0;
+ }
+
+ if (n >= a->digits) {
+ rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
+ mpd_zerocoeff(result);
+ result->digits = 1;
+ size = 1;
+ }
+ else {
+ result->digits = a->digits-n;
+ size = mpd_digits_to_size(result->digits);
+ rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
+ }
+
+ mpd_copy_flags(result, a);
+ result->exp = a->exp;
+ result->len = size;
+
+ return rnd;
+}
+
+/*
+ * Inplace shift of the coefficient to the right, no check for specials.
+ * Returns the rounding indicator for mpd_rnd_incr().
+ * The function cannot fail.
+ */
+mpd_uint_t
+mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n)
+{
+ uint32_t dummy;
+ mpd_uint_t rnd;
+ mpd_ssize_t size;
+
+ assert(n >= 0);
+
+ if (mpd_iszerocoeff(result) || n == 0) {
+ return 0;
+ }
+
+ if (n >= result->digits) {
+ rnd = _mpd_get_rnd(result->data, result->len, (n==result->digits));
+ mpd_zerocoeff(result);
+ result->digits = 1;
+ size = 1;
+ }
+ else {
+ rnd = _mpd_baseshiftr(result->data, result->data, result->len, n);
+ result->digits -= n;
+ size = mpd_digits_to_size(result->digits);
+ /* reducing the size cannot fail */
+ mpd_qresize(result, size, &dummy);
+ }
+
+ result->len = size;
+
+ return rnd;
+}
+
+/*
+ * Shift the coefficient of the operand to the right, no check for specials.
+ * Both operands may be the same pointer. Returns the rounding indicator to
+ * be used by mpd_rnd_incr(). If the result length has to be increased,
+ * mpd_qcopy() or mpd_qresize() might fail with MPD_Malloc_error. In those
+ * cases, MPD_UINT_MAX is returned.
+ */
+mpd_uint_t
+mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status)
+{
+ mpd_uint_t rnd;
+ mpd_ssize_t size;
+
+ assert(n >= 0);
+
+ if (mpd_iszerocoeff(a) || n == 0) {
+ if (!mpd_qcopy(result, a, status)) {
+ return MPD_UINT_MAX;
+ }
+ return 0;
+ }
+
+ if (n >= a->digits) {
+ rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits));
+ mpd_zerocoeff(result);
+ result->digits = 1;
+ size = 1;
+ }
+ else {
+ result->digits = a->digits-n;
+ size = mpd_digits_to_size(result->digits);
+ if (result == a) {
+ rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
+ /* reducing the size cannot fail */
+ mpd_qresize(result, size, status);
+ }
+ else {
+ if (!mpd_qresize(result, size, status)) {
+ return MPD_UINT_MAX;
+ }
+ rnd = _mpd_baseshiftr(result->data, a->data, a->len, n);
+ }
+ }
+
+ mpd_copy_flags(result, a);
+ result->exp = a->exp;
+ result->len = size;
+
+ return rnd;
+}
+
+
+/******************************************************************************/
+/* Miscellaneous operations */
+/******************************************************************************/
+
+/* Logical And */
+void
+mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ const mpd_t *big = a, *small = b;
+ mpd_uint_t x, y, z, xbit, ybit;
+ int k, mswdigits;
+ mpd_ssize_t i;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b) ||
+ mpd_isnegative(a) || mpd_isnegative(b) ||
+ a->exp != 0 || b->exp != 0) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (b->digits > a->digits) {
+ big = b;
+ small = a;
+ }
+ if (!mpd_qresize(result, big->len, status)) {
+ return;
+ }
+
+
+ /* full words */
+ for (i = 0; i < small->len-1; i++) {
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit&ybit) ? mpd_pow10[k] : 0;
+ }
+ result->data[i] = z;
+ }
+ /* most significant word of small */
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ mswdigits = mpd_word_digits(x);
+ for (k = 0; k < mswdigits; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit&ybit) ? mpd_pow10[k] : 0;
+ }
+ result->data[i++] = z;
+
+ /* scan the rest of y for digit > 1 */
+ for (; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ }
+ /* scan the rest of big for digit > 1 */
+ for (; i < big->len; i++) {
+ y = big->data[i];
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ }
+ }
+
+ mpd_clear_flags(result);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, small->len);
+ mpd_qresize(result, result->len, status);
+ mpd_setdigits(result);
+ _mpd_cap(result, ctx);
+ return;
+
+invalid_operation:
+ mpd_seterror(result, MPD_Invalid_operation, status);
+}
+
+/* Class of an operand. Returns a pointer to the constant name. */
+const char *
+mpd_class(const mpd_t *a, const mpd_context_t *ctx)
+{
+ if (mpd_isnan(a)) {
+ if (mpd_isqnan(a))
+ return "NaN";
+ else
+ return "sNaN";
+ }
+ else if (mpd_ispositive(a)) {
+ if (mpd_isinfinite(a))
+ return "+Infinity";
+ else if (mpd_iszero(a))
+ return "+Zero";
+ else if (mpd_isnormal(a, ctx))
+ return "+Normal";
+ else
+ return "+Subnormal";
+ }
+ else {
+ if (mpd_isinfinite(a))
+ return "-Infinity";
+ else if (mpd_iszero(a))
+ return "-Zero";
+ else if (mpd_isnormal(a, ctx))
+ return "-Normal";
+ else
+ return "-Subnormal";
+ }
+}
+
+/* Logical Xor */
+void
+mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_uint_t x, z, xbit;
+ mpd_ssize_t i, digits, len;
+ mpd_ssize_t q, r;
+ int k;
+
+ if (mpd_isspecial(a) || mpd_isnegative(a) || a->exp != 0) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ digits = (a->digits < ctx->prec) ? ctx->prec : a->digits;
+ _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS);
+ len = (r == 0) ? q : q+1;
+ if (!mpd_qresize(result, len, status)) {
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ x = (i < a->len) ? a->data[i] : 0;
+ z = 0;
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ xbit = x % 10;
+ x /= 10;
+ if (xbit > 1) {
+ goto invalid_operation;
+ }
+ z += !xbit ? mpd_pow10[k] : 0;
+ }
+ result->data[i] = z;
+ }
+
+ mpd_clear_flags(result);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, len);
+ mpd_qresize(result, result->len, status);
+ mpd_setdigits(result);
+ _mpd_cap(result, ctx);
+ return;
+
+invalid_operation:
+ mpd_seterror(result, MPD_Invalid_operation, status);
+}
+
+/* Exponent of the magnitude of the most significant digit of the operand. */
+void
+mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ }
+ else if (mpd_iszerocoeff(a)) {
+ mpd_setspecial(result, MPD_NEG, MPD_INF);
+ *status |= MPD_Division_by_zero;
+ }
+ else {
+ mpd_qset_ssize(result, mpd_adjexp(a), ctx, status);
+ }
+}
+
+/* Logical Or */
+void
+mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ const mpd_t *big = a, *small = b;
+ mpd_uint_t x, y, z, xbit, ybit;
+ int k, mswdigits;
+ mpd_ssize_t i;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b) ||
+ mpd_isnegative(a) || mpd_isnegative(b) ||
+ a->exp != 0 || b->exp != 0) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (b->digits > a->digits) {
+ big = b;
+ small = a;
+ }
+ if (!mpd_qresize(result, big->len, status)) {
+ return;
+ }
+
+
+ /* full words */
+ for (i = 0; i < small->len-1; i++) {
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit|ybit) ? mpd_pow10[k] : 0;
+ }
+ result->data[i] = z;
+ }
+ /* most significant word of small */
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ mswdigits = mpd_word_digits(x);
+ for (k = 0; k < mswdigits; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit|ybit) ? mpd_pow10[k] : 0;
+ }
+
+ /* scan and copy the rest of y for digit > 1 */
+ for (; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ z += ybit*mpd_pow10[k];
+ }
+ result->data[i++] = z;
+ /* scan and copy the rest of big for digit > 1 */
+ for (; i < big->len; i++) {
+ y = big->data[i];
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ }
+ result->data[i] = big->data[i];
+ }
+
+ mpd_clear_flags(result);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, big->len);
+ mpd_qresize(result, result->len, status);
+ mpd_setdigits(result);
+ _mpd_cap(result, ctx);
+ return;
+
+invalid_operation:
+ mpd_seterror(result, MPD_Invalid_operation, status);
+}
+
+/*
+ * Rotate the coefficient of a by b->data digits. b must be an integer with
+ * exponent 0.
+ */
+void
+mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ MPD_NEW_STATIC(tmp,0,0,0,0);
+ MPD_NEW_STATIC(big,0,0,0,0);
+ MPD_NEW_STATIC(small,0,0,0,0);
+ mpd_ssize_t n, lshift, rshift;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ }
+ if (b->exp != 0 || mpd_isinfinite(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ n = mpd_qget_ssize(b, &workstatus);
+ if (workstatus&MPD_Invalid_operation) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (n > ctx->prec || n < -ctx->prec) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+ if (n >= 0) {
+ lshift = n;
+ rshift = ctx->prec-n;
+ }
+ else {
+ lshift = ctx->prec+n;
+ rshift = -n;
+ }
+
+ if (a->digits > ctx->prec) {
+ if (!mpd_qcopy(&tmp, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+ _mpd_cap(&tmp, ctx);
+ a = &tmp;
+ }
+
+ if (!mpd_qshiftl(&big, a, lshift, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+ _mpd_cap(&big, ctx);
+
+ if (mpd_qshiftr(&small, a, rshift, status) == MPD_UINT_MAX) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+ _mpd_qadd(result, &big, &small, ctx, status);
+
+
+finish:
+ mpd_del(&tmp);
+ mpd_del(&big);
+ mpd_del(&small);
+}
+
+/*
+ * b must be an integer with exponent 0 and in the range +-2*(emax + prec).
+ * XXX: In my opinion +-(2*emax + prec) would be more sensible.
+ * The result is a with the value of b added to its exponent.
+ */
+void
+mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_uint_t n, maxjump;
+#ifndef LEGACY_COMPILER
+ int64_t exp;
+#else
+ mpd_uint_t x;
+ int x_sign, n_sign;
+ mpd_ssize_t exp;
+#endif
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ }
+ if (b->exp != 0 || mpd_isinfinite(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ n = mpd_qabs_uint(b, &workstatus);
+ /* the spec demands this */
+ maxjump = 2 * (mpd_uint_t)(ctx->emax + ctx->prec);
+
+ if (n > maxjump || workstatus&MPD_Invalid_operation) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+#ifndef LEGACY_COMPILER
+ exp = a->exp + (int64_t)n * mpd_arith_sign(b);
+ exp = (exp > MPD_EXP_INF) ? MPD_EXP_INF : exp;
+ exp = (exp < MPD_EXP_CLAMP) ? MPD_EXP_CLAMP : exp;
+#else
+ x = (a->exp < 0) ? -a->exp : a->exp;
+ x_sign = (a->exp < 0) ? 1 : 0;
+ n_sign = mpd_isnegative(b) ? 1 : 0;
+
+ if (x_sign == n_sign) {
+ x = x + n;
+ if (x < n) x = MPD_UINT_MAX;
+ }
+ else {
+ x_sign = (x >= n) ? x_sign : n_sign;
+ x = (x >= n) ? x - n : n - x;
+ }
+ if (!x_sign && x > MPD_EXP_INF) x = MPD_EXP_INF;
+ if (x_sign && x > -MPD_EXP_CLAMP) x = -MPD_EXP_CLAMP;
+ exp = x_sign ? -((mpd_ssize_t)x) : (mpd_ssize_t)x;
+#endif
+
+ mpd_qcopy(result, a, status);
+ result->exp = (mpd_ssize_t)exp;
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/*
+ * Shift the coefficient by n digits, positive n is a left shift. In the case
+ * of a left shift, the result is decapitated to fit the context precision. If
+ * you don't want that, use mpd_shiftl().
+ */
+void
+mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+ if (n >= 0 && n <= ctx->prec) {
+ mpd_qshiftl(result, a, n, status);
+ _mpd_cap(result, ctx);
+ }
+ else if (n < 0 && n >= -ctx->prec) {
+ if (!mpd_qcopy(result, a, status)) {
+ return;
+ }
+ _mpd_cap(result, ctx);
+ mpd_qshiftr_inplace(result, -n);
+ }
+ else {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ }
+}
+
+/*
+ * Same as mpd_shiftn(), but the shift is specified by the decimal b, which
+ * must be an integer with a zero exponent. Infinities remain infinities.
+ */
+void
+mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_ssize_t n;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ }
+ if (b->exp != 0 || mpd_isinfinite(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ n = mpd_qget_ssize(b, &workstatus);
+ if (workstatus&MPD_Invalid_operation) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (n > ctx->prec || n < -ctx->prec) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+ if (n >= 0) {
+ mpd_qshiftl(result, a, n, status);
+ _mpd_cap(result, ctx);
+ }
+ else {
+ if (!mpd_qcopy(result, a, status)) {
+ return;
+ }
+ _mpd_cap(result, ctx);
+ mpd_qshiftr_inplace(result, -n);
+ }
+}
+
+/* Logical Xor */
+void
+mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ const mpd_t *big = a, *small = b;
+ mpd_uint_t x, y, z, xbit, ybit;
+ int k, mswdigits;
+ mpd_ssize_t i;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b) ||
+ mpd_isnegative(a) || mpd_isnegative(b) ||
+ a->exp != 0 || b->exp != 0) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (b->digits > a->digits) {
+ big = b;
+ small = a;
+ }
+ if (!mpd_qresize(result, big->len, status)) {
+ return;
+ }
+
+
+ /* full words */
+ for (i = 0; i < small->len-1; i++) {
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit^ybit) ? mpd_pow10[k] : 0;
+ }
+ result->data[i] = z;
+ }
+ /* most significant word of small */
+ x = small->data[i];
+ y = big->data[i];
+ z = 0;
+ mswdigits = mpd_word_digits(x);
+ for (k = 0; k < mswdigits; k++) {
+ xbit = x % 10;
+ x /= 10;
+ ybit = y % 10;
+ y /= 10;
+ if (xbit > 1 || ybit > 1) {
+ goto invalid_operation;
+ }
+ z += (xbit^ybit) ? mpd_pow10[k] : 0;
+ }
+
+ /* scan and copy the rest of y for digit > 1 */
+ for (; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ z += ybit*mpd_pow10[k];
+ }
+ result->data[i++] = z;
+ /* scan and copy the rest of big for digit > 1 */
+ for (; i < big->len; i++) {
+ y = big->data[i];
+ for (k = 0; k < MPD_RDIGITS; k++) {
+ ybit = y % 10;
+ y /= 10;
+ if (ybit > 1) {
+ goto invalid_operation;
+ }
+ }
+ result->data[i] = big->data[i];
+ }
+
+ mpd_clear_flags(result);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, big->len);
+ mpd_qresize(result, result->len, status);
+ mpd_setdigits(result);
+ _mpd_cap(result, ctx);
+ return;
+
+invalid_operation:
+ mpd_seterror(result, MPD_Invalid_operation, status);
+}
+
+
+/******************************************************************************/
+/* Arithmetic operations */
+/******************************************************************************/
+
+/*
+ * The absolute value of a. If a is negative, the result is the same
+ * as the result of the minus operation. Otherwise, the result is the
+ * result of the plus operation.
+ */
+void
+mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ }
+
+ if (mpd_isnegative(a)) {
+ mpd_qminus(result, a, ctx, status);
+ }
+ else {
+ mpd_qplus(result, a, ctx, status);
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+static inline void
+_mpd_ptrswap(mpd_t **a, mpd_t **b)
+{
+ mpd_t *t = *a;
+ *a = *b;
+ *b = t;
+}
+
+/* Add or subtract infinities. */
+static void
+_mpd_qaddsub_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
+ uint32_t *status)
+{
+ if (mpd_isinfinite(a)) {
+ if (mpd_sign(a) != sign_b && mpd_isinfinite(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ }
+ else {
+ mpd_setspecial(result, mpd_sign(a), MPD_INF);
+ }
+ return;
+ }
+ assert(mpd_isinfinite(b));
+ mpd_setspecial(result, sign_b, MPD_INF);
+}
+
+/* Add or subtract non-special numbers. */
+static void
+_mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_t *big, *small;
+ MPD_NEW_STATIC(big_aligned,0,0,0,0);
+ MPD_NEW_CONST(tiny,0,0,0,1,1,1);
+ mpd_uint_t carry;
+ mpd_ssize_t newsize, shift;
+ mpd_ssize_t exp, i;
+ int swap = 0;
+
+
+ /* compare exponents */
+ big = (mpd_t *)a; small = (mpd_t *)b;
+ if (big->exp != small->exp) {
+ if (small->exp > big->exp) {
+ _mpd_ptrswap(&big, &small);
+ swap++;
+ }
+ if (!mpd_iszerocoeff(big)) {
+ /* Test for adjexp(small) + big->digits < adjexp(big), if big-digits > prec
+ * Test for adjexp(small) + prec + 1 < adjexp(big), if big-digits <= prec
+ * If true, the magnitudes of the numbers are so far apart that one can as
+ * well add or subtract 1*10**big->exp. */
+ exp = big->exp - 1;
+ exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1;
+ if (mpd_adjexp(small) < exp) {
+ mpd_copy_flags(&tiny, small);
+ tiny.exp = exp;
+ tiny.digits = 1;
+ tiny.len = 1;
+ tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1;
+ small = &tiny;
+ }
+ /* this cannot wrap: the difference is positive and <= maxprec+1 */
+ shift = big->exp - small->exp;
+ if (!mpd_qshiftl(&big_aligned, big, shift, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+ big = &big_aligned;
+ }
+ }
+ result->exp = small->exp;
+
+
+ /* compare length of coefficients */
+ if (big->len < small->len) {
+ _mpd_ptrswap(&big, &small);
+ swap++;
+ }
+
+ newsize = big->len;
+ if (!mpd_qresize(result, newsize, status)) {
+ goto finish;
+ }
+
+ if (mpd_sign(a) == sign_b) {
+
+ carry = _mpd_baseadd(result->data, big->data, small->data,
+ big->len, small->len);
+
+ if (carry) {
+ newsize = big->len + 1;
+ if (!mpd_qresize(result, newsize, status)) {
+ goto finish;
+ }
+ result->data[newsize-1] = carry;
+ }
+
+ result->len = newsize;
+ mpd_set_flags(result, sign_b);
+ }
+ else {
+ if (big->len == small->len) {
+ for (i=big->len-1; i >= 0; --i) {
+ if (big->data[i] != small->data[i]) {
+ if (big->data[i] < small->data[i]) {
+ _mpd_ptrswap(&big, &small);
+ swap++;
+ }
+ break;
+ }
+ }
+ }
+
+ _mpd_basesub(result->data, big->data, small->data,
+ big->len, small->len);
+ newsize = _mpd_real_size(result->data, big->len);
+ /* resize to smaller cannot fail */
+ (void)mpd_qresize(result, newsize, status);
+
+ result->len = newsize;
+ sign_b = (swap & 1) ? sign_b : mpd_sign(a);
+ mpd_set_flags(result, sign_b);
+
+ if (mpd_iszerocoeff(result)) {
+ mpd_set_positive(result);
+ if (ctx->round == MPD_ROUND_FLOOR) {
+ mpd_set_negative(result);
+ }
+ }
+ }
+
+ mpd_setdigits(result);
+
+finish:
+ mpd_del(&big_aligned);
+}
+
+/* Add a and b. No specials, no finalizing. */
+static void
+_mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
+}
+
+/* Subtract b from a. No specials, no finalizing. */
+static void
+_mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
+}
+
+/* Add a and b. */
+void
+mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ _mpd_qaddsub_inf(result, a, b, mpd_sign(b), status);
+ return;
+ }
+
+ _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* Subtract b from a. */
+void
+mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ _mpd_qaddsub_inf(result, a, b, !mpd_sign(b), status);
+ return;
+ }
+
+ _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* Add decimal and mpd_ssize_t. */
+void
+mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_ssize(&bb, b, &maxcontext, status);
+ mpd_qadd(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Add decimal and mpd_uint_t. */
+void
+mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_uint(&bb, b, &maxcontext, status);
+ mpd_qadd(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Subtract mpd_ssize_t from decimal. */
+void
+mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_ssize(&bb, b, &maxcontext, status);
+ mpd_qsub(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Subtract mpd_uint_t from decimal. */
+void
+mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_uint(&bb, b, &maxcontext, status);
+ mpd_qsub(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Add decimal and int32_t. */
+void
+mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qadd_ssize(result, a, b, ctx, status);
+}
+
+/* Add decimal and uint32_t. */
+void
+mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qadd_uint(result, a, b, ctx, status);
+}
+
+#ifdef CONFIG_64
+/* Add decimal and int64_t. */
+void
+mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qadd_ssize(result, a, b, ctx, status);
+}
+
+/* Add decimal and uint64_t. */
+void
+mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qadd_uint(result, a, b, ctx, status);
+}
+#endif
+
+/* Subtract int32_t from decimal. */
+void
+mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qsub_ssize(result, a, b, ctx, status);
+}
+
+/* Subtract uint32_t from decimal. */
+void
+mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qsub_uint(result, a, b, ctx, status);
+}
+
+#ifdef CONFIG_64
+/* Subtract int64_t from decimal. */
+void
+mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qsub_ssize(result, a, b, ctx, status);
+}
+
+/* Subtract uint64_t from decimal. */
+void
+mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qsub_uint(result, a, b, ctx, status);
+}
+#endif
+
+
+/* Divide infinities. */
+static void
+_mpd_qdiv_inf(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if (mpd_isinfinite(a)) {
+ if (mpd_isinfinite(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
+ return;
+ }
+ assert(mpd_isinfinite(b));
+ _settriple(result, mpd_sign(a)^mpd_sign(b), 0, mpd_etiny(ctx));
+ *status |= MPD_Clamped;
+}
+
+enum {NO_IDEAL_EXP, SET_IDEAL_EXP};
+/* Divide a by b. */
+static void
+_mpd_qdiv(int action, mpd_t *q, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ MPD_NEW_STATIC(aligned,0,0,0,0);
+ mpd_uint_t ld;
+ mpd_ssize_t shift, exp, tz;
+ mpd_ssize_t newsize;
+ mpd_ssize_t ideal_exp;
+ mpd_uint_t rem;
+ uint8_t sign_a = mpd_sign(a);
+ uint8_t sign_b = mpd_sign(b);
+
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(q, a, b, ctx, status)) {
+ return;
+ }
+ _mpd_qdiv_inf(q, a, b, ctx, status);
+ return;
+ }
+ if (mpd_iszerocoeff(b)) {
+ if (mpd_iszerocoeff(a)) {
+ mpd_seterror(q, MPD_Division_undefined, status);
+ }
+ else {
+ mpd_setspecial(q, sign_a^sign_b, MPD_INF);
+ *status |= MPD_Division_by_zero;
+ }
+ return;
+ }
+ if (mpd_iszerocoeff(a)) {
+ exp = a->exp - b->exp;
+ _settriple(q, sign_a^sign_b, 0, exp);
+ mpd_qfinalize(q, ctx, status);
+ return;
+ }
+
+ shift = (b->digits - a->digits) + ctx->prec + 1;
+ ideal_exp = a->exp - b->exp;
+ exp = ideal_exp - shift;
+ if (shift > 0) {
+ if (!mpd_qshiftl(&aligned, a, shift, status)) {
+ mpd_seterror(q, MPD_Malloc_error, status);
+ goto finish;
+ }
+ a = &aligned;
+ }
+ else if (shift < 0) {
+ shift = -shift;
+ if (!mpd_qshiftl(&aligned, b, shift, status)) {
+ mpd_seterror(q, MPD_Malloc_error, status);
+ goto finish;
+ }
+ b = &aligned;
+ }
+
+
+ newsize = a->len - b->len + 1;
+ if ((q != b && q != a) || (q == b && newsize > b->len)) {
+ if (!mpd_qresize(q, newsize, status)) {
+ mpd_seterror(q, MPD_Malloc_error, status);
+ goto finish;
+ }
+ }
+
+
+ if (b->len == 1) {
+ rem = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
+ }
+ else if (a->len < 2*MPD_NEWTONDIV_CUTOFF &&
+ b->len < MPD_NEWTONDIV_CUTOFF) {
+ int ret = _mpd_basedivmod(q->data, NULL, a->data, b->data,
+ a->len, b->len);
+ if (ret < 0) {
+ mpd_seterror(q, MPD_Malloc_error, status);
+ goto finish;
+ }
+ rem = ret;
+ }
+ else {
+ MPD_NEW_STATIC(r,0,0,0,0);
+ _mpd_qbarrett_divmod(q, &r, a, b, status);
+ if (mpd_isspecial(q) || mpd_isspecial(&r)) {
+ mpd_del(&r);
+ goto finish;
+ }
+ rem = !mpd_iszerocoeff(&r);
+ mpd_del(&r);
+ newsize = q->len;
+ }
+
+ newsize = _mpd_real_size(q->data, newsize);
+ /* resize to smaller cannot fail */
+ mpd_qresize(q, newsize, status);
+ q->len = newsize;
+ mpd_setdigits(q);
+
+ shift = ideal_exp - exp;
+ if (rem) {
+ ld = mpd_lsd(q->data[0]);
+ if (ld == 0 || ld == 5) {
+ q->data[0] += 1;
+ }
+ }
+ else if (action == SET_IDEAL_EXP && shift > 0) {
+ tz = mpd_trail_zeros(q);
+ shift = (tz > shift) ? shift : tz;
+ mpd_qshiftr_inplace(q, shift);
+ exp += shift;
+ }
+
+ mpd_set_flags(q, sign_a^sign_b);
+ q->exp = exp;
+
+
+finish:
+ mpd_del(&aligned);
+ mpd_qfinalize(q, ctx, status);
+}
+
+/* Divide a by b. */
+void
+mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ _mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, status);
+}
+
+/* Internal function. */
+static void
+_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ MPD_NEW_STATIC(aligned,0,0,0,0);
+ mpd_ssize_t qsize, rsize;
+ mpd_ssize_t ideal_exp, expdiff, shift;
+ uint8_t sign_a = mpd_sign(a);
+ uint8_t sign_ab = mpd_sign(a)^mpd_sign(b);
+
+
+ ideal_exp = (a->exp > b->exp) ? b->exp : a->exp;
+ if (mpd_iszerocoeff(a)) {
+ if (!mpd_qcopy(r, a, status)) {
+ goto nanresult; /* GCOV_NOT_REACHED */
+ }
+ r->exp = ideal_exp;
+ _settriple(q, sign_ab, 0, 0);
+ return;
+ }
+
+ expdiff = mpd_adjexp(a) - mpd_adjexp(b);
+ if (expdiff < 0) {
+ if (a->exp > b->exp) {
+ /* positive and less than b->digits - a->digits */
+ shift = a->exp - b->exp;
+ if (!mpd_qshiftl(r, a, shift, status)) {
+ goto nanresult;
+ }
+ r->exp = ideal_exp;
+ }
+ else {
+ if (!mpd_qcopy(r, a, status)) {
+ goto nanresult;
+ }
+ }
+ _settriple(q, sign_ab, 0, 0);
+ return;
+ }
+ if (expdiff > ctx->prec) {
+ *status |= MPD_Division_impossible;
+ goto nanresult;
+ }
+
+
+ /*
+ * At this point we have:
+ * (1) 0 <= a->exp + a->digits - b->exp - b->digits <= prec
+ * (2) a->exp - b->exp >= b->digits - a->digits
+ * (3) a->exp - b->exp <= prec + b->digits - a->digits
+ */
+ if (a->exp != b->exp) {
+ shift = a->exp - b->exp;
+ if (shift > 0) {
+ /* by (3), after the shift a->digits <= prec + b->digits */
+ if (!mpd_qshiftl(&aligned, a, shift, status)) {
+ goto nanresult;
+ }
+ a = &aligned;
+ }
+ else {
+ shift = -shift;
+ /* by (2), after the shift b->digits <= a->digits */
+ if (!mpd_qshiftl(&aligned, b, shift, status)) {
+ goto nanresult;
+ }
+ b = &aligned;
+ }
+ }
+
+
+ qsize = a->len - b->len + 1;
+ if (!(q == a && qsize < a->len) && !(q == b && qsize < b->len)) {
+ if (!mpd_qresize(q, qsize, status)) {
+ goto nanresult;
+ }
+ }
+
+ rsize = b->len;
+ if (!(r == a && rsize < a->len)) {
+ if (!mpd_qresize(r, rsize, status)) {
+ goto nanresult;
+ }
+ }
+
+ if (b->len == 1) {
+ if (a->len == 1) {
+ _mpd_div_word(&q->data[0], &r->data[0], a->data[0], b->data[0]);
+ }
+ else {
+ r->data[0] = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]);
+ }
+ }
+ else if (a->len < 2*MPD_NEWTONDIV_CUTOFF &&
+ b->len < MPD_NEWTONDIV_CUTOFF) {
+ int ret;
+ ret = _mpd_basedivmod(q->data, r->data, a->data, b->data,
+ a->len, b->len);
+ if (ret == -1) {
+ *status |= MPD_Malloc_error;
+ goto nanresult;
+ }
+ }
+ else {
+ _mpd_qbarrett_divmod(q, r, a, b, status);
+ if (mpd_isspecial(q) || mpd_isspecial(r)) {
+ goto nanresult;
+ }
+ if (mpd_isinfinite(q) || q->digits > ctx->prec) {
+ *status |= MPD_Division_impossible;
+ goto nanresult;
+ }
+ qsize = q->len;
+ rsize = r->len;
+ }
+
+ qsize = _mpd_real_size(q->data, qsize);
+ /* resize to smaller cannot fail */
+ mpd_qresize(q, qsize, status);
+ q->len = qsize;
+ mpd_setdigits(q);
+ mpd_set_flags(q, sign_ab);
+ q->exp = 0;
+ if (q->digits > ctx->prec) {
+ *status |= MPD_Division_impossible;
+ goto nanresult;
+ }
+
+ rsize = _mpd_real_size(r->data, rsize);
+ /* resize to smaller cannot fail */
+ mpd_qresize(r, rsize, status);
+ r->len = rsize;
+ mpd_setdigits(r);
+ mpd_set_flags(r, sign_a);
+ r->exp = ideal_exp;
+
+out:
+ mpd_del(&aligned);
+ return;
+
+nanresult:
+ mpd_setspecial(q, MPD_POS, MPD_NAN);
+ mpd_setspecial(r, MPD_POS, MPD_NAN);
+ goto out;
+}
+
+/* Integer division with remainder. */
+void
+mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint8_t sign = mpd_sign(a)^mpd_sign(b);
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(q, a, b, ctx, status)) {
+ mpd_qcopy(r, q, status);
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ if (mpd_isinfinite(b)) {
+ mpd_setspecial(q, MPD_POS, MPD_NAN);
+ }
+ else {
+ mpd_setspecial(q, sign, MPD_INF);
+ }
+ mpd_setspecial(r, MPD_POS, MPD_NAN);
+ *status |= MPD_Invalid_operation;
+ return;
+ }
+ if (mpd_isinfinite(b)) {
+ if (!mpd_qcopy(r, a, status)) {
+ mpd_seterror(q, MPD_Malloc_error, status);
+ return;
+ }
+ mpd_qfinalize(r, ctx, status);
+ _settriple(q, sign, 0, 0);
+ return;
+ }
+ /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+ if (mpd_iszerocoeff(b)) {
+ if (mpd_iszerocoeff(a)) {
+ mpd_setspecial(q, MPD_POS, MPD_NAN);
+ mpd_setspecial(r, MPD_POS, MPD_NAN);
+ *status |= MPD_Division_undefined;
+ }
+ else {
+ mpd_setspecial(q, sign, MPD_INF);
+ mpd_setspecial(r, MPD_POS, MPD_NAN);
+ *status |= (MPD_Division_by_zero|MPD_Invalid_operation);
+ }
+ return;
+ }
+
+ _mpd_qdivmod(q, r, a, b, ctx, status);
+ mpd_qfinalize(q, ctx, status);
+ mpd_qfinalize(r, ctx, status);
+}
+
+void
+mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ MPD_NEW_STATIC(r,0,0,0,0);
+ uint8_t sign = mpd_sign(a)^mpd_sign(b);
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(q, a, b, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
+ mpd_seterror(q, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_setspecial(q, sign, MPD_INF);
+ return;
+ }
+ if (mpd_isinfinite(b)) {
+ _settriple(q, sign, 0, 0);
+ return;
+ }
+ /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+ if (mpd_iszerocoeff(b)) {
+ if (mpd_iszerocoeff(a)) {
+ mpd_seterror(q, MPD_Division_undefined, status);
+ }
+ else {
+ mpd_setspecial(q, sign, MPD_INF);
+ *status |= MPD_Division_by_zero;
+ }
+ return;
+ }
+
+
+ _mpd_qdivmod(q, &r, a, b, ctx, status);
+ mpd_del(&r);
+ mpd_qfinalize(q, ctx, status);
+}
+
+/* Divide decimal by mpd_ssize_t. */
+void
+mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_ssize(&bb, b, &maxcontext, status);
+ mpd_qdiv(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Divide decimal by mpd_uint_t. */
+void
+mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_uint(&bb, b, &maxcontext, status);
+ mpd_qdiv(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Divide decimal by int32_t. */
+void
+mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qdiv_ssize(result, a, b, ctx, status);
+}
+
+/* Divide decimal by uint32_t. */
+void
+mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qdiv_uint(result, a, b, ctx, status);
+}
+
+#ifdef CONFIG_64
+/* Divide decimal by int64_t. */
+void
+mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qdiv_ssize(result, a, b, ctx, status);
+}
+
+/* Divide decimal by uint64_t. */
+void
+mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qdiv_uint(result, a, b, ctx, status);
+}
+#endif
+
+#if defined(_MSC_VER)
+ /* conversion from 'double' to 'mpd_ssize_t', possible loss of data */
+ #pragma warning(disable:4244)
+#endif
+/*
+ * Get the number of iterations for the Horner scheme in _mpd_qexp().
+ */
+static inline mpd_ssize_t
+_mpd_get_exp_iterations(const mpd_t *a, mpd_ssize_t prec)
+{
+ mpd_uint_t dummy;
+ mpd_uint_t msdigits;
+ double f;
+
+ /* 9 is MPD_RDIGITS for 32 bit platforms */
+ _mpd_get_msdigits(&dummy, &msdigits, a, 9);
+ f = ((double)msdigits + 1) / mpd_pow10[mpd_word_digits(msdigits)];
+
+#ifdef CONFIG_64
+ #ifdef USE_80BIT_LONG_DOUBLE
+ return ceill((1.435*(long double)prec - 1.182)
+ / log10l((long double)prec/f));
+ #else
+ /* prec > floor((1ULL<<53) / 1.435) */
+ if (prec > 6276793905742851LL) {
+ return MPD_SSIZE_MAX;
+ }
+ return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f));
+ #endif
+#else /* CONFIG_32 */
+ return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f));
+ #if defined(_MSC_VER)
+ #pragma warning(default:4244)
+ #endif
+#endif
+}
+
+/*
+ * Internal function, specials have been dealt with.
+ *
+ * The algorithm is from Hull&Abrham, Variable Precision Exponential Function,
+ * ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986.
+ *
+ * Main differences:
+ *
+ * - The number of iterations for the Horner scheme is calculated using the
+ * C log10() function.
+ *
+ * - The analysis for early abortion has been adapted for the mpd_t
+ * ranges.
+ */
+static void
+_mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_STATIC(tmp,0,0,0,0);
+ MPD_NEW_STATIC(sum,0,0,0,0);
+ MPD_NEW_CONST(word,0,0,0,1,1,1);
+ mpd_ssize_t j, n, t;
+
+ assert(!mpd_isspecial(a));
+
+ /*
+ * We are calculating e^x = e^(r*10^t) = (e^r)^(10^t), where r < 1 and t >= 0.
+ *
+ * If t > 0, we have:
+ *
+ * (1) 0.1 <= r < 1, so e^r >= e^0.1. Overflow in the final power operation
+ * will occur when (e^0.1)^(10^t) > 10^(emax+1). If we consider MAX_EMAX,
+ * this will happen for t > 10 (32 bit) or (t > 19) (64 bit).
+ *
+ * (2) -1 < r <= -0.1, so e^r > e^-1. Underflow in the final power operation
+ * will occur when (e^-1)^(10^t) < 10^(etiny-1). If we consider MIN_ETINY,
+ * this will also happen for t > 10 (32 bit) or (t > 19) (64 bit).
+ */
+#if defined(CONFIG_64)
+ #define MPD_EXP_MAX_T 19
+#elif defined(CONFIG_32)
+ #define MPD_EXP_MAX_T 10
+#endif
+ t = a->digits + a->exp;
+ t = (t > 0) ? t : 0;
+ if (t > MPD_EXP_MAX_T) {
+ if (mpd_ispositive(a)) {
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
+ }
+ else {
+ _settriple(result, MPD_POS, 0, mpd_etiny(ctx));
+ *status |= (MPD_Inexact|MPD_Rounded|MPD_Subnormal|
+ MPD_Underflow|MPD_Clamped);
+ }
+ return;
+ }
+
+ mpd_maxcontext(&workctx);
+ workctx.prec = ctx->prec + t + 2;
+ workctx.prec = (workctx.prec < 9) ? 9 : workctx.prec;
+ workctx.round = MPD_ROUND_HALF_EVEN;
+
+ if ((n = _mpd_get_exp_iterations(a, workctx.prec)) == MPD_SSIZE_MAX) {
+ mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_UNLIKELY */
+ goto finish; /* GCOV_UNLIKELY */
+ }
+
+ if (!mpd_qcopy(result, a, status)) {
+ goto finish;
+ }
+ result->exp -= t;
+
+ _settriple(&sum, MPD_POS, 1, 0);
+
+ for (j = n-1; j >= 1; j--) {
+ word.data[0] = j;
+ mpd_setdigits(&word);
+ mpd_qdiv(&tmp, result, &word, &workctx, &workctx.status);
+ mpd_qmul(&sum, &sum, &tmp, &workctx, &workctx.status);
+ mpd_qadd(&sum, &sum, &one, &workctx, &workctx.status);
+ }
+
+#ifdef CONFIG_64
+ _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status);
+#else
+ if (t <= MPD_MAX_POW10) {
+ _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status);
+ }
+ else {
+ t -= MPD_MAX_POW10;
+ _mpd_qpow_uint(&tmp, &sum, mpd_pow10[MPD_MAX_POW10], MPD_POS,
+ &workctx, status);
+ _mpd_qpow_uint(result, &tmp, mpd_pow10[t], MPD_POS, &workctx, status);
+ }
+#endif
+
+
+finish:
+ mpd_del(&tmp);
+ mpd_del(&sum);
+ *status |= (workctx.status&MPD_Errors);
+ *status |= (MPD_Inexact|MPD_Rounded);
+}
+
+/* exp(a) */
+void
+mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ _settriple(result, MPD_POS, 0, 0);
+ }
+ else {
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ }
+ return;
+ }
+ if (mpd_iszerocoeff(a)) {
+ _settriple(result, MPD_POS, 1, 0);
+ return;
+ }
+
+ workctx = *ctx;
+ workctx.round = MPD_ROUND_HALF_EVEN;
+
+ if (ctx->allcr) {
+ MPD_NEW_STATIC(t1, 0,0,0,0);
+ MPD_NEW_STATIC(t2, 0,0,0,0);
+ MPD_NEW_STATIC(ulp, 0,0,0,0);
+ MPD_NEW_STATIC(aa, 0,0,0,0);
+ mpd_ssize_t prec;
+
+ if (result == a) {
+ if (!mpd_qcopy(&aa, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ a = &aa;
+ }
+
+ workctx.clamp = 0;
+ prec = ctx->prec + 3;
+ while (1) {
+ workctx.prec = prec;
+ _mpd_qexp(result, a, &workctx, status);
+ _ssettriple(&ulp, MPD_POS, 1,
+ result->exp + result->digits-workctx.prec-1);
+
+ workctx.prec = ctx->prec;
+ mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
+ mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
+ if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
+ mpd_qcmp(&t1, &t2, status) == 0) {
+ workctx.clamp = ctx->clamp;
+ mpd_check_underflow(result, &workctx, status);
+ mpd_qfinalize(result, &workctx, status);
+ break;
+ }
+ prec += MPD_RDIGITS;
+ }
+ mpd_del(&t1);
+ mpd_del(&t2);
+ mpd_del(&ulp);
+ mpd_del(&aa);
+ }
+ else {
+ _mpd_qexp(result, a, &workctx, status);
+ mpd_check_underflow(result, &workctx, status);
+ mpd_qfinalize(result, &workctx, status);
+ }
+}
+
+/* Fused multiply-add: (a * b) + c, with a single final rounding. */
+void
+mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_t *cc = (mpd_t *)c;
+
+ if (result == c) {
+ if ((cc = mpd_qncopy(c)) == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ }
+
+ _mpd_qmul(result, a, b, ctx, &workstatus);
+ if (!(workstatus&MPD_Invalid_operation)) {
+ mpd_qadd(result, result, cc, ctx, &workstatus);
+ }
+
+ if (cc != c) mpd_del(cc);
+ *status |= workstatus;
+}
+
+static inline int
+ln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec,
+ mpd_ssize_t initprec)
+{
+ mpd_ssize_t k;
+ int i;
+
+ assert(maxprec >= 2 && initprec >= 2);
+ if (maxprec <= initprec) return -1;
+
+ i = 0; k = maxprec;
+ do {
+ k = (k+2) / 2;
+ klist[i++] = k;
+ } while (k > initprec);
+
+ return i-1;
+}
+
+#ifdef CONFIG_64
+#if MPD_RDIGITS != 19
+ #error "mpdecimal.c: MPD_RDIGITS must be 19."
+#endif
+static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = {
+ 6983716328982174407ULL, 9089704281976336583ULL, 1515961135648465461ULL,
+ 4416816335727555703ULL, 2900988039194170265ULL, 2307925037472986509ULL,
+ 107598438319191292ULL, 3466624107184669231ULL, 4450099781311469159ULL,
+ 9807828059751193854ULL, 7713456862091670584ULL, 1492198849978748873ULL,
+ 6528728696511086257ULL, 2385392051446341972ULL, 8692180205189339507ULL,
+ 6518769751037497088ULL, 2375253577097505395ULL, 9095610299291824318ULL,
+ 982748238504564801ULL, 5438635917781170543ULL, 7547331541421808427ULL,
+ 752371033310119785ULL, 3171643095059950878ULL, 9785265383207606726ULL,
+ 2932258279850258550ULL, 5497347726624257094ULL, 2976979522110718264ULL,
+ 9221477656763693866ULL, 1979650047149510504ULL, 6674183485704422507ULL,
+ 9702766860595249671ULL, 9278096762712757753ULL, 9314848524948644871ULL,
+ 6826928280848118428ULL, 754403708474699401ULL, 230105703089634572ULL,
+ 1929203337658714166ULL, 7589402567763113569ULL, 4208241314695689016ULL,
+ 2922455440575892572ULL, 9356734206705811364ULL, 2684916746550586856ULL,
+ 644507064800027750ULL, 9476834636167921018ULL, 5659121373450747856ULL,
+ 2835522011480466371ULL, 6470806855677432162ULL, 7141748003688084012ULL,
+ 9619404400222105101ULL, 5504893431493939147ULL, 6674744042432743651ULL,
+ 2287698219886746543ULL, 7773262884616336622ULL, 1985283935053089653ULL,
+ 4680843799894826233ULL, 8168948290720832555ULL, 8067566662873690987ULL,
+ 6248633409525465082ULL, 9829834196778404228ULL, 3524802359972050895ULL,
+ 3327900967572609677ULL, 110148862877297603ULL, 179914546843642076ULL,
+ 2302585092994045684ULL
+};
+#else
+#if MPD_RDIGITS != 9
+ #error "mpdecimal.c: MPD_RDIGITS must be 9."
+#endif
+static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = {
+ 401682692UL, 708474699UL, 720754403UL, 30896345UL, 602301057UL, 765871416UL,
+ 192920333UL, 763113569UL, 589402567UL, 956890167UL, 82413146UL, 589257242UL,
+ 245544057UL, 811364292UL, 734206705UL, 868569356UL, 167465505UL, 775026849UL,
+ 706480002UL, 18064450UL, 636167921UL, 569476834UL, 734507478UL, 156591213UL,
+ 148046637UL, 283552201UL, 677432162UL, 470806855UL, 880840126UL, 417480036UL,
+ 210510171UL, 940440022UL, 939147961UL, 893431493UL, 436515504UL, 440424327UL,
+ 654366747UL, 821988674UL, 622228769UL, 884616336UL, 537773262UL, 350530896UL,
+ 319852839UL, 989482623UL, 468084379UL, 720832555UL, 168948290UL, 736909878UL,
+ 675666628UL, 546508280UL, 863340952UL, 404228624UL, 834196778UL, 508959829UL,
+ 23599720UL, 967735248UL, 96757260UL, 603332790UL, 862877297UL, 760110148UL,
+ 468436420UL, 401799145UL, 299404568UL, 230258509UL
+};
+#endif
+/* _mpd_ln10 is used directly for precisions smaller than MINALLOC_MAX*RDIGITS.
+ Otherwise, it serves as the initial approximation for calculating ln(10). */
+static const mpd_t _mpd_ln10 = {
+ MPD_STATIC|MPD_CONST_DATA, -(MPD_MINALLOC_MAX*MPD_RDIGITS-1),
+ MPD_MINALLOC_MAX*MPD_RDIGITS, MPD_MINALLOC_MAX, MPD_MINALLOC_MAX,
+ (mpd_uint_t *)mpd_ln10_data
+};
+
+/* Set 'result' to ln(10), with 'prec' digits, using ROUND_HALF_EVEN. */
+void
+mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status)
+{
+ mpd_context_t varcontext, maxcontext;
+ MPD_NEW_STATIC(tmp, 0,0,0,0);
+ MPD_NEW_CONST(static10, 0,0,2,1,1,10);
+ mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
+ mpd_uint_t rnd;
+ mpd_ssize_t shift;
+ int i;
+
+ assert(prec >= 1);
+
+ shift = MPD_MINALLOC_MAX*MPD_RDIGITS-prec;
+ shift = shift < 0 ? 0 : shift;
+
+ rnd = mpd_qshiftr(result, &_mpd_ln10, shift, status);
+ if (rnd == MPD_UINT_MAX) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ result->exp = -(result->digits-1);
+
+ mpd_maxcontext(&maxcontext);
+ if (prec < MPD_MINALLOC_MAX*MPD_RDIGITS) {
+ maxcontext.prec = prec;
+ _mpd_apply_round_excess(result, rnd, &maxcontext, status);
+ *status |= (MPD_Inexact|MPD_Rounded);
+ return;
+ }
+
+ mpd_maxcontext(&varcontext);
+ varcontext.round = MPD_ROUND_TRUNC;
+
+ i = ln_schedule_prec(klist, prec+2, result->digits);
+ for (; i >= 0; i--) {
+ varcontext.prec = 2*klist[i]+3;
+ result->flags ^= MPD_NEG;
+ _mpd_qexp(&tmp, result, &varcontext, status);
+ result->flags ^= MPD_NEG;
+ mpd_qmul(&tmp, &static10, &tmp, &varcontext, status);
+ mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
+ mpd_qadd(result, result, &tmp, &maxcontext, status);
+ if (mpd_isspecial(result)) {
+ break;
+ }
+ }
+
+ mpd_del(&tmp);
+ maxcontext.prec = prec;
+ mpd_qfinalize(result, &maxcontext, status);
+}
+
+/* Initial approximations for the ln() iteration */
+static const uint16_t lnapprox[900] = {
+ /* index 0 - 400: log((i+100)/100) * 1000 */
+ 0, 10, 20, 30, 39, 49, 58, 68, 77, 86, 95, 104, 113, 122, 131, 140, 148, 157,
+ 166, 174, 182, 191, 199, 207, 215, 223, 231, 239, 247, 255, 262, 270, 278,
+ 285, 293, 300, 308, 315, 322, 329, 336, 344, 351, 358, 365, 372, 378, 385,
+ 392, 399, 406, 412, 419, 425, 432, 438, 445, 451, 457, 464, 470, 476, 482,
+ 489, 495, 501, 507, 513, 519, 525, 531, 536, 542, 548, 554, 560, 565, 571,
+ 577, 582, 588, 593, 599, 604, 610, 615, 621, 626, 631, 637, 642, 647, 652,
+ 658, 663, 668, 673, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728,
+ 732, 737, 742, 747, 751, 756, 761, 766, 770, 775, 779, 784, 788, 793, 798,
+ 802, 806, 811, 815, 820, 824, 829, 833, 837, 842, 846, 850, 854, 859, 863,
+ 867, 871, 876, 880, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 924,
+ 928, 932, 936, 940, 944, 948, 952, 956, 959, 963, 967, 971, 975, 978, 982,
+ 986, 990, 993, 997, 1001, 1004, 1008, 1012, 1015, 1019, 1022, 1026, 1030,
+ 1033, 1037, 1040, 1044, 1047, 1051, 1054, 1058, 1061, 1065, 1068, 1072, 1075,
+ 1078, 1082, 1085, 1089, 1092, 1095, 1099, 1102, 1105, 1109, 1112, 1115, 1118,
+ 1122, 1125, 1128, 1131, 1135, 1138, 1141, 1144, 1147, 1151, 1154, 1157, 1160,
+ 1163, 1166, 1169, 1172, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200,
+ 1203, 1206, 1209, 1212, 1215, 1218, 1221, 1224, 1227, 1230, 1233, 1235, 1238,
+ 1241, 1244, 1247, 1250, 1253, 1256, 1258, 1261, 1264, 1267, 1270, 1273, 1275,
+ 1278, 1281, 1284, 1286, 1289, 1292, 1295, 1297, 1300, 1303, 1306, 1308, 1311,
+ 1314, 1316, 1319, 1322, 1324, 1327, 1330, 1332, 1335, 1338, 1340, 1343, 1345,
+ 1348, 1351, 1353, 1356, 1358, 1361, 1364, 1366, 1369, 1371, 1374, 1376, 1379,
+ 1381, 1384, 1386, 1389, 1391, 1394, 1396, 1399, 1401, 1404, 1406, 1409, 1411,
+ 1413, 1416, 1418, 1421, 1423, 1426, 1428, 1430, 1433, 1435, 1437, 1440, 1442,
+ 1445, 1447, 1449, 1452, 1454, 1456, 1459, 1461, 1463, 1466, 1468, 1470, 1472,
+ 1475, 1477, 1479, 1482, 1484, 1486, 1488, 1491, 1493, 1495, 1497, 1500, 1502,
+ 1504, 1506, 1509, 1511, 1513, 1515, 1517, 1520, 1522, 1524, 1526, 1528, 1530,
+ 1533, 1535, 1537, 1539, 1541, 1543, 1545, 1548, 1550, 1552, 1554, 1556, 1558,
+ 1560, 1562, 1564, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585,
+ 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609,
+ /* index 401 - 899: -log((i+100)/1000) * 1000 */
+ 691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 668, 666, 664,
+ 662, 660, 658, 656, 654, 652, 650, 648, 646, 644, 642, 641, 639, 637, 635,
+ 633, 631, 629, 627, 626, 624, 622, 620, 618, 616, 614, 612, 611, 609, 607,
+ 605, 603, 602, 600, 598, 596, 594, 592, 591, 589, 587, 585, 583, 582, 580,
+ 578, 576, 574, 573, 571, 569, 567, 566, 564, 562, 560, 559, 557, 555, 553,
+ 552, 550, 548, 546, 545, 543, 541, 540, 538, 536, 534, 533, 531, 529, 528,
+ 526, 524, 523, 521, 519, 518, 516, 514, 512, 511, 509, 508, 506, 504, 502,
+ 501, 499, 498, 496, 494, 493, 491, 489, 488, 486, 484, 483, 481, 480, 478,
+ 476, 475, 473, 472, 470, 468, 467, 465, 464, 462, 460, 459, 457, 456, 454,
+ 453, 451, 449, 448, 446, 445, 443, 442, 440, 438, 437, 435, 434, 432, 431,
+ 429, 428, 426, 425, 423, 422, 420, 419, 417, 416, 414, 412, 411, 410, 408,
+ 406, 405, 404, 402, 400, 399, 398, 396, 394, 393, 392, 390, 389, 387, 386,
+ 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, 367, 365, 364,
+ 362, 361, 360, 358, 357, 355, 354, 352, 351, 350, 348, 347, 345, 344, 342,
+ 341, 340, 338, 337, 336, 334, 333, 331, 330, 328, 327, 326, 324, 323, 322,
+ 320, 319, 318, 316, 315, 313, 312, 311, 309, 308, 306, 305, 304, 302, 301,
+ 300, 298, 297, 296, 294, 293, 292, 290, 289, 288, 286, 285, 284, 282, 281,
+ 280, 278, 277, 276, 274, 273, 272, 270, 269, 268, 267, 265, 264, 263, 261,
+ 260, 259, 258, 256, 255, 254, 252, 251, 250, 248, 247, 246, 245, 243, 242,
+ 241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 226, 224, 223,
+ 222, 221, 219, 218, 217, 216, 214, 213, 212, 211, 210, 208, 207, 206, 205,
+ 203, 202, 201, 200, 198, 197, 196, 195, 194, 192, 191, 190, 189, 188, 186,
+ 185, 184, 183, 182, 180, 179, 178, 177, 176, 174, 173, 172, 171, 170, 168,
+ 167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 154, 153, 152, 151,
+ 150, 148, 147, 146, 145, 144, 143, 142, 140, 139, 138, 137, 136, 135, 134,
+ 132, 131, 130, 129, 128, 127, 126, 124, 123, 122, 121, 120, 119, 118, 116,
+ 115, 114, 113, 112, 111, 110, 109, 108, 106, 105, 104, 103, 102, 101, 100,
+ 99, 98, 97, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79,
+ 78, 77, 76, 75, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,
+ 58, 57, 56, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39,
+ 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
+ 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+};
+
+/* Internal ln() function that does not check for specials, zero or one. */
+static void
+_mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t varcontext, maxcontext;
+ mpd_t *z = (mpd_t *) result;
+ MPD_NEW_STATIC(v,0,0,0,0);
+ MPD_NEW_STATIC(vtmp,0,0,0,0);
+ MPD_NEW_STATIC(tmp,0,0,0,0);
+ mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
+ mpd_ssize_t maxprec, shift, t;
+ mpd_ssize_t a_digits, a_exp;
+ mpd_uint_t dummy, x;
+ int i;
+
+ assert(!mpd_isspecial(a) && !mpd_iszerocoeff(a));
+
+ /*
+ * We are calculating ln(a) = ln(v * 10^t) = ln(v) + t*ln(10),
+ * where 0.5 < v <= 5.
+ */
+ if (!mpd_qcopy(&v, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+
+ /* Initial approximation: we have at least one non-zero digit */
+ _mpd_get_msdigits(&dummy, &x, &v, 3);
+ if (x < 10) x *= 10;
+ if (x < 100) x *= 10;
+ x -= 100;
+
+ /* a may equal z */
+ a_digits = a->digits;
+ a_exp = a->exp;
+
+ mpd_minalloc(z);
+ mpd_clear_flags(z);
+ z->data[0] = lnapprox[x];
+ z->len = 1;
+ z->exp = -3;
+ mpd_setdigits(z);
+
+ if (x <= 400) {
+ v.exp = -(a_digits - 1);
+ t = a_exp + a_digits - 1;
+ }
+ else {
+ v.exp = -a_digits;
+ t = a_exp + a_digits;
+ mpd_set_negative(z);
+ }
+
+ mpd_maxcontext(&maxcontext);
+ mpd_maxcontext(&varcontext);
+ varcontext.round = MPD_ROUND_TRUNC;
+
+ maxprec = ctx->prec + 2;
+ if (x <= 10 || x >= 805) {
+ /* v is close to 1: Estimate the magnitude of the logarithm.
+ * If v = 1 or ln(v) will underflow, skip the loop. Otherwise,
+ * adjust the precision upwards in order to obtain a sufficient
+ * number of significant digits.
+ *
+ * 1) x/(1+x) < ln(1+x) < x, for x > -1, x != 0
+ *
+ * 2) (v-1)/v < ln(v) < v-1
+ */
+ mpd_t *lower = &tmp;
+ mpd_t *upper = &vtmp;
+ int cmp = _mpd_cmp(&v, &one);
+
+ varcontext.round = MPD_ROUND_CEILING;
+ varcontext.prec = maxprec;
+ mpd_qsub(upper, &v, &one, &varcontext, &varcontext.status);
+ varcontext.round = MPD_ROUND_FLOOR;
+ mpd_qdiv(lower, upper, &v, &varcontext, &varcontext.status);
+ varcontext.round = MPD_ROUND_TRUNC;
+
+ if (cmp < 0) {
+ _mpd_ptrswap(&upper, &lower);
+ }
+ if (mpd_adjexp(upper) < mpd_etiny(ctx)) {
+ _settriple(z, (cmp<0), 1, mpd_etiny(ctx)-1);
+ goto postloop;
+ }
+ /* XXX optimization: t == 0 && mpd_adjexp(lower) < 0 */
+ if (mpd_adjexp(lower) < 0) {
+ maxprec = maxprec - mpd_adjexp(lower);
+ }
+ }
+
+ i = ln_schedule_prec(klist, maxprec, 2);
+ for (; i >= 0; i--) {
+ varcontext.prec = 2*klist[i]+3;
+ z->flags ^= MPD_NEG;
+ _mpd_qexp(&tmp, z, &varcontext, status);
+ z->flags ^= MPD_NEG;
+
+ if (v.digits > varcontext.prec) {
+ shift = v.digits - varcontext.prec;
+ mpd_qshiftr(&vtmp, &v, shift, status);
+ vtmp.exp += shift;
+ mpd_qmul(&tmp, &vtmp, &tmp, &varcontext, status);
+ }
+ else {
+ mpd_qmul(&tmp, &v, &tmp, &varcontext, status);
+ }
+
+ mpd_qsub(&tmp, &tmp, &one, &maxcontext, status);
+ mpd_qadd(z, z, &tmp, &maxcontext, status);
+ if (mpd_isspecial(z)) {
+ break;
+ }
+ }
+
+postloop:
+ mpd_qln10(&v, maxprec+2, status);
+ mpd_qmul_ssize(&tmp, &v, t, &maxcontext, status);
+ varcontext.prec = maxprec+2;
+ mpd_qadd(result, &tmp, z, &varcontext, status);
+
+
+finish:
+ mpd_del(&v);
+ mpd_del(&vtmp);
+ mpd_del(&tmp);
+}
+
+/* ln(a) */
+void
+mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ mpd_ssize_t adjexp, t;
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ return;
+ }
+ if (mpd_iszerocoeff(a)) {
+ mpd_setspecial(result, MPD_NEG, MPD_INF);
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (_mpd_cmp(a, &one) == 0) {
+ _settriple(result, MPD_POS, 0, 0);
+ return;
+ }
+ /* Check if the result will overflow.
+ *
+ * 1) adjexp(a) + 1 > log10(a) >= adjexp(a)
+ *
+ * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0
+ * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0
+ *
+ * 3) |log(a)| > 2*|log10(a)|
+ */
+ adjexp = mpd_adjexp(a);
+ t = (adjexp < 0) ? -adjexp-1 : adjexp;
+ t *= 2;
+ if (mpd_exp_digits(t)-1 > ctx->emax) {
+ *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
+ mpd_setspecial(result, (adjexp<0), MPD_INF);
+ return;
+ }
+
+ workctx = *ctx;
+ workctx.round = MPD_ROUND_HALF_EVEN;
+
+ if (ctx->allcr) {
+ MPD_NEW_STATIC(t1, 0,0,0,0);
+ MPD_NEW_STATIC(t2, 0,0,0,0);
+ MPD_NEW_STATIC(ulp, 0,0,0,0);
+ MPD_NEW_STATIC(aa, 0,0,0,0);
+ mpd_ssize_t prec;
+
+ if (result == a) {
+ if (!mpd_qcopy(&aa, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ a = &aa;
+ }
+
+ workctx.clamp = 0;
+ prec = ctx->prec + 3;
+ while (1) {
+ workctx.prec = prec;
+ _mpd_qln(result, a, &workctx, status);
+ _ssettriple(&ulp, MPD_POS, 1,
+ result->exp + result->digits-workctx.prec-1);
+
+ workctx.prec = ctx->prec;
+ mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
+ mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
+ if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
+ mpd_qcmp(&t1, &t2, status) == 0) {
+ workctx.clamp = ctx->clamp;
+ mpd_check_underflow(result, &workctx, status);
+ mpd_qfinalize(result, &workctx, status);
+ break;
+ }
+ prec += MPD_RDIGITS;
+ }
+ mpd_del(&t1);
+ mpd_del(&t2);
+ mpd_del(&ulp);
+ mpd_del(&aa);
+ }
+ else {
+ _mpd_qln(result, a, &workctx, status);
+ mpd_check_underflow(result, &workctx, status);
+ mpd_qfinalize(result, &workctx, status);
+ }
+}
+
+/* Internal log10() function that does not check for specials, zero, ... */
+static void
+_mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_STATIC(ln10,0,0,0,0);
+
+ mpd_maxcontext(&workctx);
+ workctx.prec = ctx->prec + 3;
+ _mpd_qln(result, a, &workctx, status);
+ mpd_qln10(&ln10, workctx.prec, status);
+
+ workctx = *ctx;
+ workctx.round = MPD_ROUND_HALF_EVEN;
+ _mpd_qdiv(NO_IDEAL_EXP, result, result, &ln10, &workctx, status);
+
+ mpd_del(&ln10);
+}
+
+/* log10(a) */
+void
+mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ mpd_ssize_t adjexp, t;
+
+ workctx = *ctx;
+ workctx.round = MPD_ROUND_HALF_EVEN;
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ return;
+ }
+ if (mpd_iszerocoeff(a)) {
+ mpd_setspecial(result, MPD_NEG, MPD_INF);
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_coeff_ispow10(a)) {
+ uint8_t sign = 0;
+ adjexp = mpd_adjexp(a);
+ if (adjexp < 0) {
+ sign = 1;
+ adjexp = -adjexp;
+ }
+ _settriple(result, sign, adjexp, 0);
+ mpd_qfinalize(result, &workctx, status);
+ return;
+ }
+ /* Check if the result will overflow.
+ *
+ * 1) adjexp(a) + 1 > log10(a) >= adjexp(a)
+ *
+ * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0
+ * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0
+ */
+ adjexp = mpd_adjexp(a);
+ t = (adjexp < 0) ? -adjexp-1 : adjexp;
+ if (mpd_exp_digits(t)-1 > ctx->emax) {
+ *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded;
+ mpd_setspecial(result, (adjexp<0), MPD_INF);
+ return;
+ }
+
+ if (ctx->allcr) {
+ MPD_NEW_STATIC(t1, 0,0,0,0);
+ MPD_NEW_STATIC(t2, 0,0,0,0);
+ MPD_NEW_STATIC(ulp, 0,0,0,0);
+ MPD_NEW_STATIC(aa, 0,0,0,0);
+ mpd_ssize_t prec;
+
+ if (result == a) {
+ if (!mpd_qcopy(&aa, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ a = &aa;
+ }
+
+ workctx.clamp = 0;
+ prec = ctx->prec + 3;
+ while (1) {
+ workctx.prec = prec;
+ _mpd_qlog10(result, a, &workctx, status);
+ _ssettriple(&ulp, MPD_POS, 1,
+ result->exp + result->digits-workctx.prec-1);
+
+ workctx.prec = ctx->prec;
+ mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status);
+ mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status);
+ if (mpd_isspecial(result) || mpd_iszerocoeff(result) ||
+ mpd_qcmp(&t1, &t2, status) == 0) {
+ workctx.clamp = ctx->clamp;
+ mpd_check_underflow(result, &workctx, status);
+ mpd_qfinalize(result, &workctx, status);
+ break;
+ }
+ prec += MPD_RDIGITS;
+ }
+ mpd_del(&t1);
+ mpd_del(&t2);
+ mpd_del(&ulp);
+ mpd_del(&aa);
+ }
+ else {
+ _mpd_qlog10(result, a, &workctx, status);
+ mpd_check_underflow(result, &workctx, status);
+ }
+}
+
+/*
+ * Maximum of the two operands. Attention: If one operand is a quiet NaN and the
+ * other is numeric, the numeric operand is returned. This may not be what one
+ * expects.
+ */
+void
+mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isqnan(a) && !mpd_isnan(b)) {
+ mpd_qcopy(result, b, status);
+ }
+ else if (mpd_isqnan(b) && !mpd_isnan(a)) {
+ mpd_qcopy(result, a, status);
+ }
+ else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ else {
+ c = _mpd_cmp(a, b);
+ if (c == 0) {
+ c = _mpd_cmp_numequal(a, b);
+ }
+
+ if (c < 0) {
+ mpd_qcopy(result, b, status);
+ }
+ else {
+ mpd_qcopy(result, a, status);
+ }
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/*
+ * Maximum magnitude: Same as mpd_max(), but compares the operands with their
+ * sign ignored.
+ */
+void
+mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isqnan(a) && !mpd_isnan(b)) {
+ mpd_qcopy(result, b, status);
+ }
+ else if (mpd_isqnan(b) && !mpd_isnan(a)) {
+ mpd_qcopy(result, a, status);
+ }
+ else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ else {
+ c = _mpd_cmp_abs(a, b);
+ if (c == 0) {
+ c = _mpd_cmp_numequal(a, b);
+ }
+
+ if (c < 0) {
+ mpd_qcopy(result, b, status);
+ }
+ else {
+ mpd_qcopy(result, a, status);
+ }
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/*
+ * Minimum of the two operands. Attention: If one operand is a quiet NaN and the
+ * other is numeric, the numeric operand is returned. This may not be what one
+ * expects.
+ */
+void
+mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isqnan(a) && !mpd_isnan(b)) {
+ mpd_qcopy(result, b, status);
+ }
+ else if (mpd_isqnan(b) && !mpd_isnan(a)) {
+ mpd_qcopy(result, a, status);
+ }
+ else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ else {
+ c = _mpd_cmp(a, b);
+ if (c == 0) {
+ c = _mpd_cmp_numequal(a, b);
+ }
+
+ if (c < 0) {
+ mpd_qcopy(result, a, status);
+ }
+ else {
+ mpd_qcopy(result, b, status);
+ }
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/*
+ * Minimum magnitude: Same as mpd_min(), but compares the operands with their
+ * sign ignored.
+ */
+void
+mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isqnan(a) && !mpd_isnan(b)) {
+ mpd_qcopy(result, b, status);
+ }
+ else if (mpd_isqnan(b) && !mpd_isnan(a)) {
+ mpd_qcopy(result, a, status);
+ }
+ else if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ else {
+ c = _mpd_cmp_abs(a, b);
+ if (c == 0) {
+ c = _mpd_cmp_numequal(a, b);
+ }
+
+ if (c < 0) {
+ mpd_qcopy(result, a, status);
+ }
+ else {
+ mpd_qcopy(result, b, status);
+ }
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* Minimum space needed for the result array in _karatsuba_rec(). */
+static inline mpd_size_t
+_kmul_resultsize(mpd_size_t la, mpd_size_t lb)
+{
+ mpd_size_t n, m;
+
+ n = add_size_t(la, lb);
+ n = add_size_t(n, 1);
+
+ m = (la+1)/2 + 1;
+ m = mul_size_t(m, 3);
+
+ return (m > n) ? m : n;
+}
+
+/* Work space needed in _karatsuba_rec(). lim >= 4 */
+static inline mpd_size_t
+_kmul_worksize(mpd_size_t n, mpd_size_t lim)
+{
+ mpd_size_t m;
+
+ if (n <= lim) {
+ return 0;
+ }
+
+ m = (n+1)/2 + 1;
+
+ return add_size_t(mul_size_t(m, 2), _kmul_worksize(m, lim));
+}
+
+
+#define MPD_KARATSUBA_BASECASE 16 /* must be >= 4 */
+
+/*
+ * Add the product of a and b to c.
+ * c must be _kmul_resultsize(la, lb) in size.
+ * w is used as a work array and must be _kmul_worksize(a, lim) in size.
+ * Roman E. Maeder, Storage Allocation for the Karatsuba Integer Multiplication
+ * Algorithm. In "Design and implementation of symbolic computation systems",
+ * Springer, 1993, ISBN 354057235X, 9783540572350.
+ */
+static void
+_karatsuba_rec(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
+ mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
+{
+ mpd_size_t m, lt;
+
+ assert(la >= lb && lb > 0);
+ assert(la <= MPD_KARATSUBA_BASECASE || w != NULL);
+
+ if (la <= MPD_KARATSUBA_BASECASE) {
+ _mpd_basemul(c, a, b, la, lb);
+ return;
+ }
+
+ m = (la+1)/2; // ceil(la/2)
+
+ /* lb <= m < la */
+ if (lb <= m) {
+
+ /* lb can now be larger than la-m */
+ if (lb > la-m) {
+ lt = lb + lb + 1; // space needed for result array
+ mpd_uint_zero(w, lt); // clear result array
+ _karatsuba_rec(w, b, a+m, w+lt, lb, la-m); // b*ah
+ }
+ else {
+ lt = (la-m) + (la-m) + 1; // space needed for result array
+ mpd_uint_zero(w, lt); // clear result array
+ _karatsuba_rec(w, a+m, b, w+lt, la-m, lb); // ah*b
+ }
+ _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m
+
+ lt = m + m + 1; // space needed for the result array
+ mpd_uint_zero(w, lt); // clear result array
+ _karatsuba_rec(w, a, b, w+lt, m, lb); // al*b
+ _mpd_baseaddto(c, w, m+lb); // add al*b
+
+ return;
+ }
+
+ /* la >= lb > m */
+ memcpy(w, a, m * sizeof *w);
+ w[m] = 0;
+ _mpd_baseaddto(w, a+m, la-m);
+
+ memcpy(w+(m+1), b, m * sizeof *w);
+ w[m+1+m] = 0;
+ _mpd_baseaddto(w+(m+1), b+m, lb-m);
+
+ _karatsuba_rec(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1);
+
+ lt = (la-m) + (la-m) + 1;
+ mpd_uint_zero(w, lt);
+
+ _karatsuba_rec(w, a+m, b+m, w+lt, la-m, lb-m);
+
+ _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
+ _mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
+
+ lt = m + m + 1;
+ mpd_uint_zero(w, lt);
+
+ _karatsuba_rec(w, a, b, w+lt, m, m);
+ _mpd_baseaddto(c, w, m+m);
+ _mpd_basesubfrom(c+m, w, m+m);
+
+ return;
+}
+
+/*
+ * Multiply u and v, using Karatsuba multiplication. Returns a pointer
+ * to the result or NULL in case of failure (malloc error).
+ * Conditions: ulen >= vlen, ulen >= 4
+ */
+mpd_uint_t *
+_mpd_kmul(const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t ulen, mpd_size_t vlen,
+ mpd_size_t *rsize)
+{
+ mpd_uint_t *result = NULL, *w = NULL;
+ mpd_size_t m;
+
+ assert(ulen >= 4);
+ assert(ulen >= vlen);
+
+ *rsize = _kmul_resultsize(ulen, vlen);
+ if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
+ return NULL;
+ }
+
+ m = _kmul_worksize(ulen, MPD_KARATSUBA_BASECASE);
+ if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
+ mpd_free(result);
+ return NULL;
+ }
+
+ _karatsuba_rec(result, u, v, w, ulen, vlen);
+
+
+ if (w) mpd_free(w);
+ return result;
+}
+
+
+/* Determine the minimum length for the number theoretic transform. */
+static inline mpd_size_t
+_mpd_get_transform_len(mpd_size_t rsize)
+{
+ mpd_size_t log2rsize;
+ mpd_size_t x, step;
+
+ assert(rsize >= 4);
+ log2rsize = mpd_bsr(rsize);
+
+ if (rsize <= 1024) {
+ x = ((mpd_size_t)1)<<log2rsize;
+ return (rsize == x) ? x : x<<1;
+ }
+ else if (rsize <= MPD_MAXTRANSFORM_2N) {
+ x = ((mpd_size_t)1)<<log2rsize;
+ if (rsize == x) return x;
+ step = x>>1;
+ x += step;
+ return (rsize <= x) ? x : x + step;
+ }
+ else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) {
+ return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2;
+ }
+ else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
+ return 3*MPD_MAXTRANSFORM_2N;
+ }
+ else {
+ return MPD_SIZE_MAX;
+ }
+}
+
+#ifdef PPRO
+#ifndef _MSC_VER
+static inline unsigned short
+_mpd_get_control87(void)
+{
+ unsigned short cw;
+
+ __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
+ return cw;
+}
+
+static inline void
+_mpd_set_control87(unsigned short cw)
+{
+ __asm__ __volatile__ ("fldcw %0" : : "m" (cw));
+}
+#endif
+
+unsigned int
+mpd_set_fenv(void)
+{
+ unsigned int cw;
+#ifdef _MSC_VER
+ unsigned int flags =
+ _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW|
+ _EM_UNDERFLOW|_EM_INEXACT|_RC_CHOP|_PC_64;
+ unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC;
+ unsigned int dummy;
+
+ __control87_2(0, 0, &cw, NULL);
+ __control87_2(flags, mask, &dummy, NULL);
+#else
+ cw = _mpd_get_control87();
+ _mpd_set_control87(cw|0xF3F);
+#endif
+ return cw;
+}
+
+void
+mpd_restore_fenv(unsigned int cw)
+{
+#ifdef _MSC_VER
+ unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC;
+ unsigned int dummy;
+
+ __control87_2(cw, mask, &dummy, NULL);
+#else
+ _mpd_set_control87((unsigned short)cw);
+#endif
+}
+#endif /* PPRO */
+
+/*
+ * Multiply u and v, using the fast number theoretic transform. Returns
+ * a pointer to the result or NULL in case of failure (malloc error).
+ */
+mpd_uint_t *
+_mpd_fntmul(const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t ulen, mpd_size_t vlen,
+ mpd_size_t *rsize)
+{
+ mpd_uint_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *vtmp = NULL;
+ mpd_size_t n;
+
+#ifdef PPRO
+ unsigned int cw;
+ cw = mpd_set_fenv();
+#endif
+
+ *rsize = add_size_t(ulen, vlen);
+ if ((n = _mpd_get_transform_len(*rsize)) == MPD_SIZE_MAX) {
+ goto malloc_error;
+ }
+
+ if ((c1 = mpd_calloc(sizeof *c1, n)) == NULL) {
+ goto malloc_error;
+ }
+ if ((c2 = mpd_calloc(sizeof *c2, n)) == NULL) {
+ goto malloc_error;
+ }
+ if ((c3 = mpd_calloc(sizeof *c3, n)) == NULL) {
+ goto malloc_error;
+ }
+
+ memcpy(c1, u, ulen * (sizeof *c1));
+ memcpy(c2, u, ulen * (sizeof *c2));
+ memcpy(c3, u, ulen * (sizeof *c3));
+
+ if (u == v) {
+ if (!fnt_autoconvolute(c1, n, P1) ||
+ !fnt_autoconvolute(c2, n, P2) ||
+ !fnt_autoconvolute(c3, n, P3)) {
+ goto malloc_error;
+ }
+ }
+ else {
+ if ((vtmp = mpd_calloc(sizeof *vtmp, n)) == NULL) {
+ goto malloc_error;
+ }
+
+ memcpy(vtmp, v, vlen * (sizeof *vtmp));
+ if (!fnt_convolute(c1, vtmp, n, P1)) {
+ mpd_free(vtmp);
+ goto malloc_error;
+ }
+
+ memcpy(vtmp, v, vlen * (sizeof *vtmp));
+ mpd_uint_zero(vtmp+vlen, n-vlen);
+ if (!fnt_convolute(c2, vtmp, n, P2)) {
+ mpd_free(vtmp);
+ goto malloc_error;
+ }
+
+ memcpy(vtmp, v, vlen * (sizeof *vtmp));
+ mpd_uint_zero(vtmp+vlen, n-vlen);
+ if (!fnt_convolute(c3, vtmp, n, P3)) {
+ mpd_free(vtmp);
+ goto malloc_error;
+ }
+
+ mpd_free(vtmp);
+ }
+
+ crt3(c1, c2, c3, *rsize);
+
+out:
+#ifdef PPRO
+ mpd_restore_fenv(cw);
+#endif
+ if (c2) mpd_free(c2);
+ if (c3) mpd_free(c3);
+ return c1;
+
+malloc_error:
+ if (c1) mpd_free(c1);
+ c1 = NULL;
+ goto out;
+}
+
+
+/*
+ * Karatsuba multiplication with FNT/basemul as the base case.
+ */
+static int
+_karatsuba_rec_fnt(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b,
+ mpd_uint_t *w, mpd_size_t la, mpd_size_t lb)
+{
+ mpd_size_t m, lt;
+
+ assert(la >= lb && lb > 0);
+ assert(la <= 3*(MPD_MAXTRANSFORM_2N/2) || w != NULL);
+
+ if (la <= 3*(MPD_MAXTRANSFORM_2N/2)) {
+
+ if (lb <= 192) {
+ _mpd_basemul(c, b, a, lb, la);
+ }
+ else {
+ mpd_uint_t *result;
+ mpd_size_t dummy;
+
+ if ((result = _mpd_fntmul(a, b, la, lb, &dummy)) == NULL) {
+ return 0;
+ }
+ memcpy(c, result, (la+lb) * (sizeof *result));
+ mpd_free(result);
+ }
+ return 1;
+ }
+
+ m = (la+1)/2; // ceil(la/2)
+
+ /* lb <= m < la */
+ if (lb <= m) {
+
+ /* lb can now be larger than la-m */
+ if (lb > la-m) {
+ lt = lb + lb + 1; // space needed for result array
+ mpd_uint_zero(w, lt); // clear result array
+ if (!_karatsuba_rec_fnt(w, b, a+m, w+lt, lb, la-m)) { // b*ah
+ return 0; /* GCOV_UNLIKELY */
+ }
+ }
+ else {
+ lt = (la-m) + (la-m) + 1; // space needed for result array
+ mpd_uint_zero(w, lt); // clear result array
+ if (!_karatsuba_rec_fnt(w, a+m, b, w+lt, la-m, lb)) { // ah*b
+ return 0; /* GCOV_UNLIKELY */
+ }
+ }
+ _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m
+
+ lt = m + m + 1; // space needed for the result array
+ mpd_uint_zero(w, lt); // clear result array
+ if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, lb)) { // al*b
+ return 0; /* GCOV_UNLIKELY */
+ }
+ _mpd_baseaddto(c, w, m+lb); // add al*b
+
+ return 1;
+ }
+
+ /* la >= lb > m */
+ memcpy(w, a, m * sizeof *w);
+ w[m] = 0;
+ _mpd_baseaddto(w, a+m, la-m);
+
+ memcpy(w+(m+1), b, m * sizeof *w);
+ w[m+1+m] = 0;
+ _mpd_baseaddto(w+(m+1), b+m, lb-m);
+
+ if (!_karatsuba_rec_fnt(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1)) {
+ return 0; /* GCOV_UNLIKELY */
+ }
+
+ lt = (la-m) + (la-m) + 1;
+ mpd_uint_zero(w, lt);
+
+ if (!_karatsuba_rec_fnt(w, a+m, b+m, w+lt, la-m, lb-m)) {
+ return 0; /* GCOV_UNLIKELY */
+ }
+
+ _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m));
+ _mpd_basesubfrom(c+m, w, (la-m) + (lb-m));
+
+ lt = m + m + 1;
+ mpd_uint_zero(w, lt);
+
+ if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, m)) {
+ return 0; /* GCOV_UNLIKELY */
+ }
+ _mpd_baseaddto(c, w, m+m);
+ _mpd_basesubfrom(c+m, w, m+m);
+
+ return 1;
+}
+
+/*
+ * Multiply u and v, using Karatsuba multiplication with the FNT as the
+ * base case. Returns a pointer to the result or NULL in case of failure
+ * (malloc error). Conditions: ulen >= vlen, ulen >= 4.
+ */
+mpd_uint_t *
+_mpd_kmul_fnt(const mpd_uint_t *u, const mpd_uint_t *v,
+ mpd_size_t ulen, mpd_size_t vlen,
+ mpd_size_t *rsize)
+{
+ mpd_uint_t *result = NULL, *w = NULL;
+ mpd_size_t m;
+
+ assert(ulen >= 4);
+ assert(ulen >= vlen);
+
+ *rsize = _kmul_resultsize(ulen, vlen);
+ if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) {
+ return NULL;
+ }
+
+ m = _kmul_worksize(ulen, 3*(MPD_MAXTRANSFORM_2N/2));
+ if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) {
+ mpd_free(result); /* GCOV_UNLIKELY */
+ return NULL; /* GCOV_UNLIKELY */
+ }
+
+ if (!_karatsuba_rec_fnt(result, u, v, w, ulen, vlen)) {
+ mpd_free(result);
+ result = NULL;
+ }
+
+
+ if (w) mpd_free(w);
+ return result;
+}
+
+
+/* Deal with the special cases of multiplying infinities. */
+static void
+_mpd_qmul_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status)
+{
+ if (mpd_isinfinite(a)) {
+ if (mpd_iszero(b)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ }
+ else {
+ mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
+ }
+ return;
+ }
+ assert(mpd_isinfinite(b));
+ if (mpd_iszero(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ }
+ else {
+ mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF);
+ }
+}
+
+/*
+ * Internal function: Multiply a and b. _mpd_qmul deals with specials but
+ * does NOT finalize the result. This is for use in mpd_fma().
+ */
+static inline void
+_mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_t *big = (mpd_t *)a, *small = (mpd_t *)b;
+ mpd_uint_t *rdata = NULL;
+ mpd_uint_t rbuf[MPD_MINALLOC_MAX];
+ mpd_size_t rsize, i;
+
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ _mpd_qmul_inf(result, a, b, status);
+ return;
+ }
+
+ if (small->len > big->len) {
+ _mpd_ptrswap(&big, &small);
+ }
+
+ rsize = big->len + small->len;
+
+ if (big->len == 1) {
+ _mpd_singlemul(result->data, big->data[0], small->data[0]);
+ goto finish;
+ }
+ if (rsize <= (mpd_size_t)MPD_MINALLOC_MAX) {
+ if (big->len == 2) {
+ _mpd_mul_2_le2(rbuf, big->data, small->data, small->len);
+ }
+ else {
+ mpd_uint_zero(rbuf, rsize);
+ if (small->len == 1) {
+ _mpd_shortmul(rbuf, big->data, big->len, small->data[0]);
+ }
+ else {
+ _mpd_basemul(rbuf, small->data, big->data, small->len, big->len);
+ }
+ }
+ if (!mpd_qresize(result, rsize, status)) {
+ return;
+ }
+ for(i = 0; i < rsize; i++) {
+ result->data[i] = rbuf[i];
+ }
+ goto finish;
+ }
+
+
+ if (small->len == 1) {
+ if ((rdata = mpd_calloc(rsize, sizeof *rdata)) == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ _mpd_shortmul(rdata, big->data, big->len, small->data[0]);
+ }
+ else if (rsize <= 1024) {
+ rdata = _mpd_kmul(big->data, small->data, big->len, small->len, &rsize);
+ if (rdata == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ }
+ else if (rsize <= 3*MPD_MAXTRANSFORM_2N) {
+ rdata = _mpd_fntmul(big->data, small->data, big->len, small->len, &rsize);
+ if (rdata == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ }
+ else {
+ rdata = _mpd_kmul_fnt(big->data, small->data, big->len, small->len, &rsize);
+ if (rdata == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status); /* GCOV_UNLIKELY */
+ return; /* GCOV_UNLIKELY */
+ }
+ }
+
+ if (mpd_isdynamic_data(result)) {
+ mpd_free(result->data);
+ }
+ result->data = rdata;
+ result->alloc = rsize;
+ mpd_set_dynamic_data(result);
+
+
+finish:
+ mpd_set_flags(result, mpd_sign(a)^mpd_sign(b));
+ result->exp = big->exp + small->exp;
+ result->len = _mpd_real_size(result->data, rsize);
+ /* resize to smaller cannot fail */
+ mpd_qresize(result, result->len, status);
+ mpd_setdigits(result);
+}
+
+/* Multiply a and b. */
+void
+mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ _mpd_qmul(result, a, b, ctx, status);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* Multiply decimal and mpd_ssize_t. */
+void
+mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_ssize(&bb, b, &maxcontext, status);
+ mpd_qmul(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+/* Multiply decimal and mpd_uint_t. */
+void
+mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(bb,0,0,0,0);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_qsset_uint(&bb, b, &maxcontext, status);
+ mpd_qmul(result, a, &bb, ctx, status);
+ mpd_del(&bb);
+}
+
+void
+mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qmul_ssize(result, a, b, ctx, status);
+}
+
+void
+mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qmul_uint(result, a, b, ctx, status);
+}
+
+#ifdef CONFIG_64
+void
+mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qmul_ssize(result, a, b, ctx, status);
+}
+
+void
+mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_qmul_uint(result, a, b, ctx, status);
+}
+#endif
+
+/* Like the minus operator. */
+void
+mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ }
+
+ if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
+ mpd_qcopy_abs(result, a, status);
+ }
+ else {
+ mpd_qcopy_negate(result, a, status);
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* Like the plus operator. */
+void
+mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ }
+
+ if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) {
+ mpd_qcopy_abs(result, a, status);
+ }
+ else {
+ mpd_qcopy(result, a, status);
+ }
+
+ mpd_qfinalize(result, ctx, status);
+}
+
+/* The largest representable number that is smaller than the operand. */
+void
+mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx; /* function context */
+ MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ if (mpd_isnegative(a)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+ else {
+ mpd_clear_flags(result);
+ mpd_qmaxcoeff(result, ctx, status);
+ if (mpd_isnan(result)) {
+ return;
+ }
+ result->exp = ctx->emax - ctx->prec + 1;
+ return;
+ }
+ }
+ /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+
+ mpd_workcontext(&workctx, ctx);
+ workctx.round = MPD_ROUND_FLOOR;
+
+ if (!mpd_qcopy(result, a, status)) {
+ return;
+ }
+
+ mpd_qfinalize(result, &workctx, &workctx.status);
+ if (workctx.status&(MPD_Inexact|MPD_Errors)) {
+ *status |= (workctx.status&MPD_Errors);
+ return;
+ }
+
+ workctx.status = 0;
+ mpd_qsub(result, a, &tiny, &workctx, &workctx.status);
+ *status |= (workctx.status&MPD_Errors);
+}
+
+/* The smallest representable number that is larger than the operand. */
+void
+mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1);
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ if (mpd_ispositive(a)) {
+ mpd_qcopy(result, a, status);
+ }
+ else {
+ mpd_clear_flags(result);
+ mpd_qmaxcoeff(result, ctx, status);
+ if (mpd_isnan(result)) {
+ return;
+ }
+ mpd_set_flags(result, MPD_NEG);
+ result->exp = mpd_etop(ctx);
+ }
+ return;
+ }
+ }
+
+ mpd_workcontext(&workctx, ctx);
+ workctx.round = MPD_ROUND_CEILING;
+
+ if (!mpd_qcopy(result, a, status)) {
+ return;
+ }
+
+ mpd_qfinalize(result, &workctx, &workctx.status);
+ if (workctx.status & (MPD_Inexact|MPD_Errors)) {
+ *status |= (workctx.status&MPD_Errors);
+ return;
+ }
+
+ workctx.status = 0;
+ mpd_qadd(result, a, &tiny, &workctx, &workctx.status);
+ *status |= (workctx.status&MPD_Errors);
+}
+
+/*
+ * The number closest to the first operand that is in the direction towards
+ * the second operand.
+ */
+void
+mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ int c;
+
+ if (mpd_isnan(a) || mpd_isnan(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status))
+ return;
+ }
+
+ c = _mpd_cmp(a, b);
+ if (c == 0) {
+ mpd_qcopy_sign(result, a, b, status);
+ return;
+ }
+
+ if (c < 0) {
+ mpd_qnext_plus(result, a, ctx, status);
+ }
+ else {
+ mpd_qnext_minus(result, a, ctx, status);
+ }
+
+ if (mpd_isinfinite(result)) {
+ *status |= (MPD_Overflow|MPD_Rounded|MPD_Inexact);
+ }
+ else if (mpd_adjexp(result) < ctx->emin) {
+ *status |= (MPD_Underflow|MPD_Subnormal|MPD_Rounded|MPD_Inexact);
+ if (mpd_iszero(result)) {
+ *status |= MPD_Clamped;
+ }
+ }
+}
+
+/*
+ * Internal function: Integer power with mpd_uint_t exponent, base is modified!
+ * Function can fail with MPD_Malloc_error.
+ */
+static inline void
+_mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_uint_t n;
+
+ if (exp == 0) {
+ _settriple(result, resultsign, 1, 0); /* GCOV_NOT_REACHED */
+ return; /* GCOV_NOT_REACHED */
+ }
+
+ if (!mpd_qcopy(result, base, status)) {
+ return;
+ }
+
+ n = mpd_bits[mpd_bsr(exp)];
+ while (n >>= 1) {
+ mpd_qmul(result, result, result, ctx, &workstatus);
+ if (exp & n) {
+ mpd_qmul(result, result, base, ctx, &workstatus);
+ }
+ if (workstatus & (MPD_Overflow|MPD_Clamped)) {
+ break;
+ }
+ }
+
+ *status |= workstatus;
+ mpd_set_sign(result, resultsign);
+}
+
+/*
+ * Internal function: Integer power with mpd_t exponent, tbase and texp
+ * are modified!! Function can fail with MPD_Malloc_error.
+ */
+static inline void
+_mpd_qpow_mpd(mpd_t *result, mpd_t *tbase, mpd_t *texp, uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_context_t maxctx;
+ MPD_NEW_CONST(two,0,0,1,1,1,2);
+
+
+ mpd_maxcontext(&maxctx);
+
+ /* resize to smaller cannot fail */
+ mpd_qcopy(result, &one, status);
+
+ while (!mpd_iszero(texp)) {
+ if (mpd_isodd(texp)) {
+ mpd_qmul(result, result, tbase, ctx, &workstatus);
+ *status |= workstatus;
+ if (workstatus & (MPD_Overflow|MPD_Clamped)) {
+ break;
+ }
+ }
+ mpd_qmul(tbase, tbase, tbase, ctx, &workstatus);
+ mpd_qdivint(texp, texp, &two, &maxctx, &workstatus);
+ if (mpd_isnan(tbase) || mpd_isnan(texp)) {
+ mpd_seterror(result, workstatus&MPD_Errors, status);
+ return;
+ }
+ }
+ mpd_set_sign(result, resultsign);
+}
+
+/*
+ * The power function for integer exponents.
+ */
+static void
+_mpd_qpow_int(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_STATIC(tbase,0,0,0,0);
+ MPD_NEW_STATIC(texp,0,0,0,0);
+ mpd_ssize_t n;
+
+
+ mpd_workcontext(&workctx, ctx);
+ workctx.prec += (exp->digits + exp->exp + 2);
+ workctx.round = MPD_ROUND_HALF_EVEN;
+ workctx.clamp = 0;
+ if (mpd_isnegative(exp)) {
+ mpd_qdiv(&tbase, &one, base, &workctx, status);
+ if (*status&MPD_Errors) {
+ mpd_setspecial(result, MPD_POS, MPD_NAN);
+ goto finish;
+ }
+ }
+ else {
+ if (!mpd_qcopy(&tbase, base, status)) {
+ mpd_setspecial(result, MPD_POS, MPD_NAN);
+ goto finish;
+ }
+ }
+
+ n = mpd_qabs_uint(exp, &workctx.status);
+ if (workctx.status&MPD_Invalid_operation) {
+ if (!mpd_qcopy(&texp, exp, status)) {
+ mpd_setspecial(result, MPD_POS, MPD_NAN); /* GCOV_UNLIKELY */
+ goto finish; /* GCOV_UNLIKELY */
+ }
+ _mpd_qpow_mpd(result, &tbase, &texp, resultsign, &workctx, status);
+ }
+ else {
+ _mpd_qpow_uint(result, &tbase, n, resultsign, &workctx, status);
+ }
+
+ if (mpd_isinfinite(result)) {
+ /* for ROUND_DOWN, ROUND_FLOOR, etc. */
+ _settriple(result, resultsign, 1, MPD_EXP_INF);
+ }
+
+finish:
+ mpd_del(&tbase);
+ mpd_del(&texp);
+ mpd_qfinalize(result, ctx, status);
+}
+
+/*
+ * This is an internal function that does not check for NaNs.
+ */
+static int
+_qcheck_pow_one_inf(mpd_t *result, const mpd_t *base, uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_ssize_t shift;
+ int cmp;
+
+ if ((cmp = _mpd_cmp(base, &one)) == 0) {
+ shift = ctx->prec-1;
+ mpd_qshiftl(result, &one, shift, status);
+ result->exp = -shift;
+ mpd_set_flags(result, resultsign);
+ *status |= (MPD_Inexact|MPD_Rounded);
+ }
+
+ return cmp;
+}
+
+/*
+ * If base equals one, calculate the correct power of one result.
+ * Otherwise, result is undefined. Return the value of the comparison
+ * against 1.
+ *
+ * This is an internal function that does not check for specials.
+ */
+static int
+_qcheck_pow_one(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_ssize_t shift;
+ int cmp;
+
+ if ((cmp = _mpd_cmp_abs(base, &one)) == 0) {
+ if (_mpd_isint(exp)) {
+ if (mpd_isnegative(exp)) {
+ _settriple(result, resultsign, 1, 0);
+ return 0;
+ }
+ /* 1.000**3 = 1.000000000 */
+ mpd_qmul_ssize(result, exp, -base->exp, ctx, &workstatus);
+ if (workstatus&MPD_Errors) {
+ *status |= (workstatus&MPD_Errors);
+ return 0;
+ }
+ /* digits-1 after exponentiation */
+ shift = mpd_qget_ssize(result, &workstatus);
+ /* shift is MPD_SSIZE_MAX if result is too large */
+ if (shift > ctx->prec-1) {
+ shift = ctx->prec-1;
+ *status |= MPD_Rounded;
+ }
+ }
+ else if (mpd_ispositive(base)) {
+ shift = ctx->prec-1;
+ *status |= (MPD_Inexact|MPD_Rounded);
+ }
+ else {
+ return -2; /* GCOV_NOT_REACHED */
+ }
+ if (!mpd_qshiftl(result, &one, shift, status)) {
+ return 0;
+ }
+ result->exp = -shift;
+ mpd_set_flags(result, resultsign);
+ }
+
+ return cmp;
+}
+
+/*
+ * Detect certain over/underflow of x**y.
+ * ACL2 proof: pow_bounds.lisp.
+ *
+ * Symbols:
+ *
+ * e: EXP_INF or EXP_CLAMP
+ * x: base
+ * y: exponent
+ *
+ * omega(e) = log10(abs(e))
+ * zeta(x) = log10(abs(log10(x)))
+ * theta(y) = log10(abs(y))
+ *
+ * Upper and lower bounds:
+ *
+ * ub_omega(e) = ceil(log10(abs(e)))
+ * lb_theta(y) = floor(log10(abs(y)))
+ *
+ * | floor(log10(floor(abs(log10(x))))) if x < 1/10 or x >= 10
+ * lb_zeta(x) = | floor(log10(abs(x-1)/10)) if 1/10 <= x < 1
+ * | floor(log10(abs((x-1)/100))) if 1 < x < 10
+ *
+ * ub_omega(e) and lb_theta(y) are obviously upper and lower bounds
+ * for omega(e) and theta(y).
+ *
+ * lb_zeta is a lower bound for zeta(x):
+ *
+ * x < 1/10 or x >= 10:
+ *
+ * abs(log10(x)) >= 1, so the outer log10 is well defined. Since log10
+ * is strictly increasing, the end result is a lower bound.
+ *
+ * 1/10 <= x < 1:
+ *
+ * We use: log10(x) <= (x-1)/log(10)
+ * abs(log10(x)) >= abs(x-1)/log(10)
+ * abs(log10(x)) >= abs(x-1)/10
+ *
+ * 1 < x < 10:
+ *
+ * We use: (x-1)/(x*log(10)) < log10(x)
+ * abs((x-1)/100) < abs(log10(x))
+ *
+ * XXX: abs((x-1)/10) would work, need ACL2 proof.
+ *
+ *
+ * Let (0 < x < 1 and y < 0) or (x > 1 and y > 0). (H1)
+ * Let ub_omega(exp_inf) < lb_zeta(x) + lb_theta(y) (H2)
+ *
+ * Then:
+ * log10(abs(exp_inf)) < log10(abs(log10(x))) + log10(abs(y)). (1)
+ * exp_inf < log10(x) * y (2)
+ * 10**exp_inf < x**y (3)
+ *
+ * Let (0 < x < 1 and y > 0) or (x > 1 and y < 0). (H3)
+ * Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y) (H4)
+ *
+ * Then:
+ * log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)). (4)
+ * log10(x) * y < exp_clamp (5)
+ * x**y < 10**exp_clamp (6)
+ *
+ */
+static mpd_ssize_t
+_lower_bound_zeta(const mpd_t *x, uint32_t *status)
+{
+ mpd_context_t maxctx;
+ MPD_NEW_STATIC(scratch,0,0,0,0);
+ mpd_ssize_t t, u;
+
+ t = mpd_adjexp(x);
+ if (t > 0) {
+ /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */
+ return mpd_exp_digits(t) - 1;
+ }
+ else if (t < -1) {
+ /* x < 1/10 -> floor(log10(floor(abs(log10(x))))) */
+ return mpd_exp_digits(t+1) - 1;
+ }
+ else {
+ mpd_maxcontext(&maxctx);
+ mpd_qsub(&scratch, x, &one, &maxctx, status);
+ if (mpd_isspecial(&scratch)) {
+ mpd_del(&scratch);
+ return MPD_SSIZE_MAX;
+ }
+ u = mpd_adjexp(&scratch);
+ mpd_del(&scratch);
+
+ /* t == -1, 1/10 <= x < 1 -> floor(log10(abs(x-1)/10))
+ * t == 0, 1 < x < 10 -> floor(log10(abs(x-1)/100)) */
+ return (t == 0) ? u-2 : u-1;
+ }
+}
+
+/*
+ * Detect cases of certain overflow/underflow in the power function.
+ * Assumptions: x != 1, y != 0. The proof above is for positive x.
+ * If x is negative and y is an odd integer, x**y == -(abs(x)**y),
+ * so the analysis does not change.
+ */
+static int
+_qcheck_pow_bounds(mpd_t *result, const mpd_t *x, const mpd_t *y,
+ uint8_t resultsign,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ MPD_NEW_SHARED(abs_x, x);
+ mpd_ssize_t ub_omega, lb_zeta, lb_theta;
+ uint8_t sign;
+
+ mpd_set_positive(&abs_x);
+
+ lb_theta = mpd_adjexp(y);
+ lb_zeta = _lower_bound_zeta(&abs_x, status);
+ if (lb_zeta == MPD_SSIZE_MAX) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return 1;
+ }
+
+ sign = (mpd_adjexp(&abs_x) < 0) ^ mpd_sign(y);
+ if (sign == 0) {
+ /* (0 < |x| < 1 and y < 0) or (|x| > 1 and y > 0) */
+ ub_omega = mpd_exp_digits(ctx->emax);
+ if (ub_omega < lb_zeta + lb_theta) {
+ _settriple(result, resultsign, 1, MPD_EXP_INF);
+ mpd_qfinalize(result, ctx, status);
+ return 1;
+ }
+ }
+ else {
+ /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */
+ ub_omega = mpd_exp_digits(mpd_etiny(ctx));
+ if (ub_omega < lb_zeta + lb_theta) {
+ _settriple(result, resultsign, 1, mpd_etiny(ctx)-1);
+ mpd_qfinalize(result, ctx, status);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * TODO: Implement algorithm for computing exact powers from decimal.py.
+ * In order to prevent infinite loops, this has to be called before
+ * using Ziv's strategy for correct rounding.
+ */
+/*
+static int
+_mpd_qpow_exact(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ return 0;
+}
+*/
+
+/* The power function for real exponents */
+static void
+_mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_STATIC(texp,0,0,0,0);
+
+ if (!mpd_qcopy(&texp, exp, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+
+ mpd_maxcontext(&workctx);
+ workctx.prec = (base->digits > ctx->prec) ? base->digits : ctx->prec;
+ workctx.prec += (4 + MPD_EXPDIGITS);
+ workctx.round = MPD_ROUND_HALF_EVEN;
+ workctx.allcr = ctx->allcr;
+
+ mpd_qln(result, base, &workctx, &workctx.status);
+ mpd_qmul(result, result, &texp, &workctx, &workctx.status);
+ mpd_qexp(result, result, &workctx, status);
+
+ mpd_del(&texp);
+ *status |= (workctx.status&MPD_Errors);
+ *status |= (MPD_Inexact|MPD_Rounded);
+}
+
+/* The power function: base**exp */
+void
+mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint8_t resultsign = 0;
+ int intexp = 0;
+ int cmp;
+
+ if (mpd_isspecial(base) || mpd_isspecial(exp)) {
+ if (mpd_qcheck_nans(result, base, exp, ctx, status)) {
+ return;
+ }
+ }
+ if (mpd_isinteger(exp)) {
+ intexp = 1;
+ resultsign = mpd_isnegative(base) && mpd_isodd(exp);
+ }
+
+ if (mpd_iszero(base)) {
+ if (mpd_iszero(exp)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ }
+ else if (mpd_isnegative(exp)) {
+ mpd_setspecial(result, resultsign, MPD_INF);
+ }
+ else {
+ _settriple(result, resultsign, 0, 0);
+ }
+ return;
+ }
+ if (mpd_isnegative(base)) {
+ if (!intexp || mpd_isinfinite(exp)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ }
+ if (mpd_isinfinite(exp)) {
+ /* power of one */
+ cmp = _qcheck_pow_one_inf(result, base, resultsign, ctx, status);
+ if (cmp == 0) {
+ return;
+ }
+ else {
+ cmp *= mpd_arith_sign(exp);
+ if (cmp < 0) {
+ _settriple(result, resultsign, 0, 0);
+ }
+ else {
+ mpd_setspecial(result, resultsign, MPD_INF);
+ }
+ }
+ return;
+ }
+ if (mpd_isinfinite(base)) {
+ if (mpd_iszero(exp)) {
+ _settriple(result, resultsign, 1, 0);
+ }
+ else if (mpd_isnegative(exp)) {
+ _settriple(result, resultsign, 0, 0);
+ }
+ else {
+ mpd_setspecial(result, resultsign, MPD_INF);
+ }
+ return;
+ }
+ if (mpd_iszero(exp)) {
+ _settriple(result, resultsign, 1, 0);
+ return;
+ }
+ if (_qcheck_pow_one(result, base, exp, resultsign, ctx, status) == 0) {
+ return;
+ }
+ if (_qcheck_pow_bounds(result, base, exp, resultsign, ctx, status)) {
+ return;
+ }
+
+ if (intexp) {
+ _mpd_qpow_int(result, base, exp, resultsign, ctx, status);
+ }
+ else {
+ _mpd_qpow_real(result, base, exp, ctx, status);
+ if (!mpd_isspecial(result) && _mpd_cmp(result, &one) == 0) {
+ mpd_ssize_t shift = ctx->prec-1;
+ mpd_qshiftl(result, &one, shift, status);
+ result->exp = -shift;
+ }
+ if (mpd_isinfinite(result)) {
+ /* for ROUND_DOWN, ROUND_FLOOR, etc. */
+ _settriple(result, MPD_POS, 1, MPD_EXP_INF);
+ }
+ mpd_qfinalize(result, ctx, status);
+ }
+}
+
+/*
+ * Internal function: Integer powmod with mpd_uint_t exponent, base is modified!
+ * Function can fail with MPD_Malloc_error.
+ */
+static inline void
+_mpd_qpowmod_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp,
+ mpd_t *mod, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+
+ mpd_maxcontext(&maxcontext);
+
+ /* resize to smaller cannot fail */
+ mpd_qcopy(result, &one, status);
+
+ while (exp > 0) {
+ if (exp & 1) {
+ mpd_qmul(result, result, base, &maxcontext, status);
+ mpd_qrem(result, result, mod, &maxcontext, status);
+ }
+ mpd_qmul(base, base, base, &maxcontext, status);
+ mpd_qrem(base, base, mod, &maxcontext, status);
+ exp >>= 1;
+ }
+}
+
+/* The powmod function: (base**exp) % mod */
+void
+mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp,
+ const mpd_t *mod,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxcontext;
+ MPD_NEW_STATIC(tbase,0,0,0,0);
+ MPD_NEW_STATIC(texp,0,0,0,0);
+ MPD_NEW_STATIC(tmod,0,0,0,0);
+ MPD_NEW_STATIC(tmp,0,0,0,0);
+ MPD_NEW_CONST(two,0,0,1,1,1,2);
+ mpd_ssize_t tbase_exp, texp_exp;
+ mpd_ssize_t i;
+ mpd_t t;
+ mpd_uint_t r;
+ uint8_t sign;
+
+
+ if (mpd_isspecial(base) || mpd_isspecial(exp) || mpd_isspecial(mod)) {
+ if (mpd_qcheck_3nans(result, base, exp, mod, ctx, status)) {
+ return;
+ }
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+
+ if (!_mpd_isint(base) || !_mpd_isint(exp) || !_mpd_isint(mod)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_iszerocoeff(mod)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mod->digits+mod->exp > ctx->prec) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ sign = (mpd_isnegative(base)) && (mpd_isodd(exp));
+ if (mpd_iszerocoeff(exp)) {
+ if (mpd_iszerocoeff(base)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ r = (_mpd_cmp_abs(mod, &one)==0) ? 0 : 1;
+ _settriple(result, sign, r, 0);
+ return;
+ }
+ if (mpd_isnegative(exp)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_iszerocoeff(base)) {
+ _settriple(result, sign, 0, 0);
+ return;
+ }
+
+ if (!mpd_qcopy(&tmod, mod, status)) {
+ goto mpd_errors;
+ }
+ mpd_set_positive(&tmod);
+
+ mpd_maxcontext(&maxcontext);
+
+ mpd_qround_to_int(&tbase, base, &maxcontext, status);
+ mpd_qround_to_int(&texp, exp, &maxcontext, status);
+ mpd_qround_to_int(&tmod, &tmod, &maxcontext, status);
+
+ tbase_exp = tbase.exp;
+ tbase.exp = 0;
+ texp_exp = texp.exp;
+ texp.exp = 0;
+
+ /* base = (base.int % modulo * pow(10, base.exp, modulo)) % modulo */
+ mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
+ _settriple(result, MPD_POS, 1, tbase_exp);
+ mpd_qrem(result, result, &tmod, &maxcontext, status);
+ mpd_qmul(&tbase, &tbase, result, &maxcontext, status);
+ mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
+ if (mpd_isspecial(&tbase) ||
+ mpd_isspecial(&texp) ||
+ mpd_isspecial(&tmod)) {
+ goto mpd_errors;
+ }
+
+ for (i = 0; i < texp_exp; i++) {
+ _mpd_qpowmod_uint(&tmp, &tbase, 10, &tmod, status);
+ t = tmp;
+ tmp = tbase;
+ tbase = t;
+ }
+ if (mpd_isspecial(&tbase)) {
+ goto mpd_errors; /* GCOV_UNLIKELY */
+ }
+
+ /* resize to smaller cannot fail */
+ mpd_qcopy(result, &one, status);
+ while (mpd_isfinite(&texp) && !mpd_iszero(&texp)) {
+ if (mpd_isodd(&texp)) {
+ mpd_qmul(result, result, &tbase, &maxcontext, status);
+ mpd_qrem(result, result, &tmod, &maxcontext, status);
+ }
+ mpd_qmul(&tbase, &tbase, &tbase, &maxcontext, status);
+ mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status);
+ mpd_qdivint(&texp, &texp, &two, &maxcontext, status);
+ }
+ if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) ||
+ mpd_isspecial(&tmod) || mpd_isspecial(result)) {
+ /* MPD_Malloc_error */
+ goto mpd_errors;
+ }
+ else {
+ mpd_set_sign(result, sign);
+ }
+
+out:
+ mpd_del(&tbase);
+ mpd_del(&texp);
+ mpd_del(&tmod);
+ mpd_del(&tmp);
+ mpd_qfinalize(result, ctx, status);
+ return;
+
+mpd_errors:
+ mpd_setspecial(result, MPD_POS, MPD_NAN);
+ goto out;
+}
+
+void
+mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_ssize_t b_exp = b->exp;
+ mpd_ssize_t expdiff, shift;
+ mpd_uint_t rnd;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(result, a, b, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a) && mpd_isinfinite(b)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ if (b->exp > ctx->emax || b->exp < mpd_etiny(ctx)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ if (mpd_iszero(a)) {
+ _settriple(result, mpd_sign(a), 0, b->exp);
+ mpd_qfinalize(result, ctx, status);
+ return;
+ }
+
+
+ expdiff = a->exp - b->exp;
+ if (a->digits + expdiff > ctx->prec) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ if (expdiff >= 0) {
+ shift = expdiff;
+ if (!mpd_qshiftl(result, a, shift, status)) {
+ return;
+ }
+ result->exp = b_exp;
+ }
+ else {
+ /* At this point expdiff < 0 and a->digits+expdiff <= prec,
+ * so the shift before an increment will fit in prec. */
+ shift = -expdiff;
+ rnd = mpd_qshiftr(result, a, shift, status);
+ if (rnd == MPD_UINT_MAX) {
+ return;
+ }
+ result->exp = b_exp;
+ if (!_mpd_apply_round_fit(result, rnd, ctx, status)) {
+ return;
+ }
+ workstatus |= MPD_Rounded;
+ if (rnd) {
+ workstatus |= MPD_Inexact;
+ }
+ }
+
+ if (mpd_adjexp(result) > ctx->emax ||
+ mpd_adjexp(result) < mpd_etiny(ctx)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ *status |= workstatus;
+ mpd_qfinalize(result, ctx, status);
+}
+
+void
+mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_ssize_t shift, maxexp, maxshift;
+ uint8_t sign_a = mpd_sign(a);
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+ if (!mpd_qcopy(result, a, status)) {
+ return;
+ }
+ mpd_qfinalize(result, ctx, status);
+ if (mpd_isspecial(result)) {
+ return;
+ }
+ if (mpd_iszero(result)) {
+ _settriple(result, sign_a, 0, 0);
+ return;
+ }
+
+ shift = mpd_trail_zeros(result);
+ maxexp = (ctx->clamp) ? mpd_etop(ctx) : ctx->emax;
+ /* After the finalizing above result->exp <= maxexp. */
+ maxshift = maxexp - result->exp;
+ shift = (shift > maxshift) ? maxshift : shift;
+
+ mpd_qshiftr_inplace(result, shift);
+ result->exp += shift;
+}
+
+void
+mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ MPD_NEW_STATIC(q,0,0,0,0);
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(r, a, b, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_seterror(r, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(b)) {
+ mpd_qcopy(r, a, status);
+ mpd_qfinalize(r, ctx, status);
+ return;
+ }
+ /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+ if (mpd_iszerocoeff(b)) {
+ if (mpd_iszerocoeff(a)) {
+ mpd_seterror(r, MPD_Division_undefined, status);
+ }
+ else {
+ mpd_seterror(r, MPD_Invalid_operation, status);
+ }
+ return;
+ }
+
+ _mpd_qdivmod(&q, r, a, b, ctx, status);
+ mpd_del(&q);
+ mpd_qfinalize(r, ctx, status);
+}
+
+void
+mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t workctx;
+ MPD_NEW_STATIC(btmp,0,0,0,0);
+ MPD_NEW_STATIC(q,0,0,0,0);
+ mpd_ssize_t expdiff, floordigits;
+ int cmp, isodd, allnine;
+
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ if (mpd_qcheck_nans(r, a, b, ctx, status)) {
+ return;
+ }
+ if (mpd_isinfinite(a)) {
+ mpd_seterror(r, MPD_Invalid_operation, status);
+ return;
+ }
+ if (mpd_isinfinite(b)) {
+ mpd_qcopy(r, a, status);
+ mpd_qfinalize(r, ctx, status);
+ return;
+ }
+ /* debug */
+ abort(); /* GCOV_NOT_REACHED */
+ }
+ if (mpd_iszerocoeff(b)) {
+ if (mpd_iszerocoeff(a)) {
+ mpd_seterror(r, MPD_Division_undefined, status);
+ }
+ else {
+ mpd_seterror(r, MPD_Invalid_operation, status);
+ }
+ return;
+ }
+
+ if (r == b) {
+ if (!mpd_qcopy(&btmp, b, status)) {
+ mpd_seterror(r, MPD_Malloc_error, status);
+ return;
+ }
+ b = &btmp;
+ }
+
+ workctx = *ctx;
+ workctx.prec = a->digits;
+ workctx.prec = (workctx.prec > ctx->prec) ? workctx.prec : ctx->prec;
+
+ _mpd_qdivmod(&q, r, a, b, &workctx, status);
+ if (mpd_isnan(&q) || mpd_isnan(r) || q.digits > ctx->prec) {
+ mpd_seterror(r, MPD_Division_impossible, status);
+ goto finish;
+ }
+ if (mpd_iszerocoeff(r)) {
+ goto finish;
+ }
+
+ /* Deal with cases like rmnx078:
+ * remaindernear 999999999.5 1 -> NaN Division_impossible */
+ expdiff = mpd_adjexp(b) - mpd_adjexp(r);
+ if (-1 <= expdiff && expdiff <= 1) {
+
+ mpd_qtrunc(&q, &q, &workctx, &workctx.status);
+ allnine = mpd_coeff_isallnine(&q);
+ floordigits = q.digits;
+ isodd = mpd_isodd(&q);
+
+ mpd_maxcontext(&workctx);
+ if (mpd_sign(a) == mpd_sign(b)) {
+ _mpd_qsub(&q, r, b, &workctx, &workctx.status);
+ if (workctx.status&MPD_Errors) {
+ mpd_seterror(r, workctx.status&MPD_Errors, status);
+ goto finish;
+ }
+ }
+ else {
+ _mpd_qadd(&q, r, b, &workctx, &workctx.status);
+ if (workctx.status&MPD_Errors) {
+ mpd_seterror(r, workctx.status&MPD_Errors, status);
+ goto finish;
+ }
+ }
+
+ cmp = mpd_cmp_total_mag(&q, r);
+ if (cmp < 0 || (cmp == 0 && isodd)) {
+ if (allnine && floordigits == ctx->prec) {
+ mpd_seterror(r, MPD_Division_impossible, status);
+ goto finish;
+ }
+ mpd_qcopy(r, &q, status);
+ *status &= ~MPD_Rounded;
+ }
+ }
+
+
+finish:
+ mpd_del(&btmp);
+ mpd_del(&q);
+ mpd_qfinalize(r, ctx, status);
+}
+
+static void
+_mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_ssize_t expdiff, shift;
+ mpd_uint_t rnd;
+
+ if (mpd_isspecial(a)) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+
+ if (mpd_iszero(a)) {
+ _settriple(result, mpd_sign(a), 0, exp);
+ return;
+ }
+
+ expdiff = a->exp - exp;
+ if (expdiff >= 0) {
+ shift = expdiff;
+ if (a->digits + shift > MPD_MAX_PREC+1) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (!mpd_qshiftl(result, a, shift, status)) {
+ return;
+ }
+ result->exp = exp;
+ }
+ else {
+ shift = -expdiff;
+ rnd = mpd_qshiftr(result, a, shift, status);
+ if (rnd == MPD_UINT_MAX) {
+ return;
+ }
+ result->exp = exp;
+ _mpd_apply_round_excess(result, rnd, ctx, status);
+ *status |= MPD_Rounded;
+ if (rnd) {
+ *status |= MPD_Inexact;
+ }
+ }
+
+ if (mpd_issubnormal(result, ctx)) {
+ *status |= MPD_Subnormal;
+ }
+}
+
+/*
+ * Rescale a number so that it has exponent 'exp'. Does not regard context
+ * precision, emax, emin, but uses the rounding mode. Special numbers are
+ * quietly copied. Restrictions:
+ *
+ * MPD_MIN_ETINY <= exp <= MPD_MAX_EMAX+1
+ * result->digits <= MPD_MAX_PREC+1
+ */
+void
+mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ _mpd_qrescale(result, a, exp, ctx, status);
+}
+
+/*
+ * Same as mpd_qrescale, but with relaxed restrictions. The result of this
+ * function should only be used for formatting a number and never as input
+ * for other operations.
+ *
+ * MPD_MIN_ETINY-MPD_MAX_PREC <= exp <= MPD_MAX_EMAX+1
+ * result->digits <= MPD_MAX_PREC+1
+ */
+void
+mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY-MPD_MAX_PREC) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ _mpd_qrescale(result, a, exp, ctx, status);
+}
+
+/* Round to an integer according to 'action' and ctx->round. */
+enum {TO_INT_EXACT, TO_INT_SILENT, TO_INT_TRUNC};
+static void
+_mpd_qround_to_integral(int action, mpd_t *result, const mpd_t *a,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_uint_t rnd;
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ mpd_qcopy(result, a, status);
+ return;
+ }
+ if (a->exp >= 0) {
+ mpd_qcopy(result, a, status);
+ return;
+ }
+ if (mpd_iszerocoeff(a)) {
+ _settriple(result, mpd_sign(a), 0, 0);
+ return;
+ }
+
+ rnd = mpd_qshiftr(result, a, -a->exp, status);
+ if (rnd == MPD_UINT_MAX) {
+ return;
+ }
+ result->exp = 0;
+
+ if (action == TO_INT_EXACT || action == TO_INT_SILENT) {
+ _mpd_apply_round_excess(result, rnd, ctx, status);
+ if (action == TO_INT_EXACT) {
+ *status |= MPD_Rounded;
+ if (rnd) {
+ *status |= MPD_Inexact;
+ }
+ }
+ }
+}
+
+void
+mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ (void)_mpd_qround_to_integral(TO_INT_EXACT, result, a, ctx, status);
+}
+
+void
+mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, ctx, status);
+}
+
+void
+mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ (void)_mpd_qround_to_integral(TO_INT_TRUNC, result, a, ctx, status);
+}
+
+void
+mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx = *ctx;
+ workctx.round = MPD_ROUND_FLOOR;
+ (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
+ &workctx, status);
+}
+
+void
+mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t workctx = *ctx;
+ workctx.round = MPD_ROUND_CEILING;
+ (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a,
+ &workctx, status);
+}
+
+int
+mpd_same_quantum(const mpd_t *a, const mpd_t *b)
+{
+ if (mpd_isspecial(a) || mpd_isspecial(b)) {
+ return ((mpd_isnan(a) && mpd_isnan(b)) ||
+ (mpd_isinfinite(a) && mpd_isinfinite(b)));
+ }
+
+ return a->exp == b->exp;
+}
+
+/* Schedule the increase in precision for the Newton iteration. */
+static inline int
+recpr_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
+ mpd_ssize_t maxprec, mpd_ssize_t initprec)
+{
+ mpd_ssize_t k;
+ int i;
+
+ assert(maxprec > 0 && initprec > 0);
+ if (maxprec <= initprec) return -1;
+
+ i = 0; k = maxprec;
+ do {
+ k = (k+1) / 2;
+ klist[i++] = k;
+ } while (k > initprec);
+
+ return i-1;
+}
+
+/*
+ * Initial approximation for the reciprocal. Result has MPD_RDIGITS-2
+ * significant digits.
+ */
+static void
+_mpd_qreciprocal_approx(mpd_t *z, const mpd_t *v, uint32_t *status)
+{
+ mpd_uint_t p10data[2] = {0, mpd_pow10[MPD_RDIGITS-2]}; /* 10**(2*MPD_RDIGITS-2) */
+ mpd_uint_t dummy, word;
+ int n;
+
+ _mpd_get_msdigits(&dummy, &word, v, MPD_RDIGITS);
+ n = mpd_word_digits(word);
+ word *= mpd_pow10[MPD_RDIGITS-n];
+
+ mpd_qresize(z, 2, status);
+ (void)_mpd_shortdiv(z->data, p10data, 2, word);
+
+ mpd_clear_flags(z);
+ z->exp = -(v->exp + v->digits) - (MPD_RDIGITS-2);
+ z->len = (z->data[1] == 0) ? 1 : 2;
+ mpd_setdigits(z);
+}
+
+/* Reciprocal, calculated with Newton's Method. Assumption: result != a. */
+static void
+_mpd_qreciprocal(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ mpd_context_t varcontext, maxcontext;
+ mpd_t *z = result; /* current approximation */
+ mpd_t *v; /* a, normalized to a number between 0.1 and 1 */
+ MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */
+ MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
+ MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
+ MPD_NEW_CONST(two,0,0,1,1,1,2); /* const 2 */
+ mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
+ mpd_ssize_t adj, maxprec, initprec;
+ uint8_t sign = mpd_sign(a);
+ int i;
+
+ v = &vtmp;
+ assert(result != a);
+
+ mpd_clear_flags(v);
+ adj = v->digits + v->exp;
+ v->exp = -v->digits;
+
+ /* initial approximation */
+ _mpd_qreciprocal_approx(z, v, status);
+
+ mpd_maxcontext(&varcontext);
+ mpd_maxcontext(&maxcontext);
+ varcontext.round = MPD_ROUND_TRUNC;
+ maxcontext.round = MPD_ROUND_TRUNC;
+
+ maxprec = (v->digits > ctx->prec) ? v->digits : ctx->prec;
+ maxprec += 2;
+ initprec = MPD_RDIGITS-3;
+
+ i = recpr_schedule_prec(klist, maxprec, initprec);
+ for (; i >= 0; i--) {
+ mpd_qmul(&s, z, z, &maxcontext, status);
+ varcontext.prec = 2*klist[i] + 5;
+ if (v->digits > varcontext.prec) {
+ mpd_qshiftr(&t, v, v->digits-varcontext.prec, status);
+ t.exp = -varcontext.prec;
+ mpd_qmul(&t, &t, &s, &varcontext, status);
+ }
+ else {
+ mpd_qmul(&t, v, &s, &varcontext, status);
+ }
+ mpd_qmul(&s, z, &two, &maxcontext, status);
+ mpd_qsub(z, &s, &t, &maxcontext, status);
+ }
+
+ if (!mpd_isspecial(z)) {
+ z->exp -= adj;
+ mpd_set_flags(z, sign);
+ }
+
+ mpd_del(&s);
+ mpd_del(&t);
+ mpd_qfinalize(z, ctx, status);
+}
+
+/*
+ * Integer division with remainder of the coefficients: coeff(a) / coeff(b).
+ * This function is for large numbers where it is faster to divide by
+ * multiplying the dividend by the reciprocal of the divisor.
+ * The inexact result is fixed by a small loop, which should not take
+ * more than 2 iterations.
+ */
+static void
+_mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b,
+ uint32_t *status)
+{
+ mpd_context_t workctx;
+ mpd_t *qq = q, *rr = r;
+ mpd_t aa, bb;
+ int k;
+
+ mpd_maxcontext(&workctx);
+ _mpd_copy_shared(&aa, a);
+ _mpd_copy_shared(&bb, b);
+
+ mpd_set_positive(&aa);
+ mpd_set_positive(&bb);
+ aa.exp = 0;
+ bb.exp = 0;
+
+ if (q == a || q == b) {
+ if ((qq = mpd_qnew()) == NULL) {
+ *status |= MPD_Malloc_error;
+ goto nanresult;
+ }
+ }
+ if (r == a || r == b) {
+ if ((rr = mpd_qnew()) == NULL) {
+ *status |= MPD_Malloc_error;
+ goto nanresult;
+ }
+ }
+
+ /* maximum length of q + 3 digits */
+ workctx.prec = aa.digits - bb.digits + 1 + 3;
+ /* we get the reciprocal with precision maxlen(q) + 3 */
+ _mpd_qreciprocal(rr, &bb, &workctx, &workctx.status);
+
+ mpd_qmul(qq, &aa, rr, &workctx, &workctx.status);
+ mpd_qtrunc(qq, qq, &workctx, &workctx.status);
+
+ workctx.prec = aa.digits + 3;
+ /* get the remainder */
+ mpd_qmul(rr, &bb, qq, &workctx, &workctx.status);
+ mpd_qsub(rr, &aa, rr, &workctx, &workctx.status);
+
+ /* Fix the result. Algorithm from: Karl Hasselstrom, Fast Division of Large Integers */
+ for (k = 0;; k++) {
+ if (mpd_isspecial(rr)) {
+ *status |= (workctx.status&MPD_Errors);
+ goto nanresult;
+ }
+ if (k > 2) {
+ mpd_err_warn("libmpdec: internal error in " /* GCOV_NOT_REACHED */
+ "_mpd_qbarrett_divmod: please report"); /* GCOV_NOT_REACHED */
+ *status |= MPD_Invalid_operation; /* GCOV_NOT_REACHED */
+ goto nanresult; /* GCOV_NOT_REACHED */
+ }
+ else if (_mpd_cmp(&zero, rr) == 1) {
+ mpd_qadd(rr, rr, &bb, &workctx, &workctx.status);
+ mpd_qadd(qq, qq, &minus_one, &workctx, &workctx.status);
+ }
+ else if (_mpd_cmp(rr, &bb) == -1) {
+ break;
+ }
+ else {
+ mpd_qsub(rr, rr, &bb, &workctx, &workctx.status);
+ mpd_qadd(qq, qq, &one, &workctx, &workctx.status);
+ }
+ }
+
+ if (qq != q) {
+ if (!mpd_qcopy(q, qq, status)) {
+ goto nanresult; /* GCOV_UNLIKELY */
+ }
+ mpd_del(qq);
+ }
+ if (rr != r) {
+ if (!mpd_qcopy(r, rr, status)) {
+ goto nanresult; /* GCOV_UNLIKELY */
+ }
+ mpd_del(rr);
+ }
+
+ *status |= (workctx.status&MPD_Errors);
+ return;
+
+
+nanresult:
+ if (qq && qq != q) mpd_del(qq);
+ if (rr && rr != r) mpd_del(rr);
+ mpd_setspecial(q, MPD_POS, MPD_NAN);
+ mpd_setspecial(r, MPD_POS, MPD_NAN);
+}
+
+static inline int
+invroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2],
+ mpd_ssize_t maxprec, mpd_ssize_t initprec)
+{
+ mpd_ssize_t k;
+ int i;
+
+ assert(maxprec >= 3 && initprec >= 3);
+ if (maxprec <= initprec) return -1;
+
+ i = 0; k = maxprec;
+ do {
+ k = (k+3) / 2;
+ klist[i++] = k;
+ } while (k > initprec);
+
+ return i-1;
+}
+
+/*
+ * Initial approximation for the inverse square root.
+ *
+ * Input:
+ * v := 7 or 8 decimal digits with an implicit exponent of 10**-6,
+ * representing a number 1 <= x < 100.
+ *
+ * Output:
+ * An approximation to 1/sqrt(v)
+ */
+static inline void
+_invroot_init_approx(mpd_t *z, mpd_uint_t v)
+{
+ mpd_uint_t lo = 1000;
+ mpd_uint_t hi = 10000;
+ mpd_uint_t a, sq;
+
+ assert(v >= lo*lo && v < (hi+1)*(hi+1));
+
+ for(;;) {
+ a = (lo + hi) / 2;
+ sq = a * a;
+ if (v >= sq) {
+ if (v < sq + 2*a + 1) {
+ break;
+ }
+ lo = a + 1;
+ }
+ else {
+ hi = a - 1;
+ }
+ }
+
+ /* At this point a/1000 is an approximation to sqrt(v). */
+ mpd_minalloc(z);
+ mpd_clear_flags(z);
+ z->data[0] = 1000000000UL / a;
+ z->len = 1;
+ z->exp = -6;
+ mpd_setdigits(z);
+}
+
+static void
+_mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_context_t varcontext, maxcontext;
+ mpd_t *z = result; /* current approximation */
+ mpd_t *v; /* a, normalized to a number between 1 and 100 */
+ MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */
+ MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */
+ MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */
+ MPD_NEW_CONST(one_half,0,-1,1,1,1,5);
+ MPD_NEW_CONST(three,0,0,1,1,1,3);
+ mpd_ssize_t klist[MPD_MAX_PREC_LOG2];
+ mpd_ssize_t ideal_exp, shift;
+ mpd_ssize_t adj, tz;
+ mpd_ssize_t maxprec, fracdigits;
+ mpd_uint_t x, dummy;
+ int i, n;
+
+
+ ideal_exp = -(a->exp - (a->exp & 1)) / 2;
+
+ v = &vtmp;
+ if (result == a) {
+ if ((v = mpd_qncopy(a)) == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ }
+
+ /* normalize a to 1 <= v < 100 */
+ if ((v->digits+v->exp) & 1) {
+ fracdigits = v->digits - 1;
+ v->exp = -fracdigits;
+ n = (v->digits > 7) ? 7 : (int)v->digits;
+ _mpd_get_msdigits(&dummy, &x, v, n);
+ if (n < 7) {
+ x *= mpd_pow10[7-n];
+ }
+ }
+ else {
+ fracdigits = v->digits - 2;
+ v->exp = -fracdigits;
+ n = (v->digits > 8) ? 8 : (int)v->digits;
+ _mpd_get_msdigits(&dummy, &x, v, n);
+ if (n < 8) {
+ x *= mpd_pow10[8-n];
+ }
+ }
+ adj = (a->exp-v->exp) / 2;
+
+ /* initial approximation */
+ _invroot_init_approx(z, x);
+
+ mpd_maxcontext(&maxcontext);
+ mpd_maxcontext(&varcontext);
+ varcontext.round = MPD_ROUND_TRUNC;
+ maxprec = ctx->prec + 2;
+
+ i = invroot_schedule_prec(klist, maxprec, 3);
+ for (; i >= 0; i--) {
+ varcontext.prec = 2*klist[i]+2;
+ mpd_qmul(&s, z, z, &maxcontext, &workstatus);
+ if (v->digits > varcontext.prec) {
+ shift = v->digits - varcontext.prec;
+ mpd_qshiftr(&t, v, shift, &workstatus);
+ t.exp += shift;
+ mpd_qmul(&t, &t, &s, &varcontext, &workstatus);
+ }
+ else {
+ mpd_qmul(&t, v, &s, &varcontext, &workstatus);
+ }
+ mpd_qsub(&t, &three, &t, &maxcontext, &workstatus);
+ mpd_qmul(z, z, &t, &varcontext, &workstatus);
+ mpd_qmul(z, z, &one_half, &maxcontext, &workstatus);
+ }
+
+ z->exp -= adj;
+
+ tz = mpd_trail_zeros(result);
+ shift = ideal_exp - result->exp;
+ shift = (tz > shift) ? shift : tz;
+ if (shift > 0) {
+ mpd_qshiftr_inplace(result, shift);
+ result->exp += shift;
+ }
+
+
+ mpd_del(&s);
+ mpd_del(&t);
+ if (v != &vtmp) mpd_del(v);
+ *status |= (workstatus&MPD_Errors);
+ varcontext = *ctx;
+ varcontext.round = MPD_ROUND_HALF_EVEN;
+ mpd_qfinalize(result, &varcontext, status);
+}
+
+void
+mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ /* positive infinity */
+ _settriple(result, MPD_POS, 0, mpd_etiny(ctx));
+ *status |= MPD_Clamped;
+ return;
+ }
+ if (mpd_iszero(a)) {
+ mpd_setspecial(result, mpd_sign(a), MPD_INF);
+ *status |= MPD_Division_by_zero;
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ _mpd_qinvroot(result, a, ctx, status);
+}
+
+/*
+ * Ensure correct rounding. Algorithm after Hull & Abrham, "Properly Rounded
+ * Variable Precision Square Root", ACM Transactions on Mathematical Software,
+ * Vol. 11, No. 3.
+ */
+static void
+_mpd_fix_sqrt(mpd_t *result, const mpd_t *a, mpd_t *tmp,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_context_t maxctx;
+ MPD_NEW_CONST(u,0,0,1,1,1,5);
+
+ mpd_maxcontext(&maxctx);
+ u.exp = u.digits - ctx->prec + result->exp - 1;
+
+ _mpd_qsub(tmp, result, &u, &maxctx, status);
+ if (*status&MPD_Errors) goto nanresult;
+
+ _mpd_qmul(tmp, tmp, tmp, &maxctx, status);
+ if (*status&MPD_Errors) goto nanresult;
+
+ if (_mpd_cmp(tmp, a) == 1) {
+ u.exp += 1;
+ u.data[0] = 1;
+ _mpd_qsub(result, result, &u, &maxctx, status);
+ }
+ else {
+ _mpd_qadd(tmp, result, &u, &maxctx, status);
+ if (*status&MPD_Errors) goto nanresult;
+
+ _mpd_qmul(tmp, tmp, tmp, &maxctx, status);
+ if (*status&MPD_Errors) goto nanresult;
+
+ if (_mpd_cmp(tmp, a) == -1) {
+ u.exp += 1;
+ u.data[0] = 1;
+ _mpd_qadd(result, result, &u, &maxctx, status);
+ }
+ }
+
+ return;
+
+nanresult:
+ mpd_setspecial(result, MPD_POS, MPD_NAN);
+}
+
+void
+mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx,
+ uint32_t *status)
+{
+ uint32_t workstatus = 0;
+ mpd_context_t varcontext;
+ mpd_t *z = result; /* current approximation */
+ MPD_NEW_STATIC(v,0,0,0,0); /* a, normalized to a number between 1 and 10 */
+ MPD_NEW_STATIC(vtmp,0,0,0,0);
+ MPD_NEW_STATIC(tmp,0,0,0,0);
+ mpd_ssize_t ideal_exp, shift;
+ mpd_ssize_t target_prec, fracdigits;
+ mpd_ssize_t a_exp, a_digits;
+ mpd_ssize_t adj, tz;
+ mpd_uint_t dummy, t;
+ int exact = 0;
+
+
+ varcontext = *ctx;
+ varcontext.round = MPD_ROUND_HALF_EVEN;
+ ideal_exp = (a->exp - (a->exp & 1)) / 2;
+
+ if (mpd_isspecial(a)) {
+ if (mpd_qcheck_nan(result, a, ctx, status)) {
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ mpd_setspecial(result, MPD_POS, MPD_INF);
+ return;
+ }
+ if (mpd_iszero(a)) {
+ _settriple(result, mpd_sign(a), 0, ideal_exp);
+ mpd_qfinalize(result, ctx, status);
+ return;
+ }
+ if (mpd_isnegative(a)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+
+ if (!mpd_qcopy(&v, a, status)) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ goto finish;
+ }
+
+ a_exp = a->exp;
+ a_digits = a->digits;
+
+ /* normalize a to 1 <= v < 100 */
+ if ((v.digits+v.exp) & 1) {
+ fracdigits = v.digits - 1;
+ v.exp = -fracdigits;
+ _mpd_get_msdigits(&dummy, &t, &v, 3);
+ t = t < 100 ? t*10 : t;
+ t = t < 100 ? t*10 : t;
+ }
+ else {
+ fracdigits = v.digits - 2;
+ v.exp = -fracdigits;
+ _mpd_get_msdigits(&dummy, &t, &v, 4);
+ t = t < 1000 ? t*10 : t;
+ t = t < 1000 ? t*10 : t;
+ t = t < 1000 ? t*10 : t;
+ }
+ adj = (a_exp-v.exp) / 2;
+
+
+ /* use excess digits */
+ target_prec = (a_digits > ctx->prec) ? a_digits : ctx->prec;
+ target_prec += 2;
+ varcontext.prec = target_prec + 3;
+
+ /* invroot is much faster for large numbers */
+ _mpd_qinvroot(&tmp, &v, &varcontext, &workstatus);
+
+ varcontext.prec = target_prec;
+ _mpd_qdiv(NO_IDEAL_EXP, z, &one, &tmp, &varcontext, &workstatus);
+
+
+ tz = mpd_trail_zeros(result);
+ if ((result->digits-tz)*2-1 <= v.digits) {
+ _mpd_qmul(&tmp, result, result, &varcontext, &workstatus);
+ if (workstatus&MPD_Errors) {
+ mpd_seterror(result, workstatus&MPD_Errors, status);
+ goto finish;
+ }
+ exact = (_mpd_cmp(&tmp, &v) == 0);
+ }
+ *status |= (workstatus&MPD_Errors);
+
+ if (!exact && !mpd_isspecial(result) && !mpd_iszero(result)) {
+ _mpd_fix_sqrt(result, &v, &tmp, &varcontext, status);
+ if (mpd_isspecial(result)) goto finish;
+ *status |= (MPD_Rounded|MPD_Inexact);
+ }
+
+ result->exp += adj;
+ if (exact) {
+ shift = ideal_exp - result->exp;
+ shift = (tz > shift) ? shift : tz;
+ if (shift > 0) {
+ mpd_qshiftr_inplace(result, shift);
+ result->exp += shift;
+ }
+ }
+
+
+finish:
+ mpd_del(&v);
+ mpd_del(&vtmp);
+ mpd_del(&tmp);
+ varcontext.prec = ctx->prec;
+ mpd_qfinalize(result, &varcontext, status);
+}
+
+
+/******************************************************************************/
+/* Base conversions */
+/******************************************************************************/
+
+/*
+ * Returns the space needed to represent an integer mpd_t in base 'base'.
+ * The result is undefined for non-integers.
+ *
+ * Max space needed:
+ *
+ * base^n >= 10^(digits+exp)
+ * n >= log10(10^(digits+exp))/log10(base) = (digits+exp) / log10(base)
+ */
+size_t
+mpd_sizeinbase(mpd_t *a, uint32_t base)
+{
+ size_t x;
+
+ assert(mpd_isinteger(a));
+ if (mpd_iszero(a)) {
+ return 1;
+ }
+
+ x = a->digits+a->exp;
+
+#ifdef CONFIG_64
+ #ifdef USE_80BIT_LONG_DOUBLE
+ return (long double)x / log10(base) + 3;
+ #else
+ /* x > floor(((1ULL<<53)-3) * log10(2)) */
+ if (x > 2711437152599294ULL) {
+ return SIZE_MAX;
+ }
+ return (double)x / log10(base) + 3;
+ #endif
+#else /* CONFIG_32 */
+{
+ double y = x / log10(base) + 3;
+ return (y > SIZE_MAX) ? SIZE_MAX : (size_t)y;
+}
+#endif
+}
+
+/*
+ * Returns the space needed to import a base 'base' integer of length 'srclen'.
+ */
+static inline mpd_ssize_t
+_mpd_importsize(size_t srclen, uint32_t base)
+{
+#if SIZE_MAX == UINT64_MAX
+ #ifdef USE_80BIT_LONG_DOUBLE
+ long double x = (long double)srclen * (log10(base)/MPD_RDIGITS) + 3;
+ #else
+ double x;
+ if (srclen > (1ULL<<53)) {
+ return MPD_SSIZE_MAX;
+ }
+ x = (double)srclen * (log10(base)/MPD_RDIGITS) + 3;
+ #endif
+#else
+ double x = srclen * (log10(base)/MPD_RDIGITS) + 3;
+#endif
+ return (x > MPD_MAXIMPORT) ? MPD_SSIZE_MAX : (mpd_ssize_t)x;
+}
+
+
+static inline size_t
+_to_base_u16(uint16_t *w, size_t wlen, mpd_uint_t wbase,
+ mpd_uint_t *u, mpd_ssize_t ulen)
+{
+ size_t n = 0;
+
+ assert(wlen > 0 && ulen > 0);
+
+ do {
+ w[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase);
+ /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */
+ ulen = _mpd_real_size(u, ulen);
+
+ } while (u[ulen-1] != 0 && n < wlen);
+
+ /* proper termination condition */
+ assert(u[ulen-1] == 0);
+
+ return n;
+}
+
+static inline void
+_from_base_u16(mpd_uint_t *w, mpd_ssize_t wlen,
+ const mpd_uint_t *u, size_t ulen, uint32_t ubase)
+{
+ mpd_ssize_t m = 1;
+ mpd_uint_t carry;
+
+ assert(wlen > 0 && ulen > 0);
+
+ w[0] = u[--ulen];
+ while (--ulen != SIZE_MAX && m < wlen) {
+ _mpd_shortmul(w, w, m, ubase);
+ m = _mpd_real_size(w, m+1);
+ carry = _mpd_shortadd(w, m, u[ulen]);
+ if (carry) w[m++] = carry;
+ }
+
+ /* proper termination condition */
+ assert(ulen == SIZE_MAX);
+}
+
+/* target base wbase <= source base ubase */
+static inline size_t
+_baseconv_to_smaller(uint32_t *w, size_t wlen, mpd_uint_t wbase,
+ mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase)
+{
+ size_t n = 0;
+
+ assert(wlen > 0 && ulen > 0);
+
+ do {
+ w[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase);
+ /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */
+ ulen = _mpd_real_size(u, ulen);
+
+ } while (u[ulen-1] != 0 && n < wlen);
+
+ /* proper termination condition */
+ assert(u[ulen-1] == 0);
+
+ return n;
+}
+
+/* target base wbase >= source base ubase */
+static inline void
+_baseconv_to_larger(mpd_uint_t *w, mpd_ssize_t wlen, mpd_uint_t wbase,
+ const mpd_uint_t *u, size_t ulen, mpd_uint_t ubase)
+{
+ mpd_ssize_t m = 1;
+ mpd_uint_t carry;
+
+ assert(wlen > 0 && ulen > 0);
+
+ w[0] = u[--ulen];
+ while (--ulen != SIZE_MAX && m < wlen) {
+ _mpd_shortmul_b(w, w, m, ubase, wbase);
+ m = _mpd_real_size(w, m+1);
+ carry = _mpd_shortadd_b(w, m, u[ulen], wbase);
+ if (carry) w[m++] = carry;
+ }
+
+ /* proper termination condition */
+ assert(ulen == SIZE_MAX);
+}
+
+
+/*
+ * Converts an integer mpd_t to a multiprecision integer with
+ * base <= UINT16_MAX+1. The least significant word of the result
+ * is rdata[0].
+ */
+size_t
+mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t rbase,
+ const mpd_t *src, uint32_t *status)
+{
+ mpd_t *tsrc;
+ size_t n;
+
+ assert(rbase <= (1U<<16));
+ assert(rlen <= SIZE_MAX/(sizeof *rdata));
+
+ if (mpd_isspecial(src) || !_mpd_isint(src)) {
+ *status |= MPD_Invalid_operation;
+ return SIZE_MAX;
+ }
+
+ memset(rdata, 0, rlen * (sizeof *rdata));
+
+ if (mpd_iszero(src)) {
+ return 1;
+ }
+
+ if ((tsrc = mpd_qnew()) == NULL) {
+ *status |= MPD_Malloc_error;
+ return SIZE_MAX;
+ }
+
+ if (src->exp >= 0) {
+ if (!mpd_qshiftl(tsrc, src, src->exp, status)) {
+ mpd_del(tsrc);
+ return SIZE_MAX;
+ }
+ }
+ else {
+ if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
+ mpd_del(tsrc);
+ return SIZE_MAX;
+ }
+ }
+
+ n = _to_base_u16(rdata, rlen, rbase, tsrc->data, tsrc->len);
+
+ mpd_del(tsrc);
+ return n;
+}
+
+/*
+ * Converts an integer mpd_t to a multiprecision integer with
+ * base <= UINT32_MAX. The least significant word of the result
+ * is rdata[0].
+ */
+size_t
+mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t rbase,
+ const mpd_t *src, uint32_t *status)
+{
+ mpd_t *tsrc;
+ size_t n;
+
+ if (mpd_isspecial(src) || !_mpd_isint(src)) {
+ *status |= MPD_Invalid_operation;
+ return SIZE_MAX;
+ }
+#if MPD_SIZE_MAX < SIZE_MAX
+ if (rlen > MPD_SSIZE_MAX) {
+ *status |= MPD_Invalid_operation;
+ return SIZE_MAX;
+ }
+#endif
+
+ assert(rlen <= SIZE_MAX/(sizeof *rdata));
+ memset(rdata, 0, rlen * (sizeof *rdata));
+
+ if (mpd_iszero(src)) {
+ return 1;
+ }
+
+ if ((tsrc = mpd_qnew()) == NULL) {
+ *status |= MPD_Malloc_error;
+ return SIZE_MAX;
+ }
+
+ if (src->exp >= 0) {
+ if (!mpd_qshiftl(tsrc, src, src->exp, status)) {
+ mpd_del(tsrc);
+ return SIZE_MAX;
+ }
+ }
+ else {
+ if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) {
+ mpd_del(tsrc);
+ return SIZE_MAX;
+ }
+ }
+
+#ifdef CONFIG_64
+ n = _baseconv_to_smaller(rdata, rlen, rbase,
+ tsrc->data, tsrc->len, MPD_RADIX);
+#else
+ if (rbase <= MPD_RADIX) {
+ n = _baseconv_to_smaller(rdata, rlen, rbase,
+ tsrc->data, tsrc->len, MPD_RADIX);
+ }
+ else {
+ _baseconv_to_larger(rdata, (mpd_ssize_t)rlen, rbase,
+ tsrc->data, tsrc->len, MPD_RADIX);
+ n = _mpd_real_size(rdata, (mpd_ssize_t)rlen);
+ }
+#endif
+
+ mpd_del(tsrc);
+ return n;
+}
+
+
+/*
+ * Converts a multiprecision integer with base <= UINT16_MAX+1 to an mpd_t.
+ * The least significant word of the source is srcdata[0].
+ */
+void
+mpd_qimport_u16(mpd_t *result,
+ const uint16_t *srcdata, size_t srclen,
+ uint8_t srcsign, uint32_t srcbase,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_uint_t *usrc; /* uint16_t src copied to an mpd_uint_t array */
+ mpd_ssize_t rlen; /* length of the result */
+ size_t n = 0;
+
+ assert(srclen > 0);
+ assert(srcbase <= (1U<<16));
+
+ if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ for (n = 0; n < srclen; n++) {
+ usrc[n] = srcdata[n];
+ }
+
+ /* result->data is initialized to zero */
+ if (!mpd_qresize_zero(result, rlen, status)) {
+ goto finish;
+ }
+
+ _from_base_u16(result->data, rlen, usrc, srclen, srcbase);
+
+ mpd_set_flags(result, srcsign);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, rlen);
+ mpd_setdigits(result);
+
+ mpd_qresize(result, result->len, status);
+ mpd_qfinalize(result, ctx, status);
+
+
+finish:
+ mpd_free(usrc);
+}
+
+/*
+ * Converts a multiprecision integer with base <= UINT32_MAX to an mpd_t.
+ * The least significant word of the source is srcdata[0].
+ */
+void
+mpd_qimport_u32(mpd_t *result,
+ const uint32_t *srcdata, size_t srclen,
+ uint8_t srcsign, uint32_t srcbase,
+ const mpd_context_t *ctx, uint32_t *status)
+{
+ mpd_uint_t *usrc; /* uint32_t src copied to an mpd_uint_t array */
+ mpd_ssize_t rlen; /* length of the result */
+ size_t n = 0;
+
+ assert(srclen > 0);
+
+ if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) {
+ mpd_seterror(result, MPD_Invalid_operation, status);
+ return;
+ }
+ if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) {
+ mpd_seterror(result, MPD_Malloc_error, status);
+ return;
+ }
+ for (n = 0; n < srclen; n++) {
+ usrc[n] = srcdata[n];
+ }
+
+ /* result->data is initialized to zero */
+ if (!mpd_qresize_zero(result, rlen, status)) {
+ goto finish;
+ }
+
+#ifdef CONFIG_64
+ _baseconv_to_larger(result->data, rlen, MPD_RADIX,
+ usrc, srclen, srcbase);
+#else
+ if (srcbase <= MPD_RADIX) {
+ _baseconv_to_larger(result->data, rlen, MPD_RADIX,
+ usrc, srclen, srcbase);
+ }
+ else {
+ _baseconv_to_smaller(result->data, rlen, MPD_RADIX,
+ usrc, (mpd_ssize_t)srclen, srcbase);
+ }
+#endif
+
+ mpd_set_flags(result, srcsign);
+ result->exp = 0;
+ result->len = _mpd_real_size(result->data, rlen);
+ mpd_setdigits(result);
+
+ mpd_qresize(result, result->len, status);
+ mpd_qfinalize(result, ctx, status);
+
+
+finish:
+ mpd_free(usrc);
+}
+
+
+
diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h
new file mode 100644
index 0000000..4f7a922
--- /dev/null
+++ b/Modules/_decimal/libmpdec/mpdecimal.h
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef MPDECIMAL_H
+#define MPDECIMAL_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#define __STDC_LIMIT_MACROS
+#endif
+
+
+#ifndef _MSC_VER
+ #include "pyconfig.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#ifdef _MSC_VER
+ #include "vccompat.h"
+ #ifndef UNUSED
+ #define UNUSED
+ #endif
+ #define EXTINLINE extern inline
+#else
+ #ifdef HAVE_STDINT_H
+ #include <stdint.h>
+ #endif
+ #ifdef HAVE_INTTYPES_H
+ #include <inttypes.h>
+ #endif
+ #ifndef __GNUC_STDC_INLINE__
+ #define __GNUC_STDC_INLINE__
+ #endif
+ #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ #define UNUSED __attribute__((unused))
+ #else
+ #define UNUSED
+ #endif
+ #define EXTINLINE
+#endif
+
+
+#if !defined(LEGACY_COMPILER)
+ #if !defined(UINT64_MAX)
+ /* The following #error is just a warning. If the compiler indeed does
+ * not have uint64_t, it is perfectly safe to comment out the #error. */
+ #error "Warning: Compiler without uint64_t. Comment out this line."
+ #define LEGACY_COMPILER
+ #endif
+#endif
+
+
+/******************************************************************************/
+/* Configuration */
+/******************************************************************************/
+
+#if defined(UNIVERSAL)
+ #if defined(CONFIG_64) || defined(CONFIG_32)
+ #error "cannot use CONFIG_64 or CONFIG_32 with UNIVERSAL."
+ #endif
+ #if defined(__ppc__)
+ #define CONFIG_32
+ #define ANSI
+ #elif defined(__ppc64__)
+ #define CONFIG_64
+ #define ANSI
+ #elif defined(__i386__)
+ #define CONFIG_32
+ #define ANSI
+ #elif defined(__x86_64__)
+ #define CONFIG_64
+ #define ASM
+ #else
+ #error "unknown architecture for universal build."
+ #endif
+#endif
+
+
+/* BEGIN CONFIG_64 */
+#if defined(CONFIG_64)
+/* types for modular and base arithmetic */
+#define MPD_UINT_MAX UINT64_MAX
+#define MPD_BITS_PER_UINT 64
+typedef uint64_t mpd_uint_t; /* unsigned mod type */
+
+#define MPD_SIZE_MAX SIZE_MAX
+typedef size_t mpd_size_t; /* unsigned size type */
+
+/* type for exp, digits, len, prec */
+#define MPD_SSIZE_MAX INT64_MAX
+#define MPD_SSIZE_MIN INT64_MIN
+typedef int64_t mpd_ssize_t;
+#define _mpd_strtossize strtoll
+
+/* decimal arithmetic */
+#define MPD_RADIX 10000000000000000000ULL /* 10**19 */
+#define MPD_RDIGITS 19
+#define MPD_MAX_POW10 19
+#define MPD_EXPDIGITS 19 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */
+
+#define MPD_MAXTRANSFORM_2N 4294967296ULL /* 2**32 */
+#define MPD_MAX_PREC 999999999999999999LL
+#define MPD_MAX_PREC_LOG2 64
+#define MPD_ELIMIT 1000000000000000000LL
+#define MPD_MAX_EMAX 999999999999999999LL /* ELIMIT-1 */
+#define MPD_MIN_EMIN (-999999999999999999LL) /* -EMAX */
+#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1))
+#define MPD_EXP_INF 2000000000000000001LL
+#define MPD_EXP_CLAMP (-4000000000000000001LL)
+#define MPD_MAXIMPORT 105263157894736842L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */
+
+/* conversion specifiers */
+#define PRI_mpd_uint_t PRIu64
+#define PRI_mpd_ssize_t PRIi64
+/* END CONFIG_64 */
+
+
+/* BEGIN CONFIG_32 */
+#elif defined(CONFIG_32)
+/* types for modular and base arithmetic */
+#define MPD_UINT_MAX UINT32_MAX
+#define MPD_BITS_PER_UINT 32
+typedef uint32_t mpd_uint_t; /* unsigned mod type */
+
+#ifndef LEGACY_COMPILER
+#define MPD_UUINT_MAX UINT64_MAX
+typedef uint64_t mpd_uuint_t; /* double width unsigned mod type */
+#endif
+
+#define MPD_SIZE_MAX SIZE_MAX
+typedef size_t mpd_size_t; /* unsigned size type */
+
+/* type for dec->len, dec->exp, ctx->prec */
+#define MPD_SSIZE_MAX INT32_MAX
+#define MPD_SSIZE_MIN INT32_MIN
+typedef int32_t mpd_ssize_t;
+#define _mpd_strtossize strtol
+
+/* decimal arithmetic */
+#define MPD_RADIX 1000000000UL /* 10**9 */
+#define MPD_RDIGITS 9
+#define MPD_MAX_POW10 9
+#define MPD_EXPDIGITS 10 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */
+
+#define MPD_MAXTRANSFORM_2N 33554432UL /* 2**25 */
+#define MPD_MAX_PREC 425000000L
+#define MPD_MAX_PREC_LOG2 32
+#define MPD_ELIMIT 425000001L
+#define MPD_MAX_EMAX 425000000L /* ELIMIT-1 */
+#define MPD_MIN_EMIN (-425000000L) /* -EMAX */
+#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1))
+#define MPD_EXP_INF 1000000001L /* allows for emax=999999999 in the tests */
+#define MPD_EXP_CLAMP (-2000000001L) /* allows for emin=-999999999 in the tests */
+#define MPD_MAXIMPORT 94444445L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */
+
+/* conversion specifiers */
+#define PRI_mpd_uint_t PRIu32
+#define PRI_mpd_ssize_t PRIi32
+/* END CONFIG_32 */
+
+#else
+ #error "define CONFIG_64 or CONFIG_32"
+#endif
+/* END CONFIG */
+
+
+#if MPD_SIZE_MAX != MPD_UINT_MAX
+ #error "unsupported platform: need mpd_size_t == mpd_uint_t"
+#endif
+
+
+/******************************************************************************/
+/* Context */
+/******************************************************************************/
+
+enum {
+ MPD_ROUND_UP, /* round away from 0 */
+ MPD_ROUND_DOWN, /* round toward 0 (truncate) */
+ MPD_ROUND_CEILING, /* round toward +infinity */
+ MPD_ROUND_FLOOR, /* round toward -infinity */
+ MPD_ROUND_HALF_UP, /* 0.5 is rounded up */
+ MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */
+ MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */
+ MPD_ROUND_05UP, /* round zero or five away from 0 */
+ MPD_ROUND_TRUNC, /* truncate, but set infinity */
+ MPD_ROUND_GUARD
+};
+
+enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD };
+
+extern const char *mpd_round_string[MPD_ROUND_GUARD];
+extern const char *mpd_clamp_string[MPD_CLAMP_GUARD];
+
+
+typedef struct {
+ mpd_ssize_t prec; /* precision */
+ mpd_ssize_t emax; /* max positive exp */
+ mpd_ssize_t emin; /* min negative exp */
+ uint32_t traps; /* status events that should be trapped */
+ uint32_t status; /* status flags */
+ uint32_t newtrap; /* set by mpd_addstatus_raise() */
+ int round; /* rounding mode */
+ int clamp; /* clamp mode */
+ int allcr; /* all functions correctly rounded */
+} mpd_context_t;
+
+
+/* Status flags */
+#define MPD_Clamped 0x00000001U
+#define MPD_Conversion_syntax 0x00000002U
+#define MPD_Division_by_zero 0x00000004U
+#define MPD_Division_impossible 0x00000008U
+#define MPD_Division_undefined 0x00000010U
+#define MPD_Fpu_error 0x00000020U
+#define MPD_Inexact 0x00000040U
+#define MPD_Invalid_context 0x00000080U
+#define MPD_Invalid_operation 0x00000100U
+#define MPD_Malloc_error 0x00000200U
+#define MPD_Not_implemented 0x00000400U
+#define MPD_Overflow 0x00000800U
+#define MPD_Rounded 0x00001000U
+#define MPD_Subnormal 0x00002000U
+#define MPD_Underflow 0x00004000U
+#define MPD_Max_status (0x00008000U-1U)
+
+/* Conditions that result in an IEEE 754 exception */
+#define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \
+ MPD_Division_impossible | \
+ MPD_Division_undefined | \
+ MPD_Fpu_error | \
+ MPD_Invalid_context | \
+ MPD_Invalid_operation | \
+ MPD_Malloc_error) \
+
+/* Errors that require the result of an operation to be set to NaN */
+#define MPD_Errors (MPD_IEEE_Invalid_operation | \
+ MPD_Division_by_zero)
+
+/* Default traps */
+#define MPD_Traps (MPD_IEEE_Invalid_operation | \
+ MPD_Division_by_zero | \
+ MPD_Overflow | \
+ MPD_Underflow)
+
+/* Official name */
+#define MPD_Insufficient_storage MPD_Malloc_error
+
+/* IEEE 754 interchange format contexts */
+#define MPD_IEEE_CONTEXT_MAX_BITS 512 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */
+#define MPD_DECIMAL32 32
+#define MPD_DECIMAL64 64
+#define MPD_DECIMAL128 128
+
+
+#define MPD_MINALLOC_MIN 2
+#define MPD_MINALLOC_MAX 64
+extern mpd_ssize_t MPD_MINALLOC;
+extern void (* mpd_traphandler)(mpd_context_t *);
+void mpd_dflt_traphandler(mpd_context_t *);
+
+void mpd_setminalloc(mpd_ssize_t n);
+void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec);
+
+void mpd_maxcontext(mpd_context_t *ctx);
+void mpd_defaultcontext(mpd_context_t *ctx);
+void mpd_basiccontext(mpd_context_t *ctx);
+int mpd_ieee_context(mpd_context_t *ctx, int bits);
+
+mpd_ssize_t mpd_getprec(const mpd_context_t *ctx);
+mpd_ssize_t mpd_getemax(const mpd_context_t *ctx);
+mpd_ssize_t mpd_getemin(const mpd_context_t *ctx);
+int mpd_getround(const mpd_context_t *ctx);
+uint32_t mpd_gettraps(const mpd_context_t *ctx);
+uint32_t mpd_getstatus(const mpd_context_t *ctx);
+int mpd_getclamp(const mpd_context_t *ctx);
+int mpd_getcr(const mpd_context_t *ctx);
+
+int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec);
+int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax);
+int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin);
+int mpd_qsetround(mpd_context_t *ctx, int newround);
+int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags);
+int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags);
+int mpd_qsetclamp(mpd_context_t *ctx, int c);
+int mpd_qsetcr(mpd_context_t *ctx, int c);
+void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags);
+
+
+/******************************************************************************/
+/* Decimal Arithmetic */
+/******************************************************************************/
+
+/* mpd_t flags */
+#define MPD_POS ((uint8_t)0)
+#define MPD_NEG ((uint8_t)1)
+#define MPD_INF ((uint8_t)2)
+#define MPD_NAN ((uint8_t)4)
+#define MPD_SNAN ((uint8_t)8)
+#define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN)
+#define MPD_STATIC ((uint8_t)16)
+#define MPD_STATIC_DATA ((uint8_t)32)
+#define MPD_SHARED_DATA ((uint8_t)64)
+#define MPD_CONST_DATA ((uint8_t)128)
+#define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA)
+
+/* mpd_t */
+typedef struct {
+ uint8_t flags;
+ mpd_ssize_t exp;
+ mpd_ssize_t digits;
+ mpd_ssize_t len;
+ mpd_ssize_t alloc;
+ mpd_uint_t *data;
+} mpd_t;
+
+
+typedef unsigned char uchar;
+
+
+/******************************************************************************/
+/* Quiet, thread-safe functions */
+/******************************************************************************/
+
+/* format specification */
+typedef struct {
+ mpd_ssize_t min_width; /* minimum field width */
+ mpd_ssize_t prec; /* fraction digits or significant digits */
+ char type; /* conversion specifier */
+ char align; /* alignment */
+ char sign; /* sign printing/alignment */
+ char fill[5]; /* fill character */
+ const char *dot; /* decimal point */
+ const char *sep; /* thousands separator */
+ const char *grouping; /* grouping of digits */
+} mpd_spec_t;
+
+/* output to a string */
+char *mpd_to_sci(const mpd_t *dec, int fmt);
+char *mpd_to_eng(const mpd_t *dec, int fmt);
+mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt);
+mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt);
+int mpd_validate_lconv(mpd_spec_t *spec);
+int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps);
+char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status);
+char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status);
+
+#define MPD_NUM_FLAGS 15
+#define MPD_MAX_FLAG_STRING 208
+#define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18)
+#define MPD_MAX_SIGNAL_LIST 121
+int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags);
+int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]);
+int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]);
+
+/* output to a file */
+void mpd_fprint(FILE *file, const mpd_t *dec);
+void mpd_print(const mpd_t *dec);
+
+/* assignment from a string */
+void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status);
+
+/* set to NaN with error flags */
+void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status);
+/* set a special with sign and type */
+void mpd_setspecial(mpd_t *dec, uint8_t sign, uint8_t type);
+/* set coefficient to zero or all nines */
+void mpd_zerocoeff(mpd_t *result);
+void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status);
+
+/* quietly assign a C integer type to an mpd_t */
+void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status);
+#ifndef LEGACY_COMPILER
+void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status);
+#endif
+
+/* quietly assign a C integer type to an mpd_t with a static coefficient */
+void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status);
+
+/* quietly get a C integer type from an mpd_t */
+mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status);
+mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status);
+mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status);
+
+
+/* quiet functions */
+int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status);
+
+const char * mpd_class(const mpd_t *a, const mpd_context_t *ctx);
+
+int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status);
+mpd_t *mpd_qncopy(const mpd_t *a);
+int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status);
+int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status);
+int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status);
+
+void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+int mpd_same_quantum(const mpd_t *a, const mpd_t *b);
+
+void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status);
+mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status);
+mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n);
+void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status);
+
+int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status);
+int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+int mpd_cmp_total(const mpd_t *a, const mpd_t *b);
+int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b);
+int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b);
+int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b);
+
+void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+
+void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status);
+void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status);
+
+
+size_t mpd_sizeinbase(mpd_t *a, uint32_t base);
+void mpd_qimport_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen,
+ uint8_t srcsign, uint32_t srcbase,
+ const mpd_context_t *ctx, uint32_t *status);
+void mpd_qimport_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen,
+ uint8_t srcsign, uint32_t srcbase,
+ const mpd_context_t *ctx, uint32_t *status);
+size_t mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t base,
+ const mpd_t *src, uint32_t *status);
+size_t mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t base,
+ const mpd_t *src, uint32_t *status);
+
+
+/******************************************************************************/
+/* Signalling functions */
+/******************************************************************************/
+
+char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx);
+void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx);
+void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx);
+size_t mpd_export_u16(uint16_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx);
+size_t mpd_export_u32(uint32_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx);
+void mpd_finalize(mpd_t *result, mpd_context_t *ctx);
+int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx);
+void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx);
+void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx);
+void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx);
+void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx);
+void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx);
+void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx);
+void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx);
+void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx);
+void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx);
+#ifndef LEGACY_COMPILER
+void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx);
+void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx);
+#endif
+mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx);
+mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx);
+mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx);
+void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx);
+mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx);
+void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx);
+void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx);
+void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx);
+void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx);
+void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx);
+void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx);
+void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx);
+void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx);
+void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx);
+void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx);
+void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx);
+void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx);
+void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx);
+void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx);
+void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx);
+void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx);
+void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx);
+void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx);
+void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx);
+void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx);
+void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx);
+void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx);
+void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx);
+
+
+/******************************************************************************/
+/* Configuration specific */
+/******************************************************************************/
+
+#ifdef CONFIG_64
+void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status);
+int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status);
+uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status);
+
+void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status);
+void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status);
+
+void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx);
+void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx);
+int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx);
+uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx);
+
+void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx);
+void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx);
+void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx);
+void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx);
+void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx);
+void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx);
+void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx);
+void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx);
+#else
+int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status);
+uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status);
+int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx);
+uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx);
+#endif
+
+
+/******************************************************************************/
+/* Get attributes of a decimal */
+/******************************************************************************/
+
+EXTINLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec);
+EXTINLINE mpd_ssize_t mpd_etiny(const mpd_context_t *ctx);
+EXTINLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx);
+EXTINLINE mpd_uint_t mpd_msword(const mpd_t *dec);
+EXTINLINE int mpd_word_digits(mpd_uint_t word);
+/* most significant digit of a word */
+EXTINLINE mpd_uint_t mpd_msd(mpd_uint_t word);
+/* least significant digit of a word */
+EXTINLINE mpd_uint_t mpd_lsd(mpd_uint_t word);
+/* coefficient size needed to store 'digits' */
+EXTINLINE mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits);
+/* number of digits in the exponent, undefined for MPD_SSIZE_MIN */
+EXTINLINE int mpd_exp_digits(mpd_ssize_t exp);
+EXTINLINE int mpd_iscanonical(const mpd_t *dec UNUSED);
+EXTINLINE int mpd_isfinite(const mpd_t *dec);
+EXTINLINE int mpd_isinfinite(const mpd_t *dec);
+EXTINLINE int mpd_isinteger(const mpd_t *dec);
+EXTINLINE int mpd_isnan(const mpd_t *dec);
+EXTINLINE int mpd_isnegative(const mpd_t *dec);
+EXTINLINE int mpd_ispositive(const mpd_t *dec);
+EXTINLINE int mpd_isqnan(const mpd_t *dec);
+EXTINLINE int mpd_issigned(const mpd_t *dec);
+EXTINLINE int mpd_issnan(const mpd_t *dec);
+EXTINLINE int mpd_isspecial(const mpd_t *dec);
+EXTINLINE int mpd_iszero(const mpd_t *dec);
+/* undefined for special numbers */
+EXTINLINE int mpd_iszerocoeff(const mpd_t *dec);
+EXTINLINE int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx);
+EXTINLINE int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx);
+/* odd word */
+EXTINLINE int mpd_isoddword(mpd_uint_t word);
+/* odd coefficient */
+EXTINLINE int mpd_isoddcoeff(const mpd_t *dec);
+/* odd decimal, only defined for integers */
+int mpd_isodd(const mpd_t *dec);
+/* even decimal, only defined for integers */
+int mpd_iseven(const mpd_t *dec);
+/* 0 if dec is positive, 1 if dec is negative */
+EXTINLINE uint8_t mpd_sign(const mpd_t *dec);
+/* 1 if dec is positive, -1 if dec is negative */
+EXTINLINE int mpd_arith_sign(const mpd_t *dec);
+EXTINLINE long mpd_radix(void);
+EXTINLINE int mpd_isdynamic(mpd_t *dec);
+EXTINLINE int mpd_isstatic(mpd_t *dec);
+EXTINLINE int mpd_isdynamic_data(mpd_t *dec);
+EXTINLINE int mpd_isstatic_data(mpd_t *dec);
+EXTINLINE int mpd_isshared_data(mpd_t *dec);
+EXTINLINE int mpd_isconst_data(mpd_t *dec);
+EXTINLINE mpd_ssize_t mpd_trail_zeros(const mpd_t *dec);
+
+
+/******************************************************************************/
+/* Set attributes of a decimal */
+/******************************************************************************/
+
+/* set number of decimal digits in the coefficient */
+EXTINLINE void mpd_setdigits(mpd_t *result);
+EXTINLINE void mpd_set_sign(mpd_t *result, uint8_t sign);
+/* copy sign from another decimal */
+EXTINLINE void mpd_signcpy(mpd_t *result, mpd_t *a);
+EXTINLINE void mpd_set_infinity(mpd_t *result);
+EXTINLINE void mpd_set_qnan(mpd_t *result);
+EXTINLINE void mpd_set_snan(mpd_t *result);
+EXTINLINE void mpd_set_negative(mpd_t *result);
+EXTINLINE void mpd_set_positive(mpd_t *result);
+EXTINLINE void mpd_set_dynamic(mpd_t *result);
+EXTINLINE void mpd_set_static(mpd_t *result);
+EXTINLINE void mpd_set_dynamic_data(mpd_t *result);
+EXTINLINE void mpd_set_static_data(mpd_t *result);
+EXTINLINE void mpd_set_shared_data(mpd_t *result);
+EXTINLINE void mpd_set_const_data(mpd_t *result);
+EXTINLINE void mpd_clear_flags(mpd_t *result);
+EXTINLINE void mpd_set_flags(mpd_t *result, uint8_t flags);
+EXTINLINE void mpd_copy_flags(mpd_t *result, const mpd_t *a);
+
+
+/******************************************************************************/
+/* Error Macros */
+/******************************************************************************/
+
+#define mpd_err_fatal(...) \
+ do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \
+ exit(1); \
+ } while (0)
+#define mpd_err_warn(...) \
+ do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \
+ } while (0)
+
+
+/******************************************************************************/
+/* Memory handling */
+/******************************************************************************/
+
+extern void *(* mpd_mallocfunc)(size_t size);
+extern void *(* mpd_callocfunc)(size_t nmemb, size_t size);
+extern void *(* mpd_reallocfunc)(void *ptr, size_t size);
+extern void (* mpd_free)(void *ptr);
+
+void *mpd_callocfunc_em(size_t nmemb, size_t size);
+
+void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size);
+void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size);
+void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err);
+void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size);
+
+mpd_t *mpd_qnew(void);
+mpd_t *mpd_new(mpd_context_t *ctx);
+mpd_t *mpd_qnew_size(mpd_ssize_t size);
+void mpd_del(mpd_t *dec);
+
+void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len);
+int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+void mpd_minalloc(mpd_t *result);
+
+int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
+int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
+
+
+#ifdef __cplusplus
+} /* END extern "C" */
+#endif
+
+
+#endif /* MPDECIMAL_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/numbertheory.c b/Modules/_decimal/libmpdec/numbertheory.c
new file mode 100644
index 0000000..10ce6dc
--- /dev/null
+++ b/Modules/_decimal/libmpdec/numbertheory.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdlib.h>
+#include <assert.h>
+#include "bits.h"
+#include "umodarith.h"
+#include "numbertheory.h"
+
+
+/* Bignum: Initialize the Number Theoretic Transform. */
+
+
+/*
+ * Return the nth root of unity in F(p). This corresponds to e**((2*pi*i)/n)
+ * in the Fourier transform. We have w**n == 1 (mod p).
+ * n := transform length.
+ * sign := -1 for forward transform, 1 for backward transform.
+ * modnum := one of {P1, P2, P3}.
+ */
+mpd_uint_t
+_mpd_getkernel(mpd_uint_t n, int sign, int modnum)
+{
+ mpd_uint_t umod, p, r, xi;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+
+ SETMODULUS(modnum);
+ r = mpd_roots[modnum]; /* primitive root of F(p) */
+ p = umod;
+ xi = (p-1) / n;
+
+ if (sign == -1)
+ return POWMOD(r, (p-1-xi));
+ else
+ return POWMOD(r, xi);
+}
+
+/*
+ * Initialize and return transform parameters.
+ * n := transform length.
+ * sign := -1 for forward transform, 1 for backward transform.
+ * modnum := one of {P1, P2, P3}.
+ */
+struct fnt_params *
+_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum)
+{
+ struct fnt_params *tparams;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t kernel, w;
+ mpd_uint_t i;
+ mpd_size_t nhalf;
+
+ assert(ispower2(n));
+ assert(sign == -1 || sign == 1);
+ assert(P1 <= modnum && modnum <= P3);
+
+ nhalf = n/2;
+ tparams = mpd_sh_alloc(sizeof *tparams, nhalf, sizeof (mpd_uint_t));
+ if (tparams == NULL) {
+ return NULL;
+ }
+
+ SETMODULUS(modnum);
+ kernel = _mpd_getkernel(n, sign, modnum);
+
+ tparams->modnum = modnum;
+ tparams->modulus = umod;
+ tparams->kernel = kernel;
+
+ /* wtable[] := w**0, w**1, ..., w**(nhalf-1) */
+ w = 1;
+ for (i = 0; i < nhalf; i++) {
+ tparams->wtable[i] = w;
+ w = MULMOD(w, kernel);
+ }
+
+ return tparams;
+}
+
+/* Initialize wtable of size three. */
+void
+_mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum)
+{
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t kernel;
+
+ SETMODULUS(modnum);
+ kernel = _mpd_getkernel(3, sign, modnum);
+
+ w3table[0] = 1;
+ w3table[1] = kernel;
+ w3table[2] = POWMOD(kernel, 2);
+}
+
+
diff --git a/Modules/_decimal/libmpdec/numbertheory.h b/Modules/_decimal/libmpdec/numbertheory.h
new file mode 100644
index 0000000..f54d11d
--- /dev/null
+++ b/Modules/_decimal/libmpdec/numbertheory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef NUMBER_THEORY_H
+#define NUMBER_THEORY_H
+
+
+#include "constants.h"
+#include "mpdecimal.h"
+
+
+/* transform parameters */
+struct fnt_params {
+ int modnum;
+ mpd_uint_t modulus;
+ mpd_uint_t kernel;
+ mpd_uint_t wtable[];
+};
+
+
+mpd_uint_t _mpd_getkernel(mpd_uint_t n, int sign, int modnum);
+struct fnt_params *_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum);
+void _mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum);
+
+
+#ifdef PPRO
+static inline void
+ppro_setmodulus(int modnum, mpd_uint_t *umod, double *dmod, uint32_t dinvmod[3])
+{
+ *dmod = *umod = mpd_moduli[modnum];
+ dinvmod[0] = mpd_invmoduli[modnum][0];
+ dinvmod[1] = mpd_invmoduli[modnum][1];
+ dinvmod[2] = mpd_invmoduli[modnum][2];
+}
+#else
+static inline void
+std_setmodulus(int modnum, mpd_uint_t *umod)
+{
+ *umod = mpd_moduli[modnum];
+}
+#endif
+
+
+#endif
+
+
diff --git a/Modules/_decimal/libmpdec/sixstep.c b/Modules/_decimal/libmpdec/sixstep.c
new file mode 100644
index 0000000..f757814
--- /dev/null
+++ b/Modules/_decimal/libmpdec/sixstep.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bits.h"
+#include "difradix2.h"
+#include "numbertheory.h"
+#include "transpose.h"
+#include "umodarith.h"
+#include "sixstep.h"
+
+
+/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the
+ form 2**n (See literature/six-step.txt). */
+
+
+/* forward transform with sign = -1 */
+int
+six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ struct fnt_params *tparams;
+ mpd_size_t log2n, C, R;
+ mpd_uint_t kernel;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t *x, w0, w1, wstep;
+ mpd_size_t i, k;
+
+
+ assert(ispower2(n));
+ assert(n >= 16);
+ assert(n <= MPD_MAXTRANSFORM_2N);
+
+ log2n = mpd_bsr(n);
+ C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */
+ R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */
+
+
+ /* Transpose the matrix. */
+ if (!transpose_pow2(a, R, C)) {
+ return 0;
+ }
+
+ /* Length R transform on the rows. */
+ if ((tparams = _mpd_init_fnt_params(R, -1, modnum)) == NULL) {
+ return 0;
+ }
+ for (x = a; x < a+n; x += R) {
+ fnt_dif2(x, R, tparams);
+ }
+
+ /* Transpose the matrix. */
+ if (!transpose_pow2(a, C, R)) {
+ mpd_free(tparams);
+ return 0;
+ }
+
+ /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */
+ SETMODULUS(modnum);
+ kernel = _mpd_getkernel(n, -1, modnum);
+ for (i = 1; i < R; i++) {
+ w0 = 1; /* r**(i*0): initial value for k=0 */
+ w1 = POWMOD(kernel, i); /* r**(i*1): initial value for k=1 */
+ wstep = MULMOD(w1, w1); /* r**(2*i) */
+ for (k = 0; k < C; k += 2) {
+ mpd_uint_t x0 = a[i*C+k];
+ mpd_uint_t x1 = a[i*C+k+1];
+ MULMOD2(&x0, w0, &x1, w1);
+ MULMOD2C(&w0, &w1, wstep); /* r**(i*(k+2)) = r**(i*k) * r**(2*i) */
+ a[i*C+k] = x0;
+ a[i*C+k+1] = x1;
+ }
+ }
+
+ /* Length C transform on the rows. */
+ if (C != R) {
+ mpd_free(tparams);
+ if ((tparams = _mpd_init_fnt_params(C, -1, modnum)) == NULL) {
+ return 0;
+ }
+ }
+ for (x = a; x < a+n; x += C) {
+ fnt_dif2(x, C, tparams);
+ }
+ mpd_free(tparams);
+
+#if 0 /* An unordered transform is sufficient for convolution. */
+ /* Transpose the matrix. */
+ if (!transpose_pow2(a, R, C)) {
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+
+/* reverse transform, sign = 1 */
+int
+inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum)
+{
+ struct fnt_params *tparams;
+ mpd_size_t log2n, C, R;
+ mpd_uint_t kernel;
+ mpd_uint_t umod;
+#ifdef PPRO
+ double dmod;
+ uint32_t dinvmod[3];
+#endif
+ mpd_uint_t *x, w0, w1, wstep;
+ mpd_size_t i, k;
+
+
+ assert(ispower2(n));
+ assert(n >= 16);
+ assert(n <= MPD_MAXTRANSFORM_2N);
+
+ log2n = mpd_bsr(n);
+ C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */
+ R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */
+
+
+#if 0 /* An unordered transform is sufficient for convolution. */
+ /* Transpose the matrix, producing an R*C matrix. */
+ if (!transpose_pow2(a, C, R)) {
+ return 0;
+ }
+#endif
+
+ /* Length C transform on the rows. */
+ if ((tparams = _mpd_init_fnt_params(C, 1, modnum)) == NULL) {
+ return 0;
+ }
+ for (x = a; x < a+n; x += C) {
+ fnt_dif2(x, C, tparams);
+ }
+
+ /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */
+ SETMODULUS(modnum);
+ kernel = _mpd_getkernel(n, 1, modnum);
+ for (i = 1; i < R; i++) {
+ w0 = 1;
+ w1 = POWMOD(kernel, i);
+ wstep = MULMOD(w1, w1);
+ for (k = 0; k < C; k += 2) {
+ mpd_uint_t x0 = a[i*C+k];
+ mpd_uint_t x1 = a[i*C+k+1];
+ MULMOD2(&x0, w0, &x1, w1);
+ MULMOD2C(&w0, &w1, wstep);
+ a[i*C+k] = x0;
+ a[i*C+k+1] = x1;
+ }
+ }
+
+ /* Transpose the matrix. */
+ if (!transpose_pow2(a, R, C)) {
+ mpd_free(tparams);
+ return 0;
+ }
+
+ /* Length R transform on the rows. */
+ if (R != C) {
+ mpd_free(tparams);
+ if ((tparams = _mpd_init_fnt_params(R, 1, modnum)) == NULL) {
+ return 0;
+ }
+ }
+ for (x = a; x < a+n; x += R) {
+ fnt_dif2(x, R, tparams);
+ }
+ mpd_free(tparams);
+
+ /* Transpose the matrix. */
+ if (!transpose_pow2(a, C, R)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
diff --git a/Modules/_decimal/libmpdec/sixstep.h b/Modules/_decimal/libmpdec/sixstep.h
new file mode 100644
index 0000000..4d251df
--- /dev/null
+++ b/Modules/_decimal/libmpdec/sixstep.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef SIX_STEP_H
+#define SIX_STEP_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+int six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+int inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum);
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/transpose.c b/Modules/_decimal/libmpdec/transpose.c
new file mode 100644
index 0000000..5e5d4b6
--- /dev/null
+++ b/Modules/_decimal/libmpdec/transpose.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include "bits.h"
+#include "constants.h"
+#include "typearith.h"
+#include "transpose.h"
+
+
+#define BUFSIZE 4096
+#define SIDE 128
+
+
+/* Bignum: The transpose functions are used for very large transforms
+ in sixstep.c and fourstep.c. */
+
+
+/* Definition of the matrix transpose */
+void
+std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols)
+{
+ mpd_size_t idest, isrc;
+ mpd_size_t r, c;
+
+ for (r = 0; r < rows; r++) {
+ isrc = r * cols;
+ idest = r;
+ for (c = 0; c < cols; c++) {
+ dest[idest] = src[isrc];
+ isrc += 1;
+ idest += rows;
+ }
+ }
+}
+
+/*
+ * Swap half-rows of 2^n * (2*2^n) matrix.
+ * FORWARD_CYCLE: even/odd permutation of the halfrows.
+ * BACKWARD_CYCLE: reverse the even/odd permutation.
+ */
+static int
+swap_halfrows_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols, int dir)
+{
+ mpd_uint_t buf1[BUFSIZE];
+ mpd_uint_t buf2[BUFSIZE];
+ mpd_uint_t *readbuf, *writebuf, *hp;
+ mpd_size_t *done, dbits;
+ mpd_size_t b = BUFSIZE, stride;
+ mpd_size_t hn, hmax; /* halfrow number */
+ mpd_size_t m, r=0;
+ mpd_size_t offset;
+ mpd_size_t next;
+
+
+ assert(cols == mul_size_t(2, rows));
+
+ if (dir == FORWARD_CYCLE) {
+ r = rows;
+ }
+ else if (dir == BACKWARD_CYCLE) {
+ r = 2;
+ }
+ else {
+ abort(); /* GCOV_NOT_REACHED */
+ }
+
+ m = cols - 1;
+ hmax = rows; /* cycles start at odd halfrows */
+ dbits = 8 * sizeof *done;
+ if ((done = mpd_calloc(hmax/(sizeof *done) + 1, sizeof *done)) == NULL) {
+ return 0;
+ }
+
+ for (hn = 1; hn <= hmax; hn += 2) {
+
+ if (done[hn/dbits] & mpd_bits[hn%dbits]) {
+ continue;
+ }
+
+ readbuf = buf1; writebuf = buf2;
+
+ for (offset = 0; offset < cols/2; offset += b) {
+
+ stride = (offset + b < cols/2) ? b : cols/2-offset;
+
+ hp = matrix + hn*cols/2;
+ memcpy(readbuf, hp+offset, stride*(sizeof *readbuf));
+ pointerswap(&readbuf, &writebuf);
+
+ next = mulmod_size_t(hn, r, m);
+ hp = matrix + next*cols/2;
+
+ while (next != hn) {
+
+ memcpy(readbuf, hp+offset, stride*(sizeof *readbuf));
+ memcpy(hp+offset, writebuf, stride*(sizeof *writebuf));
+ pointerswap(&readbuf, &writebuf);
+
+ done[next/dbits] |= mpd_bits[next%dbits];
+
+ next = mulmod_size_t(next, r, m);
+ hp = matrix + next*cols/2;
+
+ }
+
+ memcpy(hp+offset, writebuf, stride*(sizeof *writebuf));
+
+ done[hn/dbits] |= mpd_bits[hn%dbits];
+ }
+ }
+
+ mpd_free(done);
+ return 1;
+}
+
+/* In-place transpose of a square matrix */
+static inline void
+squaretrans(mpd_uint_t *buf, mpd_size_t cols)
+{
+ mpd_uint_t tmp;
+ mpd_size_t idest, isrc;
+ mpd_size_t r, c;
+
+ for (r = 0; r < cols; r++) {
+ c = r+1;
+ isrc = r*cols + c;
+ idest = c*cols + r;
+ for (c = r+1; c < cols; c++) {
+ tmp = buf[isrc];
+ buf[isrc] = buf[idest];
+ buf[idest] = tmp;
+ isrc += 1;
+ idest += cols;
+ }
+ }
+}
+
+/*
+ * Transpose 2^n * 2^n matrix. For cache efficiency, the matrix is split into
+ * square blocks with side length 'SIDE'. First, the blocks are transposed,
+ * then a square tranposition is done on each individual block.
+ */
+static void
+squaretrans_pow2(mpd_uint_t *matrix, mpd_size_t size)
+{
+ mpd_uint_t buf1[SIDE*SIDE];
+ mpd_uint_t buf2[SIDE*SIDE];
+ mpd_uint_t *to, *from;
+ mpd_size_t b = size;
+ mpd_size_t r, c;
+ mpd_size_t i;
+
+ while (b > SIDE) b >>= 1;
+
+ for (r = 0; r < size; r += b) {
+
+ for (c = r; c < size; c += b) {
+
+ from = matrix + r*size + c;
+ to = buf1;
+ for (i = 0; i < b; i++) {
+ memcpy(to, from, b*(sizeof *to));
+ from += size;
+ to += b;
+ }
+ squaretrans(buf1, b);
+
+ if (r == c) {
+ to = matrix + r*size + c;
+ from = buf1;
+ for (i = 0; i < b; i++) {
+ memcpy(to, from, b*(sizeof *to));
+ from += b;
+ to += size;
+ }
+ continue;
+ }
+ else {
+ from = matrix + c*size + r;
+ to = buf2;
+ for (i = 0; i < b; i++) {
+ memcpy(to, from, b*(sizeof *to));
+ from += size;
+ to += b;
+ }
+ squaretrans(buf2, b);
+
+ to = matrix + c*size + r;
+ from = buf1;
+ for (i = 0; i < b; i++) {
+ memcpy(to, from, b*(sizeof *to));
+ from += b;
+ to += size;
+ }
+
+ to = matrix + r*size + c;
+ from = buf2;
+ for (i = 0; i < b; i++) {
+ memcpy(to, from, b*(sizeof *to));
+ from += b;
+ to += size;
+ }
+ }
+ }
+ }
+
+}
+
+/*
+ * In-place transposition of a 2^n x 2^n or a 2^n x (2*2^n)
+ * or a (2*2^n) x 2^n matrix.
+ */
+int
+transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols)
+{
+ mpd_size_t size = mul_size_t(rows, cols);
+
+ assert(ispower2(rows));
+ assert(ispower2(cols));
+
+ if (cols == rows) {
+ squaretrans_pow2(matrix, rows);
+ }
+ else if (cols == mul_size_t(2, rows)) {
+ if (!swap_halfrows_pow2(matrix, rows, cols, FORWARD_CYCLE)) {
+ return 0;
+ }
+ squaretrans_pow2(matrix, rows);
+ squaretrans_pow2(matrix+(size/2), rows);
+ }
+ else if (rows == mul_size_t(2, cols)) {
+ squaretrans_pow2(matrix, cols);
+ squaretrans_pow2(matrix+(size/2), cols);
+ if (!swap_halfrows_pow2(matrix, cols, rows, BACKWARD_CYCLE)) {
+ return 0;
+ }
+ }
+ else {
+ abort(); /* GCOV_NOT_REACHED */
+ }
+
+ return 1;
+}
+
+
diff --git a/Modules/_decimal/libmpdec/transpose.h b/Modules/_decimal/libmpdec/transpose.h
new file mode 100644
index 0000000..dd0aec6
--- /dev/null
+++ b/Modules/_decimal/libmpdec/transpose.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef TRANSPOSE_H
+#define TRANSPOSE_H
+
+
+#include "mpdecimal.h"
+#include <stdio.h>
+
+
+enum {FORWARD_CYCLE, BACKWARD_CYCLE};
+
+
+void std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols);
+int transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols);
+void transpose_3xpow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols);
+
+
+static inline void pointerswap(mpd_uint_t **a, mpd_uint_t **b)
+{
+ mpd_uint_t *tmp;
+
+ tmp = *b;
+ *b = *a;
+ *a = tmp;
+}
+
+
+#endif
diff --git a/Modules/_decimal/libmpdec/typearith.h b/Modules/_decimal/libmpdec/typearith.h
new file mode 100644
index 0000000..d58ad06
--- /dev/null
+++ b/Modules/_decimal/libmpdec/typearith.h
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef TYPEARITH_H
+#define TYPEARITH_H
+
+
+#include "mpdecimal.h"
+
+
+/*****************************************************************************/
+/* Low level native arithmetic on basic types */
+/*****************************************************************************/
+
+
+/** ------------------------------------------------------------
+ ** Double width multiplication and division
+ ** ------------------------------------------------------------
+ */
+
+#if defined(CONFIG_64)
+#if defined(ANSI)
+#if defined(HAVE_UINT128_T)
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ __uint128_t hl;
+
+ hl = (__uint128_t)a * b;
+
+ *hi = hl >> 64;
+ *lo = (mpd_uint_t)hl;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d)
+{
+ __uint128_t hl;
+
+ hl = ((__uint128_t)hi<<64) + lo;
+ *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */
+ *r = (mpd_uint_t)(hl - (__uint128_t)(*q) * d);
+}
+#else
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ uint32_t w[4], carry;
+ uint32_t ah, al, bh, bl;
+ uint64_t hl;
+
+ ah = (uint32_t)(a>>32); al = (uint32_t)a;
+ bh = (uint32_t)(b>>32); bl = (uint32_t)b;
+
+ hl = (uint64_t)al * bl;
+ w[0] = (uint32_t)hl;
+ carry = (uint32_t)(hl>>32);
+
+ hl = (uint64_t)ah * bl + carry;
+ w[1] = (uint32_t)hl;
+ w[2] = (uint32_t)(hl>>32);
+
+ hl = (uint64_t)al * bh + w[1];
+ w[1] = (uint32_t)hl;
+ carry = (uint32_t)(hl>>32);
+
+ hl = ((uint64_t)ah * bh + w[2]) + carry;
+ w[2] = (uint32_t)hl;
+ w[3] = (uint32_t)(hl>>32);
+
+ *hi = ((uint64_t)w[3]<<32) + w[2];
+ *lo = ((uint64_t)w[1]<<32) + w[0];
+}
+
+/*
+ * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt
+ * http://www.hackersdelight.org/permissions.htm:
+ * "You are free to use, copy, and distribute any of the code on this web
+ * site, whether modified by you or not. You need not give attribution."
+ *
+ * Slightly modified, comments are mine.
+ */
+static inline int
+nlz(uint64_t x)
+{
+ int n;
+
+ if (x == 0) return(64);
+
+ n = 0;
+ if (x <= 0x00000000FFFFFFFF) {n = n +32; x = x <<32;}
+ if (x <= 0x0000FFFFFFFFFFFF) {n = n +16; x = x <<16;}
+ if (x <= 0x00FFFFFFFFFFFFFF) {n = n + 8; x = x << 8;}
+ if (x <= 0x0FFFFFFFFFFFFFFF) {n = n + 4; x = x << 4;}
+ if (x <= 0x3FFFFFFFFFFFFFFF) {n = n + 2; x = x << 2;}
+ if (x <= 0x7FFFFFFFFFFFFFFF) {n = n + 1;}
+
+ return n;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0,
+ mpd_uint_t v)
+{
+ const mpd_uint_t b = 4294967296;
+ mpd_uint_t un1, un0,
+ vn1, vn0,
+ q1, q0,
+ un32, un21, un10,
+ rhat, t;
+ int s;
+
+ assert(u1 < v);
+
+ s = nlz(v);
+ v = v << s;
+ vn1 = v >> 32;
+ vn0 = v & 0xFFFFFFFF;
+
+ t = (s == 0) ? 0 : u0 >> (64 - s);
+ un32 = (u1 << s) | t;
+ un10 = u0 << s;
+
+ un1 = un10 >> 32;
+ un0 = un10 & 0xFFFFFFFF;
+
+ q1 = un32 / vn1;
+ rhat = un32 - q1*vn1;
+again1:
+ if (q1 >= b || q1*vn0 > b*rhat + un1) {
+ q1 = q1 - 1;
+ rhat = rhat + vn1;
+ if (rhat < b) goto again1;
+ }
+
+ /*
+ * Before again1 we had:
+ * (1) q1*vn1 + rhat = un32
+ * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1
+ *
+ * The statements inside the if-clause do not change the value
+ * of the left-hand side of (2), and the loop is only exited
+ * if q1*vn0 <= rhat*b + un1, so:
+ *
+ * (3) q1*vn1*b + q1*vn0 <= un32*b + un1
+ * (4) q1*v <= un32*b + un1
+ * (5) 0 <= un32*b + un1 - q1*v
+ *
+ * By (5) we are certain that the possible add-back step from
+ * Knuth's algorithm D is never required.
+ *
+ * Since the final quotient is less than 2**64, the following
+ * must be true:
+ *
+ * (6) un32*b + un1 - q1*v <= UINT64_MAX
+ *
+ * This means that in the following line, the high words
+ * of un32*b and q1*v can be discarded without any effect
+ * on the result.
+ */
+ un21 = un32*b + un1 - q1*v;
+
+ q0 = un21 / vn1;
+ rhat = un21 - q0*vn1;
+again2:
+ if (q0 >= b || q0*vn0 > b*rhat + un0) {
+ q0 = q0 - 1;
+ rhat = rhat + vn1;
+ if (rhat < b) goto again2;
+ }
+
+ *q = q1*b + q0;
+ *r = (un21*b + un0 - q0*v) >> s;
+}
+#endif
+
+/* END ANSI */
+#elif defined(ASM)
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ mpd_uint_t h, l;
+
+ asm ( "mulq %3\n\t"
+ : "=d" (h), "=a" (l)
+ : "%a" (a), "rm" (b)
+ : "cc"
+ );
+
+ *hi = h;
+ *lo = l;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d)
+{
+ mpd_uint_t qq, rr;
+
+ asm ( "divq %4\n\t"
+ : "=a" (qq), "=d" (rr)
+ : "a" (lo), "d" (hi), "rm" (d)
+ : "cc"
+ );
+
+ *q = qq;
+ *r = rr;
+}
+/* END GCC ASM */
+#elif defined(MASM)
+#include <intrin.h>
+#pragma intrinsic(_umul128)
+
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ *lo = _umul128(a, b, hi);
+}
+
+void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d);
+
+/* END MASM (_MSC_VER) */
+#else
+ #error "need platform specific 128 bit multiplication and division"
+#endif
+
+#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d
+static inline void
+_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp)
+{
+ assert(exp <= 19);
+
+ if (exp <= 9) {
+ if (exp <= 4) {
+ switch (exp) {
+ case 0: *q = v; *r = 0; break;
+ case 1: DIVMOD(q, r, v, 10UL); break;
+ case 2: DIVMOD(q, r, v, 100UL); break;
+ case 3: DIVMOD(q, r, v, 1000UL); break;
+ case 4: DIVMOD(q, r, v, 10000UL); break;
+ }
+ }
+ else {
+ switch (exp) {
+ case 5: DIVMOD(q, r, v, 100000UL); break;
+ case 6: DIVMOD(q, r, v, 1000000UL); break;
+ case 7: DIVMOD(q, r, v, 10000000UL); break;
+ case 8: DIVMOD(q, r, v, 100000000UL); break;
+ case 9: DIVMOD(q, r, v, 1000000000UL); break;
+ }
+ }
+ }
+ else {
+ if (exp <= 14) {
+ switch (exp) {
+ case 10: DIVMOD(q, r, v, 10000000000ULL); break;
+ case 11: DIVMOD(q, r, v, 100000000000ULL); break;
+ case 12: DIVMOD(q, r, v, 1000000000000ULL); break;
+ case 13: DIVMOD(q, r, v, 10000000000000ULL); break;
+ case 14: DIVMOD(q, r, v, 100000000000000ULL); break;
+ }
+ }
+ else {
+ switch (exp) {
+ case 15: DIVMOD(q, r, v, 1000000000000000ULL); break;
+ case 16: DIVMOD(q, r, v, 10000000000000000ULL); break;
+ case 17: DIVMOD(q, r, v, 100000000000000000ULL); break;
+ case 18: DIVMOD(q, r, v, 1000000000000000000ULL); break;
+ case 19: DIVMOD(q, r, v, 10000000000000000000ULL); break; /* GCOV_NOT_REACHED */
+ }
+ }
+ }
+}
+
+/* END CONFIG_64 */
+#elif defined(CONFIG_32)
+#if defined(ANSI)
+#if !defined(LEGACY_COMPILER)
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ mpd_uuint_t hl;
+
+ hl = (mpd_uuint_t)a * b;
+
+ *hi = hl >> 32;
+ *lo = (mpd_uint_t)hl;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d)
+{
+ mpd_uuint_t hl;
+
+ hl = ((mpd_uuint_t)hi<<32) + lo;
+ *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */
+ *r = (mpd_uint_t)(hl - (mpd_uuint_t)(*q) * d);
+}
+/* END ANSI + uint64_t */
+#else
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ uint16_t w[4], carry;
+ uint16_t ah, al, bh, bl;
+ uint32_t hl;
+
+ ah = (uint16_t)(a>>16); al = (uint16_t)a;
+ bh = (uint16_t)(b>>16); bl = (uint16_t)b;
+
+ hl = (uint32_t)al * bl;
+ w[0] = (uint16_t)hl;
+ carry = (uint16_t)(hl>>16);
+
+ hl = (uint32_t)ah * bl + carry;
+ w[1] = (uint16_t)hl;
+ w[2] = (uint16_t)(hl>>16);
+
+ hl = (uint32_t)al * bh + w[1];
+ w[1] = (uint16_t)hl;
+ carry = (uint16_t)(hl>>16);
+
+ hl = ((uint32_t)ah * bh + w[2]) + carry;
+ w[2] = (uint16_t)hl;
+ w[3] = (uint16_t)(hl>>16);
+
+ *hi = ((uint32_t)w[3]<<16) + w[2];
+ *lo = ((uint32_t)w[1]<<16) + w[0];
+}
+
+/*
+ * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt
+ * http://www.hackersdelight.org/permissions.htm:
+ * "You are free to use, copy, and distribute any of the code on this web
+ * site, whether modified by you or not. You need not give attribution."
+ *
+ * Slightly modified, comments are mine.
+ */
+static inline int
+nlz(uint32_t x)
+{
+ int n;
+
+ if (x == 0) return(32);
+
+ n = 0;
+ if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
+ if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
+ if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
+ if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
+ if (x <= 0x7FFFFFFF) {n = n + 1;}
+
+ return n;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0,
+ mpd_uint_t v)
+{
+ const mpd_uint_t b = 65536;
+ mpd_uint_t un1, un0,
+ vn1, vn0,
+ q1, q0,
+ un32, un21, un10,
+ rhat, t;
+ int s;
+
+ assert(u1 < v);
+
+ s = nlz(v);
+ v = v << s;
+ vn1 = v >> 16;
+ vn0 = v & 0xFFFF;
+
+ t = (s == 0) ? 0 : u0 >> (32 - s);
+ un32 = (u1 << s) | t;
+ un10 = u0 << s;
+
+ un1 = un10 >> 16;
+ un0 = un10 & 0xFFFF;
+
+ q1 = un32 / vn1;
+ rhat = un32 - q1*vn1;
+again1:
+ if (q1 >= b || q1*vn0 > b*rhat + un1) {
+ q1 = q1 - 1;
+ rhat = rhat + vn1;
+ if (rhat < b) goto again1;
+ }
+
+ /*
+ * Before again1 we had:
+ * (1) q1*vn1 + rhat = un32
+ * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1
+ *
+ * The statements inside the if-clause do not change the value
+ * of the left-hand side of (2), and the loop is only exited
+ * if q1*vn0 <= rhat*b + un1, so:
+ *
+ * (3) q1*vn1*b + q1*vn0 <= un32*b + un1
+ * (4) q1*v <= un32*b + un1
+ * (5) 0 <= un32*b + un1 - q1*v
+ *
+ * By (5) we are certain that the possible add-back step from
+ * Knuth's algorithm D is never required.
+ *
+ * Since the final quotient is less than 2**32, the following
+ * must be true:
+ *
+ * (6) un32*b + un1 - q1*v <= UINT32_MAX
+ *
+ * This means that in the following line, the high words
+ * of un32*b and q1*v can be discarded without any effect
+ * on the result.
+ */
+ un21 = un32*b + un1 - q1*v;
+
+ q0 = un21 / vn1;
+ rhat = un21 - q0*vn1;
+again2:
+ if (q0 >= b || q0*vn0 > b*rhat + un0) {
+ q0 = q0 - 1;
+ rhat = rhat + vn1;
+ if (rhat < b) goto again2;
+ }
+
+ *q = q1*b + q0;
+ *r = (un21*b + un0 - q0*v) >> s;
+}
+#endif /* END ANSI + LEGACY_COMPILER */
+
+/* END ANSI */
+#elif defined(ASM)
+static inline void
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ mpd_uint_t h, l;
+
+ asm ( "mull %3\n\t"
+ : "=d" (h), "=a" (l)
+ : "%a" (a), "rm" (b)
+ : "cc"
+ );
+
+ *hi = h;
+ *lo = l;
+}
+
+static inline void
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d)
+{
+ mpd_uint_t qq, rr;
+
+ asm ( "divl %4\n\t"
+ : "=a" (qq), "=d" (rr)
+ : "a" (lo), "d" (hi), "rm" (d)
+ : "cc"
+ );
+
+ *q = qq;
+ *r = rr;
+}
+/* END GCC ASM */
+#elif defined(MASM)
+static inline void __cdecl
+_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
+{
+ mpd_uint_t h, l;
+
+ __asm {
+ mov eax, a
+ mul b
+ mov h, edx
+ mov l, eax
+ }
+
+ *hi = h;
+ *lo = l;
+}
+
+static inline void __cdecl
+_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
+ mpd_uint_t d)
+{
+ mpd_uint_t qq, rr;
+
+ __asm {
+ mov eax, lo
+ mov edx, hi
+ div d
+ mov qq, eax
+ mov rr, edx
+ }
+
+ *q = qq;
+ *r = rr;
+}
+/* END MASM (_MSC_VER) */
+#else
+ #error "need platform specific 64 bit multiplication and division"
+#endif
+
+#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d
+static inline void
+_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp)
+{
+ assert(exp <= 9);
+
+ if (exp <= 4) {
+ switch (exp) {
+ case 0: *q = v; *r = 0; break;
+ case 1: DIVMOD(q, r, v, 10UL); break;
+ case 2: DIVMOD(q, r, v, 100UL); break;
+ case 3: DIVMOD(q, r, v, 1000UL); break;
+ case 4: DIVMOD(q, r, v, 10000UL); break;
+ }
+ }
+ else {
+ switch (exp) {
+ case 5: DIVMOD(q, r, v, 100000UL); break;
+ case 6: DIVMOD(q, r, v, 1000000UL); break;
+ case 7: DIVMOD(q, r, v, 10000000UL); break;
+ case 8: DIVMOD(q, r, v, 100000000UL); break;
+ case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */
+ }
+ }
+}
+/* END CONFIG_32 */
+
+/* NO CONFIG */
+#else
+ #error "define CONFIG_64 or CONFIG_32"
+#endif /* CONFIG */
+
+
+static inline void
+_mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d)
+{
+ *q = v / d;
+ *r = v - *q * d;
+}
+
+static inline void
+_mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d)
+{
+ *q = v / d;
+ *r = v - *q * d;
+}
+
+
+/** ------------------------------------------------------------
+ ** Arithmetic with overflow checking
+ ** ------------------------------------------------------------
+ */
+
+/* The following macros do call exit() in case of an overflow.
+ If the library is used correctly (i.e. with valid context
+ parameters), such overflows cannot occur. The macros are used
+ as sanity checks in a couple of strategic places and should
+ be viewed as a handwritten version of gcc's -ftrapv option. */
+
+static inline mpd_size_t
+add_size_t(mpd_size_t a, mpd_size_t b)
+{
+ if (a > MPD_SIZE_MAX - b) {
+ mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
+ }
+ return a + b;
+}
+
+static inline mpd_size_t
+sub_size_t(mpd_size_t a, mpd_size_t b)
+{
+ if (b > a) {
+ mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
+ }
+ return a - b;
+}
+
+#if MPD_SIZE_MAX != MPD_UINT_MAX
+ #error "adapt mul_size_t() and mulmod_size_t()"
+#endif
+
+static inline mpd_size_t
+mul_size_t(mpd_size_t a, mpd_size_t b)
+{
+ mpd_uint_t hi, lo;
+
+ _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
+ if (hi) {
+ mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
+ }
+ return lo;
+}
+
+static inline mpd_size_t
+add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
+{
+ mpd_size_t ret;
+
+ *overflow = 0;
+ ret = a + b;
+ if (ret < a) *overflow = 1;
+ return ret;
+}
+
+static inline mpd_size_t
+mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
+{
+ mpd_uint_t lo;
+
+ _mpd_mul_words((mpd_uint_t *)overflow, &lo, (mpd_uint_t)a,
+ (mpd_uint_t)b);
+ return lo;
+}
+
+static inline mpd_ssize_t
+mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m)
+{
+ mpd_ssize_t r = a % m;
+ return (r < 0) ? r + m : r;
+}
+
+static inline mpd_size_t
+mulmod_size_t(mpd_size_t a, mpd_size_t b, mpd_size_t m)
+{
+ mpd_uint_t hi, lo;
+ mpd_uint_t q, r;
+
+ _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
+ _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m);
+
+ return r;
+}
+
+
+#endif /* TYPEARITH_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/umodarith.h b/Modules/_decimal/libmpdec/umodarith.h
new file mode 100644
index 0000000..c062a1e
--- /dev/null
+++ b/Modules/_decimal/libmpdec/umodarith.h
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef UMODARITH_H
+#define UMODARITH_H
+
+
+#include "constants.h"
+#include "mpdecimal.h"
+#include "typearith.h"
+
+
+/* Bignum: Low level routines for unsigned modular arithmetic. These are
+ used in the fast convolution functions for very large coefficients. */
+
+
+/**************************************************************************/
+/* ANSI modular arithmetic */
+/**************************************************************************/
+
+
+/*
+ * Restrictions: a < m and b < m
+ * ACL2 proof: umodarith.lisp: addmod-correct
+ */
+static inline mpd_uint_t
+addmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ mpd_uint_t s;
+
+ s = a + b;
+ s = (s < a) ? s - m : s;
+ s = (s >= m) ? s - m : s;
+
+ return s;
+}
+
+/*
+ * Restrictions: a < m and b < m
+ * ACL2 proof: umodarith.lisp: submod-2-correct
+ */
+static inline mpd_uint_t
+submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ mpd_uint_t d;
+
+ d = a - b;
+ d = (a < b) ? d + m : d;
+
+ return d;
+}
+
+/*
+ * Restrictions: a < 2m and b < 2m
+ * ACL2 proof: umodarith.lisp: section ext-submod
+ */
+static inline mpd_uint_t
+ext_submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ mpd_uint_t d;
+
+ a = (a >= m) ? a - m : a;
+ b = (b >= m) ? b - m : b;
+
+ d = a - b;
+ d = (a < b) ? d + m : d;
+
+ return d;
+}
+
+/*
+ * Reduce double word modulo m.
+ * Restrictions: m != 0
+ * ACL2 proof: umodarith.lisp: section dw-reduce
+ */
+static inline mpd_uint_t
+dw_reduce(mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m)
+{
+ mpd_uint_t r1, r2, w;
+
+ _mpd_div_word(&w, &r1, hi, m);
+ _mpd_div_words(&w, &r2, r1, lo, m);
+
+ return r2;
+}
+
+/*
+ * Subtract double word from a.
+ * Restrictions: a < m
+ * ACL2 proof: umodarith.lisp: section dw-submod
+ */
+static inline mpd_uint_t
+dw_submod(mpd_uint_t a, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m)
+{
+ mpd_uint_t d, r;
+
+ r = dw_reduce(hi, lo, m);
+ d = a - r;
+ d = (a < r) ? d + m : d;
+
+ return d;
+}
+
+#ifdef CONFIG_64
+
+/**************************************************************************/
+/* 64-bit modular arithmetic */
+/**************************************************************************/
+
+/*
+ * A proof of the algorithm is in literature/mulmod-64.txt. An ACL2
+ * proof is in umodarith.lisp: section "Fast modular reduction".
+ *
+ * Algorithm: calculate (a * b) % p:
+ *
+ * a) hi, lo <- a * b # Calculate a * b.
+ *
+ * b) hi, lo <- R(hi, lo) # Reduce modulo p.
+ *
+ * c) Repeat step b) until 0 <= hi * 2**64 + lo < 2*p.
+ *
+ * d) If the result is less than p, return lo. Otherwise return lo - p.
+ */
+
+static inline mpd_uint_t
+x64_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ mpd_uint_t hi, lo, x, y;
+
+
+ _mpd_mul_words(&hi, &lo, a, b);
+
+ if (m & (1ULL<<32)) { /* P1 */
+
+ /* first reduction */
+ x = y = hi;
+ hi >>= 32;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 32;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ /* second reduction */
+ x = y = hi;
+ hi >>= 32;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 32;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ return (hi || lo >= m ? lo - m : lo);
+ }
+ else if (m & (1ULL<<34)) { /* P2 */
+
+ /* first reduction */
+ x = y = hi;
+ hi >>= 30;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 34;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ /* second reduction */
+ x = y = hi;
+ hi >>= 30;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 34;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ /* third reduction */
+ x = y = hi;
+ hi >>= 30;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 34;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ return (hi || lo >= m ? lo - m : lo);
+ }
+ else { /* P3 */
+
+ /* first reduction */
+ x = y = hi;
+ hi >>= 24;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 40;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ /* second reduction */
+ x = y = hi;
+ hi >>= 24;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 40;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ /* third reduction */
+ x = y = hi;
+ hi >>= 24;
+
+ x = lo - x;
+ if (x > lo) hi--;
+
+ y <<= 40;
+ lo = y + x;
+ if (lo < y) hi++;
+
+ return (hi || lo >= m ? lo - m : lo);
+ }
+}
+
+static inline void
+x64_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m)
+{
+ *a = x64_mulmod(*a, w, m);
+ *b = x64_mulmod(*b, w, m);
+}
+
+static inline void
+x64_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1,
+ mpd_uint_t m)
+{
+ *a0 = x64_mulmod(*a0, b0, m);
+ *a1 = x64_mulmod(*a1, b1, m);
+}
+
+static inline mpd_uint_t
+x64_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod)
+{
+ mpd_uint_t r = 1;
+
+ while (exp > 0) {
+ if (exp & 1)
+ r = x64_mulmod(r, base, umod);
+ base = x64_mulmod(base, base, umod);
+ exp >>= 1;
+ }
+
+ return r;
+}
+
+/* END CONFIG_64 */
+#else /* CONFIG_32 */
+
+
+/**************************************************************************/
+/* 32-bit modular arithmetic */
+/**************************************************************************/
+
+#if defined(ANSI)
+#if !defined(LEGACY_COMPILER)
+/* HAVE_UINT64_T */
+static inline mpd_uint_t
+std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ return ((mpd_uuint_t) a * b) % m;
+}
+
+static inline void
+std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m)
+{
+ *a = ((mpd_uuint_t) *a * w) % m;
+ *b = ((mpd_uuint_t) *b * w) % m;
+}
+
+static inline void
+std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1,
+ mpd_uint_t m)
+{
+ *a0 = ((mpd_uuint_t) *a0 * b0) % m;
+ *a1 = ((mpd_uuint_t) *a1 * b1) % m;
+}
+/* END HAVE_UINT64_T */
+#else
+/* LEGACY_COMPILER */
+static inline mpd_uint_t
+std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m)
+{
+ mpd_uint_t hi, lo, q, r;
+ _mpd_mul_words(&hi, &lo, a, b);
+ _mpd_div_words(&q, &r, hi, lo, m);
+ return r;
+}
+
+static inline void
+std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m)
+{
+ *a = std_mulmod(*a, w, m);
+ *b = std_mulmod(*b, w, m);
+}
+
+static inline void
+std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1,
+ mpd_uint_t m)
+{
+ *a0 = std_mulmod(*a0, b0, m);
+ *a1 = std_mulmod(*a1, b1, m);
+}
+/* END LEGACY_COMPILER */
+#endif
+
+static inline mpd_uint_t
+std_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod)
+{
+ mpd_uint_t r = 1;
+
+ while (exp > 0) {
+ if (exp & 1)
+ r = std_mulmod(r, base, umod);
+ base = std_mulmod(base, base, umod);
+ exp >>= 1;
+ }
+
+ return r;
+}
+#endif /* ANSI CONFIG_32 */
+
+
+/**************************************************************************/
+/* Pentium Pro modular arithmetic */
+/**************************************************************************/
+
+/*
+ * A proof of the algorithm is in literature/mulmod-ppro.txt. The FPU
+ * control word must be set to 64-bit precision and truncation mode
+ * prior to using these functions.
+ *
+ * Algorithm: calculate (a * b) % p:
+ *
+ * p := prime < 2**31
+ * pinv := (long double)1.0 / p (precalculated)
+ *
+ * a) n = a * b # Calculate exact product.
+ * b) qest = n * pinv # Calculate estimate for q = n / p.
+ * c) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient.
+ * d) r = n - q * p # Calculate remainder.
+ *
+ * Remarks:
+ *
+ * - p = dmod and pinv = dinvmod.
+ * - dinvmod points to an array of three uint32_t, which is interpreted
+ * as an 80 bit long double by fldt.
+ * - Intel compilers prior to version 11 do not seem to handle the
+ * __GNUC__ inline assembly correctly.
+ * - random tests are provided in tests/extended/ppro_mulmod.c
+ */
+
+#if defined(PPRO)
+#if defined(ASM)
+
+/* Return (a * b) % dmod */
+static inline mpd_uint_t
+ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod)
+{
+ mpd_uint_t retval;
+
+ asm (
+ "fildl %2\n\t"
+ "fildl %1\n\t"
+ "fmulp %%st, %%st(1)\n\t"
+ "fldt (%4)\n\t"
+ "fmul %%st(1), %%st\n\t"
+ "flds %5\n\t"
+ "fadd %%st, %%st(1)\n\t"
+ "fsubrp %%st, %%st(1)\n\t"
+ "fldl (%3)\n\t"
+ "fmulp %%st, %%st(1)\n\t"
+ "fsubrp %%st, %%st(1)\n\t"
+ "fistpl %0\n\t"
+ : "=m" (retval)
+ : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63)
+ : "st", "memory"
+ );
+
+ return retval;
+}
+
+/*
+ * Two modular multiplications in parallel:
+ * *a0 = (*a0 * w) % dmod
+ * *a1 = (*a1 * w) % dmod
+ */
+static inline void
+ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w,
+ double *dmod, uint32_t *dinvmod)
+{
+ asm (
+ "fildl %2\n\t"
+ "fildl (%1)\n\t"
+ "fmul %%st(1), %%st\n\t"
+ "fxch %%st(1)\n\t"
+ "fildl (%0)\n\t"
+ "fmulp %%st, %%st(1) \n\t"
+ "fldt (%4)\n\t"
+ "flds %5\n\t"
+ "fld %%st(2)\n\t"
+ "fmul %%st(2)\n\t"
+ "fadd %%st(1)\n\t"
+ "fsub %%st(1)\n\t"
+ "fmull (%3)\n\t"
+ "fsubrp %%st, %%st(3)\n\t"
+ "fxch %%st(2)\n\t"
+ "fistpl (%0)\n\t"
+ "fmul %%st(2)\n\t"
+ "fadd %%st(1)\n\t"
+ "fsubp %%st, %%st(1)\n\t"
+ "fmull (%3)\n\t"
+ "fsubrp %%st, %%st(1)\n\t"
+ "fistpl (%1)\n\t"
+ : : "r" (a0), "r" (a1), "m" (w),
+ "r" (dmod), "r" (dinvmod),
+ "m" (MPD_TWO63)
+ : "st", "memory"
+ );
+}
+
+/*
+ * Two modular multiplications in parallel:
+ * *a0 = (*a0 * b0) % dmod
+ * *a1 = (*a1 * b1) % dmod
+ */
+static inline void
+ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1,
+ double *dmod, uint32_t *dinvmod)
+{
+ asm (
+ "fildl %3\n\t"
+ "fildl (%2)\n\t"
+ "fmulp %%st, %%st(1)\n\t"
+ "fildl %1\n\t"
+ "fildl (%0)\n\t"
+ "fmulp %%st, %%st(1)\n\t"
+ "fldt (%5)\n\t"
+ "fld %%st(2)\n\t"
+ "fmul %%st(1), %%st\n\t"
+ "fxch %%st(1)\n\t"
+ "fmul %%st(2), %%st\n\t"
+ "flds %6\n\t"
+ "fldl (%4)\n\t"
+ "fxch %%st(3)\n\t"
+ "fadd %%st(1), %%st\n\t"
+ "fxch %%st(2)\n\t"
+ "fadd %%st(1), %%st\n\t"
+ "fxch %%st(2)\n\t"
+ "fsub %%st(1), %%st\n\t"
+ "fxch %%st(2)\n\t"
+ "fsubp %%st, %%st(1)\n\t"
+ "fxch %%st(1)\n\t"
+ "fmul %%st(2), %%st\n\t"
+ "fxch %%st(1)\n\t"
+ "fmulp %%st, %%st(2)\n\t"
+ "fsubrp %%st, %%st(3)\n\t"
+ "fsubrp %%st, %%st(1)\n\t"
+ "fxch %%st(1)\n\t"
+ "fistpl (%2)\n\t"
+ "fistpl (%0)\n\t"
+ : : "r" (a0), "m" (b0), "r" (a1), "m" (b1),
+ "r" (dmod), "r" (dinvmod),
+ "m" (MPD_TWO63)
+ : "st", "memory"
+ );
+}
+/* END PPRO GCC ASM */
+#elif defined(MASM)
+
+/* Return (a * b) % dmod */
+static inline mpd_uint_t __cdecl
+ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod)
+{
+ mpd_uint_t retval;
+
+ __asm {
+ mov eax, dinvmod
+ mov edx, dmod
+ fild b
+ fild a
+ fmulp st(1), st
+ fld TBYTE PTR [eax]
+ fmul st, st(1)
+ fld MPD_TWO63
+ fadd st(1), st
+ fsubp st(1), st
+ fld QWORD PTR [edx]
+ fmulp st(1), st
+ fsubp st(1), st
+ fistp retval
+ }
+
+ return retval;
+}
+
+/*
+ * Two modular multiplications in parallel:
+ * *a0 = (*a0 * w) % dmod
+ * *a1 = (*a1 * w) % dmod
+ */
+static inline mpd_uint_t __cdecl
+ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w,
+ double *dmod, uint32_t *dinvmod)
+{
+ __asm {
+ mov ecx, dmod
+ mov edx, a1
+ mov ebx, dinvmod
+ mov eax, a0
+ fild w
+ fild DWORD PTR [edx]
+ fmul st, st(1)
+ fxch st(1)
+ fild DWORD PTR [eax]
+ fmulp st(1), st
+ fld TBYTE PTR [ebx]
+ fld MPD_TWO63
+ fld st(2)
+ fmul st, st(2)
+ fadd st, st(1)
+ fsub st, st(1)
+ fmul QWORD PTR [ecx]
+ fsubp st(3), st
+ fxch st(2)
+ fistp DWORD PTR [eax]
+ fmul st, st(2)
+ fadd st, st(1)
+ fsubrp st(1), st
+ fmul QWORD PTR [ecx]
+ fsubp st(1), st
+ fistp DWORD PTR [edx]
+ }
+}
+
+/*
+ * Two modular multiplications in parallel:
+ * *a0 = (*a0 * b0) % dmod
+ * *a1 = (*a1 * b1) % dmod
+ */
+static inline void __cdecl
+ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1,
+ double *dmod, uint32_t *dinvmod)
+{
+ __asm {
+ mov ecx, dmod
+ mov edx, a1
+ mov ebx, dinvmod
+ mov eax, a0
+ fild b1
+ fild DWORD PTR [edx]
+ fmulp st(1), st
+ fild b0
+ fild DWORD PTR [eax]
+ fmulp st(1), st
+ fld TBYTE PTR [ebx]
+ fld st(2)
+ fmul st, st(1)
+ fxch st(1)
+ fmul st, st(2)
+ fld DWORD PTR MPD_TWO63
+ fld QWORD PTR [ecx]
+ fxch st(3)
+ fadd st, st(1)
+ fxch st(2)
+ fadd st, st(1)
+ fxch st(2)
+ fsub st, st(1)
+ fxch st(2)
+ fsubrp st(1), st
+ fxch st(1)
+ fmul st, st(2)
+ fxch st(1)
+ fmulp st(2), st
+ fsubp st(3), st
+ fsubp st(1), st
+ fxch st(1)
+ fistp DWORD PTR [edx]
+ fistp DWORD PTR [eax]
+ }
+}
+#endif /* PPRO MASM (_MSC_VER) */
+
+
+/* Return (base ** exp) % dmod */
+static inline mpd_uint_t
+ppro_powmod(mpd_uint_t base, mpd_uint_t exp, double *dmod, uint32_t *dinvmod)
+{
+ mpd_uint_t r = 1;
+
+ while (exp > 0) {
+ if (exp & 1)
+ r = ppro_mulmod(r, base, dmod, dinvmod);
+ base = ppro_mulmod(base, base, dmod, dinvmod);
+ exp >>= 1;
+ }
+
+ return r;
+}
+#endif /* PPRO */
+#endif /* CONFIG_32 */
+
+
+#endif /* UMODARITH_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/vccompat.h b/Modules/_decimal/libmpdec/vccompat.h
new file mode 100644
index 0000000..276e037
--- /dev/null
+++ b/Modules/_decimal/libmpdec/vccompat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef VCCOMPAT_H
+#define VCCOMPAT_H
+
+
+/* Visual C fixes: no stdint.h, no snprintf ... */
+#ifdef _MSC_VER
+ #include "vcstdint.h"
+ #undef inline
+ #define inline __inline
+ #undef random
+ #define random rand
+ #undef srandom
+ #define srandom srand
+ #undef snprintf
+ #define snprintf sprintf_s
+ #define HAVE_SNPRINTF
+ #undef strncasecmp
+ #define strncasecmp _strnicmp
+ #undef strcasecmp
+ #define strcasecmp _stricmp
+ #undef strtoll
+ #define strtoll _strtoi64
+ #define strdup _strdup
+ #define PRIi64 "I64i"
+ #define PRIu64 "I64u"
+ #define PRIi32 "I32i"
+ #define PRIu32 "I32u"
+#endif
+
+
+#endif /* VCCOMPAT_H */
+
+
+
diff --git a/Modules/_decimal/libmpdec/vcdiv64.asm b/Modules/_decimal/libmpdec/vcdiv64.asm
new file mode 100644
index 0000000..31bba08
--- /dev/null
+++ b/Modules/_decimal/libmpdec/vcdiv64.asm
@@ -0,0 +1,48 @@
+;
+; Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; 1. Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; 2. Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+; SUCH DAMAGE.
+;
+
+
+PUBLIC _mpd_div_words
+_TEXT SEGMENT
+q$ = 8
+r$ = 16
+hi$ = 24
+lo$ = 32
+d$ = 40
+_mpd_div_words PROC
+ mov r10, rdx
+ mov rdx, r8
+ mov rax, r9
+ div QWORD PTR d$[rsp]
+ mov QWORD PTR [r10], rdx
+ mov QWORD PTR [rcx], rax
+ ret 0
+_mpd_div_words ENDP
+_TEXT ENDS
+END
+
+
diff --git a/Modules/_decimal/libmpdec/vcstdint.h b/Modules/_decimal/libmpdec/vcstdint.h
new file mode 100644
index 0000000..e032ff1
--- /dev/null
+++ b/Modules/_decimal/libmpdec/vcstdint.h
@@ -0,0 +1,232 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+ extern "C++" {
+#endif
+# include <wchar.h>
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+ }
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/Modules/_decimal/tests/README.txt b/Modules/_decimal/tests/README.txt
new file mode 100644
index 0000000..97b6ff6
--- /dev/null
+++ b/Modules/_decimal/tests/README.txt
@@ -0,0 +1,15 @@
+
+
+This directory contains extended tests and a benchmark against decimal.py:
+
+ bench.py -> Benchmark for small and large precisions.
+ Usage: ../../../python bench.py
+
+ formathelper.py ->
+ randdec.py -> Generate test cases for deccheck.py.
+ randfloat.py ->
+
+ deccheck.py -> Run extended tests.
+ Usage: ../../../python deccheck.py [--short|--medium|--long|--all]
+
+
diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py
new file mode 100644
index 0000000..013f0f6
--- /dev/null
+++ b/Modules/_decimal/tests/bench.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+#
+# Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved.
+# Modified and extended by Stefan Krah.
+#
+
+# Usage: ../../../python bench.py
+
+
+import time
+from math import log, ceil
+from test.support import import_fresh_module
+
+C = import_fresh_module('decimal', fresh=['_decimal'])
+P = import_fresh_module('decimal', blocked=['_decimal'])
+
+
+# Pi function from the decimal.py documentation
+def pi_float(prec):
+ """native float"""
+ lasts, t, s, n, na, d, da = 0, 3.0, 3, 1, 0, 0, 24
+ while s != lasts:
+ lasts = s
+ n, na = n+na, na+8
+ d, da = d+da, da+32
+ t = (t * n) / d
+ s += t
+ return s
+
+def pi_cdecimal(prec):
+ """cdecimal"""
+ C.getcontext().prec = prec
+ D = C.Decimal
+ lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24)
+ while s != lasts:
+ lasts = s
+ n, na = n+na, na+8
+ d, da = d+da, da+32
+ t = (t * n) / d
+ s += t
+ return s
+
+def pi_decimal(prec):
+ """decimal"""
+ P.getcontext().prec = prec
+ D = P.Decimal
+ lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24)
+ while s != lasts:
+ lasts = s
+ n, na = n+na, na+8
+ d, da = d+da, da+32
+ t = (t * n) / d
+ s += t
+ return s
+
+def factorial(n, m):
+ if (n > m):
+ return factorial(m, n)
+ elif m == 0:
+ return 1
+ elif n == m:
+ return n
+ else:
+ return factorial(n, (n+m)//2) * factorial((n+m)//2 + 1, m)
+
+
+print("\n# ======================================================================")
+print("# Calculating pi, 10000 iterations")
+print("# ======================================================================\n")
+
+for prec in [9, 19]:
+ print("\nPrecision: %d decimal digits\n" % prec)
+ for func in [pi_float, pi_cdecimal, pi_decimal]:
+ start = time.time()
+ for i in range(10000):
+ x = func(prec)
+ print("%s:" % func.__name__.replace("pi_", ""))
+ print("result: %s" % str(x))
+ print("time: %fs\n" % (time.time()-start))
+
+
+print("\n# ======================================================================")
+print("# Factorial")
+print("# ======================================================================\n")
+
+C.getcontext().prec = C.MAX_PREC
+
+for n in [100000, 1000000]:
+
+ print("n = %d\n" % n)
+
+ # C version of decimal
+ start_calc = time.time()
+ x = factorial(C.Decimal(n), 0)
+ end_calc = time.time()
+ start_conv = time.time()
+ sx = str(x)
+ end_conv = time.time()
+ print("cdecimal:")
+ print("calculation time: %fs" % (end_calc-start_calc))
+ print("conversion time: %fs\n" % (end_conv-start_conv))
+
+ # Python integers
+ start_calc = time.time()
+ y = factorial(n, 0)
+ end_calc = time.time()
+ start_conv = time.time()
+ sy = str(y)
+ end_conv = time.time()
+
+ print("int:")
+ print("calculation time: %fs" % (end_calc-start_calc))
+ print("conversion time: %fs\n\n" % (end_conv-start_conv))
+
+ assert(sx == sy)
diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py
new file mode 100644
index 0000000..aefbed6
--- /dev/null
+++ b/Modules/_decimal/tests/deccheck.py
@@ -0,0 +1,1074 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# Usage: python deccheck.py [--short|--medium|--long|--all]
+#
+
+import sys, random
+from copy import copy
+from collections import defaultdict
+from test.support import import_fresh_module
+from randdec import randfloat, all_unary, all_binary, all_ternary
+from formathelper import rand_format, rand_locale
+
+C = import_fresh_module('decimal', fresh=['_decimal'])
+P = import_fresh_module('decimal', blocked=['_decimal'])
+EXIT_STATUS = 0
+
+
+# Contains all categories of Decimal methods.
+Functions = {
+ # Plain unary:
+ 'unary': (
+ '__abs__', '__bool__', '__ceil__', '__complex__', '__copy__',
+ '__floor__', '__float__', '__hash__', '__int__', '__neg__',
+ '__pos__', '__reduce__', '__repr__', '__str__', '__trunc__',
+ 'adjusted', 'as_tuple', 'canonical', 'conjugate', 'copy_abs',
+ 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite',
+ 'is_nan', 'is_qnan', 'is_signed', 'is_snan', 'is_zero', 'radix'
+ ),
+ # Unary with optional context:
+ 'unary_ctx': (
+ 'exp', 'is_normal', 'is_subnormal', 'ln', 'log10', 'logb',
+ 'logical_invert', 'next_minus', 'next_plus', 'normalize',
+ 'number_class', 'sqrt', 'to_eng_string'
+ ),
+ # Unary with optional rounding mode and context:
+ 'unary_rnd_ctx': ('to_integral', 'to_integral_exact', 'to_integral_value'),
+ # Plain binary:
+ 'binary': (
+ '__add__', '__divmod__', '__eq__', '__floordiv__', '__ge__', '__gt__',
+ '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__pow__',
+ '__radd__', '__rdivmod__', '__rfloordiv__', '__rmod__', '__rmul__',
+ '__rpow__', '__rsub__', '__rtruediv__', '__sub__', '__truediv__',
+ 'compare_total', 'compare_total_mag', 'copy_sign', 'quantize',
+ 'same_quantum'
+ ),
+ # Binary with optional context:
+ 'binary_ctx': (
+ 'compare', 'compare_signal', 'logical_and', 'logical_or', 'logical_xor',
+ 'max', 'max_mag', 'min', 'min_mag', 'next_toward', 'remainder_near',
+ 'rotate', 'scaleb', 'shift'
+ ),
+ # Plain ternary:
+ 'ternary': ('__pow__',),
+ # Ternary with optional context:
+ 'ternary_ctx': ('fma',),
+ # Special:
+ 'special': ('__format__', '__reduce_ex__', '__round__', 'from_float',
+ 'quantize'),
+ # Properties:
+ 'property': ('real', 'imag')
+}
+
+# Contains all categories of Context methods. The n-ary classification
+# applies to the number of Decimal arguments.
+ContextFunctions = {
+ # Plain nullary:
+ 'nullary': ('context.__hash__', 'context.__reduce__', 'context.radix'),
+ # Plain unary:
+ 'unary': ('context.abs', 'context.canonical', 'context.copy_abs',
+ 'context.copy_decimal', 'context.copy_negate',
+ 'context.create_decimal', 'context.exp', 'context.is_canonical',
+ 'context.is_finite', 'context.is_infinite', 'context.is_nan',
+ 'context.is_normal', 'context.is_qnan', 'context.is_signed',
+ 'context.is_snan', 'context.is_subnormal', 'context.is_zero',
+ 'context.ln', 'context.log10', 'context.logb',
+ 'context.logical_invert', 'context.minus', 'context.next_minus',
+ 'context.next_plus', 'context.normalize', 'context.number_class',
+ 'context.plus', 'context.sqrt', 'context.to_eng_string',
+ 'context.to_integral', 'context.to_integral_exact',
+ 'context.to_integral_value', 'context.to_sci_string'
+ ),
+ # Plain binary:
+ 'binary': ('context.add', 'context.compare', 'context.compare_signal',
+ 'context.compare_total', 'context.compare_total_mag',
+ 'context.copy_sign', 'context.divide', 'context.divide_int',
+ 'context.divmod', 'context.logical_and', 'context.logical_or',
+ 'context.logical_xor', 'context.max', 'context.max_mag',
+ 'context.min', 'context.min_mag', 'context.multiply',
+ 'context.next_toward', 'context.power', 'context.quantize',
+ 'context.remainder', 'context.remainder_near', 'context.rotate',
+ 'context.same_quantum', 'context.scaleb', 'context.shift',
+ 'context.subtract'
+ ),
+ # Plain ternary:
+ 'ternary': ('context.fma', 'context.power'),
+ # Special:
+ 'special': ('context.__reduce_ex__', 'context.create_decimal_from_float')
+}
+
+# Functions that require a restricted exponent range for reasonable runtimes.
+UnaryRestricted = [
+ '__ceil__', '__floor__', '__int__', '__long__', '__trunc__',
+ 'to_integral', 'to_integral_value'
+]
+
+BinaryRestricted = ['__round__']
+
+TernaryRestricted = ['__pow__', 'context.power']
+
+
+# ======================================================================
+# Unified Context
+# ======================================================================
+
+# Translate symbols.
+CondMap = {
+ C.Clamped: P.Clamped,
+ C.ConversionSyntax: P.ConversionSyntax,
+ C.DivisionByZero: P.DivisionByZero,
+ C.DivisionImpossible: P.InvalidOperation,
+ C.DivisionUndefined: P.DivisionUndefined,
+ C.Inexact: P.Inexact,
+ C.InvalidContext: P.InvalidContext,
+ C.InvalidOperation: P.InvalidOperation,
+ C.Overflow: P.Overflow,
+ C.Rounded: P.Rounded,
+ C.Subnormal: P.Subnormal,
+ C.Underflow: P.Underflow,
+ C.FloatOperation: P.FloatOperation,
+}
+
+RoundMap = {
+ C.ROUND_UP: P.ROUND_UP,
+ C.ROUND_DOWN: P.ROUND_DOWN,
+ C.ROUND_CEILING: P.ROUND_CEILING,
+ C.ROUND_FLOOR: P.ROUND_FLOOR,
+ C.ROUND_HALF_UP: P.ROUND_HALF_UP,
+ C.ROUND_HALF_DOWN: P.ROUND_HALF_DOWN,
+ C.ROUND_HALF_EVEN: P.ROUND_HALF_EVEN,
+ C.ROUND_05UP: P.ROUND_05UP
+}
+RoundModes = RoundMap.items()
+
+
+class Context(object):
+ """Provides a convenient way of syncing the C and P contexts"""
+
+ __slots__ = ['c', 'p']
+
+ def __init__(self, c_ctx=None, p_ctx=None):
+ """Initialization is from the C context"""
+ self.c = C.getcontext() if c_ctx is None else c_ctx
+ self.p = P.getcontext() if p_ctx is None else p_ctx
+ self.p.prec = self.c.prec
+ self.p.Emin = self.c.Emin
+ self.p.Emax = self.c.Emax
+ self.p.rounding = RoundMap[self.c.rounding]
+ self.p.capitals = self.c.capitals
+ self.settraps([sig for sig in self.c.traps if self.c.traps[sig]])
+ self.setstatus([sig for sig in self.c.flags if self.c.flags[sig]])
+ self.p.clamp = self.c.clamp
+
+ def __str__(self):
+ return str(self.c) + '\n' + str(self.p)
+
+ def getprec(self):
+ assert(self.c.prec == self.p.prec)
+ return self.c.prec
+
+ def setprec(self, val):
+ self.c.prec = val
+ self.p.prec = val
+
+ def getemin(self):
+ assert(self.c.Emin == self.p.Emin)
+ return self.c.Emin
+
+ def setemin(self, val):
+ self.c.Emin = val
+ self.p.Emin = val
+
+ def getemax(self):
+ assert(self.c.Emax == self.p.Emax)
+ return self.c.Emax
+
+ def setemax(self, val):
+ self.c.Emax = val
+ self.p.Emax = val
+
+ def getround(self):
+ assert(self.c.rounding == RoundMap[self.p.rounding])
+ return self.c.rounding
+
+ def setround(self, val):
+ self.c.rounding = val
+ self.p.rounding = RoundMap[val]
+
+ def getcapitals(self):
+ assert(self.c.capitals == self.p.capitals)
+ return self.c.capitals
+
+ def setcapitals(self, val):
+ self.c.capitals = val
+ self.p.capitals = val
+
+ def getclamp(self):
+ assert(self.c.clamp == self.p.clamp)
+ return self.c.clamp
+
+ def setclamp(self, val):
+ self.c.clamp = val
+ self.p.clamp = val
+
+ prec = property(getprec, setprec)
+ Emin = property(getemin, setemin)
+ Emax = property(getemax, setemax)
+ rounding = property(getround, setround)
+ clamp = property(getclamp, setclamp)
+ capitals = property(getcapitals, setcapitals)
+
+ def clear_traps(self):
+ self.c.clear_traps()
+ for trap in self.p.traps:
+ self.p.traps[trap] = False
+
+ def clear_status(self):
+ self.c.clear_flags()
+ self.p.clear_flags()
+
+ def settraps(self, lst):
+ """lst: C signal list"""
+ self.clear_traps()
+ for signal in lst:
+ self.c.traps[signal] = True
+ self.p.traps[CondMap[signal]] = True
+
+ def setstatus(self, lst):
+ """lst: C signal list"""
+ self.clear_status()
+ for signal in lst:
+ self.c.flags[signal] = True
+ self.p.flags[CondMap[signal]] = True
+
+ def assert_eq_status(self):
+ """assert equality of C and P status"""
+ for signal in self.c.flags:
+ if self.c.flags[signal] == (not self.p.flags[CondMap[signal]]):
+ return False
+ return True
+
+
+# We don't want exceptions so that we can compare the status flags.
+context = Context()
+context.Emin = C.MIN_EMIN
+context.Emax = C.MAX_EMAX
+context.clear_traps()
+
+# When creating decimals, _decimal is ultimately limited by the maximum
+# context values. We emulate this restriction for decimal.py.
+maxcontext = P.Context(
+ prec=C.MAX_PREC,
+ Emin=C.MIN_EMIN,
+ Emax=C.MAX_EMAX,
+ rounding=P.ROUND_HALF_UP,
+ capitals=1
+)
+maxcontext.clamp = 0
+
+def RestrictedDecimal(value):
+ maxcontext.traps = copy(context.p.traps)
+ maxcontext.clear_flags()
+ if isinstance(value, str):
+ value = value.strip()
+ dec = maxcontext.create_decimal(value)
+ if maxcontext.flags[P.Inexact] or \
+ maxcontext.flags[P.Rounded] or \
+ maxcontext.flags[P.InvalidOperation]:
+ return context.p._raise_error(P.InvalidOperation)
+ if maxcontext.flags[P.FloatOperation]:
+ context.p.flags[P.FloatOperation] = True
+ return dec
+
+
+# ======================================================================
+# TestSet: Organize data and events during a single test case
+# ======================================================================
+
+class RestrictedList(list):
+ """List that can only be modified by appending items."""
+ def __getattribute__(self, name):
+ if name != 'append':
+ raise AttributeError("unsupported operation")
+ return list.__getattribute__(self, name)
+ def unsupported(self, *_):
+ raise AttributeError("unsupported operation")
+ __add__ = __delattr__ = __delitem__ = __iadd__ = __imul__ = unsupported
+ __mul__ = __reversed__ = __rmul__ = __setattr__ = __setitem__ = unsupported
+
+class TestSet(object):
+ """A TestSet contains the original input operands, converted operands,
+ Python exceptions that occurred either during conversion or during
+ execution of the actual function, and the final results.
+
+ For safety, most attributes are lists that only support the append
+ operation.
+
+ If a function name is prefixed with 'context.', the corresponding
+ context method is called.
+ """
+ def __init__(self, funcname, operands):
+ if funcname.startswith("context."):
+ self.funcname = funcname.replace("context.", "")
+ self.contextfunc = True
+ else:
+ self.funcname = funcname
+ self.contextfunc = False
+ self.op = operands # raw operand tuple
+ self.context = context # context used for the operation
+ self.cop = RestrictedList() # converted C.Decimal operands
+ self.cex = RestrictedList() # Python exceptions for C.Decimal
+ self.cresults = RestrictedList() # C.Decimal results
+ self.pop = RestrictedList() # converted P.Decimal operands
+ self.pex = RestrictedList() # Python exceptions for P.Decimal
+ self.presults = RestrictedList() # P.Decimal results
+
+
+# ======================================================================
+# SkipHandler: skip known discrepancies
+# ======================================================================
+
+class SkipHandler:
+ """Handle known discrepancies between decimal.py and _decimal.so.
+ These are either ULP differences in the power function or
+ extremely minor issues."""
+
+ def __init__(self):
+ self.ulpdiff = 0
+ self.powmod_zeros = 0
+ self.maxctx = P.Context(Emax=10**18, Emin=-10**18)
+
+ def default(self, t):
+ return False
+ __ge__ = __gt__ = __le__ = __lt__ = __ne__ = __eq__ = default
+ __reduce__ = __format__ = __repr__ = __str__ = default
+
+ def harrison_ulp(self, dec):
+ """ftp://ftp.inria.fr/INRIA/publication/publi-pdf/RR/RR-5504.pdf"""
+ a = dec.next_plus()
+ b = dec.next_minus()
+ return abs(a - b)
+
+ def standard_ulp(self, dec, prec):
+ return P._dec_from_triple(0, '1', dec._exp+len(dec._int)-prec)
+
+ def rounding_direction(self, x, mode):
+ """Determine the effective direction of the rounding when
+ the exact result x is rounded according to mode.
+ Return -1 for downwards, 0 for undirected, 1 for upwards,
+ 2 for ROUND_05UP."""
+ cmp = 1 if x.compare_total(P.Decimal("+0")) >= 0 else -1
+
+ if mode in (P.ROUND_HALF_EVEN, P.ROUND_HALF_UP, P.ROUND_HALF_DOWN):
+ return 0
+ elif mode == P.ROUND_CEILING:
+ return 1
+ elif mode == P.ROUND_FLOOR:
+ return -1
+ elif mode == P.ROUND_UP:
+ return cmp
+ elif mode == P.ROUND_DOWN:
+ return -cmp
+ elif mode == P.ROUND_05UP:
+ return 2
+ else:
+ raise ValueError("Unexpected rounding mode: %s" % mode)
+
+ def check_ulpdiff(self, exact, rounded):
+ # current precision
+ p = context.p.prec
+
+ # Convert infinities to the largest representable number + 1.
+ x = exact
+ if exact.is_infinite():
+ x = P._dec_from_triple(exact._sign, '10', context.p.Emax)
+ y = rounded
+ if rounded.is_infinite():
+ y = P._dec_from_triple(rounded._sign, '10', context.p.Emax)
+
+ # err = (rounded - exact) / ulp(rounded)
+ self.maxctx.prec = p * 2
+ t = self.maxctx.subtract(y, x)
+ if context.c.flags[C.Clamped] or \
+ context.c.flags[C.Underflow]:
+ # The standard ulp does not work in Underflow territory.
+ ulp = self.harrison_ulp(y)
+ else:
+ ulp = self.standard_ulp(y, p)
+ # Error in ulps.
+ err = self.maxctx.divide(t, ulp)
+
+ dir = self.rounding_direction(x, context.p.rounding)
+ if dir == 0:
+ if P.Decimal("-0.6") < err < P.Decimal("0.6"):
+ return True
+ elif dir == 1: # directed, upwards
+ if P.Decimal("-0.1") < err < P.Decimal("1.1"):
+ return True
+ elif dir == -1: # directed, downwards
+ if P.Decimal("-1.1") < err < P.Decimal("0.1"):
+ return True
+ else: # ROUND_05UP
+ if P.Decimal("-1.1") < err < P.Decimal("1.1"):
+ return True
+
+ print("ulp: %s error: %s exact: %s c_rounded: %s"
+ % (ulp, err, exact, rounded))
+ return False
+
+ def bin_resolve_ulp(self, t):
+ """Check if results of _decimal's power function are within the
+ allowed ulp ranges."""
+ # NaNs are beyond repair.
+ if t.rc.is_nan() or t.rp.is_nan():
+ return False
+
+ # "exact" result, double precision, half_even
+ self.maxctx.prec = context.p.prec * 2
+
+ op1, op2 = t.pop[0], t.pop[1]
+ if t.contextfunc:
+ exact = getattr(self.maxctx, t.funcname)(op1, op2)
+ else:
+ exact = getattr(op1, t.funcname)(op2, context=self.maxctx)
+
+ # _decimal's rounded result
+ rounded = P.Decimal(t.cresults[0])
+
+ self.ulpdiff += 1
+ return self.check_ulpdiff(exact, rounded)
+
+ ############################ Correct rounding #############################
+ def resolve_underflow(self, t):
+ """In extremely rare cases where the infinite precision result is just
+ below etiny, cdecimal does not set Subnormal/Underflow. Example:
+
+ setcontext(Context(prec=21, rounding=ROUND_UP, Emin=-55, Emax=85))
+ Decimal("1.00000000000000000000000000000000000000000000000"
+ "0000000100000000000000000000000000000000000000000"
+ "0000000000000025").ln()
+ """
+ if t.cresults != t.presults:
+ return False # Results must be identical.
+ if context.c.flags[C.Rounded] and \
+ context.c.flags[C.Inexact] and \
+ context.p.flags[P.Rounded] and \
+ context.p.flags[P.Inexact]:
+ return True # Subnormal/Underflow may be missing.
+ return False
+
+ def exp(self, t):
+ """Resolve Underflow or ULP difference."""
+ return self.resolve_underflow(t)
+
+ def log10(self, t):
+ """Resolve Underflow or ULP difference."""
+ return self.resolve_underflow(t)
+
+ def ln(self, t):
+ """Resolve Underflow or ULP difference."""
+ return self.resolve_underflow(t)
+
+ def __pow__(self, t):
+ """Always calls the resolve function. C.Decimal does not have correct
+ rounding for the power function."""
+ if context.c.flags[C.Rounded] and \
+ context.c.flags[C.Inexact] and \
+ context.p.flags[P.Rounded] and \
+ context.p.flags[P.Inexact]:
+ return self.bin_resolve_ulp(t)
+ else:
+ return False
+ power = __rpow__ = __pow__
+
+ ############################## Technicalities #############################
+ def __float__(self, t):
+ """NaN comparison in the verify() function obviously gives an
+ incorrect answer: nan == nan -> False"""
+ if t.cop[0].is_nan() and t.pop[0].is_nan():
+ return True
+ return False
+ __complex__ = __float__
+
+ def __radd__(self, t):
+ """decimal.py gives precedence to the first NaN; this is
+ not important, as __radd__ will not be called for
+ two decimal arguments."""
+ if t.rc.is_nan() and t.rp.is_nan():
+ return True
+ return False
+ __rmul__ = __radd__
+
+ ################################ Various ##################################
+ def __round__(self, t):
+ """Exception: Decimal('1').__round__(-100000000000000000000000000)
+ Should it really be InvalidOperation?"""
+ if t.rc is None and t.rp.is_nan():
+ return True
+ return False
+
+shandler = SkipHandler()
+def skip_error(t):
+ return getattr(shandler, t.funcname, shandler.default)(t)
+
+
+# ======================================================================
+# Handling verification errors
+# ======================================================================
+
+class VerifyError(Exception):
+ """Verification failed."""
+ pass
+
+def function_as_string(t):
+ if t.contextfunc:
+ cargs = t.cop
+ pargs = t.pop
+ cfunc = "c_func: %s(" % t.funcname
+ pfunc = "p_func: %s(" % t.funcname
+ else:
+ cself, cargs = t.cop[0], t.cop[1:]
+ pself, pargs = t.pop[0], t.pop[1:]
+ cfunc = "c_func: %s.%s(" % (repr(cself), t.funcname)
+ pfunc = "p_func: %s.%s(" % (repr(pself), t.funcname)
+
+ err = cfunc
+ for arg in cargs:
+ err += "%s, " % repr(arg)
+ err = err.rstrip(", ")
+ err += ")\n"
+
+ err += pfunc
+ for arg in pargs:
+ err += "%s, " % repr(arg)
+ err = err.rstrip(", ")
+ err += ")"
+
+ return err
+
+def raise_error(t):
+ global EXIT_STATUS
+
+ if skip_error(t):
+ return
+ EXIT_STATUS = 1
+
+ err = "Error in %s:\n\n" % t.funcname
+ err += "input operands: %s\n\n" % (t.op,)
+ err += function_as_string(t)
+ err += "\n\nc_result: %s\np_result: %s\n\n" % (t.cresults, t.presults)
+ err += "c_exceptions: %s\np_exceptions: %s\n\n" % (t.cex, t.pex)
+ err += "%s\n\n" % str(t.context)
+
+ raise VerifyError(err)
+
+
+# ======================================================================
+# Main testing functions
+#
+# The procedure is always (t is the TestSet):
+#
+# convert(t) -> Initialize the TestSet as necessary.
+#
+# Return 0 for early abortion (e.g. if a TypeError
+# occurs during conversion, there is nothing to test).
+#
+# Return 1 for continuing with the test case.
+#
+# callfuncs(t) -> Call the relevant function for each implementation
+# and record the results in the TestSet.
+#
+# verify(t) -> Verify the results. If verification fails, details
+# are printed to stdout.
+# ======================================================================
+
+def convert(t, convstr=True):
+ """ t is the testset. At this stage the testset contains a tuple of
+ operands t.op of various types. For decimal methods the first
+ operand (self) is always converted to Decimal. If 'convstr' is
+ true, string operands are converted as well.
+
+ Context operands are of type deccheck.Context, rounding mode
+ operands are given as a tuple (C.rounding, P.rounding).
+
+ Other types (float, int, etc.) are left unchanged.
+ """
+ for i, op in enumerate(t.op):
+
+ context.clear_status()
+
+ if not t.contextfunc and i == 0 or \
+ convstr and isinstance(op, str):
+ try:
+ c = C.Decimal(op)
+ cex = None
+ except (TypeError, ValueError, OverflowError) as e:
+ c = None
+ cex = e.__class__
+
+ try:
+ p = RestrictedDecimal(op)
+ pex = None
+ except (TypeError, ValueError, OverflowError) as e:
+ p = None
+ pex = e.__class__
+
+ t.cop.append(c)
+ t.cex.append(cex)
+ t.pop.append(p)
+ t.pex.append(pex)
+
+ if cex is pex:
+ if str(c) != str(p) or not context.assert_eq_status():
+ raise_error(t)
+ if cex and pex:
+ # nothing to test
+ return 0
+ else:
+ raise_error(t)
+
+ elif isinstance(op, Context):
+ t.context = op
+ t.cop.append(op.c)
+ t.pop.append(op.p)
+
+ elif op in RoundModes:
+ t.cop.append(op[0])
+ t.pop.append(op[1])
+
+ else:
+ t.cop.append(op)
+ t.pop.append(op)
+
+ return 1
+
+def callfuncs(t):
+ """ t is the testset. At this stage the testset contains operand lists
+ t.cop and t.pop for the C and Python versions of decimal.
+ For Decimal methods, the first operands are of type C.Decimal and
+ P.Decimal respectively. The remaining operands can have various types.
+ For Context methods, all operands can have any type.
+
+ t.rc and t.rp are the results of the operation.
+ """
+ context.clear_status()
+
+ try:
+ if t.contextfunc:
+ cargs = t.cop
+ t.rc = getattr(context.c, t.funcname)(*cargs)
+ else:
+ cself = t.cop[0]
+ cargs = t.cop[1:]
+ t.rc = getattr(cself, t.funcname)(*cargs)
+ t.cex.append(None)
+ except (TypeError, ValueError, OverflowError, MemoryError) as e:
+ t.rc = None
+ t.cex.append(e.__class__)
+
+ try:
+ if t.contextfunc:
+ pargs = t.pop
+ t.rp = getattr(context.p, t.funcname)(*pargs)
+ else:
+ pself = t.pop[0]
+ pargs = t.pop[1:]
+ t.rp = getattr(pself, t.funcname)(*pargs)
+ t.pex.append(None)
+ except (TypeError, ValueError, OverflowError, MemoryError) as e:
+ t.rp = None
+ t.pex.append(e.__class__)
+
+def verify(t, stat):
+ """ t is the testset. At this stage the testset contains the following
+ tuples:
+
+ t.op: original operands
+ t.cop: C.Decimal operands (see convert for details)
+ t.pop: P.Decimal operands (see convert for details)
+ t.rc: C result
+ t.rp: Python result
+
+ t.rc and t.rp can have various types.
+ """
+ t.cresults.append(str(t.rc))
+ t.presults.append(str(t.rp))
+ if isinstance(t.rc, C.Decimal) and isinstance(t.rp, P.Decimal):
+ # General case: both results are Decimals.
+ t.cresults.append(t.rc.to_eng_string())
+ t.cresults.append(t.rc.as_tuple())
+ t.cresults.append(str(t.rc.imag))
+ t.cresults.append(str(t.rc.real))
+ t.presults.append(t.rp.to_eng_string())
+ t.presults.append(t.rp.as_tuple())
+ t.presults.append(str(t.rp.imag))
+ t.presults.append(str(t.rp.real))
+
+ nc = t.rc.number_class().lstrip('+-s')
+ stat[nc] += 1
+ else:
+ # Results from e.g. __divmod__ can only be compared as strings.
+ if not isinstance(t.rc, tuple) and not isinstance(t.rp, tuple):
+ if t.rc != t.rp:
+ raise_error(t)
+ stat[type(t.rc).__name__] += 1
+
+ # The return value lists must be equal.
+ if t.cresults != t.presults:
+ raise_error(t)
+ # The Python exception lists (TypeError, etc.) must be equal.
+ if t.cex != t.pex:
+ raise_error(t)
+ # The context flags must be equal.
+ if not t.context.assert_eq_status():
+ raise_error(t)
+
+
+# ======================================================================
+# Main test loops
+#
+# test_method(method, testspecs, testfunc) ->
+#
+# Loop through various context settings. The degree of
+# thoroughness is determined by 'testspec'. For each
+# setting, call 'testfunc'. Generally, 'testfunc' itself
+# a loop, iterating through many test cases generated
+# by the functions in randdec.py.
+#
+# test_n-ary(method, prec, exp_range, restricted_range, itr, stat) ->
+#
+# 'test_unary', 'test_binary' and 'test_ternary' are the
+# main test functions passed to 'test_method'. They deal
+# with the regular cases. The thoroughness of testing is
+# determined by 'itr'.
+#
+# 'prec', 'exp_range' and 'restricted_range' are passed
+# to the test-generating functions and limit the generated
+# values. In some cases, for reasonable run times a
+# maximum exponent of 9999 is required.
+#
+# The 'stat' parameter is passed down to the 'verify'
+# function, which records statistics for the result values.
+# ======================================================================
+
+def log(fmt, args=None):
+ if args:
+ sys.stdout.write(''.join((fmt, '\n')) % args)
+ else:
+ sys.stdout.write(''.join((str(fmt), '\n')))
+ sys.stdout.flush()
+
+def test_method(method, testspecs, testfunc):
+ """Iterate a test function through many context settings."""
+ log("testing %s ...", method)
+ stat = defaultdict(int)
+ for spec in testspecs:
+ if 'samples' in spec:
+ spec['prec'] = sorted(random.sample(range(1, 101),
+ spec['samples']))
+ for prec in spec['prec']:
+ context.prec = prec
+ for expts in spec['expts']:
+ emin, emax = expts
+ if emin == 'rand':
+ context.Emin = random.randrange(-1000, 0)
+ context.Emax = random.randrange(prec, 1000)
+ else:
+ context.Emin, context.Emax = emin, emax
+ if prec > context.Emax: continue
+ log(" prec: %d emin: %d emax: %d",
+ (context.prec, context.Emin, context.Emax))
+ restr_range = 9999 if context.Emax > 9999 else context.Emax+99
+ for rounding in sorted(RoundMap):
+ context.rounding = rounding
+ context.capitals = random.randrange(2)
+ if spec['clamp'] == 'rand':
+ context.clamp = random.randrange(2)
+ else:
+ context.clamp = spec['clamp']
+ exprange = context.c.Emax
+ testfunc(method, prec, exprange, restr_range,
+ spec['iter'], stat)
+ log(" result types: %s" % sorted([t for t in stat.items()]))
+
+def test_unary(method, prec, exp_range, restricted_range, itr, stat):
+ """Iterate a unary function through many test cases."""
+ if method in UnaryRestricted:
+ exp_range = restricted_range
+ for op in all_unary(prec, exp_range, itr):
+ t = TestSet(method, op)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def test_binary(method, prec, exp_range, restricted_range, itr, stat):
+ """Iterate a binary function through many test cases."""
+ if method in BinaryRestricted:
+ exp_range = restricted_range
+ for op in all_binary(prec, exp_range, itr):
+ t = TestSet(method, op)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def test_ternary(method, prec, exp_range, restricted_range, itr, stat):
+ """Iterate a ternary function through many test cases."""
+ if method in TernaryRestricted:
+ exp_range = restricted_range
+ for op in all_ternary(prec, exp_range, itr):
+ t = TestSet(method, op)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def test_format(method, prec, exp_range, restricted_range, itr, stat):
+ """Iterate the __format__ method through many test cases."""
+ for op in all_unary(prec, exp_range, itr):
+ fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn')
+ fmt2 = rand_locale()
+ for fmt in (fmt1, fmt2):
+ fmtop = (op[0], fmt)
+ t = TestSet(method, fmtop)
+ try:
+ if not convert(t, convstr=False):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+ for op in all_unary(prec, 9999, itr):
+ fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%')
+ fmt2 = rand_locale()
+ for fmt in (fmt1, fmt2):
+ fmtop = (op[0], fmt)
+ t = TestSet(method, fmtop)
+ try:
+ if not convert(t, convstr=False):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def test_round(method, prec, exprange, restricted_range, itr, stat):
+ """Iterate the __round__ method through many test cases."""
+ for op in all_unary(prec, 9999, itr):
+ n = random.randrange(10)
+ roundop = (op[0], n)
+ t = TestSet(method, roundop)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def test_from_float(method, prec, exprange, restricted_range, itr, stat):
+ """Iterate the __float__ method through many test cases."""
+ for rounding in sorted(RoundMap):
+ context.rounding = rounding
+ for i in range(1000):
+ f = randfloat()
+ op = (f,) if method.startswith("context.") else ("sNaN", f)
+ t = TestSet(method, op)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+def randcontext(exprange):
+ c = Context(C.Context(), P.Context())
+ c.Emax = random.randrange(1, exprange+1)
+ c.Emin = random.randrange(-exprange, 0)
+ maxprec = 100 if c.Emax >= 100 else c.Emax
+ c.prec = random.randrange(1, maxprec+1)
+ c.clamp = random.randrange(2)
+ c.clear_traps()
+ return c
+
+def test_quantize_api(method, prec, exprange, restricted_range, itr, stat):
+ """Iterate the 'quantize' method through many test cases, using
+ the optional arguments."""
+ for op in all_binary(prec, restricted_range, itr):
+ for rounding in RoundModes:
+ c = randcontext(exprange)
+ quantizeop = (op[0], op[1], rounding, c)
+ t = TestSet(method, quantizeop)
+ try:
+ if not convert(t):
+ continue
+ callfuncs(t)
+ verify(t, stat)
+ except VerifyError as err:
+ log(err)
+
+
+def check_untested(funcdict, c_cls, p_cls):
+ """Determine untested, C-only and Python-only attributes.
+ Uncomment print lines for debugging."""
+ c_attr = set(dir(c_cls))
+ p_attr = set(dir(p_cls))
+ intersect = c_attr & p_attr
+
+ funcdict['c_only'] = tuple(sorted(c_attr-intersect))
+ funcdict['p_only'] = tuple(sorted(p_attr-intersect))
+
+ tested = set()
+ for lst in funcdict.values():
+ for v in lst:
+ v = v.replace("context.", "") if c_cls == C.Context else v
+ tested.add(v)
+
+ funcdict['untested'] = tuple(sorted(intersect-tested))
+
+ #for key in ('untested', 'c_only', 'p_only'):
+ # s = 'Context' if c_cls == C.Context else 'Decimal'
+ # print("\n%s %s:\n%s" % (s, key, funcdict[key]))
+
+
+if __name__ == '__main__':
+
+ import time
+
+ randseed = int(time.time())
+ random.seed(randseed)
+
+ # Set up the testspecs list. A testspec is simply a dictionary
+ # that determines the amount of different contexts that 'test_method'
+ # will generate.
+ base_expts = [(C.MIN_EMIN, C.MAX_EMAX)]
+ if C.MAX_EMAX == 999999999999999999:
+ base_expts.append((-999999999, 999999999))
+
+ # Basic contexts.
+ base = {
+ 'expts': base_expts,
+ 'prec': [],
+ 'clamp': 'rand',
+ 'iter': None,
+ 'samples': None,
+ }
+ # Contexts with small values for prec, emin, emax.
+ small = {
+ 'prec': [1, 2, 3, 4, 5],
+ 'expts': [(-1, 1), (-2, 2), (-3, 3), (-4, 4), (-5, 5)],
+ 'clamp': 'rand',
+ 'iter': None
+ }
+ # IEEE interchange format.
+ ieee = [
+ # DECIMAL32
+ {'prec': [7], 'expts': [(-95, 96)], 'clamp': 1, 'iter': None},
+ # DECIMAL64
+ {'prec': [16], 'expts': [(-383, 384)], 'clamp': 1, 'iter': None},
+ # DECIMAL128
+ {'prec': [34], 'expts': [(-6143, 6144)], 'clamp': 1, 'iter': None}
+ ]
+
+ if '--medium' in sys.argv:
+ base['expts'].append(('rand', 'rand'))
+ # 5 random precisions
+ base['samples'] = 5
+ testspecs = [small] + ieee + [base]
+ if '--long' in sys.argv:
+ base['expts'].append(('rand', 'rand'))
+ # 10 random precisions
+ base['samples'] = 10
+ testspecs = [small] + ieee + [base]
+ elif '--all' in sys.argv:
+ base['expts'].append(('rand', 'rand'))
+ # All precisions in [1, 100]
+ base['samples'] = 100
+ testspecs = [small] + ieee + [base]
+ else: # --short
+ rand_ieee = random.choice(ieee)
+ base['iter'] = small['iter'] = rand_ieee['iter'] = 1
+ # 1 random precision and exponent pair
+ base['samples'] = 1
+ base['expts'] = [random.choice(base_expts)]
+ # 1 random precision and exponent pair
+ prec = random.randrange(1, 6)
+ small['prec'] = [prec]
+ small['expts'] = [(-prec, prec)]
+ testspecs = [small, rand_ieee, base]
+
+ check_untested(Functions, C.Decimal, P.Decimal)
+ check_untested(ContextFunctions, C.Context, P.Context)
+
+
+ log("\n\nRandom seed: %d\n\n", randseed)
+
+ # Decimal methods:
+ for method in Functions['unary'] + Functions['unary_ctx'] + \
+ Functions['unary_rnd_ctx']:
+ test_method(method, testspecs, test_unary)
+
+ for method in Functions['binary'] + Functions['binary_ctx']:
+ test_method(method, testspecs, test_binary)
+
+ for method in Functions['ternary'] + Functions['ternary_ctx']:
+ test_method(method, testspecs, test_ternary)
+
+ test_method('__format__', testspecs, test_format)
+ test_method('__round__', testspecs, test_round)
+ test_method('from_float', testspecs, test_from_float)
+ test_method('quantize', testspecs, test_quantize_api)
+
+ # Context methods:
+ for method in ContextFunctions['unary']:
+ test_method(method, testspecs, test_unary)
+
+ for method in ContextFunctions['binary']:
+ test_method(method, testspecs, test_binary)
+
+ for method in ContextFunctions['ternary']:
+ test_method(method, testspecs, test_ternary)
+
+ test_method('context.create_decimal_from_float', testspecs, test_from_float)
+
+
+ sys.exit(EXIT_STATUS)
diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py
new file mode 100644
index 0000000..9da2b37
--- /dev/null
+++ b/Modules/_decimal/tests/formathelper.py
@@ -0,0 +1,344 @@
+#
+# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+
+# Generate PEP-3101 format strings.
+
+
+import os, sys, locale, random
+import platform, subprocess
+from test.support import import_fresh_module
+from distutils.spawn import find_executable
+
+C = import_fresh_module('decimal', fresh=['_decimal'])
+P = import_fresh_module('decimal', blocked=['_decimal'])
+
+
+windows_lang_strings = [
+ "chinese", "chinese-simplified", "chinese-traditional", "czech", "danish",
+ "dutch", "belgian", "english", "australian", "canadian", "english-nz",
+ "english-uk", "english-us", "finnish", "french", "french-belgian",
+ "french-canadian", "french-swiss", "german", "german-austrian",
+ "german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss",
+ "japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk",
+ "polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish",
+ "spanish-mexican", "spanish-modern", "swedish", "turkish",
+]
+
+preferred_encoding = {
+ 'cs_CZ': 'ISO8859-2',
+ 'cs_CZ.iso88592': 'ISO8859-2',
+ 'czech': 'ISO8859-2',
+ 'eesti': 'ISO8859-1',
+ 'estonian': 'ISO8859-1',
+ 'et_EE': 'ISO8859-15',
+ 'et_EE.ISO-8859-15': 'ISO8859-15',
+ 'et_EE.iso885915': 'ISO8859-15',
+ 'et_EE.iso88591': 'ISO8859-1',
+ 'fi_FI.iso88591': 'ISO8859-1',
+ 'fi_FI': 'ISO8859-15',
+ 'fi_FI@euro': 'ISO8859-15',
+ 'fi_FI.iso885915@euro': 'ISO8859-15',
+ 'finnish': 'ISO8859-1',
+ 'lv_LV': 'ISO8859-13',
+ 'lv_LV.iso885913': 'ISO8859-13',
+ 'nb_NO': 'ISO8859-1',
+ 'nb_NO.iso88591': 'ISO8859-1',
+ 'bokmal': 'ISO8859-1',
+ 'nn_NO': 'ISO8859-1',
+ 'nn_NO.iso88591': 'ISO8859-1',
+ 'no_NO': 'ISO8859-1',
+ 'norwegian': 'ISO8859-1',
+ 'nynorsk': 'ISO8859-1',
+ 'ru_RU': 'ISO8859-5',
+ 'ru_RU.iso88595': 'ISO8859-5',
+ 'russian': 'ISO8859-5',
+ 'ru_RU.KOI8-R': 'KOI8-R',
+ 'ru_RU.koi8r': 'KOI8-R',
+ 'ru_RU.CP1251': 'CP1251',
+ 'ru_RU.cp1251': 'CP1251',
+ 'sk_SK': 'ISO8859-2',
+ 'sk_SK.iso88592': 'ISO8859-2',
+ 'slovak': 'ISO8859-2',
+ 'sv_FI': 'ISO8859-1',
+ 'sv_FI.iso88591': 'ISO8859-1',
+ 'sv_FI@euro': 'ISO8859-15',
+ 'sv_FI.iso885915@euro': 'ISO8859-15',
+ 'uk_UA': 'KOI8-U',
+ 'uk_UA.koi8u': 'KOI8-U'
+}
+
+integers = [
+ "",
+ "1",
+ "12",
+ "123",
+ "1234",
+ "12345",
+ "123456",
+ "1234567",
+ "12345678",
+ "123456789",
+ "1234567890",
+ "12345678901",
+ "123456789012",
+ "1234567890123",
+ "12345678901234",
+ "123456789012345",
+ "1234567890123456",
+ "12345678901234567",
+ "123456789012345678",
+ "1234567890123456789",
+ "12345678901234567890",
+ "123456789012345678901",
+ "1234567890123456789012",
+]
+
+numbers = [
+ "0", "-0", "+0",
+ "0.0", "-0.0", "+0.0",
+ "0e0", "-0e0", "+0e0",
+ ".0", "-.0",
+ ".1", "-.1",
+ "1.1", "-1.1",
+ "1e1", "-1e1"
+]
+
+# Get the list of available locales.
+if platform.system() == 'Windows':
+ locale_list = windows_lang_strings
+else:
+ locale_list = ['C']
+ if os.path.isfile("/var/lib/locales/supported.d/local"):
+ # On Ubuntu, `locale -a` gives the wrong case for some locales,
+ # so we get the correct names directly:
+ with open("/var/lib/locales/supported.d/local") as f:
+ locale_list = [loc.split()[0] for loc in f.readlines() \
+ if not loc.startswith('#')]
+ elif find_executable('locale'):
+ locale_list = subprocess.Popen(["locale", "-a"],
+ stdout=subprocess.PIPE).communicate()[0]
+ try:
+ locale_list = locale_list.decode()
+ except UnicodeDecodeError:
+ # Some distributions insist on using latin-1 characters
+ # in their locale names.
+ locale_list = locale_list.decode('latin-1')
+ locale_list = locale_list.split('\n')
+try:
+ locale_list.remove('')
+except ValueError:
+ pass
+
+# Debian
+if os.path.isfile("/etc/locale.alias"):
+ with open("/etc/locale.alias") as f:
+ while 1:
+ try:
+ line = f.readline()
+ except UnicodeDecodeError:
+ continue
+ if line == "":
+ break
+ if line.startswith('#'):
+ continue
+ x = line.split()
+ if len(x) == 2:
+ if x[0] in locale_list:
+ locale_list.remove(x[0])
+
+# FreeBSD
+if platform.system() == 'FreeBSD':
+ # http://www.freebsd.org/cgi/query-pr.cgi?pr=142173
+ # en_GB.US-ASCII has 163 as the currency symbol.
+ for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8',
+ 'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8',
+ 'sl_SI.ISO8859-2', 'sl_SI.UTF-8',
+ 'en_GB.US-ASCII']:
+ try:
+ locale_list.remove(loc)
+ except ValueError:
+ pass
+
+# Print a testcase in the format of the IBM tests (for runtest.c):
+def get_preferred_encoding():
+ loc = locale.setlocale(locale.LC_CTYPE)
+ if loc in preferred_encoding:
+ return preferred_encoding[loc]
+ else:
+ return locale.getpreferredencoding()
+
+def printit(testno, s, fmt, encoding=None):
+ if not encoding:
+ encoding = get_preferred_encoding()
+ try:
+ result = format(P.Decimal(s), fmt)
+ fmt = str(fmt.encode(encoding))[2:-1]
+ result = str(result.encode(encoding))[2:-1]
+ if "'" in result:
+ sys.stdout.write("xfmt%d format %s '%s' -> \"%s\"\n"
+ % (testno, s, fmt, result))
+ else:
+ sys.stdout.write("xfmt%d format %s '%s' -> '%s'\n"
+ % (testno, s, fmt, result))
+ except Exception as err:
+ sys.stderr.write("%s %s %s\n" % (err, s, fmt))
+
+
+# Check if an integer can be converted to a valid fill character.
+def check_fillchar(i):
+ try:
+ c = chr(i)
+ c.encode('utf-8').decode()
+ format(P.Decimal(0), c + '<19g')
+ if c in ("'", '"', '\\'):
+ return None
+ return c
+ except:
+ return None
+
+# Generate all unicode characters that are accepted as
+# fill characters by decimal.py.
+def all_fillchars():
+ for i in range(32, 0x110002):
+ c = check_fillchar(i)
+ if c: yield c
+
+# Return random fill character.
+def rand_fillchar():
+ while 1:
+ i = random.randrange(32, 0x110002)
+ c = check_fillchar(i)
+ if c: return c
+
+# Generate random format strings
+# [[fill]align][sign][#][0][width][.precision][type]
+def rand_format(fill, typespec='EeGgFfn%'):
+ active = sorted(random.sample(range(7), random.randrange(8)))
+ have_align = 0
+ s = ''
+ for elem in active:
+ if elem == 0: # fill+align
+ s += fill
+ s += random.choice('<>=^')
+ have_align = 1
+ elif elem == 1: # sign
+ s += random.choice('+- ')
+ elif elem == 2 and not have_align: # zeropad
+ s += '0'
+ elif elem == 3: # width
+ s += str(random.randrange(1, 100))
+ elif elem == 4: # thousands separator
+ s += ','
+ elif elem == 5: # prec
+ s += '.'
+ s += str(random.randrange(100))
+ elif elem == 6:
+ if 4 in active: c = typespec.replace('n', '')
+ else: c = typespec
+ s += random.choice(c)
+ return s
+
+# Partially brute force all possible format strings containing a thousands
+# separator. Fall back to random where the runtime would become excessive.
+# [[fill]align][sign][#][0][width][,][.precision][type]
+def all_format_sep():
+ for align in ('', '<', '>', '=', '^'):
+ for fill in ('', 'x'):
+ if align == '': fill = ''
+ for sign in ('', '+', '-', ' '):
+ for zeropad in ('', '0'):
+ if align != '': zeropad = ''
+ for width in ['']+[str(y) for y in range(1, 15)]+['101']:
+ for prec in ['']+['.'+str(y) for y in range(15)]:
+ # for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'):
+ type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%'))
+ yield ''.join((fill, align, sign, zeropad, width, ',', prec, type))
+
+# Partially brute force all possible format strings with an 'n' specifier.
+# [[fill]align][sign][#][0][width][,][.precision][type]
+def all_format_loc():
+ for align in ('', '<', '>', '=', '^'):
+ for fill in ('', 'x'):
+ if align == '': fill = ''
+ for sign in ('', '+', '-', ' '):
+ for zeropad in ('', '0'):
+ if align != '': zeropad = ''
+ for width in ['']+[str(y) for y in range(1, 20)]+['101']:
+ for prec in ['']+['.'+str(y) for y in range(1, 20)]:
+ yield ''.join((fill, align, sign, zeropad, width, prec, 'n'))
+
+# Generate random format strings with a unicode fill character
+# [[fill]align][sign][#][0][width][,][.precision][type]
+def randfill(fill):
+ active = sorted(random.sample(range(5), random.randrange(6)))
+ s = ''
+ s += str(fill)
+ s += random.choice('<>=^')
+ for elem in active:
+ if elem == 0: # sign
+ s += random.choice('+- ')
+ elif elem == 1: # width
+ s += str(random.randrange(1, 100))
+ elif elem == 2: # thousands separator
+ s += ','
+ elif elem == 3: # prec
+ s += '.'
+ s += str(random.randrange(100))
+ elif elem == 4:
+ if 2 in active: c = 'EeGgFf%'
+ else: c = 'EeGgFfn%'
+ s += random.choice(c)
+ return s
+
+# Generate random format strings with random locale setting
+# [[fill]align][sign][#][0][width][,][.precision][type]
+def rand_locale():
+ try:
+ loc = random.choice(locale_list)
+ locale.setlocale(locale.LC_ALL, loc)
+ except locale.Error as err:
+ pass
+ active = sorted(random.sample(range(5), random.randrange(6)))
+ s = ''
+ have_align = 0
+ for elem in active:
+ if elem == 0: # fill+align
+ s += chr(random.randrange(32, 128))
+ s += random.choice('<>=^')
+ have_align = 1
+ elif elem == 1: # sign
+ s += random.choice('+- ')
+ elif elem == 2 and not have_align: # zeropad
+ s += '0'
+ elif elem == 3: # width
+ s += str(random.randrange(1, 100))
+ elif elem == 4: # prec
+ s += '.'
+ s += str(random.randrange(100))
+ s += 'n'
+ return s
diff --git a/Modules/_decimal/tests/randdec.py b/Modules/_decimal/tests/randdec.py
new file mode 100644
index 0000000..80858bf
--- /dev/null
+++ b/Modules/_decimal/tests/randdec.py
@@ -0,0 +1,559 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+
+# Generate test cases for deccheck.py.
+
+
+#
+# Grammar from http://speleotrove.com/decimal/daconvs.html
+#
+# sign ::= '+' | '-'
+# digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
+# '8' | '9'
+# indicator ::= 'e' | 'E'
+# digits ::= digit [digit]...
+# decimal-part ::= digits '.' [digits] | ['.'] digits
+# exponent-part ::= indicator [sign] digits
+# infinity ::= 'Infinity' | 'Inf'
+# nan ::= 'NaN' [digits] | 'sNaN' [digits]
+# numeric-value ::= decimal-part [exponent-part] | infinity
+# numeric-string ::= [sign] numeric-value | [sign] nan
+#
+
+
+from random import randrange, sample
+from fractions import Fraction
+from randfloat import un_randfloat, bin_randfloat, tern_randfloat
+
+
+def sign():
+ if randrange(2):
+ if randrange(2): return '+'
+ return ''
+ return '-'
+
+def indicator():
+ return "eE"[randrange(2)]
+
+def digits(maxprec):
+ if maxprec == 0: return ''
+ return str(randrange(10**maxprec))
+
+def dot():
+ if randrange(2): return '.'
+ return ''
+
+def decimal_part(maxprec):
+ if randrange(100) > 60: # integers
+ return digits(maxprec)
+ if randrange(2):
+ intlen = randrange(1, maxprec+1)
+ fraclen = maxprec-intlen
+ intpart = digits(intlen)
+ fracpart = digits(fraclen)
+ return ''.join((intpart, '.', fracpart))
+ else:
+ return ''.join((dot(), digits(maxprec)))
+
+def expdigits(maxexp):
+ return str(randrange(maxexp))
+
+def exponent_part(maxexp):
+ return ''.join((indicator(), sign(), expdigits(maxexp)))
+
+def infinity():
+ if randrange(2): return 'Infinity'
+ return 'Inf'
+
+def nan():
+ d = ''
+ if randrange(2):
+ d = digits(randrange(99))
+ if randrange(2):
+ return ''.join(('NaN', d))
+ else:
+ return ''.join(('sNaN', d))
+
+def numeric_value(maxprec, maxexp):
+ if randrange(100) > 90:
+ return infinity()
+ exp_part = ''
+ if randrange(100) > 60:
+ exp_part = exponent_part(maxexp)
+ return ''.join((decimal_part(maxprec), exp_part))
+
+def numeric_string(maxprec, maxexp):
+ if randrange(100) > 95:
+ return ''.join((sign(), nan()))
+ else:
+ return ''.join((sign(), numeric_value(maxprec, maxexp)))
+
+def randdec(maxprec, maxexp):
+ return numeric_string(maxprec, maxexp)
+
+def rand_adjexp(maxprec, maxadjexp):
+ d = digits(maxprec)
+ maxexp = maxadjexp-len(d)+1
+ if maxexp == 0: maxexp = 1
+ exp = str(randrange(maxexp-2*(abs(maxexp)), maxexp))
+ return ''.join((sign(), d, 'E', exp))
+
+
+def ndigits(n):
+ if n < 1: return 0
+ return randrange(10**(n-1), 10**n)
+
+def randtuple(maxprec, maxexp):
+ n = randrange(100)
+ sign = randrange(2)
+ coeff = ndigits(maxprec)
+ if n >= 95:
+ coeff = ()
+ exp = 'F'
+ elif n >= 85:
+ coeff = tuple(map(int, str(ndigits(maxprec))))
+ exp = "nN"[randrange(2)]
+ else:
+ coeff = tuple(map(int, str(ndigits(maxprec))))
+ exp = randrange(-maxexp, maxexp)
+ return (sign, coeff, exp)
+
+def from_triple(sign, coeff, exp):
+ return ''.join((str(sign*coeff), indicator(), str(exp)))
+
+
+# Close to 10**n
+def un_close_to_pow10(prec, maxexp, itr=None):
+ if itr is None:
+ lst = range(prec+30)
+ else:
+ lst = sample(range(prec+30), itr)
+ nines = [10**n - 1 for n in lst]
+ pow10 = [10**n for n in lst]
+ for coeff in nines:
+ yield coeff
+ yield -coeff
+ yield from_triple(1, coeff, randrange(2*maxexp))
+ yield from_triple(-1, coeff, randrange(2*maxexp))
+ for coeff in pow10:
+ yield coeff
+ yield -coeff
+
+# Close to 10**n
+def bin_close_to_pow10(prec, maxexp, itr=None):
+ if itr is None:
+ lst = range(prec+30)
+ else:
+ lst = sample(range(prec+30), itr)
+ nines = [10**n - 1 for n in lst]
+ pow10 = [10**n for n in lst]
+ for coeff in nines:
+ yield coeff, 1
+ yield -coeff, -1
+ yield 1, coeff
+ yield -1, -coeff
+ yield from_triple(1, coeff, randrange(2*maxexp)), 1
+ yield from_triple(-1, coeff, randrange(2*maxexp)), -1
+ yield 1, from_triple(1, coeff, -randrange(2*maxexp))
+ yield -1, from_triple(-1, coeff, -randrange(2*maxexp))
+ for coeff in pow10:
+ yield coeff, -1
+ yield -coeff, 1
+ yield 1, -coeff
+ yield -coeff, 1
+
+# Close to 1:
+def close_to_one_greater(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("1.", '0'*randrange(prec),
+ str(randrange(rprec))))
+
+def close_to_one_less(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("0.9", '9'*randrange(prec),
+ str(randrange(rprec))))
+
+# Close to 0:
+def close_to_zero_greater(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("0.", '0'*randrange(prec),
+ str(randrange(rprec))))
+
+def close_to_zero_less(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("-0.", '0'*randrange(prec),
+ str(randrange(rprec))))
+
+# Close to emax:
+def close_to_emax_less(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("9.", '9'*randrange(prec),
+ str(randrange(rprec)), "E", str(emax)))
+
+def close_to_emax_greater(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("1.", '0'*randrange(prec),
+ str(randrange(rprec)), "E", str(emax+1)))
+
+# Close to emin:
+def close_to_emin_greater(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("1.", '0'*randrange(prec),
+ str(randrange(rprec)), "E", str(emin)))
+
+def close_to_emin_less(prec, emax, emin):
+ rprec = 10**prec
+ return ''.join(("9.", '9'*randrange(prec),
+ str(randrange(rprec)), "E", str(emin-1)))
+
+# Close to etiny:
+def close_to_etiny_greater(prec, emax, emin):
+ rprec = 10**prec
+ etiny = emin - (prec - 1)
+ return ''.join(("1.", '0'*randrange(prec),
+ str(randrange(rprec)), "E", str(etiny)))
+
+def close_to_etiny_less(prec, emax, emin):
+ rprec = 10**prec
+ etiny = emin - (prec - 1)
+ return ''.join(("9.", '9'*randrange(prec),
+ str(randrange(rprec)), "E", str(etiny-1)))
+
+
+def close_to_min_etiny_greater(prec, max_prec, min_emin):
+ rprec = 10**prec
+ etiny = min_emin - (max_prec - 1)
+ return ''.join(("1.", '0'*randrange(prec),
+ str(randrange(rprec)), "E", str(etiny)))
+
+def close_to_min_etiny_less(prec, max_prec, min_emin):
+ rprec = 10**prec
+ etiny = min_emin - (max_prec - 1)
+ return ''.join(("9.", '9'*randrange(prec),
+ str(randrange(rprec)), "E", str(etiny-1)))
+
+
+close_funcs = [
+ close_to_one_greater, close_to_one_less, close_to_zero_greater,
+ close_to_zero_less, close_to_emax_less, close_to_emax_greater,
+ close_to_emin_greater, close_to_emin_less, close_to_etiny_greater,
+ close_to_etiny_less, close_to_min_etiny_greater, close_to_min_etiny_less
+]
+
+
+def un_close_numbers(prec, emax, emin, itr=None):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func in close_funcs:
+ yield func(prec, emax, emin)
+
+def bin_close_numbers(prec, emax, emin, itr=None):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func1 in close_funcs:
+ for func2 in close_funcs:
+ yield func1(prec, emax, emin), func2(prec, emax, emin)
+ for func in close_funcs:
+ yield randdec(prec, emax), func(prec, emax, emin)
+ yield func(prec, emax, emin), randdec(prec, emax)
+
+def tern_close_numbers(prec, emax, emin, itr):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func1 in close_funcs:
+ for func2 in close_funcs:
+ for func3 in close_funcs:
+ yield (func1(prec, emax, emin), func2(prec, emax, emin),
+ func3(prec, emax, emin))
+ for func in close_funcs:
+ yield (randdec(prec, emax), func(prec, emax, emin),
+ func(prec, emax, emin))
+ yield (func(prec, emax, emin), randdec(prec, emax),
+ func(prec, emax, emin))
+ yield (func(prec, emax, emin), func(prec, emax, emin),
+ randdec(prec, emax))
+ for func in close_funcs:
+ yield (randdec(prec, emax), randdec(prec, emax),
+ func(prec, emax, emin))
+ yield (randdec(prec, emax), func(prec, emax, emin),
+ randdec(prec, emax))
+ yield (func(prec, emax, emin), randdec(prec, emax),
+ randdec(prec, emax))
+
+
+# If itr == None, test all digit lengths up to prec + 30
+def un_incr_digits(prec, maxexp, itr):
+ if itr is None:
+ lst = range(prec+30)
+ else:
+ lst = sample(range(prec+30), itr)
+ for m in lst:
+ yield from_triple(1, ndigits(m), 0)
+ yield from_triple(-1, ndigits(m), 0)
+ yield from_triple(1, ndigits(m), randrange(maxexp))
+ yield from_triple(-1, ndigits(m), randrange(maxexp))
+
+# If itr == None, test all digit lengths up to prec + 30
+# Also output decimals im tuple form.
+def un_incr_digits_tuple(prec, maxexp, itr):
+ if itr is None:
+ lst = range(prec+30)
+ else:
+ lst = sample(range(prec+30), itr)
+ for m in lst:
+ yield from_triple(1, ndigits(m), 0)
+ yield from_triple(-1, ndigits(m), 0)
+ yield from_triple(1, ndigits(m), randrange(maxexp))
+ yield from_triple(-1, ndigits(m), randrange(maxexp))
+ # test from tuple
+ yield (0, tuple(map(int, str(ndigits(m)))), 0)
+ yield (1, tuple(map(int, str(ndigits(m)))), 0)
+ yield (0, tuple(map(int, str(ndigits(m)))), randrange(maxexp))
+ yield (1, tuple(map(int, str(ndigits(m)))), randrange(maxexp))
+
+# If itr == None, test all combinations of digit lengths up to prec + 30
+def bin_incr_digits(prec, maxexp, itr):
+ if itr is None:
+ lst1 = range(prec+30)
+ lst2 = range(prec+30)
+ else:
+ lst1 = sample(range(prec+30), itr)
+ lst2 = sample(range(prec+30), itr)
+ for m in lst1:
+ x = from_triple(1, ndigits(m), 0)
+ yield x, x
+ x = from_triple(-1, ndigits(m), 0)
+ yield x, x
+ x = from_triple(1, ndigits(m), randrange(maxexp))
+ yield x, x
+ x = from_triple(-1, ndigits(m), randrange(maxexp))
+ yield x, x
+ for m in lst1:
+ for n in lst2:
+ x = from_triple(1, ndigits(m), 0)
+ y = from_triple(1, ndigits(n), 0)
+ yield x, y
+ x = from_triple(-1, ndigits(m), 0)
+ y = from_triple(1, ndigits(n), 0)
+ yield x, y
+ x = from_triple(1, ndigits(m), 0)
+ y = from_triple(-1, ndigits(n), 0)
+ yield x, y
+ x = from_triple(-1, ndigits(m), 0)
+ y = from_triple(-1, ndigits(n), 0)
+ yield x, y
+ x = from_triple(1, ndigits(m), randrange(maxexp))
+ y = from_triple(1, ndigits(n), randrange(maxexp))
+ yield x, y
+ x = from_triple(-1, ndigits(m), randrange(maxexp))
+ y = from_triple(1, ndigits(n), randrange(maxexp))
+ yield x, y
+ x = from_triple(1, ndigits(m), randrange(maxexp))
+ y = from_triple(-1, ndigits(n), randrange(maxexp))
+ yield x, y
+ x = from_triple(-1, ndigits(m), randrange(maxexp))
+ y = from_triple(-1, ndigits(n), randrange(maxexp))
+ yield x, y
+
+
+def randsign():
+ return (1, -1)[randrange(2)]
+
+# If itr == None, test all combinations of digit lengths up to prec + 30
+def tern_incr_digits(prec, maxexp, itr):
+ if itr is None:
+ lst1 = range(prec+30)
+ lst2 = range(prec+30)
+ lst3 = range(prec+30)
+ else:
+ lst1 = sample(range(prec+30), itr)
+ lst2 = sample(range(prec+30), itr)
+ lst3 = sample(range(prec+30), itr)
+ for m in lst1:
+ for n in lst2:
+ for p in lst3:
+ x = from_triple(randsign(), ndigits(m), 0)
+ y = from_triple(randsign(), ndigits(n), 0)
+ z = from_triple(randsign(), ndigits(p), 0)
+ yield x, y, z
+
+
+# Tests for the 'logical' functions
+def bindigits(prec):
+ z = 0
+ for i in range(prec):
+ z += randrange(2) * 10**i
+ return z
+
+def logical_un_incr_digits(prec, itr):
+ if itr is None:
+ lst = range(prec+30)
+ else:
+ lst = sample(range(prec+30), itr)
+ for m in lst:
+ yield from_triple(1, bindigits(m), 0)
+
+def logical_bin_incr_digits(prec, itr):
+ if itr is None:
+ lst1 = range(prec+30)
+ lst2 = range(prec+30)
+ else:
+ lst1 = sample(range(prec+30), itr)
+ lst2 = sample(range(prec+30), itr)
+ for m in lst1:
+ x = from_triple(1, bindigits(m), 0)
+ yield x, x
+ for m in lst1:
+ for n in lst2:
+ x = from_triple(1, bindigits(m), 0)
+ y = from_triple(1, bindigits(n), 0)
+ yield x, y
+
+
+def randint():
+ p = randrange(1, 100)
+ return ndigits(p) * (1,-1)[randrange(2)]
+
+def randfloat():
+ p = randrange(1, 100)
+ s = numeric_value(p, 383)
+ try:
+ f = float(numeric_value(p, 383))
+ except ValueError:
+ f = 0.0
+ return f
+
+def randcomplex():
+ real = randfloat()
+ if randrange(100) > 30:
+ imag = 0.0
+ else:
+ imag = randfloat()
+ return complex(real, imag)
+
+def randfraction():
+ num = randint()
+ denom = randint()
+ if denom == 0:
+ denom = 1
+ return Fraction(num, denom)
+
+number_funcs = [randint, randfloat, randcomplex, randfraction]
+
+def un_random_mixed_op(itr=None):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func in number_funcs:
+ yield func()
+ # Test garbage input
+ for x in (['x'], ('y',), {'z'}, {1:'z'}):
+ yield x
+
+def bin_random_mixed_op(prec, emax, emin, itr=None):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func in number_funcs:
+ yield randdec(prec, emax), func()
+ yield func(), randdec(prec, emax)
+ for number in number_funcs:
+ for dec in close_funcs:
+ yield dec(prec, emax, emin), number()
+ # Test garbage input
+ for x in (['x'], ('y',), {'z'}, {1:'z'}):
+ for y in (['x'], ('y',), {'z'}, {1:'z'}):
+ yield x, y
+
+def tern_random_mixed_op(prec, emax, emin, itr):
+ if itr is None:
+ itr = 1000
+ for _ in range(itr):
+ for func in number_funcs:
+ yield randdec(prec, emax), randdec(prec, emax), func()
+ yield randdec(prec, emax), func(), func()
+ yield func(), func(), func()
+ # Test garbage input
+ for x in (['x'], ('y',), {'z'}, {1:'z'}):
+ for y in (['x'], ('y',), {'z'}, {1:'z'}):
+ for z in (['x'], ('y',), {'z'}, {1:'z'}):
+ yield x, y, z
+
+def all_unary(prec, exp_range, itr):
+ for a in un_close_to_pow10(prec, exp_range, itr):
+ yield (a,)
+ for a in un_close_numbers(prec, exp_range, -exp_range, itr):
+ yield (a,)
+ for a in un_incr_digits_tuple(prec, exp_range, itr):
+ yield (a,)
+ for a in un_randfloat():
+ yield (a,)
+ for a in un_random_mixed_op(itr):
+ yield (a,)
+ for a in logical_un_incr_digits(prec, itr):
+ yield (a,)
+ for _ in range(100):
+ yield (randdec(prec, exp_range),)
+ for _ in range(100):
+ yield (randtuple(prec, exp_range),)
+
+def all_binary(prec, exp_range, itr):
+ for a, b in bin_close_to_pow10(prec, exp_range, itr):
+ yield a, b
+ for a, b in bin_close_numbers(prec, exp_range, -exp_range, itr):
+ yield a, b
+ for a, b in bin_incr_digits(prec, exp_range, itr):
+ yield a, b
+ for a, b in bin_randfloat():
+ yield a, b
+ for a, b in bin_random_mixed_op(prec, exp_range, -exp_range, itr):
+ yield a, b
+ for a, b in logical_bin_incr_digits(prec, itr):
+ yield a, b
+ for _ in range(100):
+ yield randdec(prec, exp_range), randdec(prec, exp_range)
+
+def all_ternary(prec, exp_range, itr):
+ for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr):
+ yield a, b, c
+ for a, b, c in tern_incr_digits(prec, exp_range, itr):
+ yield a, b, c
+ for a, b, c in tern_randfloat():
+ yield a, b, c
+ for a, b, c in tern_random_mixed_op(prec, exp_range, -exp_range, itr):
+ yield a, b, c
+ for _ in range(100):
+ a = randdec(prec, 2*exp_range)
+ b = randdec(prec, 2*exp_range)
+ c = randdec(prec, 2*exp_range)
+ yield a, b, c
diff --git a/Modules/_decimal/tests/randfloat.py b/Modules/_decimal/tests/randfloat.py
new file mode 100644
index 0000000..1687303
--- /dev/null
+++ b/Modules/_decimal/tests/randfloat.py
@@ -0,0 +1,250 @@
+# Copyright (c) 2010 Python Software Foundation. All Rights Reserved.
+# Adapted from Python's Lib/test/test_strtod.py (by Mark Dickinson)
+
+# More test cases for deccheck.py.
+
+import random
+
+TEST_SIZE = 2
+
+
+def test_short_halfway_cases():
+ # exact halfway cases with a small number of significant digits
+ for k in 0, 5, 10, 15, 20:
+ # upper = smallest integer >= 2**54/5**k
+ upper = -(-2**54//5**k)
+ # lower = smallest odd number >= 2**53/5**k
+ lower = -(-2**53//5**k)
+ if lower % 2 == 0:
+ lower += 1
+ for i in range(10 * TEST_SIZE):
+ # Select a random odd n in [2**53/5**k,
+ # 2**54/5**k). Then n * 10**k gives a halfway case
+ # with small number of significant digits.
+ n, e = random.randrange(lower, upper, 2), k
+
+ # Remove any additional powers of 5.
+ while n % 5 == 0:
+ n, e = n // 5, e + 1
+ assert n % 10 in (1, 3, 7, 9)
+
+ # Try numbers of the form n * 2**p2 * 10**e, p2 >= 0,
+ # until n * 2**p2 has more than 20 significant digits.
+ digits, exponent = n, e
+ while digits < 10**20:
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+ # Same again, but with extra trailing zeros.
+ s = '{}e{}'.format(digits * 10**40, exponent - 40)
+ yield s
+ digits *= 2
+
+ # Try numbers of the form n * 5**p2 * 10**(e - p5), p5
+ # >= 0, with n * 5**p5 < 10**20.
+ digits, exponent = n, e
+ while digits < 10**20:
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+ # Same again, but with extra trailing zeros.
+ s = '{}e{}'.format(digits * 10**40, exponent - 40)
+ yield s
+ digits *= 5
+ exponent -= 1
+
+def test_halfway_cases():
+ # test halfway cases for the round-half-to-even rule
+ for i in range(1000):
+ for j in range(TEST_SIZE):
+ # bit pattern for a random finite positive (or +0.0) float
+ bits = random.randrange(2047*2**52)
+
+ # convert bit pattern to a number of the form m * 2**e
+ e, m = divmod(bits, 2**52)
+ if e:
+ m, e = m + 2**52, e - 1
+ e -= 1074
+
+ # add 0.5 ulps
+ m, e = 2*m + 1, e - 1
+
+ # convert to a decimal string
+ if e >= 0:
+ digits = m << e
+ exponent = 0
+ else:
+ # m * 2**e = (m * 5**-e) * 10**e
+ digits = m * 5**-e
+ exponent = e
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+
+def test_boundaries():
+ # boundaries expressed as triples (n, e, u), where
+ # n*10**e is an approximation to the boundary value and
+ # u*10**e is 1ulp
+ boundaries = [
+ (10000000000000000000, -19, 1110), # a power of 2 boundary (1.0)
+ (17976931348623159077, 289, 1995), # overflow boundary (2.**1024)
+ (22250738585072013831, -327, 4941), # normal/subnormal (2.**-1022)
+ (0, -327, 4941), # zero
+ ]
+ for n, e, u in boundaries:
+ for j in range(1000):
+ for i in range(TEST_SIZE):
+ digits = n + random.randrange(-3*u, 3*u)
+ exponent = e
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+ n *= 10
+ u *= 10
+ e -= 1
+
+def test_underflow_boundary():
+ # test values close to 2**-1075, the underflow boundary; similar
+ # to boundary_tests, except that the random error doesn't scale
+ # with n
+ for exponent in range(-400, -320):
+ base = 10**-exponent // 2**1075
+ for j in range(TEST_SIZE):
+ digits = base + random.randrange(-1000, 1000)
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+
+def test_bigcomp():
+ for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50:
+ dig10 = 10**ndigs
+ for i in range(100 * TEST_SIZE):
+ digits = random.randrange(dig10)
+ exponent = random.randrange(-400, 400)
+ s = '{}e{}'.format(digits, exponent)
+ yield s
+
+def test_parsing():
+ # make '0' more likely to be chosen than other digits
+ digits = '000000123456789'
+ signs = ('+', '-', '')
+
+ # put together random short valid strings
+ # \d*[.\d*]?e
+ for i in range(1000):
+ for j in range(TEST_SIZE):
+ s = random.choice(signs)
+ intpart_len = random.randrange(5)
+ s += ''.join(random.choice(digits) for _ in range(intpart_len))
+ if random.choice([True, False]):
+ s += '.'
+ fracpart_len = random.randrange(5)
+ s += ''.join(random.choice(digits)
+ for _ in range(fracpart_len))
+ else:
+ fracpart_len = 0
+ if random.choice([True, False]):
+ s += random.choice(['e', 'E'])
+ s += random.choice(signs)
+ exponent_len = random.randrange(1, 4)
+ s += ''.join(random.choice(digits)
+ for _ in range(exponent_len))
+
+ if intpart_len + fracpart_len:
+ yield s
+
+test_particular = [
+ # squares
+ '1.00000000100000000025',
+ '1.0000000000000000000000000100000000000000000000000' #...
+ '00025',
+ '1.0000000000000000000000000000000000000000000010000' #...
+ '0000000000000000000000000000000000000000025',
+ '1.0000000000000000000000000000000000000000000000000' #...
+ '000001000000000000000000000000000000000000000000000' #...
+ '000000000025',
+ '0.99999999900000000025',
+ '0.9999999999999999999999999999999999999999999999999' #...
+ '999000000000000000000000000000000000000000000000000' #...
+ '000025',
+ '0.9999999999999999999999999999999999999999999999999' #...
+ '999999999999999999999999999999999999999999999999999' #...
+ '999999999999999999999999999999999999999990000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '0000000000000000000000000000025',
+
+ '1.0000000000000000000000000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '100000000000000000000000000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000001',
+ '1.0000000000000000000000000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '500000000000000000000000000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000005',
+ '1.0000000000000000000000000000000000000000000000000' #...
+ '000000000100000000000000000000000000000000000000000' #...
+ '000000000000000000250000000000000002000000000000000' #...
+ '000000000000000000000000000000000000000000010000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '0000000000000000001',
+ '1.0000000000000000000000000000000000000000000000000' #...
+ '000000000100000000000000000000000000000000000000000' #...
+ '000000000000000000249999999999999999999999999999999' #...
+ '999999999999979999999999999999999999999999999999999' #...
+ '999999999999999999999900000000000000000000000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '00000000000000000000000001',
+
+ '0.9999999999999999999999999999999999999999999999999' #...
+ '999999999900000000000000000000000000000000000000000' #...
+ '000000000000000000249999999999999998000000000000000' #...
+ '000000000000000000000000000000000000000000010000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '0000000000000000001',
+ '0.9999999999999999999999999999999999999999999999999' #...
+ '999999999900000000000000000000000000000000000000000' #...
+ '000000000000000000250000001999999999999999999999999' #...
+ '999999999999999999999999999999999990000000000000000' #...
+ '000000000000000000000000000000000000000000000000000' #...
+ '1',
+
+ # tough cases for ln etc.
+ '1.000000000000000000000000000000000000000000000000' #...
+ '00000000000000000000000000000000000000000000000000' #...
+ '00100000000000000000000000000000000000000000000000' #...
+ '00000000000000000000000000000000000000000000000000' #...
+ '0001',
+ '0.999999999999999999999999999999999999999999999999' #...
+ '99999999999999999999999999999999999999999999999999' #...
+ '99899999999999999999999999999999999999999999999999' #...
+ '99999999999999999999999999999999999999999999999999' #...
+ '99999999999999999999999999999999999999999999999999' #...
+ '9999'
+ ]
+
+
+TESTCASES = [
+ [x for x in test_short_halfway_cases()],
+ [x for x in test_halfway_cases()],
+ [x for x in test_boundaries()],
+ [x for x in test_underflow_boundary()],
+ [x for x in test_bigcomp()],
+ [x for x in test_parsing()],
+ test_particular
+]
+
+def un_randfloat():
+ for i in range(1000):
+ l = random.choice(TESTCASES[:6])
+ yield random.choice(l)
+ for v in test_particular:
+ yield v
+
+def bin_randfloat():
+ for i in range(1000):
+ l1 = random.choice(TESTCASES)
+ l2 = random.choice(TESTCASES)
+ yield random.choice(l1), random.choice(l2)
+
+def tern_randfloat():
+ for i in range(1000):
+ l1 = random.choice(TESTCASES)
+ l2 = random.choice(TESTCASES)
+ l3 = random.choice(TESTCASES)
+ yield random.choice(l1), random.choice(l2), random.choice(l3)
diff --git a/Modules/_decimal/tests/runall-memorydebugger.sh b/Modules/_decimal/tests/runall-memorydebugger.sh
new file mode 100644
index 0000000..44ff3b3
--- /dev/null
+++ b/Modules/_decimal/tests/runall-memorydebugger.sh
@@ -0,0 +1,175 @@
+#!/bin/sh
+
+#
+# Purpose: test with and without threads, all machine configurations, pydebug,
+# refleaks, release build and release build with valgrind.
+#
+# Synopsis: ./runall-memorydebugger.sh [--all-configs64 | --all-configs32]
+#
+# Requirements: valgrind
+#
+
+# Set additional CFLAGS for ./configure
+ADD_CFLAGS=
+
+
+CONFIGS_64="x64 uint128 ansi64 universal"
+CONFIGS_32="ppro ansi32 ansi-legacy universal"
+
+VALGRIND="valgrind --tool=memcheck --leak-resolution=high \
+ --db-attach=yes --suppressions=Misc/valgrind-python.supp"
+
+# Get args
+case $@ in
+ *--all-configs64*)
+ CONFIGS=$CONFIGS_64
+ ;;
+ *--all-configs32*)
+ CONFIGS=$CONFIGS_32
+ ;;
+ *)
+ CONFIGS="auto"
+ ;;
+esac
+
+# gmake required
+GMAKE=`which gmake`
+if [ X"$GMAKE" = X"" ]; then
+ GMAKE=make
+fi
+
+# Pretty print configurations
+print_config ()
+{
+ len=`echo $@ | wc -c`
+ margin="#%"`expr \( 74 - $len \) / 2`"s"
+
+ echo ""
+ echo "# ========================================================================"
+ printf $margin ""
+ echo $@
+ echo "# ========================================================================"
+ echo ""
+}
+
+
+cd ..
+
+# test_decimal: refleak, regular and Valgrind tests
+for args in "--without-threads" ""; do
+ for config in $CONFIGS; do
+
+ unset PYTHON_DECIMAL_WITH_MACHINE
+ libmpdec_config=$config
+ if [ X"$config" != X"auto" ]; then
+ PYTHON_DECIMAL_WITH_MACHINE=$config
+ export PYTHON_DECIMAL_WITH_MACHINE
+ else
+ libmpdec_config=""
+ fi
+
+ ############ refleak tests ###########
+ print_config "refleak tests: config=$config" $args
+ printf "\nbuilding python ...\n\n"
+
+ cd ../../
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ======================== refleak tests ===========================\n\n"
+ ./python -m test -uall -R 2:2 test_decimal
+
+
+ ############ regular tests ###########
+ print_config "regular tests: config=$config" $args
+ printf "\nbuilding python ...\n\n"
+
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ======================== regular tests ===========================\n\n"
+ ./python -m test -uall test_decimal
+
+
+ ########### valgrind tests ###########
+ valgrind=$VALGRIND
+ case "$config" in
+ # Valgrind has no support for 80 bit long double arithmetic.
+ ppro) valgrind= ;;
+ auto) case `uname -m` in
+ i386|i486|i586|i686) valgrind= ;;
+ esac
+ esac
+
+ print_config "valgrind tests: config=$config" $args
+ printf "\nbuilding python ...\n\n"
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ======================== valgrind tests ===========================\n\n"
+ $valgrind ./python -m test -uall test_decimal
+
+ cd Modules/_decimal
+ done
+done
+
+# deccheck
+cd ../../
+for config in $CONFIGS; do
+ for args in "--without-threads" ""; do
+
+ unset PYTHON_DECIMAL_WITH_MACHINE
+ if [ X"$config" != X"auto" ]; then
+ PYTHON_DECIMAL_WITH_MACHINE=$config
+ export PYTHON_DECIMAL_WITH_MACHINE
+ fi
+
+ ############ debug ############
+ print_config "deccheck: config=$config --with-pydebug" $args
+ printf "\nbuilding python ...\n\n"
+
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ========================== debug ===========================\n\n"
+ ./python Modules/_decimal/tests/deccheck.py
+
+ ########### regular ###########
+ print_config "deccheck: config=$config " $args
+ printf "\nbuilding python ...\n\n"
+
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ======================== regular ===========================\n\n"
+ ./python Modules/_decimal/tests/deccheck.py
+
+ ########### valgrind ###########
+ valgrind=$VALGRIND
+ case "$config" in
+ # Valgrind has no support for 80 bit long double arithmetic.
+ ppro) valgrind= ;;
+ auto) case `uname -m` in
+ i386|i486|i586|i686) valgrind= ;;
+ esac
+ esac
+
+ print_config "valgrind deccheck: config=$config " $args
+ printf "\nbuilding python ...\n\n"
+
+ $GMAKE distclean > /dev/null 2>&1
+ ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1
+ $GMAKE | grep _decimal
+
+ printf "\n\n# ======================== valgrind ==========================\n\n"
+ $valgrind ./python Modules/_decimal/tests/deccheck.py
+ done
+done
+
+
+
diff --git a/Modules/_decimal/tests/runall.bat b/Modules/_decimal/tests/runall.bat
new file mode 100644
index 0000000..0d02e25
--- /dev/null
+++ b/Modules/_decimal/tests/runall.bat
@@ -0,0 +1,121 @@
+@ECHO OFF
+
+rem Test all machine configurations, pydebug, refleaks, release build.
+
+cd ..
+
+call vcvarsall x64
+echo.
+echo # ======================================================================
+echo # test_decimal: platform=x64
+echo # ======================================================================
+echo.
+
+cd ..\..\PCbuild
+echo # ==================== refleak tests =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1
+amd64\python_d.exe -m test -uall -R 2:2 test_decimal
+echo.
+
+echo # ==================== regular tests =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Release|x64" > NUL 2>&1
+amd64\python.exe -m test -uall test_decimal
+echo.
+echo.
+
+
+call vcvarsall x86
+echo.
+echo # ======================================================================
+echo # test_decimal: platform=x86
+echo # ======================================================================
+echo.
+
+echo # ==================== refleak tests =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1
+python_d.exe -m test -uall -R 2:2 test_decimal
+echo.
+
+echo # ==================== regular tests =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Release|win32" > NUL 2>&1
+python.exe -m test -uall test_decimal
+echo.
+echo.
+
+
+call vcvarsall x64
+echo.
+echo # ======================================================================
+echo # deccheck: platform=x64
+echo # ======================================================================
+echo.
+echo.
+echo # ==================== debug build =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1
+amd64\python_d.exe ..\Modules\_decimal\tests\deccheck.py
+echo.
+echo.
+
+echo # =================== release build ======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Release|x64" > NUL 2>&1
+amd64\python.exe ..\Modules\_decimal\tests\deccheck.py
+echo.
+echo.
+
+
+call vcvarsall x86
+echo.
+echo # ======================================================================
+echo # deccheck: platform=x86
+echo # ======================================================================
+echo.
+echo.
+echo # ==================== debug build =======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1
+python_d.exe ..\Modules\_decimal\tests\deccheck.py
+echo.
+echo.
+
+echo # =================== release build ======================
+echo.
+echo building python ...
+echo.
+vcbuild /clean pcbuild.sln > NUL 2>&1
+vcbuild pcbuild.sln "Release|win32" > NUL 2>&1
+python.exe ..\Modules\_decimal\tests\deccheck.py
+echo.
+echo.
+
+
+cd ..\Modules\_decimal\tests
+
+
+
diff --git a/PCbuild/_decimal.vcproj b/PCbuild/_decimal.vcproj
new file mode 100644
index 0000000..1d047c2
--- /dev/null
+++ b/PCbuild/_decimal.vcproj
@@ -0,0 +1,743 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="_decimal"
+ ProjectGUID="{0E9791DB-593A-465F-98BC-681011311617}"
+ RootNamespace="_decimal"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd_d.vsprops"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/D_CRT_SECURE_NO_WARNINGS /DCONFIG_32 /DPPRO /DMASM"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd_d.vsprops;.\x64.vsprops"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/D_CRT_SECURE_NO_WARNINGS /DCONFIG_64 /DMASM"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/D_CRT_SECURE_NO_WARNINGS /DCONFIG_32 /DPPRO /DMASM"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops;.\x64.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/D_CRT_SECURE_NO_WARNINGS /DCONFIG_64 /DMASM"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="PGInstrument|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops;.\pginstrument.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/DCONFIG_32 /DPPRO /D_CRT_SECURE_NO_WARNINGS"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="PGInstrument|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops;.\x64.vsprops;.\pginstrument.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/DCONFIG_64 /D_CRT_SECURE_NO_WARNINGS"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="PGUpdate|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops;.\pgupdate.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/DCONFIG_32 /DPPRO /D_CRT_SECURE_NO_WARNINGS"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="PGUpdate|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets=".\pyd.vsprops;.\x64.vsprops;.\pgupdate.vsprops"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\Modules\_decimal;..\Modules\_decimal\libmpdec"
+ AdditionalOptions="/DCONFIG_64 /D_CRT_SECURE_NO_WARNINGS"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="0"
+ BaseAddress="0x1D1A0000"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath="..\Modules\_decimal\docstrings.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\basearith.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\bits.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\constants.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\convolute.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\crt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\difradix2.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\fnt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\fourstep.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\mpdecimal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\numbertheory.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\sixstep.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\transpose.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\typearith.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\umodarith.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\vccompat.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\vcstdint.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath="..\Modules\_decimal\_decimal.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\basearith.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\constants.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\context.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\convolute.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\crt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\difradix2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\fnt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\fourstep.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\io.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\memory.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\mpdecimal.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\numbertheory.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\sixstep.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\transpose.c"
+ >
+ </File>
+ <File
+ RelativePath="..\Modules\_decimal\libmpdec\vcdiv64.asm"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="ml64 /nologo /c /Zi /Fo &quot;$(IntDir)\vcdiv64.obj&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
+ Outputs="$(IntDir)\vcdiv64.obj"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="ml64 /nologo /c /Zi /Fo &quot;$(IntDir)\vcdiv64.obj&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
+ Outputs="$(IntDir)\vcdiv64.obj"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="PGInstrument|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="PGInstrument|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="ml64 /nologo /c /Fo &quot;$(IntDir)\vcdiv64.obj&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
+ Outputs="$(IntDir)\vcdiv64.obj"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="PGUpdate|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="PGUpdate|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="ml64 /nologo /c /Fo &quot;$(IntDir)\vcdiv64.obj&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
+ Outputs="$(IntDir)\vcdiv64.obj"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln
index ac6f224..bc0758c 100644
--- a/PCbuild/pcbuild.sln
+++ b/PCbuild/pcbuild.sln
@@ -38,6 +38,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winsound", "winsound.vcproj
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_decimal", "_decimal.vcproj", "{0E9791DB-593A-465F-98BC-681011311617}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes", "_ctypes.vcproj", "{0E9791DB-593A-465F-98BC-681011311618}"
ProjectSection(ProjectDependencies) = postProject
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
@@ -271,6 +276,22 @@ Global
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.Build.0 = Release|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = Release|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.Build.0 = PGInstrument|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.Build.0 = PGUpdate|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.ActiveCfg = Release|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.Build.0 = Release|Win32
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.ActiveCfg = Release|x64
+ {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.Build.0 = Release|x64
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/configure b/configure
index be7684a..7c1113d 100755
--- a/configure
+++ b/configure
@@ -6863,6 +6863,13 @@ $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h
fi
+ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default"
+if test "x$ac_cv_type___uint128_t" = xyes; then :
+
+$as_echo "#define HAVE_GCC_UINT128_T 1" >>confdefs.h
+
+fi
+
# Sizes of various common basic types
# ANSI C requires sizeof(char) == 1, so no need to check it
@@ -12034,6 +12041,40 @@ $as_echo "default LIBC=\"$LIBC\"" >&6; }
fi
+# **************************************
+# * Check for gcc x64 inline assembler *
+# **************************************
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5
+$as_echo_n "checking for x64 gcc inline assembler... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ __asm__ __volatile__ ("movq %rcx, %rax");
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_gcc_asm_for_x64=yes
+else
+ have_gcc_asm_for_x64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5
+$as_echo "$have_gcc_asm_for_x64" >&6; }
+if test "$have_gcc_asm_for_x64" = yes
+then
+
+$as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h
+
+fi
+
# **************************************************
# * Check for various properties of floating point *
# **************************************************
@@ -14228,6 +14269,136 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
$as_echo "done" >&6; }
+# Availability of -O2:
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5
+$as_echo_n "checking for -O2... " >&6; }
+saved_cflags="$CFLAGS"
+CFLAGS="-O2"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_O2=yes
+else
+ have_O2=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_O2" >&5
+$as_echo "$have_O2" >&6; }
+CFLAGS="$saved_cflags"
+
+# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
+# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5
+$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; }
+saved_cflags="$CFLAGS"
+CFLAGS="-O2 -D_FORTIFY_SOURCE=2"
+if test "$have_O2" = no; then
+ CFLAGS=""
+fi
+if test "$cross_compiling" = yes; then :
+ have_glibc_memmove_bug=undefined
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+void foo(void *p, void *q) { memmove(p, q, 19); }
+int main() {
+ char a[32] = "123456789000000000";
+ foo(&a[9], a);
+ if (strcmp(a, "123456789123456789000000000") != 0)
+ return 1;
+ foo(a, &a[9]);
+ if (strcmp(a, "123456789000000000") != 0)
+ return 1;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_glibc_memmove_bug=no
+else
+ have_glibc_memmove_bug=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+CFLAGS="$saved_cflags"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5
+$as_echo "$have_glibc_memmove_bug" >&6; }
+if test "$have_glibc_memmove_bug" = yes; then
+
+$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h
+
+fi
+
+if test "$have_gcc_asm_for_x87" = yes; then
+ # Some versions of gcc miscompile inline asm:
+ # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
+ # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
+ case $CC in
+ *gcc*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5
+$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; }
+ saved_cflags="$CFLAGS"
+ CFLAGS="-O2"
+ if test "$cross_compiling" = yes; then :
+ have_ipa_pure_const_bug=undefined
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ __attribute__((noinline)) int
+ foo(int *p) {
+ int r;
+ asm ( "movl \$6, (%1)\n\t"
+ "xorl %0, %0\n\t"
+ : "=r" (r) : "r" (p) : "memory"
+ );
+ return r;
+ }
+ int main() {
+ int p = 8;
+ if ((foo(&p) ? : p) != 6)
+ return 1;
+ return 0;
+ }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_ipa_pure_const_bug=no
+else
+ have_ipa_pure_const_bug=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ CFLAGS="$saved_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5
+$as_echo "$have_ipa_pure_const_bug" >&6; }
+ if test "$have_ipa_pure_const_bug" = yes; then
+
+$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h
+
+ fi
+ ;;
+ esac
+fi
+
# generate output files
ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc"
diff --git a/configure.ac b/configure.ac
index 0ae5003..78bcbe7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1483,6 +1483,8 @@ AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_CHECK_TYPE(ssize_t,
AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides ssize_t]),,)
+AC_CHECK_TYPE(__uint128_t,
+ AC_DEFINE(HAVE_GCC_UINT128_T, 1, [Define if your compiler provides __uint128_t]),,)
# Sizes of various common basic types
# ANSI C requires sizeof(char) == 1, so no need to check it
@@ -3329,6 +3331,21 @@ else AC_MSG_ERROR([proper usage is --with-libc=STRING])
fi],
[AC_MSG_RESULT(default LIBC="$LIBC")])
+# **************************************
+# * Check for gcc x64 inline assembler *
+# **************************************
+
+AC_MSG_CHECKING(for x64 gcc inline assembler)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+ __asm__ __volatile__ ("movq %rcx, %rax");
+]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no])
+AC_MSG_RESULT($have_gcc_asm_for_x64)
+if test "$have_gcc_asm_for_x64" = yes
+then
+ AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1,
+ [Define if we can use x64 gcc inline assembler])
+fi
+
# **************************************************
# * Check for various properties of floating point *
# **************************************************
@@ -4333,6 +4350,89 @@ for dir in $SRCDIRS; do
done
AC_MSG_RESULT(done)
+# Availability of -O2:
+AC_MSG_CHECKING(for -O2)
+saved_cflags="$CFLAGS"
+CFLAGS="-O2"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+]])],[have_O2=yes],[have_O2=no])
+AC_MSG_RESULT($have_O2)
+CFLAGS="$saved_cflags"
+
+# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
+# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
+AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug)
+saved_cflags="$CFLAGS"
+CFLAGS="-O2 -D_FORTIFY_SOURCE=2"
+if test "$have_O2" = no; then
+ CFLAGS=""
+fi
+AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+void foo(void *p, void *q) { memmove(p, q, 19); }
+int main() {
+ char a[32] = "123456789000000000";
+ foo(&a[9], a);
+ if (strcmp(a, "123456789123456789000000000") != 0)
+ return 1;
+ foo(a, &a[9]);
+ if (strcmp(a, "123456789000000000") != 0)
+ return 1;
+ return 0;
+}
+]])],
+[have_glibc_memmove_bug=no],
+[have_glibc_memmove_bug=yes],
+[have_glibc_memmove_bug=undefined])
+CFLAGS="$saved_cflags"
+AC_MSG_RESULT($have_glibc_memmove_bug)
+if test "$have_glibc_memmove_bug" = yes; then
+ AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1,
+ [Define if glibc has incorrect _FORTIFY_SOURCE wrappers
+ for memmove and bcopy.])
+fi
+
+if test "$have_gcc_asm_for_x87" = yes; then
+ # Some versions of gcc miscompile inline asm:
+ # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
+ # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
+ case $CC in
+ *gcc*)
+ AC_MSG_CHECKING(for gcc ipa-pure-const bug)
+ saved_cflags="$CFLAGS"
+ CFLAGS="-O2"
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ __attribute__((noinline)) int
+ foo(int *p) {
+ int r;
+ asm ( "movl \$6, (%1)\n\t"
+ "xorl %0, %0\n\t"
+ : "=r" (r) : "r" (p) : "memory"
+ );
+ return r;
+ }
+ int main() {
+ int p = 8;
+ if ((foo(&p) ? : p) != 6)
+ return 1;
+ return 0;
+ }
+ ]])],
+ [have_ipa_pure_const_bug=no],
+ [have_ipa_pure_const_bug=yes],
+ [have_ipa_pure_const_bug=undefined])
+ CFLAGS="$saved_cflags"
+ AC_MSG_RESULT($have_ipa_pure_const_bug)
+ if test "$have_ipa_pure_const_bug" = yes; then
+ AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1,
+ [Define if gcc has the ipa-pure-const bug.])
+ fi
+ ;;
+ esac
+fi
+
# generate output files
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc)
AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 0ebcc30..aaa8509 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -304,10 +304,16 @@
/* Define to 1 if you have the `gamma' function. */
#undef HAVE_GAMMA
+/* Define if we can use x64 gcc inline assembler */
+#undef HAVE_GCC_ASM_FOR_X64
+
/* Define if we can use gcc inline assembler to get and set x87 control word
*/
#undef HAVE_GCC_ASM_FOR_X87
+/* Define if your compiler provides __uint128_t */
+#undef HAVE_GCC_UINT128_T
+
/* Define if you have the getaddrinfo function. */
#undef HAVE_GETADDRINFO
@@ -392,6 +398,10 @@
/* Define to 1 if you have the `getwd' function. */
#undef HAVE_GETWD
+/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and
+ bcopy. */
+#undef HAVE_GLIBC_MEMMOVE_BUG
+
/* Define to 1 if you have the <grp.h> header file. */
#undef HAVE_GRP_H
@@ -422,6 +432,9 @@
/* Define to 1 if you have the <io.h> header file. */
#undef HAVE_IO_H
+/* Define if gcc has the ipa-pure-const bug. */
+#undef HAVE_IPA_PURE_CONST_BUG
+
/* Define to 1 if you have the `kill' function. */
#undef HAVE_KILL
diff --git a/setup.py b/setup.py
index 7650996..6c8d378 100644
--- a/setup.py
+++ b/setup.py
@@ -1342,6 +1342,9 @@ class PyBuildExt(build_ext):
exts.append(Extension('_codecs_%s' % loc,
['cjkcodecs/_codecs_%s.c' % loc]))
+ # Stefan Krah's _decimal module
+ exts.append(self._decimal_ext())
+
# Thomas Heller's _ctypes module
self.detect_ctypes(inc_dirs, lib_dirs)
@@ -1792,6 +1795,116 @@ class PyBuildExt(build_ext):
ext.libraries.append(ffi_lib)
self.use_system_libffi = True
+ def _decimal_ext(self):
+ sources = [
+ '_decimal/_decimal.c',
+ '_decimal/libmpdec/basearith.c',
+ '_decimal/libmpdec/constants.c',
+ '_decimal/libmpdec/context.c',
+ '_decimal/libmpdec/convolute.c',
+ '_decimal/libmpdec/crt.c',
+ '_decimal/libmpdec/difradix2.c',
+ '_decimal/libmpdec/fnt.c',
+ '_decimal/libmpdec/fourstep.c',
+ '_decimal/libmpdec/io.c',
+ '_decimal/libmpdec/memory.c',
+ '_decimal/libmpdec/mpdecimal.c',
+ '_decimal/libmpdec/numbertheory.c',
+ '_decimal/libmpdec/sixstep.c',
+ '_decimal/libmpdec/transpose.c',
+ ]
+ depends = [
+ '_decimal/docstrings.h',
+ '_decimal/libmpdec/basearith.h',
+ '_decimal/libmpdec/bits.h',
+ '_decimal/libmpdec/constants.h',
+ '_decimal/libmpdec/convolute.h',
+ '_decimal/libmpdec/crt.h',
+ '_decimal/libmpdec/difradix2.h',
+ '_decimal/libmpdec/fnt.h',
+ '_decimal/libmpdec/fourstep.h',
+ '_decimal/libmpdec/io.h',
+ '_decimal/libmpdec/memory.h',
+ '_decimal/libmpdec/mpdecimal.h',
+ '_decimal/libmpdec/numbertheory.h',
+ '_decimal/libmpdec/sixstep.h',
+ '_decimal/libmpdec/transpose.h',
+ '_decimal/libmpdec/typearith.h',
+ '_decimal/libmpdec/umodarith.h',
+ ]
+ config = {
+ 'x64': [('CONFIG_64','1'), ('ASM','1')],
+ 'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')],
+ 'ansi64': [('CONFIG_64','1'), ('ANSI','1')],
+ 'ppro': [('CONFIG_32','1'), ('PPRO','1'), ('ASM','1')],
+ 'ansi32': [('CONFIG_32','1'), ('ANSI','1')],
+ 'ansi-legacy': [('CONFIG_32','1'), ('ANSI','1'),
+ ('LEGACY_COMPILER','1')],
+ 'universal': [('UNIVERSAL','1')]
+ }
+
+ include_dirs = ['./Modules/_decimal/libmpdec']
+ extra_compile_args = []
+ undef_macros=['NDEBUG']
+
+ platform = self.get_platform()
+ cc = sysconfig.get_config_var('CC')
+ sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T')
+ machine = os.environ.get('PYTHON_DECIMAL_WITH_MACHINE')
+
+ if machine:
+ # Override automatic configuration to facilitate testing.
+ define_macros = config[machine]
+ elif platform == 'darwin':
+ # Universal here means: build with the same options Python
+ # was built with.
+ define_macros = config['universal']
+ elif sizeof_size_t == 8:
+ if sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X64'):
+ define_macros = config['x64']
+ elif sysconfig.get_config_var('HAVE_GCC_UINT128_T'):
+ define_macros = config['uint128']
+ else:
+ define_macros = config['ansi64']
+ elif sizeof_size_t == 4:
+ ppro = sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X87')
+ if ppro and ('gcc' in cc or 'clang' in cc) and \
+ not 'sunos' in platform:
+ # solaris: problems with register allocation.
+ # icc >= 11.0 works as well.
+ define_macros = config['ppro']
+ else:
+ define_macros = config['ansi32']
+ else:
+ raise DistutilsError("_decimal: unsupported architecture")
+
+ # Workarounds for toolchain bugs:
+ if sysconfig.get_config_var('HAVE_IPA_PURE_CONST_BUG'):
+ # Some versions of gcc miscompile inline asm:
+ # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
+ # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
+ extra_compile_args.append('-fno-ipa-pure-const')
+ if sysconfig.get_config_var('HAVE_GLIBC_MEMMOVE_BUG'):
+ # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
+ # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
+ undef_macros.append('_FORTIFY_SOURCE')
+
+ # Faster version without thread local contexts:
+ if not sysconfig.get_config_var('WITH_THREAD'):
+ define_macros.append(('WITHOUT_THREADS', 1))
+
+ # Uncomment for extra functionality:
+ #define_macros.append(('EXTRA_FUNCTIONALITY', 1))
+ ext = Extension (
+ '_decimal',
+ include_dirs=include_dirs,
+ define_macros=define_macros,
+ undef_macros=undef_macros,
+ extra_compile_args=extra_compile_args,
+ sources=sources,
+ depends=depends
+ )
+ return ext
class PyBuildInstall(install):
# Suppress the warning about installation into the lib_dynload