mirror of https://github.com/python/cpython
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:
parent
8bfccd852e
commit
1919b7e72b
|
@ -9,6 +9,7 @@
|
|||
.. moduleauthor:: Raymond Hettinger <python at rcn.com>
|
||||
.. moduleauthor:: Aahz <aahz at pobox.com>
|
||||
.. moduleauthor:: Tim Peters <tim.one at comcast.net>
|
||||
.. moduleauthor:: Stefan Krah <skrah at bytereef.org>
|
||||
.. sectionauthor:: Raymond D. Hettinger <python at rcn.com>
|
||||
|
||||
.. import modules for testing inline doctests with the Sphinx doctest builder
|
||||
|
@ -20,8 +21,9 @@
|
|||
# make sure each group gets a fresh context
|
||||
setcontext(Context())
|
||||
|
||||
The :mod:`decimal` module provides support for decimal floating point
|
||||
arithmetic. It offers several advantages over the :class:`float` datatype:
|
||||
The :mod:`decimal` module provides support for fast correctly-rounded
|
||||
decimal floating point arithmetic. It offers several advantages over the
|
||||
:class:`float` datatype:
|
||||
|
||||
* Decimal "is based on a floating-point model which was designed with people
|
||||
in mind, and necessarily has a paramount guiding principle -- computers must
|
||||
|
@ -92,7 +94,7 @@ computation. Depending on the needs of the application, signals may be ignored,
|
|||
considered as informational, or treated as exceptions. The signals in the
|
||||
decimal module are: :const:`Clamped`, :const:`InvalidOperation`,
|
||||
:const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`,
|
||||
:const:`Overflow`, and :const:`Underflow`.
|
||||
:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`.
|
||||
|
||||
For each signal there is a flag and a trap enabler. When a signal is
|
||||
encountered, its flag is set to one, then, if the trap enabler is
|
||||
|
@ -122,7 +124,7 @@ precision, rounding, or enabled traps::
|
|||
|
||||
>>> from decimal import *
|
||||
>>> getcontext()
|
||||
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
|
||||
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
|
||||
InvalidOperation])
|
||||
|
||||
|
@ -132,7 +134,7 @@ Decimal instances can be constructed from integers, strings, floats, or tuples.
|
|||
Construction from an integer or a float performs an exact conversion of the
|
||||
value of that integer or float. Decimal numbers include special values such as
|
||||
:const:`NaN` which stands for "Not a number", positive and negative
|
||||
:const:`Infinity`, and :const:`-0`.
|
||||
:const:`Infinity`, and :const:`-0`::
|
||||
|
||||
>>> getcontext().prec = 28
|
||||
>>> Decimal(10)
|
||||
|
@ -152,6 +154,25 @@ value of that integer or float. Decimal numbers include special values such as
|
|||
>>> Decimal('-Infinity')
|
||||
Decimal('-Infinity')
|
||||
|
||||
If the :exc:`FloatOperation` signal is trapped, accidental mixing of
|
||||
decimals and floats in constructors or ordering comparisons raises
|
||||
an exception::
|
||||
|
||||
>>> c = getcontext()
|
||||
>>> c.traps[FloatOperation] = True
|
||||
>>> Decimal(3.14)
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
|
||||
>>> Decimal('3.5') < 3.7
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
|
||||
>>> Decimal('3.5') == 3.5
|
||||
True
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
The significance of a new Decimal is determined solely by the number of digits
|
||||
input. Context precision and rounding only come into play during arithmetic
|
||||
operations.
|
||||
|
@ -169,6 +190,16 @@ operations.
|
|||
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
|
||||
Decimal('5.85988')
|
||||
|
||||
If the internal limits of the C version are exceeded, constructing
|
||||
a decimal raises :class:`InvalidOperation`::
|
||||
|
||||
>>> Decimal("1e9999999999999999999")
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
|
||||
Decimals interact well with much of the rest of Python. Here is a small decimal
|
||||
floating point flying circus:
|
||||
|
||||
|
@ -244,7 +275,7 @@ enabled:
|
|||
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
|
||||
|
||||
>>> ExtendedContext
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
|
||||
capitals=1, clamp=0, flags=[], traps=[])
|
||||
>>> setcontext(ExtendedContext)
|
||||
>>> Decimal(1) / Decimal(7)
|
||||
|
@ -269,7 +300,7 @@ using the :meth:`clear_flags` method. ::
|
|||
>>> Decimal(355) / Decimal(113)
|
||||
Decimal('3.14159292')
|
||||
>>> getcontext()
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
|
||||
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
|
||||
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
|
||||
|
||||
The *flags* entry shows that the rational approximation to :const:`Pi` was
|
||||
|
@ -358,6 +389,10 @@ Decimal objects
|
|||
The argument to the constructor is now permitted to be a :class:`float`
|
||||
instance.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
:class:`float` arguments raise an exception if the :exc:`FloatOperation`
|
||||
trap is set. By default the trap is off.
|
||||
|
||||
Decimal floating point objects share many properties with the other built-in
|
||||
numeric types such as :class:`float` and :class:`int`. All of the usual math
|
||||
operations and special methods apply. Likewise, decimal objects can be
|
||||
|
@ -880,39 +915,33 @@ described below. In addition, the module provides three pre-made contexts:
|
|||
In single threaded environments, it is preferable to not use this context at
|
||||
all. Instead, simply create contexts explicitly as described below.
|
||||
|
||||
The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps
|
||||
for Overflow, InvalidOperation, and DivisionByZero.
|
||||
The default values are :attr:`prec`\ =\ :const:`28`,
|
||||
:attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`,
|
||||
and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and
|
||||
:class:`DivisionByZero`.
|
||||
|
||||
In addition to the three supplied contexts, new contexts can be created with the
|
||||
:class:`Context` constructor.
|
||||
|
||||
|
||||
.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None)
|
||||
.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
|
||||
|
||||
Creates a new context. If a field is not specified or is :const:`None`, the
|
||||
default values are copied from the :const:`DefaultContext`. If the *flags*
|
||||
field is not specified or is :const:`None`, all flags are cleared.
|
||||
|
||||
The *prec* field is a positive integer that sets the precision for arithmetic
|
||||
operations in the context.
|
||||
*prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets
|
||||
the precision for arithmetic operations in the context.
|
||||
|
||||
The *rounding* option is one of:
|
||||
|
||||
* :const:`ROUND_CEILING` (towards :const:`Infinity`),
|
||||
* :const:`ROUND_DOWN` (towards zero),
|
||||
* :const:`ROUND_FLOOR` (towards :const:`-Infinity`),
|
||||
* :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero),
|
||||
* :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer),
|
||||
* :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or
|
||||
* :const:`ROUND_UP` (away from zero).
|
||||
* :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero
|
||||
would have been 0 or 5; otherwise towards zero)
|
||||
The *rounding* option is one of the constants listed in the section
|
||||
`Rounding Modes`_.
|
||||
|
||||
The *traps* and *flags* fields list any signals to be set. Generally, new
|
||||
contexts should only set traps and leave the flags clear.
|
||||
|
||||
The *Emin* and *Emax* fields are integers specifying the outer limits allowable
|
||||
for exponents.
|
||||
for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`],
|
||||
*Emax* in the range [:const:`0`, :const:`MAX_EMAX`].
|
||||
|
||||
The *capitals* field is either :const:`0` or :const:`1` (the default). If set to
|
||||
:const:`1`, exponents are printed with a capital :const:`E`; otherwise, a
|
||||
|
@ -951,6 +980,12 @@ In addition to the three supplied contexts, new contexts can be created with the
|
|||
|
||||
Resets all of the flags to :const:`0`.
|
||||
|
||||
.. method:: clear_traps()
|
||||
|
||||
Resets all of the traps to :const:`0`.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. method:: copy()
|
||||
|
||||
Return a duplicate of the context.
|
||||
|
@ -1250,8 +1285,13 @@ In addition to the three supplied contexts, new contexts can be created with the
|
|||
With two arguments, compute ``x**y``. If ``x`` is negative then ``y``
|
||||
must be integral. The result will be inexact unless ``y`` is integral and
|
||||
the result is finite and can be expressed exactly in 'precision' digits.
|
||||
The result should always be correctly rounded, using the rounding mode of
|
||||
the current thread's context.
|
||||
The rounding mode of the context is used. Results are always correctly-rounded
|
||||
in the Python version.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
The C module computes :meth:`power` in terms of the correctly-rounded
|
||||
:meth:`exp` and :meth:`ln` functions. The result is well-defined but
|
||||
only "almost always correctly-rounded".
|
||||
|
||||
With three arguments, compute ``(x**y) % modulo``. For the three argument
|
||||
form, the following restrictions on the arguments hold:
|
||||
|
@ -1339,6 +1379,66 @@ In addition to the three supplied contexts, new contexts can be created with the
|
|||
|
||||
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
.. _decimal-rounding-modes:
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
The constants in this section are only relevant for the C module. They
|
||||
are also included in the pure Python version for compatibility.
|
||||
|
||||
+--------------------+---------------------+------------------------------+
|
||||
| | 32-bit | 64-bit |
|
||||
+====================+=====================+==============================+
|
||||
| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` |
|
||||
+--------------------+---------------------+------------------------------+
|
||||
| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` |
|
||||
+--------------------+---------------------+------------------------------+
|
||||
| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` |
|
||||
+--------------------+---------------------+------------------------------+
|
||||
|
||||
.. data:: HAVE_THREADS
|
||||
|
||||
The default value is True. If Python is compiled without threads, the
|
||||
C version automatically disables the expensive thread local context
|
||||
machinery. In this case, the value is False.
|
||||
|
||||
Rounding modes
|
||||
--------------
|
||||
|
||||
.. data:: ROUND_CEILING
|
||||
|
||||
Round towards :const:`Infinity`.
|
||||
|
||||
.. data:: ROUND_DOWN
|
||||
|
||||
Round towards zero.
|
||||
|
||||
.. data:: ROUND_FLOOR
|
||||
|
||||
Round towards :const:`-Infinity`.
|
||||
|
||||
.. data:: ROUND_HALF_DOWN
|
||||
|
||||
Round to nearest with ties going towards zero.
|
||||
|
||||
.. data:: ROUND_HALF_EVEN
|
||||
|
||||
Round to nearest with ties going to nearest even integer.
|
||||
|
||||
.. data:: ROUND_HALF_UP
|
||||
|
||||
Round to nearest with ties going away from zero.
|
||||
|
||||
.. data:: ROUND_UP
|
||||
|
||||
Round away from zero.
|
||||
|
||||
.. data:: ROUND_05UP
|
||||
|
||||
Round away from zero if last digit after rounding towards zero would have
|
||||
been 0 or 5; otherwise round towards zero.
|
||||
|
||||
|
||||
.. _decimal-signals:
|
||||
|
||||
|
@ -1403,7 +1503,6 @@ condition.
|
|||
Infinity / Infinity
|
||||
x % 0
|
||||
Infinity % x
|
||||
x._rescale( non-integer )
|
||||
sqrt(-x) and x > 0
|
||||
0 ** 0
|
||||
x ** (non-integer)
|
||||
|
@ -1446,6 +1545,23 @@ condition.
|
|||
Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact`
|
||||
and :class:`Subnormal` are also signaled.
|
||||
|
||||
|
||||
.. class:: FloatOperation
|
||||
|
||||
Enable stricter semantics for mixing floats and Decimals.
|
||||
|
||||
If the signal is not trapped (default), mixing floats and Decimals is
|
||||
permitted in the :class:`~decimal.Decimal` constructor,
|
||||
:meth:`~decimal.Context.create_decimal` and all comparison operators.
|
||||
Both conversion and comparisons are exact. Any occurrence of a mixed
|
||||
operation is silently recorded by setting :exc:`FloatOperation` in the
|
||||
context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float`
|
||||
or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag.
|
||||
|
||||
Otherwise (the signal is trapped), only equality comparisons and explicit
|
||||
conversions are silent. All other mixed operations raise :exc:`FloatOperation`.
|
||||
|
||||
|
||||
The following table summarizes the hierarchy of signals::
|
||||
|
||||
exceptions.ArithmeticError(exceptions.Exception)
|
||||
|
@ -1458,10 +1574,12 @@ The following table summarizes the hierarchy of signals::
|
|||
InvalidOperation
|
||||
Rounded
|
||||
Subnormal
|
||||
FloatOperation
|
||||
|
||||
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
.. _decimal-notes:
|
||||
|
||||
Floating Point Notes
|
||||
|
@ -1571,7 +1689,7 @@ normalized floating point representations, it is not immediately obvious that
|
|||
the following calculation returns a value equal to zero:
|
||||
|
||||
>>> 1 / Decimal('Infinity')
|
||||
Decimal('0E-1000000026')
|
||||
Decimal('0E-1000026')
|
||||
|
||||
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
@ -1583,7 +1701,7 @@ Working with threads
|
|||
|
||||
The :func:`getcontext` function accesses a different :class:`Context` object for
|
||||
each thread. Having separate thread contexts means that threads may make
|
||||
changes (such as ``getcontext.prec=10``) without interfering with other threads.
|
||||
changes (such as ``getcontext().prec=10``) without interfering with other threads.
|
||||
|
||||
Likewise, the :func:`setcontext` function automatically assigns its target to
|
||||
the current thread.
|
||||
|
|
|
@ -8,9 +8,9 @@ Numeric and Mathematical Modules
|
|||
The modules described in this chapter provide numeric and math-related functions
|
||||
and data types. The :mod:`numbers` module defines an abstract hierarchy of
|
||||
numeric types. The :mod:`math` and :mod:`cmath` modules contain various
|
||||
mathematical functions for floating-point and complex numbers. For users more
|
||||
interested in decimal accuracy than in speed, the :mod:`decimal` module supports
|
||||
exact representations of decimal numbers.
|
||||
mathematical functions for floating-point and complex numbers. The :mod:`decimal`
|
||||
module supports exact representations of decimal numbers, using arbitrary precision
|
||||
arithmetic.
|
||||
|
||||
The following modules are documented in this chapter:
|
||||
|
||||
|
|
|
@ -596,6 +596,93 @@ curses
|
|||
|
||||
(Contributed by Iñigo Serna in :issue:`6755`)
|
||||
|
||||
decimal
|
||||
-------
|
||||
|
||||
:issue:`7652` - integrate fast native decimal arithmetic.
|
||||
C-module and libmpdec written by Stefan Krah.
|
||||
|
||||
The new C version of the decimal module integrates the high speed libmpdec
|
||||
library for arbitrary precision correctly-rounded decimal arithmetic.
|
||||
libmpdec conforms to IBM's General Decimal Arithmetic Specification.
|
||||
|
||||
Performance gains range from 12x for database applications to 80x for
|
||||
numerically intensive applications:
|
||||
|
||||
+---------+-------------+--------------+-------------+
|
||||
| | decimal.py | _decimal | speedup |
|
||||
+=========+=============+==============+=============+
|
||||
| pi | 42.75s | 0.58s | 74x |
|
||||
+---------+-------------+--------------+-------------+
|
||||
| telco | 172.19s | 5.68s | 30x |
|
||||
+---------+-------------+--------------+-------------+
|
||||
| psycopg | 3.57s | 0.29s | 12x |
|
||||
+---------+-------------+--------------+-------------+
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
* The :exc:`~decimal.FloatOperation` signal optionally enables stricter
|
||||
semantics for mixing floats and Decimals.
|
||||
|
||||
* If Python is compiled without threads, the C version automatically
|
||||
disables the expensive thread local context machinery. In this case,
|
||||
the variable :data:`~decimal.HAVE_THREADS` is set to False.
|
||||
|
||||
API changes
|
||||
~~~~~~~~~~~
|
||||
|
||||
* The C module has the following context limits, depending on the machine
|
||||
architecture:
|
||||
|
||||
+-------------------+---------------------+------------------------------+
|
||||
| | 32-bit | 64-bit |
|
||||
+===================+=====================+==============================+
|
||||
| :const:`MAX_PREC` | :const:`425000000` | :const:`999999999999999999` |
|
||||
+-------------------+---------------------+------------------------------+
|
||||
| :const:`MAX_EMAX` | :const:`425000000` | :const:`999999999999999999` |
|
||||
+-------------------+---------------------+------------------------------+
|
||||
| :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` |
|
||||
+-------------------+---------------------+------------------------------+
|
||||
|
||||
* In the context templates (:class:`~decimal.DefaultContext`,
|
||||
:class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`)
|
||||
the magnitude of :attr:`~decimal.Context.Emax` and
|
||||
:attr:`~decimal.Context.Emin` has changed to :const:`999999`.
|
||||
|
||||
* The :class:`~decimal.Decimal` constructor in decimal.py does not observe
|
||||
the context limits and converts values with arbitrary exponents or precision
|
||||
exactly. Since the C version has internal limits, the following scheme is
|
||||
used: If possible, values are converted exactly, otherwise
|
||||
:exc:`~decimal.InvalidOperation` is raised and the result is NaN. In the
|
||||
latter case it is always possible to use :meth:`~decimal.Context.create_decimal`
|
||||
in order to obtain a rounded or inexact value.
|
||||
|
||||
|
||||
* The power function in decimal.py is always correctly-rounded. In the
|
||||
C version, it is defined in terms of the correctly-rounded
|
||||
:meth:`~decimal.Decimal.exp` and :meth:`~decimal.Decimal.ln` functions,
|
||||
but the final result is only "almost always correctly rounded".
|
||||
|
||||
|
||||
* In the C version, the context dictionary containing the signals is a
|
||||
:class:`~collections.abc.MutableMapping`. For speed reasons,
|
||||
:attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` always
|
||||
refer to the same :class:`~collections.abc.MutableMapping` that the context
|
||||
was initialized with. If a new signal dictionary is assigned,
|
||||
:attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps`
|
||||
are updated with the new values, but they do not reference the RHS
|
||||
dictionary.
|
||||
|
||||
|
||||
* Pickling a :class:`~decimal.Context` produces a different output in order
|
||||
to have a common interchange format for the Python and C versions.
|
||||
|
||||
|
||||
* The order of arguments in the :class:`~decimal.Context` constructor has been
|
||||
changed to match the order displayed by :func:`repr`.
|
||||
|
||||
|
||||
faulthandler
|
||||
------------
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
|
||||
/* This is published for the benefit of "friend" marshal.c only. */
|
||||
/* This is published for the benefit of "friends" marshal.c and _decimal.c. */
|
||||
|
||||
/* Parameters of the long integer representation. There are two different
|
||||
sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit
|
||||
|
|
192
Lib/decimal.py
192
Lib/decimal.py
|
@ -46,8 +46,8 @@ Decimal('1')
|
|||
Decimal('-0.0123')
|
||||
>>> Decimal(123456)
|
||||
Decimal('123456')
|
||||
>>> Decimal('123.45e12345678901234567890')
|
||||
Decimal('1.2345E+12345678901234567892')
|
||||
>>> Decimal('123.45e12345678')
|
||||
Decimal('1.2345E+12345680')
|
||||
>>> Decimal('1.33') + Decimal('1.27')
|
||||
Decimal('2.60')
|
||||
>>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41')
|
||||
|
@ -122,13 +122,20 @@ __all__ = [
|
|||
# Exceptions
|
||||
'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero',
|
||||
'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow',
|
||||
'FloatOperation',
|
||||
|
||||
# Constants for use in setting up contexts
|
||||
'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING',
|
||||
'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP',
|
||||
|
||||
# Functions for manipulating contexts
|
||||
'setcontext', 'getcontext', 'localcontext'
|
||||
'setcontext', 'getcontext', 'localcontext',
|
||||
|
||||
# Limits for the C version for compatibility
|
||||
'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY',
|
||||
|
||||
# C version: compile time choice that enables the thread local context
|
||||
'HAVE_THREADS'
|
||||
]
|
||||
|
||||
__version__ = '1.70' # Highest version of the spec this complies with
|
||||
|
@ -137,6 +144,7 @@ __version__ = '1.70' # Highest version of the spec this complies with
|
|||
import copy as _copy
|
||||
import math as _math
|
||||
import numbers as _numbers
|
||||
import sys
|
||||
|
||||
try:
|
||||
from collections import namedtuple as _namedtuple
|
||||
|
@ -154,6 +162,19 @@ ROUND_UP = 'ROUND_UP'
|
|||
ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
|
||||
ROUND_05UP = 'ROUND_05UP'
|
||||
|
||||
# Compatibility with the C version
|
||||
HAVE_THREADS = True
|
||||
if sys.maxsize == 2**63-1:
|
||||
MAX_PREC = 999999999999999999
|
||||
MAX_EMAX = 999999999999999999
|
||||
MIN_EMIN = -999999999999999999
|
||||
else:
|
||||
MAX_PREC = 425000000
|
||||
MAX_EMAX = 425000000
|
||||
MIN_EMIN = -425000000
|
||||
|
||||
MIN_ETINY = MIN_EMIN - (MAX_PREC-1)
|
||||
|
||||
# Errors
|
||||
|
||||
class DecimalException(ArithmeticError):
|
||||
|
@ -370,9 +391,24 @@ class Underflow(Inexact, Rounded, Subnormal):
|
|||
In all cases, Inexact, Rounded, and Subnormal will also be raised.
|
||||
"""
|
||||
|
||||
class FloatOperation(DecimalException):
|
||||
"""Enable stricter semantics for mixing floats and Decimals.
|
||||
|
||||
If the signal is not trapped (default), mixing floats and Decimals is
|
||||
permitted in the Decimal() constructor, context.create_decimal() and
|
||||
all comparison operators. Both conversion and comparisons are exact.
|
||||
Any occurrence of a mixed operation is silently recorded by setting
|
||||
FloatOperation in the context flags. Explicit conversions with
|
||||
Decimal.from_float() or context.create_decimal_from_float() do not
|
||||
set the flag.
|
||||
|
||||
Otherwise (the signal is trapped), only equality comparisons and explicit
|
||||
conversions are silent. All other mixed operations raise FloatOperation.
|
||||
"""
|
||||
|
||||
# List of public traps and flags
|
||||
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
|
||||
Underflow, InvalidOperation, Subnormal]
|
||||
Underflow, InvalidOperation, Subnormal, FloatOperation]
|
||||
|
||||
# Map conditions (per the spec) to signals
|
||||
_condition_map = {ConversionSyntax:InvalidOperation,
|
||||
|
@ -380,6 +416,10 @@ _condition_map = {ConversionSyntax:InvalidOperation,
|
|||
DivisionUndefined:InvalidOperation,
|
||||
InvalidContext:InvalidOperation}
|
||||
|
||||
# Valid rounding modes
|
||||
_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING,
|
||||
ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP)
|
||||
|
||||
##### Context Functions ##################################################
|
||||
|
||||
# The getcontext() and setcontext() function manage access to a thread-local
|
||||
|
@ -392,12 +432,11 @@ try:
|
|||
import threading
|
||||
except ImportError:
|
||||
# Python was compiled without threads; create a mock object instead
|
||||
import sys
|
||||
class MockThreading(object):
|
||||
def local(self, sys=sys):
|
||||
return sys.modules[__name__]
|
||||
threading = MockThreading()
|
||||
del sys, MockThreading
|
||||
del MockThreading
|
||||
|
||||
try:
|
||||
threading.local
|
||||
|
@ -650,6 +689,11 @@ class Decimal(object):
|
|||
return self
|
||||
|
||||
if isinstance(value, float):
|
||||
if context is None:
|
||||
context = getcontext()
|
||||
context._raise_error(FloatOperation,
|
||||
"strict semantics for mixing floats and Decimals are "
|
||||
"enabled")
|
||||
value = Decimal.from_float(value)
|
||||
self._exp = value._exp
|
||||
self._sign = value._sign
|
||||
|
@ -684,7 +728,9 @@ class Decimal(object):
|
|||
"""
|
||||
if isinstance(f, int): # handle integer inputs
|
||||
return cls(f)
|
||||
if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float
|
||||
if not isinstance(f, float):
|
||||
raise TypeError("argument must be int or float.")
|
||||
if _math.isinf(f) or _math.isnan(f):
|
||||
return cls(repr(f))
|
||||
if _math.copysign(1.0, f) == 1.0:
|
||||
sign = 0
|
||||
|
@ -1906,11 +1952,12 @@ class Decimal(object):
|
|||
def _power_modulo(self, other, modulo, context=None):
|
||||
"""Three argument version of __pow__"""
|
||||
|
||||
# if can't convert other and modulo to Decimal, raise
|
||||
# TypeError; there's no point returning NotImplemented (no
|
||||
# equivalent of __rpow__ for three argument pow)
|
||||
other = _convert_other(other, raiseit=True)
|
||||
modulo = _convert_other(modulo, raiseit=True)
|
||||
other = _convert_other(other)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
modulo = _convert_other(modulo)
|
||||
if modulo is NotImplemented:
|
||||
return modulo
|
||||
|
||||
if context is None:
|
||||
context = getcontext()
|
||||
|
@ -3832,10 +3879,8 @@ class Context(object):
|
|||
clamp - If 1, change exponents if too high (Default 0)
|
||||
"""
|
||||
|
||||
def __init__(self, prec=None, rounding=None,
|
||||
traps=None, flags=None,
|
||||
Emin=None, Emax=None,
|
||||
capitals=None, clamp=None,
|
||||
def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
|
||||
capitals=None, clamp=None, flags=None, traps=None,
|
||||
_ignored_flags=None):
|
||||
# Set defaults; for everything except flags and _ignored_flags,
|
||||
# inherit from DefaultContext.
|
||||
|
@ -3859,17 +3904,78 @@ class Context(object):
|
|||
if traps is None:
|
||||
self.traps = dc.traps.copy()
|
||||
elif not isinstance(traps, dict):
|
||||
self.traps = dict((s, int(s in traps)) for s in _signals)
|
||||
self.traps = dict((s, int(s in traps)) for s in _signals + traps)
|
||||
else:
|
||||
self.traps = traps
|
||||
|
||||
if flags is None:
|
||||
self.flags = dict.fromkeys(_signals, 0)
|
||||
elif not isinstance(flags, dict):
|
||||
self.flags = dict((s, int(s in flags)) for s in _signals)
|
||||
self.flags = dict((s, int(s in flags)) for s in _signals + flags)
|
||||
else:
|
||||
self.flags = flags
|
||||
|
||||
def _set_integer_check(self, name, value, vmin, vmax):
|
||||
if not isinstance(value, int):
|
||||
raise TypeError("%s must be an integer" % name)
|
||||
if vmin == '-inf':
|
||||
if value > vmax:
|
||||
raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value))
|
||||
elif vmax == 'inf':
|
||||
if value < vmin:
|
||||
raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value))
|
||||
else:
|
||||
if value < vmin or value > vmax:
|
||||
raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value))
|
||||
return object.__setattr__(self, name, value)
|
||||
|
||||
def _set_signal_dict(self, name, d):
|
||||
if not isinstance(d, dict):
|
||||
raise TypeError("%s must be a signal dict" % d)
|
||||
for key in d:
|
||||
if not key in _signals:
|
||||
raise KeyError("%s is not a valid signal dict" % d)
|
||||
for key in _signals:
|
||||
if not key in d:
|
||||
raise KeyError("%s is not a valid signal dict" % d)
|
||||
return object.__setattr__(self, name, d)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name == 'prec':
|
||||
return self._set_integer_check(name, value, 1, 'inf')
|
||||
elif name == 'Emin':
|
||||
return self._set_integer_check(name, value, '-inf', 0)
|
||||
elif name == 'Emax':
|
||||
return self._set_integer_check(name, value, 0, 'inf')
|
||||
elif name == 'capitals':
|
||||
return self._set_integer_check(name, value, 0, 1)
|
||||
elif name == 'clamp':
|
||||
return self._set_integer_check(name, value, 0, 1)
|
||||
elif name == 'rounding':
|
||||
if not value in _rounding_modes:
|
||||
# raise TypeError even for strings to have consistency
|
||||
# among various implementations.
|
||||
raise TypeError("%s: invalid rounding mode" % value)
|
||||
return object.__setattr__(self, name, value)
|
||||
elif name == 'flags' or name == 'traps':
|
||||
return self._set_signal_dict(name, value)
|
||||
elif name == '_ignored_flags':
|
||||
return object.__setattr__(self, name, value)
|
||||
else:
|
||||
raise AttributeError(
|
||||
"'decimal.Context' object has no attribute '%s'" % name)
|
||||
|
||||
def __delattr__(self, name):
|
||||
raise AttributeError("%s cannot be deleted" % name)
|
||||
|
||||
# Support for pickling, copy, and deepcopy
|
||||
def __reduce__(self):
|
||||
flags = [sig for sig, v in self.flags.items() if v]
|
||||
traps = [sig for sig, v in self.traps.items() if v]
|
||||
return (self.__class__,
|
||||
(self.prec, self.rounding, self.Emin, self.Emax,
|
||||
self.capitals, self.clamp, flags, traps))
|
||||
|
||||
def __repr__(self):
|
||||
"""Show the current context."""
|
||||
s = []
|
||||
|
@ -3888,18 +3994,24 @@ class Context(object):
|
|||
for flag in self.flags:
|
||||
self.flags[flag] = 0
|
||||
|
||||
def clear_traps(self):
|
||||
"""Reset all traps to zero"""
|
||||
for flag in self.traps:
|
||||
self.traps[flag] = 0
|
||||
|
||||
def _shallow_copy(self):
|
||||
"""Returns a shallow copy from self."""
|
||||
nc = Context(self.prec, self.rounding, self.traps,
|
||||
self.flags, self.Emin, self.Emax,
|
||||
self.capitals, self.clamp, self._ignored_flags)
|
||||
nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
|
||||
self.capitals, self.clamp, self.flags, self.traps,
|
||||
self._ignored_flags)
|
||||
return nc
|
||||
|
||||
def copy(self):
|
||||
"""Returns a deep copy from self."""
|
||||
nc = Context(self.prec, self.rounding, self.traps.copy(),
|
||||
self.flags.copy(), self.Emin, self.Emax,
|
||||
self.capitals, self.clamp, self._ignored_flags)
|
||||
nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
|
||||
self.capitals, self.clamp,
|
||||
self.flags.copy(), self.traps.copy(),
|
||||
self._ignored_flags)
|
||||
return nc
|
||||
__copy__ = copy
|
||||
|
||||
|
@ -4062,6 +4174,8 @@ class Context(object):
|
|||
>>> ExtendedContext.canonical(Decimal('2.50'))
|
||||
Decimal('2.50')
|
||||
"""
|
||||
if not isinstance(a, Decimal):
|
||||
raise TypeError("canonical requires a Decimal as an argument.")
|
||||
return a.canonical(context=self)
|
||||
|
||||
def compare(self, a, b):
|
||||
|
@ -4372,6 +4486,8 @@ class Context(object):
|
|||
>>> ExtendedContext.is_canonical(Decimal('2.50'))
|
||||
True
|
||||
"""
|
||||
if not isinstance(a, Decimal):
|
||||
raise TypeError("is_canonical requires a Decimal as an argument.")
|
||||
return a.is_canonical()
|
||||
|
||||
def is_finite(self, a):
|
||||
|
@ -4964,7 +5080,7 @@ class Context(object):
|
|||
+Normal
|
||||
+Infinity
|
||||
|
||||
>>> c = Context(ExtendedContext)
|
||||
>>> c = ExtendedContext.copy()
|
||||
>>> c.Emin = -999
|
||||
>>> c.Emax = 999
|
||||
>>> c.number_class(Decimal('Infinity'))
|
||||
|
@ -5916,6 +6032,12 @@ def _convert_for_comparison(self, other, equality_op=False):
|
|||
if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
|
||||
other = other.real
|
||||
if isinstance(other, float):
|
||||
context = getcontext()
|
||||
if equality_op:
|
||||
context.flags[FloatOperation] = 1
|
||||
else:
|
||||
context._raise_error(FloatOperation,
|
||||
"strict semantics for mixing floats and Decimals are enabled")
|
||||
return self, Decimal.from_float(other)
|
||||
return NotImplemented, NotImplemented
|
||||
|
||||
|
@ -5929,8 +6051,8 @@ DefaultContext = Context(
|
|||
prec=28, rounding=ROUND_HALF_EVEN,
|
||||
traps=[DivisionByZero, Overflow, InvalidOperation],
|
||||
flags=[],
|
||||
Emax=999999999,
|
||||
Emin=-999999999,
|
||||
Emax=999999,
|
||||
Emin=-999999,
|
||||
capitals=1,
|
||||
clamp=0
|
||||
)
|
||||
|
@ -6080,7 +6202,7 @@ def _parse_format_specifier(format_spec, _localeconv=None):
|
|||
# if format type is 'g' or 'G' then a precision of 0 makes little
|
||||
# sense; convert it to 1. Same if format type is unspecified.
|
||||
if format_dict['precision'] == 0:
|
||||
if format_dict['type'] is None or format_dict['type'] in 'gG':
|
||||
if format_dict['type'] is None or format_dict['type'] in 'gGn':
|
||||
format_dict['precision'] = 1
|
||||
|
||||
# determine thousands separator, grouping, and decimal separator, and
|
||||
|
@ -6254,16 +6376,26 @@ _SignedInfinity = (_Infinity, _NegativeInfinity)
|
|||
|
||||
# Constants related to the hash implementation; hash(x) is based
|
||||
# on the reduction of x modulo _PyHASH_MODULUS
|
||||
import sys
|
||||
_PyHASH_MODULUS = sys.hash_info.modulus
|
||||
# hash values to use for positive and negative infinities, and nans
|
||||
_PyHASH_INF = sys.hash_info.inf
|
||||
_PyHASH_NAN = sys.hash_info.nan
|
||||
del sys
|
||||
|
||||
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
|
||||
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
|
||||
del sys
|
||||
|
||||
try:
|
||||
import _decimal
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
s1 = set(dir())
|
||||
s2 = set(dir(_decimal))
|
||||
for name in s1 - s2:
|
||||
del globals()[name]
|
||||
del s1, s2, name
|
||||
from _decimal import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest, decimal
|
||||
|
|
|
@ -1416,7 +1416,7 @@ def run_unittest(*classes):
|
|||
#=======================================================================
|
||||
# doctest driver.
|
||||
|
||||
def run_doctest(module, verbosity=None):
|
||||
def run_doctest(module, verbosity=None, optionflags=0):
|
||||
"""Run doctest on the given module. Return (#failures, #tests).
|
||||
|
||||
If optional argument verbosity is not specified (or is None), pass
|
||||
|
@ -1431,7 +1431,7 @@ def run_doctest(module, verbosity=None):
|
|||
else:
|
||||
verbosity = None
|
||||
|
||||
f, t = doctest.testmod(module, verbose=verbosity)
|
||||
f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags)
|
||||
if f:
|
||||
raise TestFailed("%d of %d doctests failed" % (f, t))
|
||||
if verbose:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -401,14 +401,10 @@ class FractionTest(unittest.TestCase):
|
|||
|
||||
def testMixingWithDecimal(self):
|
||||
# Decimal refuses mixed arithmetic (but not mixed comparisons)
|
||||
self.assertRaisesMessage(
|
||||
TypeError,
|
||||
"unsupported operand type(s) for +: 'Fraction' and 'Decimal'",
|
||||
operator.add, F(3,11), Decimal('3.1415926'))
|
||||
self.assertRaisesMessage(
|
||||
TypeError,
|
||||
"unsupported operand type(s) for +: 'Decimal' and 'Fraction'",
|
||||
operator.add, Decimal('3.1415926'), F(3,11))
|
||||
self.assertRaises(TypeError, operator.add,
|
||||
F(3,11), Decimal('3.1415926'))
|
||||
self.assertRaises(TypeError, operator.add,
|
||||
Decimal('3.1415926'), F(3,11))
|
||||
|
||||
def testComparisons(self):
|
||||
self.assertTrue(F(1, 2) < F(2, 3))
|
||||
|
|
|
@ -150,7 +150,7 @@ class ComparisonTest(unittest.TestCase):
|
|||
# int, float, Fraction, Decimal
|
||||
test_values = [
|
||||
float('-inf'),
|
||||
D('-1e999999999'),
|
||||
D('-1e425000000'),
|
||||
-1e308,
|
||||
F(-22, 7),
|
||||
-3.14,
|
||||
|
|
|
@ -30,6 +30,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #7652: Integrate the decimal floating point libmpdec library to speed
|
||||
up the decimal module. Performance gains of the new C implementation are
|
||||
between 12x and 80x, depending on the application.
|
||||
|
||||
- Issue #3573: IDLE hangs when passing invalid command line args
|
||||
(directory(ies) instead of file(s)) (Patch by Guilherme Polo)
|
||||
|
||||
|
|
|
@ -456,3 +456,16 @@
|
|||
fun:PyUnicode_FSConverter
|
||||
}
|
||||
|
||||
# Additional suppressions for the unified decimal tests:
|
||||
{
|
||||
test_decimal
|
||||
Memcheck:Addr4
|
||||
fun:PyUnicodeUCS2_FSConverter
|
||||
}
|
||||
|
||||
{
|
||||
test_decimal2
|
||||
Memcheck:Addr4
|
||||
fun:PyUnicode_FSConverter
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
@ -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).
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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))
|
|
@ -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/
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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/
|
||||
|
||||
|
|
@ -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)))))))
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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_ ]
|
|
@ -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]
|
||||
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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 "$(IntDir)\vcdiv64.obj" "$(InputPath)"
"
|
||||
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 "$(IntDir)\vcdiv64.obj" "$(InputPath)"
"
|
||||
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 "$(IntDir)\vcdiv64.obj" "$(InputPath)"
"
|
||||
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 "$(IntDir)\vcdiv64.obj" "$(InputPath)"
"
|
||||
Outputs="$(IntDir)\vcdiv64.obj"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -38,6 +38,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winsound", "winsound.vcproj
|
|||
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_decimal", "_decimal.vcproj", "{0E9791DB-593A-465F-98BC-681011311617}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes", "_ctypes.vcproj", "{0E9791DB-593A-465F-98BC-681011311618}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}
|
||||
|
@ -271,6 +276,22 @@ Global
|
|||
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.Build.0 = Release|Win32
|
||||
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64
|
||||
{28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = Release|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.Build.0 = PGInstrument|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.Build.0 = PGUpdate|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.Build.0 = Release|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Release|x64.ActiveCfg = Release|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311617}.Release|x64.Build.0 = Release|x64
|
||||
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
|
|
@ -6863,6 +6863,13 @@ $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h
|
|||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default"
|
||||
if test "x$ac_cv_type___uint128_t" = xyes; then :
|
||||
|
||||
$as_echo "#define HAVE_GCC_UINT128_T 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Sizes of various common basic types
|
||||
# ANSI C requires sizeof(char) == 1, so no need to check it
|
||||
|
@ -12034,6 +12041,40 @@ $as_echo "default LIBC=\"$LIBC\"" >&6; }
|
|||
fi
|
||||
|
||||
|
||||
# **************************************
|
||||
# * Check for gcc x64 inline assembler *
|
||||
# **************************************
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5
|
||||
$as_echo_n "checking for x64 gcc inline assembler... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
__asm__ __volatile__ ("movq %rcx, %rax");
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
have_gcc_asm_for_x64=yes
|
||||
else
|
||||
have_gcc_asm_for_x64=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5
|
||||
$as_echo "$have_gcc_asm_for_x64" >&6; }
|
||||
if test "$have_gcc_asm_for_x64" = yes
|
||||
then
|
||||
|
||||
$as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# **************************************************
|
||||
# * Check for various properties of floating point *
|
||||
# **************************************************
|
||||
|
@ -14228,6 +14269,136 @@ done
|
|||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
|
||||
$as_echo "done" >&6; }
|
||||
|
||||
# Availability of -O2:
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5
|
||||
$as_echo_n "checking for -O2... " >&6; }
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
have_O2=yes
|
||||
else
|
||||
have_O2=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_O2" >&5
|
||||
$as_echo "$have_O2" >&6; }
|
||||
CFLAGS="$saved_cflags"
|
||||
|
||||
# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
|
||||
# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5
|
||||
$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; }
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2 -D_FORTIFY_SOURCE=2"
|
||||
if test "$have_O2" = no; then
|
||||
CFLAGS=""
|
||||
fi
|
||||
if test "$cross_compiling" = yes; then :
|
||||
have_glibc_memmove_bug=undefined
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
void foo(void *p, void *q) { memmove(p, q, 19); }
|
||||
int main() {
|
||||
char a[32] = "123456789000000000";
|
||||
foo(&a[9], a);
|
||||
if (strcmp(a, "123456789123456789000000000") != 0)
|
||||
return 1;
|
||||
foo(a, &a[9]);
|
||||
if (strcmp(a, "123456789000000000") != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_run "$LINENO"; then :
|
||||
have_glibc_memmove_bug=no
|
||||
else
|
||||
have_glibc_memmove_bug=yes
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
CFLAGS="$saved_cflags"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5
|
||||
$as_echo "$have_glibc_memmove_bug" >&6; }
|
||||
if test "$have_glibc_memmove_bug" = yes; then
|
||||
|
||||
$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
if test "$have_gcc_asm_for_x87" = yes; then
|
||||
# Some versions of gcc miscompile inline asm:
|
||||
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
|
||||
# http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
|
||||
case $CC in
|
||||
*gcc*)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5
|
||||
$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; }
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2"
|
||||
if test "$cross_compiling" = yes; then :
|
||||
have_ipa_pure_const_bug=undefined
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
__attribute__((noinline)) int
|
||||
foo(int *p) {
|
||||
int r;
|
||||
asm ( "movl \$6, (%1)\n\t"
|
||||
"xorl %0, %0\n\t"
|
||||
: "=r" (r) : "r" (p) : "memory"
|
||||
);
|
||||
return r;
|
||||
}
|
||||
int main() {
|
||||
int p = 8;
|
||||
if ((foo(&p) ? : p) != 6)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_run "$LINENO"; then :
|
||||
have_ipa_pure_const_bug=no
|
||||
else
|
||||
have_ipa_pure_const_bug=yes
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
CFLAGS="$saved_cflags"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5
|
||||
$as_echo "$have_ipa_pure_const_bug" >&6; }
|
||||
if test "$have_ipa_pure_const_bug" = yes; then
|
||||
|
||||
$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# generate output files
|
||||
ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc"
|
||||
|
||||
|
|
100
configure.ac
100
configure.ac
|
@ -1483,6 +1483,8 @@ AC_TYPE_INT32_T
|
|||
AC_TYPE_INT64_T
|
||||
AC_CHECK_TYPE(ssize_t,
|
||||
AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides ssize_t]),,)
|
||||
AC_CHECK_TYPE(__uint128_t,
|
||||
AC_DEFINE(HAVE_GCC_UINT128_T, 1, [Define if your compiler provides __uint128_t]),,)
|
||||
|
||||
# Sizes of various common basic types
|
||||
# ANSI C requires sizeof(char) == 1, so no need to check it
|
||||
|
@ -3329,6 +3331,21 @@ else AC_MSG_ERROR([proper usage is --with-libc=STRING])
|
|||
fi],
|
||||
[AC_MSG_RESULT(default LIBC="$LIBC")])
|
||||
|
||||
# **************************************
|
||||
# * Check for gcc x64 inline assembler *
|
||||
# **************************************
|
||||
|
||||
AC_MSG_CHECKING(for x64 gcc inline assembler)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
__asm__ __volatile__ ("movq %rcx, %rax");
|
||||
]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no])
|
||||
AC_MSG_RESULT($have_gcc_asm_for_x64)
|
||||
if test "$have_gcc_asm_for_x64" = yes
|
||||
then
|
||||
AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1,
|
||||
[Define if we can use x64 gcc inline assembler])
|
||||
fi
|
||||
|
||||
# **************************************************
|
||||
# * Check for various properties of floating point *
|
||||
# **************************************************
|
||||
|
@ -4333,6 +4350,89 @@ for dir in $SRCDIRS; do
|
|||
done
|
||||
AC_MSG_RESULT(done)
|
||||
|
||||
# Availability of -O2:
|
||||
AC_MSG_CHECKING(for -O2)
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
|
||||
]])],[have_O2=yes],[have_O2=no])
|
||||
AC_MSG_RESULT($have_O2)
|
||||
CFLAGS="$saved_cflags"
|
||||
|
||||
# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
|
||||
# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
|
||||
AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug)
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2 -D_FORTIFY_SOURCE=2"
|
||||
if test "$have_O2" = no; then
|
||||
CFLAGS=""
|
||||
fi
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
void foo(void *p, void *q) { memmove(p, q, 19); }
|
||||
int main() {
|
||||
char a[32] = "123456789000000000";
|
||||
foo(&a[9], a);
|
||||
if (strcmp(a, "123456789123456789000000000") != 0)
|
||||
return 1;
|
||||
foo(a, &a[9]);
|
||||
if (strcmp(a, "123456789000000000") != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
]])],
|
||||
[have_glibc_memmove_bug=no],
|
||||
[have_glibc_memmove_bug=yes],
|
||||
[have_glibc_memmove_bug=undefined])
|
||||
CFLAGS="$saved_cflags"
|
||||
AC_MSG_RESULT($have_glibc_memmove_bug)
|
||||
if test "$have_glibc_memmove_bug" = yes; then
|
||||
AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1,
|
||||
[Define if glibc has incorrect _FORTIFY_SOURCE wrappers
|
||||
for memmove and bcopy.])
|
||||
fi
|
||||
|
||||
if test "$have_gcc_asm_for_x87" = yes; then
|
||||
# Some versions of gcc miscompile inline asm:
|
||||
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
|
||||
# http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
|
||||
case $CC in
|
||||
*gcc*)
|
||||
AC_MSG_CHECKING(for gcc ipa-pure-const bug)
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="-O2"
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
__attribute__((noinline)) int
|
||||
foo(int *p) {
|
||||
int r;
|
||||
asm ( "movl \$6, (%1)\n\t"
|
||||
"xorl %0, %0\n\t"
|
||||
: "=r" (r) : "r" (p) : "memory"
|
||||
);
|
||||
return r;
|
||||
}
|
||||
int main() {
|
||||
int p = 8;
|
||||
if ((foo(&p) ? : p) != 6)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
]])],
|
||||
[have_ipa_pure_const_bug=no],
|
||||
[have_ipa_pure_const_bug=yes],
|
||||
[have_ipa_pure_const_bug=undefined])
|
||||
CFLAGS="$saved_cflags"
|
||||
AC_MSG_RESULT($have_ipa_pure_const_bug)
|
||||
if test "$have_ipa_pure_const_bug" = yes; then
|
||||
AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1,
|
||||
[Define if gcc has the ipa-pure-const bug.])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# generate output files
|
||||
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc)
|
||||
AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])
|
||||
|
|
|
@ -304,10 +304,16 @@
|
|||
/* Define to 1 if you have the `gamma' function. */
|
||||
#undef HAVE_GAMMA
|
||||
|
||||
/* Define if we can use x64 gcc inline assembler */
|
||||
#undef HAVE_GCC_ASM_FOR_X64
|
||||
|
||||
/* Define if we can use gcc inline assembler to get and set x87 control word
|
||||
*/
|
||||
#undef HAVE_GCC_ASM_FOR_X87
|
||||
|
||||
/* Define if your compiler provides __uint128_t */
|
||||
#undef HAVE_GCC_UINT128_T
|
||||
|
||||
/* Define if you have the getaddrinfo function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
|
@ -392,6 +398,10 @@
|
|||
/* Define to 1 if you have the `getwd' function. */
|
||||
#undef HAVE_GETWD
|
||||
|
||||
/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and
|
||||
bcopy. */
|
||||
#undef HAVE_GLIBC_MEMMOVE_BUG
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#undef HAVE_GRP_H
|
||||
|
||||
|
@ -422,6 +432,9 @@
|
|||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#undef HAVE_IO_H
|
||||
|
||||
/* Define if gcc has the ipa-pure-const bug. */
|
||||
#undef HAVE_IPA_PURE_CONST_BUG
|
||||
|
||||
/* Define to 1 if you have the `kill' function. */
|
||||
#undef HAVE_KILL
|
||||
|
||||
|
|
113
setup.py
113
setup.py
|
@ -1342,6 +1342,9 @@ class PyBuildExt(build_ext):
|
|||
exts.append(Extension('_codecs_%s' % loc,
|
||||
['cjkcodecs/_codecs_%s.c' % loc]))
|
||||
|
||||
# Stefan Krah's _decimal module
|
||||
exts.append(self._decimal_ext())
|
||||
|
||||
# Thomas Heller's _ctypes module
|
||||
self.detect_ctypes(inc_dirs, lib_dirs)
|
||||
|
||||
|
@ -1792,6 +1795,116 @@ class PyBuildExt(build_ext):
|
|||
ext.libraries.append(ffi_lib)
|
||||
self.use_system_libffi = True
|
||||
|
||||
def _decimal_ext(self):
|
||||
sources = [
|
||||
'_decimal/_decimal.c',
|
||||
'_decimal/libmpdec/basearith.c',
|
||||
'_decimal/libmpdec/constants.c',
|
||||
'_decimal/libmpdec/context.c',
|
||||
'_decimal/libmpdec/convolute.c',
|
||||
'_decimal/libmpdec/crt.c',
|
||||
'_decimal/libmpdec/difradix2.c',
|
||||
'_decimal/libmpdec/fnt.c',
|
||||
'_decimal/libmpdec/fourstep.c',
|
||||
'_decimal/libmpdec/io.c',
|
||||
'_decimal/libmpdec/memory.c',
|
||||
'_decimal/libmpdec/mpdecimal.c',
|
||||
'_decimal/libmpdec/numbertheory.c',
|
||||
'_decimal/libmpdec/sixstep.c',
|
||||
'_decimal/libmpdec/transpose.c',
|
||||
]
|
||||
depends = [
|
||||
'_decimal/docstrings.h',
|
||||
'_decimal/libmpdec/basearith.h',
|
||||
'_decimal/libmpdec/bits.h',
|
||||
'_decimal/libmpdec/constants.h',
|
||||
'_decimal/libmpdec/convolute.h',
|
||||
'_decimal/libmpdec/crt.h',
|
||||
'_decimal/libmpdec/difradix2.h',
|
||||
'_decimal/libmpdec/fnt.h',
|
||||
'_decimal/libmpdec/fourstep.h',
|
||||
'_decimal/libmpdec/io.h',
|
||||
'_decimal/libmpdec/memory.h',
|
||||
'_decimal/libmpdec/mpdecimal.h',
|
||||
'_decimal/libmpdec/numbertheory.h',
|
||||
'_decimal/libmpdec/sixstep.h',
|
||||
'_decimal/libmpdec/transpose.h',
|
||||
'_decimal/libmpdec/typearith.h',
|
||||
'_decimal/libmpdec/umodarith.h',
|
||||
]
|
||||
config = {
|
||||
'x64': [('CONFIG_64','1'), ('ASM','1')],
|
||||
'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')],
|
||||
'ansi64': [('CONFIG_64','1'), ('ANSI','1')],
|
||||
'ppro': [('CONFIG_32','1'), ('PPRO','1'), ('ASM','1')],
|
||||
'ansi32': [('CONFIG_32','1'), ('ANSI','1')],
|
||||
'ansi-legacy': [('CONFIG_32','1'), ('ANSI','1'),
|
||||
('LEGACY_COMPILER','1')],
|
||||
'universal': [('UNIVERSAL','1')]
|
||||
}
|
||||
|
||||
include_dirs = ['./Modules/_decimal/libmpdec']
|
||||
extra_compile_args = []
|
||||
undef_macros=['NDEBUG']
|
||||
|
||||
platform = self.get_platform()
|
||||
cc = sysconfig.get_config_var('CC')
|
||||
sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T')
|
||||
machine = os.environ.get('PYTHON_DECIMAL_WITH_MACHINE')
|
||||
|
||||
if machine:
|
||||
# Override automatic configuration to facilitate testing.
|
||||
define_macros = config[machine]
|
||||
elif platform == 'darwin':
|
||||
# Universal here means: build with the same options Python
|
||||
# was built with.
|
||||
define_macros = config['universal']
|
||||
elif sizeof_size_t == 8:
|
||||
if sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X64'):
|
||||
define_macros = config['x64']
|
||||
elif sysconfig.get_config_var('HAVE_GCC_UINT128_T'):
|
||||
define_macros = config['uint128']
|
||||
else:
|
||||
define_macros = config['ansi64']
|
||||
elif sizeof_size_t == 4:
|
||||
ppro = sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X87')
|
||||
if ppro and ('gcc' in cc or 'clang' in cc) and \
|
||||
not 'sunos' in platform:
|
||||
# solaris: problems with register allocation.
|
||||
# icc >= 11.0 works as well.
|
||||
define_macros = config['ppro']
|
||||
else:
|
||||
define_macros = config['ansi32']
|
||||
else:
|
||||
raise DistutilsError("_decimal: unsupported architecture")
|
||||
|
||||
# Workarounds for toolchain bugs:
|
||||
if sysconfig.get_config_var('HAVE_IPA_PURE_CONST_BUG'):
|
||||
# Some versions of gcc miscompile inline asm:
|
||||
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
|
||||
# http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
|
||||
extra_compile_args.append('-fno-ipa-pure-const')
|
||||
if sysconfig.get_config_var('HAVE_GLIBC_MEMMOVE_BUG'):
|
||||
# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
|
||||
# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
|
||||
undef_macros.append('_FORTIFY_SOURCE')
|
||||
|
||||
# Faster version without thread local contexts:
|
||||
if not sysconfig.get_config_var('WITH_THREAD'):
|
||||
define_macros.append(('WITHOUT_THREADS', 1))
|
||||
|
||||
# Uncomment for extra functionality:
|
||||
#define_macros.append(('EXTRA_FUNCTIONALITY', 1))
|
||||
ext = Extension (
|
||||
'_decimal',
|
||||
include_dirs=include_dirs,
|
||||
define_macros=define_macros,
|
||||
undef_macros=undef_macros,
|
||||
extra_compile_args=extra_compile_args,
|
||||
sources=sources,
|
||||
depends=depends
|
||||
)
|
||||
return ext
|
||||
|
||||
class PyBuildInstall(install):
|
||||
# Suppress the warning about installation into the lib_dynload
|
||||
|
|
Loading…
Reference in New Issue