mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Update {_py,}decimal.py from 3.13.5 (#6034)
This commit is contained in:
259
Lib/_pydecimal.py
vendored
259
Lib/_pydecimal.py
vendored
@@ -13,104 +13,7 @@
|
||||
# bug) and will be backported. At this point the spec is stabilizing
|
||||
# and the updates are becoming fewer, smaller, and less significant.
|
||||
|
||||
"""
|
||||
This is an implementation of decimal floating point arithmetic based on
|
||||
the General Decimal Arithmetic Specification:
|
||||
|
||||
http://speleotrove.com/decimal/decarith.html
|
||||
|
||||
and IEEE standard 854-1987:
|
||||
|
||||
http://en.wikipedia.org/wiki/IEEE_854-1987
|
||||
|
||||
Decimal floating point has finite precision with arbitrarily large bounds.
|
||||
|
||||
The purpose of this module is to support arithmetic using familiar
|
||||
"schoolhouse" rules and to avoid some of the tricky representation
|
||||
issues associated with binary floating point. The package is especially
|
||||
useful for financial applications or for contexts where users have
|
||||
expectations that are at odds with binary floating point (for instance,
|
||||
in binary floating point, 1.00 % 0.1 gives 0.09999999999999995 instead
|
||||
of 0.0; Decimal('1.00') % Decimal('0.1') returns the expected
|
||||
Decimal('0.00')).
|
||||
|
||||
Here are some examples of using the decimal module:
|
||||
|
||||
>>> from decimal import *
|
||||
>>> setcontext(ExtendedContext)
|
||||
>>> Decimal(0)
|
||||
Decimal('0')
|
||||
>>> Decimal('1')
|
||||
Decimal('1')
|
||||
>>> Decimal('-.0123')
|
||||
Decimal('-0.0123')
|
||||
>>> Decimal(123456)
|
||||
Decimal('123456')
|
||||
>>> 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')
|
||||
Decimal('-2.20')
|
||||
>>> dig = Decimal(1)
|
||||
>>> print(dig / Decimal(3))
|
||||
0.333333333
|
||||
>>> getcontext().prec = 18
|
||||
>>> print(dig / Decimal(3))
|
||||
0.333333333333333333
|
||||
>>> print(dig.sqrt())
|
||||
1
|
||||
>>> print(Decimal(3).sqrt())
|
||||
1.73205080756887729
|
||||
>>> print(Decimal(3) ** 123)
|
||||
4.85192780976896427E+58
|
||||
>>> inf = Decimal(1) / Decimal(0)
|
||||
>>> print(inf)
|
||||
Infinity
|
||||
>>> neginf = Decimal(-1) / Decimal(0)
|
||||
>>> print(neginf)
|
||||
-Infinity
|
||||
>>> print(neginf + inf)
|
||||
NaN
|
||||
>>> print(neginf * inf)
|
||||
-Infinity
|
||||
>>> print(dig / 0)
|
||||
Infinity
|
||||
>>> getcontext().traps[DivisionByZero] = 1
|
||||
>>> print(dig / 0)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
...
|
||||
...
|
||||
decimal.DivisionByZero: x / 0
|
||||
>>> c = Context()
|
||||
>>> c.traps[InvalidOperation] = 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
0
|
||||
>>> c.divide(Decimal(0), Decimal(0))
|
||||
Decimal('NaN')
|
||||
>>> c.traps[InvalidOperation] = 1
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>> c.flags[InvalidOperation] = 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
0
|
||||
>>> print(c.divide(Decimal(0), Decimal(0)))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
...
|
||||
...
|
||||
decimal.InvalidOperation: 0 / 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>> c.flags[InvalidOperation] = 0
|
||||
>>> c.traps[InvalidOperation] = 0
|
||||
>>> print(c.divide(Decimal(0), Decimal(0)))
|
||||
NaN
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>>
|
||||
"""
|
||||
"""Python decimal arithmetic module"""
|
||||
|
||||
__all__ = [
|
||||
# Two major classes
|
||||
@@ -140,8 +43,11 @@ __all__ = [
|
||||
# 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'
|
||||
# C version: compile time choice that enables the thread local context (deprecated, now always true)
|
||||
'HAVE_THREADS',
|
||||
|
||||
# C version: compile time choice that enables the coroutine local context
|
||||
'HAVE_CONTEXTVAR'
|
||||
]
|
||||
|
||||
__xname__ = __name__ # sys.modules lookup (--without-threads)
|
||||
@@ -156,7 +62,7 @@ import sys
|
||||
|
||||
try:
|
||||
from collections import namedtuple as _namedtuple
|
||||
DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent')
|
||||
DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent', module='decimal')
|
||||
except ImportError:
|
||||
DecimalTuple = lambda *args: args
|
||||
|
||||
@@ -172,6 +78,7 @@ ROUND_05UP = 'ROUND_05UP'
|
||||
|
||||
# Compatibility with the C version
|
||||
HAVE_THREADS = True
|
||||
HAVE_CONTEXTVAR = True
|
||||
if sys.maxsize == 2**63-1:
|
||||
MAX_PREC = 999999999999999999
|
||||
MAX_EMAX = 999999999999999999
|
||||
@@ -190,7 +97,7 @@ class DecimalException(ArithmeticError):
|
||||
|
||||
Used exceptions derive from this.
|
||||
If an exception derives from another exception besides this (such as
|
||||
Underflow (Inexact, Rounded, Subnormal) that indicates that it is only
|
||||
Underflow (Inexact, Rounded, Subnormal)) that indicates that it is only
|
||||
called if the others are present. This isn't actually used for
|
||||
anything, though.
|
||||
|
||||
@@ -238,7 +145,7 @@ class InvalidOperation(DecimalException):
|
||||
x ** (+-)INF
|
||||
An operand is invalid
|
||||
|
||||
The result of the operation after these is a quiet positive NaN,
|
||||
The result of the operation after this is a quiet positive NaN,
|
||||
except when the cause is a signaling NaN, in which case the result is
|
||||
also a quiet NaN, but with the original sign, and an optional
|
||||
diagnostic information.
|
||||
@@ -431,82 +338,40 @@ _rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING,
|
||||
##### Context Functions ##################################################
|
||||
|
||||
# The getcontext() and setcontext() function manage access to a thread-local
|
||||
# current context. Py2.4 offers direct support for thread locals. If that
|
||||
# is not available, use threading.current_thread() which is slower but will
|
||||
# work for older Pythons. If threads are not part of the build, create a
|
||||
# mock threading object with threading.local() returning the module namespace.
|
||||
# current context.
|
||||
|
||||
try:
|
||||
import threading
|
||||
except ImportError:
|
||||
# Python was compiled without threads; create a mock object instead
|
||||
class MockThreading(object):
|
||||
def local(self, sys=sys):
|
||||
return sys.modules[__xname__]
|
||||
threading = MockThreading()
|
||||
del MockThreading
|
||||
import contextvars
|
||||
|
||||
try:
|
||||
threading.local
|
||||
_current_context_var = contextvars.ContextVar('decimal_context')
|
||||
|
||||
except AttributeError:
|
||||
_context_attributes = frozenset(
|
||||
['prec', 'Emin', 'Emax', 'capitals', 'clamp', 'rounding', 'flags', 'traps']
|
||||
)
|
||||
|
||||
# To fix reloading, force it to create a new context
|
||||
# Old contexts have different exceptions in their dicts, making problems.
|
||||
if hasattr(threading.current_thread(), '__decimal_context__'):
|
||||
del threading.current_thread().__decimal_context__
|
||||
def getcontext():
|
||||
"""Returns this thread's context.
|
||||
|
||||
def setcontext(context):
|
||||
"""Set this thread's context to context."""
|
||||
if context in (DefaultContext, BasicContext, ExtendedContext):
|
||||
context = context.copy()
|
||||
context.clear_flags()
|
||||
threading.current_thread().__decimal_context__ = context
|
||||
If this thread does not yet have a context, returns
|
||||
a new context and sets this thread's context.
|
||||
New contexts are copies of DefaultContext.
|
||||
"""
|
||||
try:
|
||||
return _current_context_var.get()
|
||||
except LookupError:
|
||||
context = Context()
|
||||
_current_context_var.set(context)
|
||||
return context
|
||||
|
||||
def getcontext():
|
||||
"""Returns this thread's context.
|
||||
def setcontext(context):
|
||||
"""Set this thread's context to context."""
|
||||
if context in (DefaultContext, BasicContext, ExtendedContext):
|
||||
context = context.copy()
|
||||
context.clear_flags()
|
||||
_current_context_var.set(context)
|
||||
|
||||
If this thread does not yet have a context, returns
|
||||
a new context and sets this thread's context.
|
||||
New contexts are copies of DefaultContext.
|
||||
"""
|
||||
try:
|
||||
return threading.current_thread().__decimal_context__
|
||||
except AttributeError:
|
||||
context = Context()
|
||||
threading.current_thread().__decimal_context__ = context
|
||||
return context
|
||||
del contextvars # Don't contaminate the namespace
|
||||
|
||||
else:
|
||||
|
||||
local = threading.local()
|
||||
if hasattr(local, '__decimal_context__'):
|
||||
del local.__decimal_context__
|
||||
|
||||
def getcontext(_local=local):
|
||||
"""Returns this thread's context.
|
||||
|
||||
If this thread does not yet have a context, returns
|
||||
a new context and sets this thread's context.
|
||||
New contexts are copies of DefaultContext.
|
||||
"""
|
||||
try:
|
||||
return _local.__decimal_context__
|
||||
except AttributeError:
|
||||
context = Context()
|
||||
_local.__decimal_context__ = context
|
||||
return context
|
||||
|
||||
def setcontext(context, _local=local):
|
||||
"""Set this thread's context to context."""
|
||||
if context in (DefaultContext, BasicContext, ExtendedContext):
|
||||
context = context.copy()
|
||||
context.clear_flags()
|
||||
_local.__decimal_context__ = context
|
||||
|
||||
del threading, local # Don't contaminate the namespace
|
||||
|
||||
def localcontext(ctx=None):
|
||||
def localcontext(ctx=None, **kwargs):
|
||||
"""Return a context manager for a copy of the supplied context
|
||||
|
||||
Uses a copy of the current context if no context is specified
|
||||
@@ -542,8 +407,14 @@ def localcontext(ctx=None):
|
||||
>>> print(getcontext().prec)
|
||||
28
|
||||
"""
|
||||
if ctx is None: ctx = getcontext()
|
||||
return _ContextManager(ctx)
|
||||
if ctx is None:
|
||||
ctx = getcontext()
|
||||
ctx_manager = _ContextManager(ctx)
|
||||
for key, value in kwargs.items():
|
||||
if key not in _context_attributes:
|
||||
raise TypeError(f"'{key}' is an invalid keyword argument for this function")
|
||||
setattr(ctx_manager.new_context, key, value)
|
||||
return ctx_manager
|
||||
|
||||
|
||||
##### Decimal class #######################################################
|
||||
@@ -553,7 +424,7 @@ def localcontext(ctx=None):
|
||||
# numbers.py for more detail.
|
||||
|
||||
class Decimal(object):
|
||||
"""Floating point class for decimal arithmetic."""
|
||||
"""Floating-point class for decimal arithmetic."""
|
||||
|
||||
__slots__ = ('_exp','_int','_sign', '_is_special')
|
||||
# Generally, the value of the Decimal instance is given by
|
||||
@@ -993,7 +864,7 @@ class Decimal(object):
|
||||
if self.is_snan():
|
||||
raise TypeError('Cannot hash a signaling NaN value.')
|
||||
elif self.is_nan():
|
||||
return _PyHASH_NAN
|
||||
return object.__hash__(self)
|
||||
else:
|
||||
if self._sign:
|
||||
return -_PyHASH_INF
|
||||
@@ -1674,13 +1545,13 @@ class Decimal(object):
|
||||
|
||||
__trunc__ = __int__
|
||||
|
||||
@property
|
||||
def real(self):
|
||||
return self
|
||||
real = property(real)
|
||||
|
||||
@property
|
||||
def imag(self):
|
||||
return Decimal(0)
|
||||
imag = property(imag)
|
||||
|
||||
def conjugate(self):
|
||||
return self
|
||||
@@ -2260,10 +2131,16 @@ class Decimal(object):
|
||||
else:
|
||||
return None
|
||||
|
||||
if xc >= 10**p:
|
||||
# An exact power of 10 is representable, but can convert to a
|
||||
# string of any length. But an exact power of 10 shouldn't be
|
||||
# possible at this point.
|
||||
assert xc > 1, self
|
||||
assert xc % 10 != 0, self
|
||||
strxc = str(xc)
|
||||
if len(strxc) > p:
|
||||
return None
|
||||
xe = -e-xe
|
||||
return _dec_from_triple(0, str(xc), xe)
|
||||
return _dec_from_triple(0, strxc, xe)
|
||||
|
||||
# now y is positive; find m and n such that y = m/n
|
||||
if ye >= 0:
|
||||
@@ -2272,7 +2149,7 @@ class Decimal(object):
|
||||
if xe != 0 and len(str(abs(yc*xe))) <= -ye:
|
||||
return None
|
||||
xc_bits = _nbits(xc)
|
||||
if xc != 1 and len(str(abs(yc)*xc_bits)) <= -ye:
|
||||
if len(str(abs(yc)*xc_bits)) <= -ye:
|
||||
return None
|
||||
m, n = yc, 10**(-ye)
|
||||
while m % 2 == n % 2 == 0:
|
||||
@@ -2285,7 +2162,7 @@ class Decimal(object):
|
||||
# compute nth root of xc*10**xe
|
||||
if n > 1:
|
||||
# if 1 < xc < 2**n then xc isn't an nth power
|
||||
if xc != 1 and xc_bits <= n:
|
||||
if xc_bits <= n:
|
||||
return None
|
||||
|
||||
xe, rem = divmod(xe, n)
|
||||
@@ -2313,13 +2190,18 @@ class Decimal(object):
|
||||
return None
|
||||
xc = xc**m
|
||||
xe *= m
|
||||
if xc > 10**p:
|
||||
# An exact power of 10 is representable, but can convert to a string
|
||||
# of any length. But an exact power of 10 shouldn't be possible at
|
||||
# this point.
|
||||
assert xc > 1, self
|
||||
assert xc % 10 != 0, self
|
||||
str_xc = str(xc)
|
||||
if len(str_xc) > p:
|
||||
return None
|
||||
|
||||
# by this point the result *is* exactly representable
|
||||
# adjust the exponent to get as close as possible to the ideal
|
||||
# exponent, if necessary
|
||||
str_xc = str(xc)
|
||||
if other._isinteger() and other._sign == 0:
|
||||
ideal_exponent = self._exp*int(other)
|
||||
zeros = min(xe-ideal_exponent, p-len(str_xc))
|
||||
@@ -3837,6 +3719,10 @@ class Decimal(object):
|
||||
# represented in fixed point; rescale them to 0e0.
|
||||
if not self and self._exp > 0 and spec['type'] in 'fF%':
|
||||
self = self._rescale(0, rounding)
|
||||
if not self and spec['no_neg_0'] and self._sign:
|
||||
adjusted_sign = 0
|
||||
else:
|
||||
adjusted_sign = self._sign
|
||||
|
||||
# figure out placement of the decimal point
|
||||
leftdigits = self._exp + len(self._int)
|
||||
@@ -3867,7 +3753,7 @@ class Decimal(object):
|
||||
|
||||
# done with the decimal-specific stuff; hand over the rest
|
||||
# of the formatting to the _format_number function
|
||||
return _format_number(self._sign, intpart, fracpart, exp, spec)
|
||||
return _format_number(adjusted_sign, intpart, fracpart, exp, spec)
|
||||
|
||||
def _dec_from_triple(sign, coefficient, exponent, special=False):
|
||||
"""Create a decimal instance directly, without any validation,
|
||||
@@ -5677,8 +5563,6 @@ class _WorkRep(object):
|
||||
def __repr__(self):
|
||||
return "(%r, %r, %r)" % (self.sign, self.int, self.exp)
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
|
||||
def _normalize(op1, op2, prec = 0):
|
||||
@@ -6187,7 +6071,7 @@ _exact_half = re.compile('50*$').match
|
||||
#
|
||||
# A format specifier for Decimal looks like:
|
||||
#
|
||||
# [[fill]align][sign][#][0][minimumwidth][,][.precision][type]
|
||||
# [[fill]align][sign][z][#][0][minimumwidth][,][.precision][type]
|
||||
|
||||
_parse_format_specifier_regex = re.compile(r"""\A
|
||||
(?:
|
||||
@@ -6195,6 +6079,7 @@ _parse_format_specifier_regex = re.compile(r"""\A
|
||||
(?P<align>[<>=^])
|
||||
)?
|
||||
(?P<sign>[-+ ])?
|
||||
(?P<no_neg_0>z)?
|
||||
(?P<alt>\#)?
|
||||
(?P<zeropad>0)?
|
||||
(?P<minimumwidth>(?!0)\d+)?
|
||||
|
||||
108
Lib/decimal.py
vendored
108
Lib/decimal.py
vendored
@@ -1,11 +1,109 @@
|
||||
"""Decimal fixed-point and floating-point arithmetic.
|
||||
|
||||
This is an implementation of decimal floating-point arithmetic based on
|
||||
the General Decimal Arithmetic Specification:
|
||||
|
||||
http://speleotrove.com/decimal/decarith.html
|
||||
|
||||
and IEEE standard 854-1987:
|
||||
|
||||
http://en.wikipedia.org/wiki/IEEE_854-1987
|
||||
|
||||
Decimal floating point has finite precision with arbitrarily large bounds.
|
||||
|
||||
The purpose of this module is to support arithmetic using familiar
|
||||
"schoolhouse" rules and to avoid some of the tricky representation
|
||||
issues associated with binary floating point. The package is especially
|
||||
useful for financial applications or for contexts where users have
|
||||
expectations that are at odds with binary floating point (for instance,
|
||||
in binary floating point, 1.00 % 0.1 gives 0.09999999999999995 instead
|
||||
of 0.0; Decimal('1.00') % Decimal('0.1') returns the expected
|
||||
Decimal('0.00')).
|
||||
|
||||
Here are some examples of using the decimal module:
|
||||
|
||||
>>> from decimal import *
|
||||
>>> setcontext(ExtendedContext)
|
||||
>>> Decimal(0)
|
||||
Decimal('0')
|
||||
>>> Decimal('1')
|
||||
Decimal('1')
|
||||
>>> Decimal('-.0123')
|
||||
Decimal('-0.0123')
|
||||
>>> Decimal(123456)
|
||||
Decimal('123456')
|
||||
>>> 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')
|
||||
Decimal('-2.20')
|
||||
>>> dig = Decimal(1)
|
||||
>>> print(dig / Decimal(3))
|
||||
0.333333333
|
||||
>>> getcontext().prec = 18
|
||||
>>> print(dig / Decimal(3))
|
||||
0.333333333333333333
|
||||
>>> print(dig.sqrt())
|
||||
1
|
||||
>>> print(Decimal(3).sqrt())
|
||||
1.73205080756887729
|
||||
>>> print(Decimal(3) ** 123)
|
||||
4.85192780976896427E+58
|
||||
>>> inf = Decimal(1) / Decimal(0)
|
||||
>>> print(inf)
|
||||
Infinity
|
||||
>>> neginf = Decimal(-1) / Decimal(0)
|
||||
>>> print(neginf)
|
||||
-Infinity
|
||||
>>> print(neginf + inf)
|
||||
NaN
|
||||
>>> print(neginf * inf)
|
||||
-Infinity
|
||||
>>> print(dig / 0)
|
||||
Infinity
|
||||
>>> getcontext().traps[DivisionByZero] = 1
|
||||
>>> print(dig / 0)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
...
|
||||
...
|
||||
decimal.DivisionByZero: x / 0
|
||||
>>> c = Context()
|
||||
>>> c.traps[InvalidOperation] = 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
0
|
||||
>>> c.divide(Decimal(0), Decimal(0))
|
||||
Decimal('NaN')
|
||||
>>> c.traps[InvalidOperation] = 1
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>> c.flags[InvalidOperation] = 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
0
|
||||
>>> print(c.divide(Decimal(0), Decimal(0)))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
...
|
||||
...
|
||||
decimal.InvalidOperation: 0 / 0
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>> c.flags[InvalidOperation] = 0
|
||||
>>> c.traps[InvalidOperation] = 0
|
||||
>>> print(c.divide(Decimal(0), Decimal(0)))
|
||||
NaN
|
||||
>>> print(c.flags[InvalidOperation])
|
||||
1
|
||||
>>>
|
||||
"""
|
||||
|
||||
try:
|
||||
from _decimal import *
|
||||
from _decimal import __doc__
|
||||
from _decimal import __version__
|
||||
from _decimal import __libmpdec_version__
|
||||
except ImportError:
|
||||
from _pydecimal import *
|
||||
from _pydecimal import __doc__
|
||||
from _pydecimal import __version__
|
||||
from _pydecimal import __libmpdec_version__
|
||||
import _pydecimal
|
||||
import sys
|
||||
_pydecimal.__doc__ = __doc__
|
||||
sys.modules[__name__] = _pydecimal
|
||||
|
||||
2
Lib/test/decimaltestdata/abs.decTest
vendored
2
Lib/test/decimaltestdata/abs.decTest
vendored
@@ -20,7 +20,7 @@
|
||||
version: 2.59
|
||||
|
||||
-- This set of tests primarily tests the existence of the operator.
|
||||
-- Additon, subtraction, rounding, and more overflows are tested
|
||||
-- Addition, subtraction, rounding, and more overflows are tested
|
||||
-- elsewhere.
|
||||
|
||||
precision: 9
|
||||
|
||||
2
Lib/test/decimaltestdata/ddFMA.decTest
vendored
2
Lib/test/decimaltestdata/ddFMA.decTest
vendored
@@ -1663,7 +1663,7 @@ ddfma375087 fma 1 12345678 1E-33 -> 12345678.00000001 Inexac
|
||||
ddfma375088 fma 1 12345678 1E-34 -> 12345678.00000001 Inexact Rounded
|
||||
ddfma375089 fma 1 12345678 1E-35 -> 12345678.00000001 Inexact Rounded
|
||||
|
||||
-- desctructive subtraction (from remainder tests)
|
||||
-- destructive subtraction (from remainder tests)
|
||||
|
||||
-- +++ some of these will be off-by-one remainder vs remainderNear
|
||||
|
||||
|
||||
2
Lib/test/decimaltestdata/ddQuantize.decTest
vendored
2
Lib/test/decimaltestdata/ddQuantize.decTest
vendored
@@ -462,7 +462,7 @@ ddqua520 quantize 1.234 1e359 -> 0E+359 Inexact Rounded
|
||||
ddqua521 quantize 123.456 1e359 -> 0E+359 Inexact Rounded
|
||||
ddqua522 quantize 1.234 1e359 -> 0E+359 Inexact Rounded
|
||||
ddqua523 quantize 123.456 1e359 -> 0E+359 Inexact Rounded
|
||||
-- next four are "won't fit" overfl
|
||||
-- next four are "won't fit" overflow
|
||||
ddqua526 quantize 1.234 1e-299 -> NaN Invalid_operation
|
||||
ddqua527 quantize 123.456 1e-299 -> NaN Invalid_operation
|
||||
ddqua528 quantize 1.234 1e-299 -> NaN Invalid_operation
|
||||
|
||||
2
Lib/test/decimaltestdata/ddRemainder.decTest
vendored
2
Lib/test/decimaltestdata/ddRemainder.decTest
vendored
@@ -422,7 +422,7 @@ ddrem757 remainder 1 sNaN -> NaN Invalid_operation
|
||||
ddrem758 remainder 1000 sNaN -> NaN Invalid_operation
|
||||
ddrem759 remainder Inf -sNaN -> -NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
ddrem760 remainder NaN1 NaN7 -> NaN1
|
||||
ddrem761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
ddrem762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation
|
||||
|
||||
@@ -450,7 +450,7 @@ ddrmn757 remaindernear 1 sNaN -> NaN Invalid_operation
|
||||
ddrmn758 remaindernear 1000 sNaN -> NaN Invalid_operation
|
||||
ddrmn759 remaindernear Inf -sNaN -> -NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
ddrmn760 remaindernear NaN1 NaN7 -> NaN1
|
||||
ddrmn761 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
ddrmn762 remaindernear NaN3 sNaN9 -> NaN9 Invalid_operation
|
||||
|
||||
2
Lib/test/decimaltestdata/dqRemainder.decTest
vendored
2
Lib/test/decimaltestdata/dqRemainder.decTest
vendored
@@ -418,7 +418,7 @@ dqrem757 remainder 1 sNaN -> NaN Invalid_operation
|
||||
dqrem758 remainder 1000 sNaN -> NaN Invalid_operation
|
||||
dqrem759 remainder Inf -sNaN -> -NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
dqrem760 remainder NaN1 NaN7 -> NaN1
|
||||
dqrem761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
dqrem762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation
|
||||
|
||||
@@ -450,7 +450,7 @@ dqrmn757 remaindernear 1 sNaN -> NaN Invalid_operation
|
||||
dqrmn758 remaindernear 1000 sNaN -> NaN Invalid_operation
|
||||
dqrmn759 remaindernear Inf -sNaN -> -NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
dqrmn760 remaindernear NaN1 NaN7 -> NaN1
|
||||
dqrmn761 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
dqrmn762 remaindernear NaN3 sNaN9 -> NaN9 Invalid_operation
|
||||
|
||||
2
Lib/test/decimaltestdata/exp.decTest
vendored
2
Lib/test/decimaltestdata/exp.decTest
vendored
@@ -28,7 +28,7 @@ rounding: half_even
|
||||
maxExponent: 384
|
||||
minexponent: -383
|
||||
|
||||
-- basics (examples in specificiation, etc.)
|
||||
-- basics (examples in specification, etc.)
|
||||
expx001 exp -Infinity -> 0
|
||||
expx002 exp -10 -> 0.0000453999298 Inexact Rounded
|
||||
expx003 exp -1 -> 0.367879441 Inexact Rounded
|
||||
|
||||
2
Lib/test/decimaltestdata/extra.decTest
vendored
2
Lib/test/decimaltestdata/extra.decTest
vendored
@@ -156,7 +156,7 @@ extr1302 fma -Inf 0E-456 sNaN148 -> NaN Invalid_operation
|
||||
|
||||
-- max/min/max_mag/min_mag bug in 2.5.2/2.6/3.0: max(NaN, finite) gave
|
||||
-- incorrect answers when the finite number required rounding; similarly
|
||||
-- for the other thre functions
|
||||
-- for the other three functions
|
||||
maxexponent: 999
|
||||
minexponent: -999
|
||||
precision: 6
|
||||
|
||||
2
Lib/test/decimaltestdata/remainder.decTest
vendored
2
Lib/test/decimaltestdata/remainder.decTest
vendored
@@ -435,7 +435,7 @@ remx757 remainder 1 sNaN -> NaN Invalid_operation
|
||||
remx758 remainder 1000 sNaN -> NaN Invalid_operation
|
||||
remx759 remainder Inf -sNaN -> -NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
remx760 remainder NaN1 NaN7 -> NaN1
|
||||
remx761 remainder sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
remx762 remainder NaN3 sNaN9 -> NaN9 Invalid_operation
|
||||
|
||||
@@ -498,7 +498,7 @@ rmnx758 remaindernear 1000 sNaN -> NaN Invalid_operation
|
||||
rmnx759 remaindernear Inf sNaN -> NaN Invalid_operation
|
||||
rmnx760 remaindernear NaN sNaN -> NaN Invalid_operation
|
||||
|
||||
-- propaging NaNs
|
||||
-- propagating NaNs
|
||||
rmnx761 remaindernear NaN1 NaN7 -> NaN1
|
||||
rmnx762 remaindernear sNaN2 NaN8 -> NaN2 Invalid_operation
|
||||
rmnx763 remaindernear NaN3 -sNaN9 -> -NaN9 Invalid_operation
|
||||
|
||||
149
Lib/test/test_decimal.py
vendored
149
Lib/test/test_decimal.py
vendored
@@ -24,6 +24,7 @@ you're working through IDLE, you can import this test module and call test()
|
||||
with the corresponding argument.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import math
|
||||
import os, sys
|
||||
import operator
|
||||
@@ -812,8 +813,6 @@ class ExplicitConstructionTest:
|
||||
x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
|
||||
self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_unicode_digits(self):
|
||||
Decimal = self.decimal.Decimal
|
||||
|
||||
@@ -831,6 +830,11 @@ class CExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase):
|
||||
class PyExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase):
|
||||
decimal = P
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_unicode_digits(self): # TODO(RUSTPYTHON): Remove this test when it pass
|
||||
return super().test_unicode_digits()
|
||||
|
||||
class ImplicitConstructionTest:
|
||||
'''Unit tests for Implicit Construction cases of Decimal.'''
|
||||
|
||||
@@ -916,8 +920,6 @@ class PyImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase):
|
||||
|
||||
class FormatTest:
|
||||
'''Unit tests for the format function.'''
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_formatting(self):
|
||||
Decimal = self.decimal.Decimal
|
||||
|
||||
@@ -1113,6 +1115,13 @@ class FormatTest:
|
||||
('z>z6.1f', '-0.', 'zzz0.0'),
|
||||
('x>z6.1f', '-0.', 'xxx0.0'),
|
||||
('🖤>z6.1f', '-0.', '🖤🖤🖤0.0'), # multi-byte fill char
|
||||
('\x00>z6.1f', '-0.', '\x00\x00\x000.0'), # null fill char
|
||||
|
||||
# issue 114563 ('z' format on F type in cdecimal)
|
||||
('z3,.10F', '-6.24E-323', '0.0000000000'),
|
||||
|
||||
# issue 91060 ('#' format in cdecimal)
|
||||
('#', '0', '0.'),
|
||||
|
||||
# issue 6850
|
||||
('a=-7.0', '0.12345', 'aaaa0.1'),
|
||||
@@ -1128,8 +1137,6 @@ class FormatTest:
|
||||
# bytes format argument
|
||||
self.assertRaises(TypeError, Decimal(1).__format__, b'-020')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_negative_zero_format_directed_rounding(self):
|
||||
with self.decimal.localcontext() as ctx:
|
||||
ctx.rounding = ROUND_CEILING
|
||||
@@ -1228,7 +1235,31 @@ class FormatTest:
|
||||
self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'),
|
||||
'-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5')
|
||||
|
||||
@run_with_locale('LC_ALL', 'ps_AF')
|
||||
def test_deprecated_N_format(self):
|
||||
Decimal = self.decimal.Decimal
|
||||
h = Decimal('6.62607015e-34')
|
||||
if self.decimal == C:
|
||||
with self.assertWarns(DeprecationWarning) as cm:
|
||||
r = format(h, 'N')
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
self.assertEqual(r, format(h, 'n').upper())
|
||||
with self.assertWarns(DeprecationWarning) as cm:
|
||||
r = format(h, '010.3N')
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
self.assertEqual(r, format(h, '010.3n').upper())
|
||||
else:
|
||||
self.assertRaises(ValueError, format, h, 'N')
|
||||
self.assertRaises(ValueError, format, h, '010.3N')
|
||||
with warnings_helper.check_no_warnings(self):
|
||||
self.assertEqual(format(h, 'N>10.3'), 'NN6.63E-34')
|
||||
self.assertEqual(format(h, 'N>10.3n'), 'NN6.63e-34')
|
||||
self.assertEqual(format(h, 'N>10.3e'), 'N6.626e-34')
|
||||
self.assertEqual(format(h, 'N>10.3f'), 'NNNNN0.000')
|
||||
self.assertRaises(ValueError, format, h, '>Nf')
|
||||
self.assertRaises(ValueError, format, h, '10Nf')
|
||||
self.assertRaises(ValueError, format, h, 'Nx')
|
||||
|
||||
@run_with_locale('LC_ALL', 'ps_AF', '')
|
||||
def test_wide_char_separator_decimal_point(self):
|
||||
# locale with wide char separator and decimal point
|
||||
Decimal = self.decimal.Decimal
|
||||
@@ -1911,8 +1942,6 @@ class UsabilityTest:
|
||||
x = 1100 ** 1248
|
||||
self.assertEqual(hashit(Decimal(x)), hashit(x))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_hash_method_nan(self):
|
||||
Decimal = self.decimal.Decimal
|
||||
self.assertRaises(TypeError, hash, Decimal('sNaN'))
|
||||
@@ -2048,7 +2077,9 @@ class UsabilityTest:
|
||||
#to quantize, which is already extensively tested
|
||||
test_triples = [
|
||||
('123.456', -4, '0E+4'),
|
||||
('-123.456', -4, '-0E+4'),
|
||||
('123.456', -3, '0E+3'),
|
||||
('-123.456', -3, '-0E+3'),
|
||||
('123.456', -2, '1E+2'),
|
||||
('123.456', -1, '1.2E+2'),
|
||||
('123.456', 0, '123'),
|
||||
@@ -2718,8 +2749,6 @@ class PythonAPItests:
|
||||
x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN)
|
||||
self.assertEqual(x, Decimal('8.71E+799'))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_complex(self):
|
||||
Decimal = self.decimal.Decimal
|
||||
|
||||
@@ -2894,6 +2923,11 @@ class CPythonAPItests(PythonAPItests, unittest.TestCase):
|
||||
class PyPythonAPItests(PythonAPItests, unittest.TestCase):
|
||||
decimal = P
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_complex(self): # TODO(RUSTPYTHON): Remove this test when it pass
|
||||
return super().test_complex()
|
||||
|
||||
class ContextAPItests:
|
||||
|
||||
def test_none_args(self):
|
||||
@@ -3663,8 +3697,6 @@ class ContextWithStatement:
|
||||
self.assertIsNot(new_ctx, set_ctx, 'did not copy the context')
|
||||
self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_localcontext_kwargs(self):
|
||||
with self.decimal.localcontext(
|
||||
prec=10, rounding=ROUND_HALF_DOWN,
|
||||
@@ -3693,8 +3725,6 @@ class ContextWithStatement:
|
||||
self.assertRaises(TypeError, self.decimal.localcontext, Emin="")
|
||||
self.assertRaises(TypeError, self.decimal.localcontext, Emax="")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_local_context_kwargs_does_not_overwrite_existing_argument(self):
|
||||
ctx = self.decimal.getcontext()
|
||||
orig_prec = ctx.prec
|
||||
@@ -4362,7 +4392,8 @@ class CheckAttributes(unittest.TestCase):
|
||||
|
||||
self.assertEqual(C.__version__, P.__version__)
|
||||
|
||||
self.assertEqual(dir(C), dir(P))
|
||||
self.assertLessEqual(set(dir(C)), set(dir(P)))
|
||||
self.assertEqual([n for n in dir(C) if n[:2] != '__'], sorted(P.__all__))
|
||||
|
||||
def test_context_attributes(self):
|
||||
|
||||
@@ -4438,6 +4469,15 @@ class Coverage:
|
||||
self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True)
|
||||
# three arg power
|
||||
self.assertEqual(pow(Decimal(10), 2, 7), 2)
|
||||
if self.decimal == C:
|
||||
self.assertEqual(pow(10, Decimal(2), 7), 2)
|
||||
self.assertEqual(pow(10, 2, Decimal(7)), 2)
|
||||
else:
|
||||
# XXX: Three-arg power doesn't use __rpow__.
|
||||
self.assertRaises(TypeError, pow, 10, Decimal(2), 7)
|
||||
# XXX: There is no special method to dispatch on the
|
||||
# third arg of three-arg power.
|
||||
self.assertRaises(TypeError, pow, 10, 2, Decimal(7))
|
||||
# exp
|
||||
self.assertEqual(Decimal("1.01").exp(), 3)
|
||||
# is_normal
|
||||
@@ -4648,6 +4688,11 @@ class PyCoverage(Coverage, unittest.TestCase):
|
||||
sys.set_int_max_str_digits(self._previous_int_limit)
|
||||
super().tearDown()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_implicit_context(self): # TODO(RUSTPYTHON): Remove this test when it pass
|
||||
return super().test_implicit_context()
|
||||
|
||||
class PyFunctionality(unittest.TestCase):
|
||||
"""Extra functionality in decimal.py"""
|
||||
|
||||
@@ -4699,9 +4744,33 @@ class PyWhitebox(unittest.TestCase):
|
||||
|
||||
c.prec = 1
|
||||
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||
self.assertEqual(x, Decimal('3e-6'))
|
||||
c.prec = 2
|
||||
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||
self.assertEqual(x, Decimal('2.6e-6'))
|
||||
c.prec = 3
|
||||
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||
self.assertEqual(x, Decimal('2.56e-6'))
|
||||
c.prec = 28
|
||||
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||
self.assertEqual(x, Decimal('2.56e-6'))
|
||||
|
||||
c.prec = 201
|
||||
x = Decimal(2**578) ** Decimal("-0.5")
|
||||
|
||||
# See https://github.com/python/cpython/issues/118027
|
||||
# Testing for an exact power could appear to hang, in the Python
|
||||
# version, as it attempted to compute 10**(MAX_EMAX + 1).
|
||||
# Fixed via https://github.com/python/cpython/pull/118503.
|
||||
c.prec = P.MAX_PREC
|
||||
c.Emax = P.MAX_EMAX
|
||||
c.Emin = P.MIN_EMIN
|
||||
c.traps[P.Inexact] = 1
|
||||
D2 = Decimal(2)
|
||||
# If the bug is still present, the next statement won't complete.
|
||||
res = D2 ** 117
|
||||
self.assertEqual(res, 1 << 117)
|
||||
|
||||
def test_py_immutability_operations(self):
|
||||
# Do operations and check that it didn't change internal objects.
|
||||
Decimal = P.Decimal
|
||||
@@ -5625,6 +5694,25 @@ class CWhitebox(unittest.TestCase):
|
||||
self.assertEqual(Decimal.from_float(cls(101.1)),
|
||||
Decimal.from_float(101.1))
|
||||
|
||||
def test_c_immutable_types(self):
|
||||
SignalDict = type(C.Context().flags)
|
||||
SignalDictMixin = SignalDict.__bases__[0]
|
||||
ContextManager = type(C.localcontext())
|
||||
types = (
|
||||
SignalDictMixin,
|
||||
ContextManager,
|
||||
C.Decimal,
|
||||
C.Context,
|
||||
)
|
||||
for tp in types:
|
||||
with self.subTest(tp=tp):
|
||||
with self.assertRaisesRegex(TypeError, "immutable"):
|
||||
tp.foo = 1
|
||||
|
||||
def test_c_disallow_instantiation(self):
|
||||
ContextManager = type(C.localcontext())
|
||||
check_disallow_instantiation(self, ContextManager)
|
||||
|
||||
def test_c_signaldict_segfault(self):
|
||||
# See gh-106263 for details.
|
||||
SignalDict = type(C.Context().flags)
|
||||
@@ -5655,6 +5743,20 @@ class CWhitebox(unittest.TestCase):
|
||||
with self.assertRaisesRegex(ValueError, err_msg):
|
||||
sd.copy()
|
||||
|
||||
def test_format_fallback_capitals(self):
|
||||
# Fallback to _pydecimal formatting (triggered by `#` format which
|
||||
# is unsupported by mpdecimal) should honor the current context.
|
||||
x = C.Decimal('6.09e+23')
|
||||
self.assertEqual(format(x, '#'), '6.09E+23')
|
||||
with C.localcontext(capitals=0):
|
||||
self.assertEqual(format(x, '#'), '6.09e+23')
|
||||
|
||||
def test_format_fallback_rounding(self):
|
||||
y = C.Decimal('6.09')
|
||||
self.assertEqual(format(y, '#.1f'), '6.1')
|
||||
with C.localcontext(rounding=C.ROUND_DOWN):
|
||||
self.assertEqual(format(y, '#.1f'), '6.0')
|
||||
|
||||
@requires_docstrings
|
||||
@requires_cdecimal
|
||||
class SignatureTest(unittest.TestCase):
|
||||
@@ -5818,13 +5920,17 @@ def load_tests(loader, tests, pattern):
|
||||
|
||||
if TODO_TESTS is None:
|
||||
from doctest import DocTestSuite, IGNORE_EXCEPTION_DETAIL
|
||||
orig_context = orig_sys_decimal.getcontext().copy()
|
||||
for mod in C, P:
|
||||
if not mod:
|
||||
continue
|
||||
def setUp(slf, mod=mod):
|
||||
sys.modules['decimal'] = mod
|
||||
def tearDown(slf):
|
||||
init(mod)
|
||||
def tearDown(slf, mod=mod):
|
||||
sys.modules['decimal'] = orig_sys_decimal
|
||||
mod.setcontext(ORIGINAL_CONTEXT[mod].copy())
|
||||
orig_sys_decimal.setcontext(orig_context.copy())
|
||||
optionflags = IGNORE_EXCEPTION_DETAIL if mod is C else 0
|
||||
sys.modules['decimal'] = mod
|
||||
tests.addTest(DocTestSuite(mod, setUp=setUp, tearDown=tearDown,
|
||||
@@ -5839,11 +5945,12 @@ def setUpModule():
|
||||
TEST_ALL = ARITH if ARITH is not None else is_resource_enabled('decimal')
|
||||
|
||||
def tearDownModule():
|
||||
if C: C.setcontext(ORIGINAL_CONTEXT[C])
|
||||
P.setcontext(ORIGINAL_CONTEXT[P])
|
||||
if C: C.setcontext(ORIGINAL_CONTEXT[C].copy())
|
||||
P.setcontext(ORIGINAL_CONTEXT[P].copy())
|
||||
if not C:
|
||||
warnings.warn('C tests skipped: no module named _decimal.',
|
||||
UserWarning)
|
||||
logging.getLogger(__name__).warning(
|
||||
'C tests skipped: no module named _decimal.'
|
||||
)
|
||||
if not orig_sys_decimal is sys.modules['decimal']:
|
||||
raise TestFailed("Internal error: unbalanced number of changes to "
|
||||
"sys.modules['decimal'].")
|
||||
|
||||
Reference in New Issue
Block a user