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.
This commit is contained in:
Stefan Krah 2012-03-21 18:25:23 +01:00
parent 8bfccd852e
commit 1919b7e72b
71 changed files with 31412 additions and 1031 deletions

View File

@ -9,6 +9,7 @@
.. moduleauthor:: Raymond Hettinger <python at rcn.com> .. moduleauthor:: Raymond Hettinger <python at rcn.com>
.. moduleauthor:: Aahz <aahz at pobox.com> .. moduleauthor:: Aahz <aahz at pobox.com>
.. moduleauthor:: Tim Peters <tim.one at comcast.net> .. moduleauthor:: Tim Peters <tim.one at comcast.net>
.. moduleauthor:: Stefan Krah <skrah at bytereef.org>
.. sectionauthor:: Raymond D. Hettinger <python at rcn.com> .. sectionauthor:: Raymond D. Hettinger <python at rcn.com>
.. import modules for testing inline doctests with the Sphinx doctest builder .. import modules for testing inline doctests with the Sphinx doctest builder
@ -20,8 +21,9 @@
# make sure each group gets a fresh context # make sure each group gets a fresh context
setcontext(Context()) setcontext(Context())
The :mod:`decimal` module provides support for decimal floating point The :mod:`decimal` module provides support for fast correctly-rounded
arithmetic. It offers several advantages over the :class:`float` datatype: 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 * Decimal "is based on a floating-point model which was designed with people
in mind, and necessarily has a paramount guiding principle -- computers must 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 considered as informational, or treated as exceptions. The signals in the
decimal module are: :const:`Clamped`, :const:`InvalidOperation`, decimal module are: :const:`Clamped`, :const:`InvalidOperation`,
:const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`, :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 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 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 * >>> from decimal import *
>>> getcontext() >>> 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, capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation]) 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 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 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:`NaN` which stands for "Not a number", positive and negative
:const:`Infinity`, and :const:`-0`. :const:`Infinity`, and :const:`-0`::
>>> getcontext().prec = 28 >>> getcontext().prec = 28
>>> Decimal(10) >>> Decimal(10)
@ -152,6 +154,25 @@ value of that integer or float. Decimal numbers include special values such as
>>> Decimal('-Infinity') >>> Decimal('-Infinity')
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 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 input. Context precision and rounding only come into play during arithmetic
operations. operations.
@ -169,6 +190,16 @@ operations.
>>> Decimal('3.1415926535') + Decimal('2.7182818285') >>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988') 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 Decimals interact well with much of the rest of Python. Here is a small decimal
floating point flying circus: floating point flying circus:
@ -244,7 +275,7 @@ enabled:
Decimal('0.142857142857142857142857142857142857142857142857142857142857') Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext >>> 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=[]) capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext) >>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7) >>> Decimal(1) / Decimal(7)
@ -269,7 +300,7 @@ using the :meth:`clear_flags` method. ::
>>> Decimal(355) / Decimal(113) >>> Decimal(355) / Decimal(113)
Decimal('3.14159292') Decimal('3.14159292')
>>> getcontext() >>> 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=[]) capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
The *flags* entry shows that the rational approximation to :const:`Pi` was 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` The argument to the constructor is now permitted to be a :class:`float`
instance. 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 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 numeric types such as :class:`float` and :class:`int`. All of the usual math
operations and special methods apply. Likewise, decimal objects can be 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 In single threaded environments, it is preferable to not use this context at
all. Instead, simply create contexts explicitly as described below. all. Instead, simply create contexts explicitly as described below.
The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps The default values are :attr:`prec`\ =\ :const:`28`,
for Overflow, InvalidOperation, and DivisionByZero. :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 In addition to the three supplied contexts, new contexts can be created with the
:class:`Context` constructor. :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 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* default values are copied from the :const:`DefaultContext`. If the *flags*
field is not specified or is :const:`None`, all flags are cleared. 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 *prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets
operations in the context. the precision for arithmetic operations in the context.
The *rounding* option is one of: The *rounding* option is one of the constants listed in the section
`Rounding Modes`_.
* :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 *traps* and *flags* fields list any signals to be set. Generally, new The *traps* and *flags* fields list any signals to be set. Generally, new
contexts should only set traps and leave the flags clear. contexts should only set traps and leave the flags clear.
The *Emin* and *Emax* fields are integers specifying the outer limits allowable 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 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 :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`. Resets all of the flags to :const:`0`.
.. method:: clear_traps()
Resets all of the traps to :const:`0`.
.. versionadded:: 3.3
.. method:: copy() .. method:: copy()
Return a duplicate of the context. 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`` 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 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 is finite and can be expressed exactly in 'precision' digits.
The result should always be correctly rounded, using the rounding mode of The rounding mode of the context is used. Results are always correctly-rounded
the current thread's context. 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 With three arguments, compute ``(x**y) % modulo``. For the three argument
form, the following restrictions on the arguments hold: 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: .. _decimal-signals:
@ -1403,7 +1503,6 @@ condition.
Infinity / Infinity Infinity / Infinity
x % 0 x % 0
Infinity % x Infinity % x
x._rescale( non-integer )
sqrt(-x) and x > 0 sqrt(-x) and x > 0
0 ** 0 0 ** 0
x ** (non-integer) x ** (non-integer)
@ -1446,6 +1545,23 @@ condition.
Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact` Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact`
and :class:`Subnormal` are also signaled. 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:: The following table summarizes the hierarchy of signals::
exceptions.ArithmeticError(exceptions.Exception) exceptions.ArithmeticError(exceptions.Exception)
@ -1458,10 +1574,12 @@ The following table summarizes the hierarchy of signals::
InvalidOperation InvalidOperation
Rounded Rounded
Subnormal Subnormal
FloatOperation
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. _decimal-notes: .. _decimal-notes:
Floating Point 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: the following calculation returns a value equal to zero:
>>> 1 / Decimal('Infinity') >>> 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 The :func:`getcontext` function accesses a different :class:`Context` object for
each thread. Having separate thread contexts means that threads may make 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 Likewise, the :func:`setcontext` function automatically assigns its target to
the current thread. the current thread.

View File

@ -8,9 +8,9 @@ Numeric and Mathematical Modules
The modules described in this chapter provide numeric and math-related functions The modules described in this chapter provide numeric and math-related functions
and data types. The :mod:`numbers` module defines an abstract hierarchy of and data types. The :mod:`numbers` module defines an abstract hierarchy of
numeric types. The :mod:`math` and :mod:`cmath` modules contain various numeric types. The :mod:`math` and :mod:`cmath` modules contain various
mathematical functions for floating-point and complex numbers. For users more mathematical functions for floating-point and complex numbers. The :mod:`decimal`
interested in decimal accuracy than in speed, the :mod:`decimal` module supports module supports exact representations of decimal numbers, using arbitrary precision
exact representations of decimal numbers. arithmetic.
The following modules are documented in this chapter: The following modules are documented in this chapter:

View File

@ -596,6 +596,93 @@ curses
(Contributed by Iñigo Serna in :issue:`6755`) (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 faulthandler
------------ ------------

View File

@ -6,7 +6,7 @@ extern "C" {
#endif #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 /* 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 sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit

View File

@ -46,8 +46,8 @@ Decimal('1')
Decimal('-0.0123') Decimal('-0.0123')
>>> Decimal(123456) >>> Decimal(123456)
Decimal('123456') Decimal('123456')
>>> Decimal('123.45e12345678901234567890') >>> Decimal('123.45e12345678')
Decimal('1.2345E+12345678901234567892') Decimal('1.2345E+12345680')
>>> Decimal('1.33') + Decimal('1.27') >>> Decimal('1.33') + Decimal('1.27')
Decimal('2.60') Decimal('2.60')
>>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41')
@ -122,13 +122,20 @@ __all__ = [
# Exceptions # Exceptions
'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero', 'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero',
'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow', 'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow',
'FloatOperation',
# Constants for use in setting up contexts # Constants for use in setting up contexts
'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING', 'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING',
'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP', 'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP',
# Functions for manipulating contexts # 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 __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 copy as _copy
import math as _math import math as _math
import numbers as _numbers import numbers as _numbers
import sys
try: try:
from collections import namedtuple as _namedtuple from collections import namedtuple as _namedtuple
@ -154,6 +162,19 @@ ROUND_UP = 'ROUND_UP'
ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
ROUND_05UP = 'ROUND_05UP' 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 # Errors
class DecimalException(ArithmeticError): class DecimalException(ArithmeticError):
@ -370,9 +391,24 @@ class Underflow(Inexact, Rounded, Subnormal):
In all cases, Inexact, Rounded, and Subnormal will also be raised. 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 # List of public traps and flags
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded, _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
Underflow, InvalidOperation, Subnormal] Underflow, InvalidOperation, Subnormal, FloatOperation]
# Map conditions (per the spec) to signals # Map conditions (per the spec) to signals
_condition_map = {ConversionSyntax:InvalidOperation, _condition_map = {ConversionSyntax:InvalidOperation,
@ -380,6 +416,10 @@ _condition_map = {ConversionSyntax:InvalidOperation,
DivisionUndefined:InvalidOperation, DivisionUndefined:InvalidOperation,
InvalidContext: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 ################################################## ##### Context Functions ##################################################
# The getcontext() and setcontext() function manage access to a thread-local # The getcontext() and setcontext() function manage access to a thread-local
@ -392,12 +432,11 @@ try:
import threading import threading
except ImportError: except ImportError:
# Python was compiled without threads; create a mock object instead # Python was compiled without threads; create a mock object instead
import sys
class MockThreading(object): class MockThreading(object):
def local(self, sys=sys): def local(self, sys=sys):
return sys.modules[__name__] return sys.modules[__name__]
threading = MockThreading() threading = MockThreading()
del sys, MockThreading del MockThreading
try: try:
threading.local threading.local
@ -650,6 +689,11 @@ class Decimal(object):
return self return self
if isinstance(value, float): 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) value = Decimal.from_float(value)
self._exp = value._exp self._exp = value._exp
self._sign = value._sign self._sign = value._sign
@ -684,7 +728,9 @@ class Decimal(object):
""" """
if isinstance(f, int): # handle integer inputs if isinstance(f, int): # handle integer inputs
return cls(f) 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)) return cls(repr(f))
if _math.copysign(1.0, f) == 1.0: if _math.copysign(1.0, f) == 1.0:
sign = 0 sign = 0
@ -1906,11 +1952,12 @@ class Decimal(object):
def _power_modulo(self, other, modulo, context=None): def _power_modulo(self, other, modulo, context=None):
"""Three argument version of __pow__""" """Three argument version of __pow__"""
# if can't convert other and modulo to Decimal, raise other = _convert_other(other)
# TypeError; there's no point returning NotImplemented (no if other is NotImplemented:
# equivalent of __rpow__ for three argument pow) return other
other = _convert_other(other, raiseit=True) modulo = _convert_other(modulo)
modulo = _convert_other(modulo, raiseit=True) if modulo is NotImplemented:
return modulo
if context is None: if context is None:
context = getcontext() context = getcontext()
@ -3832,10 +3879,8 @@ class Context(object):
clamp - If 1, change exponents if too high (Default 0) clamp - If 1, change exponents if too high (Default 0)
""" """
def __init__(self, prec=None, rounding=None, def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
traps=None, flags=None, capitals=None, clamp=None, flags=None, traps=None,
Emin=None, Emax=None,
capitals=None, clamp=None,
_ignored_flags=None): _ignored_flags=None):
# Set defaults; for everything except flags and _ignored_flags, # Set defaults; for everything except flags and _ignored_flags,
# inherit from DefaultContext. # inherit from DefaultContext.
@ -3859,17 +3904,78 @@ class Context(object):
if traps is None: if traps is None:
self.traps = dc.traps.copy() self.traps = dc.traps.copy()
elif not isinstance(traps, dict): 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: else:
self.traps = traps self.traps = traps
if flags is None: if flags is None:
self.flags = dict.fromkeys(_signals, 0) self.flags = dict.fromkeys(_signals, 0)
elif not isinstance(flags, dict): 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: else:
self.flags = flags 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): def __repr__(self):
"""Show the current context.""" """Show the current context."""
s = [] s = []
@ -3888,18 +3994,24 @@ class Context(object):
for flag in self.flags: for flag in self.flags:
self.flags[flag] = 0 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): def _shallow_copy(self):
"""Returns a shallow copy from self.""" """Returns a shallow copy from self."""
nc = Context(self.prec, self.rounding, self.traps, nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
self.flags, self.Emin, self.Emax, self.capitals, self.clamp, self.flags, self.traps,
self.capitals, self.clamp, self._ignored_flags) self._ignored_flags)
return nc return nc
def copy(self): def copy(self):
"""Returns a deep copy from self.""" """Returns a deep copy from self."""
nc = Context(self.prec, self.rounding, self.traps.copy(), nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
self.flags.copy(), self.Emin, self.Emax, self.capitals, self.clamp,
self.capitals, self.clamp, self._ignored_flags) self.flags.copy(), self.traps.copy(),
self._ignored_flags)
return nc return nc
__copy__ = copy __copy__ = copy
@ -4062,6 +4174,8 @@ class Context(object):
>>> ExtendedContext.canonical(Decimal('2.50')) >>> ExtendedContext.canonical(Decimal('2.50'))
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) return a.canonical(context=self)
def compare(self, a, b): def compare(self, a, b):
@ -4372,6 +4486,8 @@ class Context(object):
>>> ExtendedContext.is_canonical(Decimal('2.50')) >>> ExtendedContext.is_canonical(Decimal('2.50'))
True True
""" """
if not isinstance(a, Decimal):
raise TypeError("is_canonical requires a Decimal as an argument.")
return a.is_canonical() return a.is_canonical()
def is_finite(self, a): def is_finite(self, a):
@ -4964,7 +5080,7 @@ class Context(object):
+Normal +Normal
+Infinity +Infinity
>>> c = Context(ExtendedContext) >>> c = ExtendedContext.copy()
>>> c.Emin = -999 >>> c.Emin = -999
>>> c.Emax = 999 >>> c.Emax = 999
>>> c.number_class(Decimal('Infinity')) >>> 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: if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
other = other.real other = other.real
if isinstance(other, float): 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 self, Decimal.from_float(other)
return NotImplemented, NotImplemented return NotImplemented, NotImplemented
@ -5929,8 +6051,8 @@ DefaultContext = Context(
prec=28, rounding=ROUND_HALF_EVEN, prec=28, rounding=ROUND_HALF_EVEN,
traps=[DivisionByZero, Overflow, InvalidOperation], traps=[DivisionByZero, Overflow, InvalidOperation],
flags=[], flags=[],
Emax=999999999, Emax=999999,
Emin=-999999999, Emin=-999999,
capitals=1, capitals=1,
clamp=0 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 # 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. # sense; convert it to 1. Same if format type is unspecified.
if format_dict['precision'] == 0: 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 format_dict['precision'] = 1
# determine thousands separator, grouping, and decimal separator, and # 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 # Constants related to the hash implementation; hash(x) is based
# on the reduction of x modulo _PyHASH_MODULUS # on the reduction of x modulo _PyHASH_MODULUS
import sys
_PyHASH_MODULUS = sys.hash_info.modulus _PyHASH_MODULUS = sys.hash_info.modulus
# hash values to use for positive and negative infinities, and nans # hash values to use for positive and negative infinities, and nans
_PyHASH_INF = sys.hash_info.inf _PyHASH_INF = sys.hash_info.inf
_PyHASH_NAN = sys.hash_info.nan _PyHASH_NAN = sys.hash_info.nan
del sys
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _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__': if __name__ == '__main__':
import doctest, decimal import doctest, decimal

View File

@ -1416,7 +1416,7 @@ def run_unittest(*classes):
#======================================================================= #=======================================================================
# doctest driver. # 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). """Run doctest on the given module. Return (#failures, #tests).
If optional argument verbosity is not specified (or is None), pass If optional argument verbosity is not specified (or is None), pass
@ -1431,7 +1431,7 @@ def run_doctest(module, verbosity=None):
else: else:
verbosity = None verbosity = None
f, t = doctest.testmod(module, verbose=verbosity) f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags)
if f: if f:
raise TestFailed("%d of %d doctests failed" % (f, t)) raise TestFailed("%d of %d doctests failed" % (f, t))
if verbose: if verbose:

File diff suppressed because it is too large Load Diff

View File

@ -401,14 +401,10 @@ class FractionTest(unittest.TestCase):
def testMixingWithDecimal(self): def testMixingWithDecimal(self):
# Decimal refuses mixed arithmetic (but not mixed comparisons) # Decimal refuses mixed arithmetic (but not mixed comparisons)
self.assertRaisesMessage( self.assertRaises(TypeError, operator.add,
TypeError, F(3,11), Decimal('3.1415926'))
"unsupported operand type(s) for +: 'Fraction' and 'Decimal'", self.assertRaises(TypeError, operator.add,
operator.add, F(3,11), Decimal('3.1415926')) Decimal('3.1415926'), F(3,11))
self.assertRaisesMessage(
TypeError,
"unsupported operand type(s) for +: 'Decimal' and 'Fraction'",
operator.add, Decimal('3.1415926'), F(3,11))
def testComparisons(self): def testComparisons(self):
self.assertTrue(F(1, 2) < F(2, 3)) self.assertTrue(F(1, 2) < F(2, 3))

View File

@ -150,7 +150,7 @@ class ComparisonTest(unittest.TestCase):
# int, float, Fraction, Decimal # int, float, Fraction, Decimal
test_values = [ test_values = [
float('-inf'), float('-inf'),
D('-1e999999999'), D('-1e425000000'),
-1e308, -1e308,
F(-22, 7), F(-22, 7),
-3.14, -3.14,

View File

@ -30,6 +30,10 @@ Core and Builtins
Library 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 - Issue #3573: IDLE hangs when passing invalid command line args
(directory(ies) instead of file(s)) (Patch by Guilherme Polo) (directory(ies) instead of file(s)) (Patch by Guilherme Polo)

View File

@ -456,3 +456,16 @@
fun:PyUnicode_FSConverter fun:PyUnicode_FSConverter
} }
# Additional suppressions for the unified decimal tests:
{
test_decimal
Memcheck:Addr4
fun:PyUnicodeUCS2_FSConverter
}
{
test_decimal2
Memcheck:Addr4
fun:PyUnicode_FSConverter
}

View File

@ -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.

View File

@ -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).

5512
Modules/_decimal/_decimal.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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>

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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"
};

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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))

View File

@ -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/

View File

@ -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

View File

@ -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.

View File

@ -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/

View File

@ -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)))))))

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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_ ]

View File

@ -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]

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

743
PCbuild/_decimal.vcproj Normal file
View File

@ -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>

View File

@ -38,6 +38,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winsound", "winsound.vcproj
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
EndProjectSection EndProjectSection
EndProject 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}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes", "_ctypes.vcproj", "{0E9791DB-593A-465F-98BC-681011311618}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} {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|Win32.Build.0 = Release|Win32
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64 {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = 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.ActiveCfg = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32 {0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32
{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64 {0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64

171
configure vendored
View File

@ -6863,6 +6863,13 @@ $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h
fi 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 # Sizes of various common basic types
# ANSI C requires sizeof(char) == 1, so no need to check it # ANSI C requires sizeof(char) == 1, so no need to check it
@ -12034,6 +12041,40 @@ $as_echo "default LIBC=\"$LIBC\"" >&6; }
fi 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 * # * Check for various properties of floating point *
# ************************************************** # **************************************************
@ -14228,6 +14269,136 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
$as_echo "done" >&6; } $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 # generate output files
ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc" ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc"

View File

@ -1483,6 +1483,8 @@ AC_TYPE_INT32_T
AC_TYPE_INT64_T AC_TYPE_INT64_T
AC_CHECK_TYPE(ssize_t, AC_CHECK_TYPE(ssize_t,
AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides 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 # Sizes of various common basic types
# ANSI C requires sizeof(char) == 1, so no need to check it # 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], fi],
[AC_MSG_RESULT(default LIBC="$LIBC")]) [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 * # * Check for various properties of floating point *
# ************************************************** # **************************************************
@ -4333,6 +4350,89 @@ for dir in $SRCDIRS; do
done done
AC_MSG_RESULT(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 # generate output files
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc) AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc)
AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix]) AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])

View File

@ -304,10 +304,16 @@
/* Define to 1 if you have the `gamma' function. */ /* Define to 1 if you have the `gamma' function. */
#undef HAVE_GAMMA #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 /* Define if we can use gcc inline assembler to get and set x87 control word
*/ */
#undef HAVE_GCC_ASM_FOR_X87 #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. */ /* Define if you have the getaddrinfo function. */
#undef HAVE_GETADDRINFO #undef HAVE_GETADDRINFO
@ -392,6 +398,10 @@
/* Define to 1 if you have the `getwd' function. */ /* Define to 1 if you have the `getwd' function. */
#undef HAVE_GETWD #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. */ /* Define to 1 if you have the <grp.h> header file. */
#undef HAVE_GRP_H #undef HAVE_GRP_H
@ -422,6 +432,9 @@
/* Define to 1 if you have the <io.h> header file. */ /* Define to 1 if you have the <io.h> header file. */
#undef HAVE_IO_H #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. */ /* Define to 1 if you have the `kill' function. */
#undef HAVE_KILL #undef HAVE_KILL

113
setup.py
View File

@ -1342,6 +1342,9 @@ class PyBuildExt(build_ext):
exts.append(Extension('_codecs_%s' % loc, exts.append(Extension('_codecs_%s' % loc,
['cjkcodecs/_codecs_%s.c' % loc])) ['cjkcodecs/_codecs_%s.c' % loc]))
# Stefan Krah's _decimal module
exts.append(self._decimal_ext())
# Thomas Heller's _ctypes module # Thomas Heller's _ctypes module
self.detect_ctypes(inc_dirs, lib_dirs) self.detect_ctypes(inc_dirs, lib_dirs)
@ -1792,6 +1795,116 @@ class PyBuildExt(build_ext):
ext.libraries.append(ffi_lib) ext.libraries.append(ffi_lib)
self.use_system_libffi = True 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): class PyBuildInstall(install):
# Suppress the warning about installation into the lib_dynload # Suppress the warning about installation into the lib_dynload