mirror of
https://github.com/python/cpython.git
synced 2025-07-31 23:23:11 +00:00
Revert r50706 (Whitespace normalization) and
r50697: Comments and docs cleanups, and some little fixes per recommendation from Raymond Hettinger.
This commit is contained in:
parent
100a4e944b
commit
cfe3128cd5
1 changed files with 184 additions and 205 deletions
197
Lib/decimal.py
197
Lib/decimal.py
|
@ -29,8 +29,8 @@ and IEEE standard 854-1987:
|
||||||
|
|
||||||
Decimal floating point has finite precision with arbitrarily large bounds.
|
Decimal floating point has finite precision with arbitrarily large bounds.
|
||||||
|
|
||||||
The purpose of this module is to support arithmetic using familiar
|
The purpose of the module is to support arithmetic using familiar
|
||||||
"schoolhouse" rules and to avoid some of the tricky representation
|
"schoolhouse" rules and to avoid the some of tricky representation
|
||||||
issues associated with binary floating point. The package is especially
|
issues associated with binary floating point. The package is especially
|
||||||
useful for financial applications or for contexts where users have
|
useful for financial applications or for contexts where users have
|
||||||
expectations that are at odds with binary floating point (for instance,
|
expectations that are at odds with binary floating point (for instance,
|
||||||
|
@ -160,17 +160,17 @@ class DecimalException(ArithmeticError):
|
||||||
called if the others are present. This isn't actually used for
|
called if the others are present. This isn't actually used for
|
||||||
anything, though.
|
anything, though.
|
||||||
|
|
||||||
|
handle -- Called when context._raise_error is called and the
|
||||||
|
trap_enabler is set. First argument is self, second is the
|
||||||
|
context. More arguments can be given, those being after
|
||||||
|
the explanation in _raise_error (For example,
|
||||||
|
context._raise_error(NewError, '(-x)!', self._sign) would
|
||||||
|
call NewError().handle(context, self._sign).)
|
||||||
|
|
||||||
To define a new exception, it should be sufficient to have it derive
|
To define a new exception, it should be sufficient to have it derive
|
||||||
from DecimalException.
|
from DecimalException.
|
||||||
"""
|
"""
|
||||||
def handle(self, context, *args):
|
def handle(self, context, *args):
|
||||||
"""Called when context._raise_error is called and trap_enabler is set.
|
|
||||||
|
|
||||||
First argument is self, second is the context. More arguments can
|
|
||||||
be given, those being after the explanation in _raise_error (For
|
|
||||||
example, context._raise_error(NewError, '(-x)!', self._sign) would
|
|
||||||
call NewError().handle(context, self._sign).)
|
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,7 +185,6 @@ class Clamped(DecimalException):
|
||||||
this latter case, the exponent is reduced to fit and the corresponding
|
this latter case, the exponent is reduced to fit and the corresponding
|
||||||
number of zero digits are appended to the coefficient ("fold-down").
|
number of zero digits are appended to the coefficient ("fold-down").
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidOperation(DecimalException):
|
class InvalidOperation(DecimalException):
|
||||||
|
@ -212,7 +211,6 @@ class InvalidOperation(DecimalException):
|
||||||
return Decimal( (args[1]._sign, args[1]._int, 'n') )
|
return Decimal( (args[1]._sign, args[1]._int, 'n') )
|
||||||
return NaN
|
return NaN
|
||||||
|
|
||||||
|
|
||||||
class ConversionSyntax(InvalidOperation):
|
class ConversionSyntax(InvalidOperation):
|
||||||
"""Trying to convert badly formed string.
|
"""Trying to convert badly formed string.
|
||||||
|
|
||||||
|
@ -220,10 +218,10 @@ class ConversionSyntax(InvalidOperation):
|
||||||
converted to a number and it does not conform to the numeric string
|
converted to a number and it does not conform to the numeric string
|
||||||
syntax. The result is [0,qNaN].
|
syntax. The result is [0,qNaN].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, *args):
|
def handle(self, context, *args):
|
||||||
return (0, (0,), 'n') #Passed to something which uses a tuple.
|
return (0, (0,), 'n') #Passed to something which uses a tuple.
|
||||||
|
|
||||||
|
|
||||||
class DivisionByZero(DecimalException, ZeroDivisionError):
|
class DivisionByZero(DecimalException, ZeroDivisionError):
|
||||||
"""Division by 0.
|
"""Division by 0.
|
||||||
|
|
||||||
|
@ -236,12 +234,12 @@ class DivisionByZero(DecimalException, ZeroDivisionError):
|
||||||
or of the signs of the operands for divide, or is 1 for an odd power of
|
or of the signs of the operands for divide, or is 1 for an odd power of
|
||||||
-0, for power.
|
-0, for power.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, sign, double = None, *args):
|
def handle(self, context, sign, double = None, *args):
|
||||||
if double is not None:
|
if double is not None:
|
||||||
return (Infsign[sign],)*2
|
return (Infsign[sign],)*2
|
||||||
return Infsign[sign]
|
return Infsign[sign]
|
||||||
|
|
||||||
|
|
||||||
class DivisionImpossible(InvalidOperation):
|
class DivisionImpossible(InvalidOperation):
|
||||||
"""Cannot perform the division adequately.
|
"""Cannot perform the division adequately.
|
||||||
|
|
||||||
|
@ -249,10 +247,10 @@ class DivisionImpossible(InvalidOperation):
|
||||||
divide-integer or remainder operation had too many digits (would be
|
divide-integer or remainder operation had too many digits (would be
|
||||||
longer than precision). The result is [0,qNaN].
|
longer than precision). The result is [0,qNaN].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, *args):
|
def handle(self, context, *args):
|
||||||
return (NaN, NaN)
|
return (NaN, NaN)
|
||||||
|
|
||||||
|
|
||||||
class DivisionUndefined(InvalidOperation, ZeroDivisionError):
|
class DivisionUndefined(InvalidOperation, ZeroDivisionError):
|
||||||
"""Undefined result of division.
|
"""Undefined result of division.
|
||||||
|
|
||||||
|
@ -260,12 +258,12 @@ class DivisionUndefined(InvalidOperation, ZeroDivisionError):
|
||||||
attempted (during a divide-integer, divide, or remainder operation), and
|
attempted (during a divide-integer, divide, or remainder operation), and
|
||||||
the dividend is also zero. The result is [0,qNaN].
|
the dividend is also zero. The result is [0,qNaN].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, tup=None, *args):
|
def handle(self, context, tup=None, *args):
|
||||||
if tup is not None:
|
if tup is not None:
|
||||||
return (NaN, NaN) # For 0 %0, 0 // 0
|
return (NaN, NaN) #for 0 %0, 0 // 0
|
||||||
return NaN
|
return NaN
|
||||||
|
|
||||||
|
|
||||||
class Inexact(DecimalException):
|
class Inexact(DecimalException):
|
||||||
"""Had to round, losing information.
|
"""Had to round, losing information.
|
||||||
|
|
||||||
|
@ -279,7 +277,6 @@ class Inexact(DecimalException):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidContext(InvalidOperation):
|
class InvalidContext(InvalidOperation):
|
||||||
"""Invalid context. Unknown rounding, for example.
|
"""Invalid context. Unknown rounding, for example.
|
||||||
|
|
||||||
|
@ -290,10 +287,10 @@ class InvalidContext(InvalidOperation):
|
||||||
was specified. These aspects of the context need only be checked when
|
was specified. These aspects of the context need only be checked when
|
||||||
the values are required to be used. The result is [0,qNaN].
|
the values are required to be used. The result is [0,qNaN].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, *args):
|
def handle(self, context, *args):
|
||||||
return NaN
|
return NaN
|
||||||
|
|
||||||
|
|
||||||
class Rounded(DecimalException):
|
class Rounded(DecimalException):
|
||||||
"""Number got rounded (not necessarily changed during rounding).
|
"""Number got rounded (not necessarily changed during rounding).
|
||||||
|
|
||||||
|
@ -307,7 +304,6 @@ class Rounded(DecimalException):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Subnormal(DecimalException):
|
class Subnormal(DecimalException):
|
||||||
"""Exponent < Emin before rounding.
|
"""Exponent < Emin before rounding.
|
||||||
|
|
||||||
|
@ -320,7 +316,6 @@ class Subnormal(DecimalException):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Overflow(Inexact, Rounded):
|
class Overflow(Inexact, Rounded):
|
||||||
"""Numerical overflow.
|
"""Numerical overflow.
|
||||||
|
|
||||||
|
@ -342,6 +337,7 @@ class Overflow(Inexact, Rounded):
|
||||||
result is 0, or is [1,inf] otherwise. In all cases, Inexact and Rounded
|
result is 0, or is [1,inf] otherwise. In all cases, Inexact and Rounded
|
||||||
will also be raised.
|
will also be raised.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, sign, *args):
|
def handle(self, context, sign, *args):
|
||||||
if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
|
if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
|
||||||
ROUND_HALF_DOWN, ROUND_UP):
|
ROUND_HALF_DOWN, ROUND_UP):
|
||||||
|
@ -372,8 +368,6 @@ class Underflow(Inexact, Rounded, Subnormal):
|
||||||
|
|
||||||
In all cases, Inexact, Rounded, and Subnormal will also be raised.
|
In all cases, Inexact, Rounded, and Subnormal will also be raised.
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# List of public traps and flags
|
# List of public traps and flags
|
||||||
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
|
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
|
||||||
|
@ -385,27 +379,25 @@ _condition_map = {ConversionSyntax:InvalidOperation,
|
||||||
DivisionUndefined:InvalidOperation,
|
DivisionUndefined:InvalidOperation,
|
||||||
InvalidContext:InvalidOperation}
|
InvalidContext:InvalidOperation}
|
||||||
|
|
||||||
##### Context Functions #####################################################
|
##### Context Functions #######################################
|
||||||
|
|
||||||
# The getcontext() and setcontext() function manage access to a thread-local
|
# The getcontext() and setcontext() function manage access to a thread-local
|
||||||
# current context. Py2.4 offers direct support for thread locals. If that
|
# current context. Py2.4 offers direct support for thread locals. If that
|
||||||
# is not available, use threading.currentThread() which is slower but will
|
# is not available, use threading.currentThread() which is slower but will
|
||||||
# work for older Pythons. If threads are not part of the build, create a
|
# work for older Pythons. If threads are not part of the build, create a
|
||||||
# mock threading object with threading.local() returning the module
|
# mock threading object with threading.local() returning the module namespace.
|
||||||
# namespace.
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import threading
|
import threading
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# Python was compiled without threads; create a mock object instead
|
# Python was compiled without threads; create a mock object instead
|
||||||
import sys
|
import sys
|
||||||
class MockThreading(object):
|
class MockThreading:
|
||||||
def local(self, sys=sys):
|
def local(self, sys=sys):
|
||||||
return sys.modules[__name__]
|
return sys.modules[__name__]
|
||||||
threading = MockThreading()
|
threading = MockThreading()
|
||||||
del sys, MockThreading
|
del sys, MockThreading
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
threading.local
|
threading.local
|
||||||
|
|
||||||
|
@ -467,7 +459,7 @@ else:
|
||||||
del threading, local # Don't contaminate the namespace
|
del threading, local # Don't contaminate the namespace
|
||||||
|
|
||||||
|
|
||||||
##### Decimal class ##########################################################
|
##### Decimal class ###########################################
|
||||||
|
|
||||||
class Decimal(object):
|
class Decimal(object):
|
||||||
"""Floating point class for decimal arithmetic."""
|
"""Floating point class for decimal arithmetic."""
|
||||||
|
@ -483,7 +475,7 @@ class Decimal(object):
|
||||||
|
|
||||||
>>> Decimal('3.14') # string input
|
>>> Decimal('3.14') # string input
|
||||||
Decimal("3.14")
|
Decimal("3.14")
|
||||||
>>> Decimal((0, (3, 1, 4), -2)) # tuple (sign, digit_tuple, exponent)
|
>>> Decimal((0, (3, 1, 4), -2)) # tuple input (sign, digit_tuple, exponent)
|
||||||
Decimal("3.14")
|
Decimal("3.14")
|
||||||
>>> Decimal(314) # int or long
|
>>> Decimal(314) # int or long
|
||||||
Decimal("314")
|
Decimal("314")
|
||||||
|
@ -522,13 +514,12 @@ class Decimal(object):
|
||||||
# tuple/list conversion (possibly from as_tuple())
|
# tuple/list conversion (possibly from as_tuple())
|
||||||
if isinstance(value, (list,tuple)):
|
if isinstance(value, (list,tuple)):
|
||||||
if len(value) != 3:
|
if len(value) != 3:
|
||||||
raise ValueError('Invalid arguments')
|
raise ValueError, 'Invalid arguments'
|
||||||
if value[0] not in (0,1):
|
if value[0] not in (0,1):
|
||||||
raise ValueError('Invalid sign')
|
raise ValueError, 'Invalid sign'
|
||||||
for digit in value[1]:
|
for digit in value[1]:
|
||||||
if not isinstance(digit, (int,long)) or digit < 0:
|
if not isinstance(digit, (int,long)) or digit < 0:
|
||||||
raise ValueError("The second value in the tuple must be "+
|
raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
|
||||||
"composed of non negative integer elements.")
|
|
||||||
|
|
||||||
self._sign = value[0]
|
self._sign = value[0]
|
||||||
self._int = tuple(value[1])
|
self._int = tuple(value[1])
|
||||||
|
@ -577,8 +568,7 @@ class Decimal(object):
|
||||||
self._sign, self._int, self._exp = _string2exact(value)
|
self._sign, self._int, self._exp = _string2exact(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self._is_special = True
|
self._is_special = True
|
||||||
self._sign, self._int, self._exp = \
|
self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
|
||||||
context._raise_error(ConversionSyntax)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
raise TypeError("Cannot convert %r to Decimal" % value)
|
raise TypeError("Cannot convert %r to Decimal" % value)
|
||||||
|
@ -680,7 +670,7 @@ class Decimal(object):
|
||||||
if self_adjusted == other_adjusted and \
|
if self_adjusted == other_adjusted and \
|
||||||
self._int + (0,)*(self._exp - other._exp) == \
|
self._int + (0,)*(self._exp - other._exp) == \
|
||||||
other._int + (0,)*(other._exp - self._exp):
|
other._int + (0,)*(other._exp - self._exp):
|
||||||
return 0 # Equal, except in precision. ([0]*(-x) = [])
|
return 0 #equal, except in precision. ([0]*(-x) = [])
|
||||||
elif self_adjusted > other_adjusted and self._int[0] != 0:
|
elif self_adjusted > other_adjusted and self._int[0] != 0:
|
||||||
return (-1)**self._sign
|
return (-1)**self._sign
|
||||||
elif self_adjusted < other_adjusted and other._int[0] != 0:
|
elif self_adjusted < other_adjusted and other._int[0] != 0:
|
||||||
|
@ -691,7 +681,7 @@ class Decimal(object):
|
||||||
context = getcontext()
|
context = getcontext()
|
||||||
|
|
||||||
context = context._shallow_copy()
|
context = context._shallow_copy()
|
||||||
rounding = context._set_rounding(ROUND_UP) # Round away from 0
|
rounding = context._set_rounding(ROUND_UP) #round away from 0
|
||||||
|
|
||||||
flags = context._ignore_all_flags()
|
flags = context._ignore_all_flags()
|
||||||
res = self.__sub__(other, context=context)
|
res = self.__sub__(other, context=context)
|
||||||
|
@ -729,7 +719,7 @@ class Decimal(object):
|
||||||
if other is NotImplemented:
|
if other is NotImplemented:
|
||||||
return other
|
return other
|
||||||
|
|
||||||
# Compare(NaN, NaN) = NaN
|
#compare(NaN, NaN) = NaN
|
||||||
if (self._is_special or other and other._is_special):
|
if (self._is_special or other and other._is_special):
|
||||||
ans = self._check_nans(other, context)
|
ans = self._check_nans(other, context)
|
||||||
if ans:
|
if ans:
|
||||||
|
@ -1062,8 +1052,8 @@ class Decimal(object):
|
||||||
ans = self._check_nans(context=context)
|
ans = self._check_nans(context=context)
|
||||||
if ans:
|
if ans:
|
||||||
return ans
|
return ans
|
||||||
# Must be infinite, and incrementing makes no difference
|
|
||||||
return Decimal(self)
|
return Decimal(self) # Must be infinite, and incrementing makes no difference
|
||||||
|
|
||||||
L = list(self._int)
|
L = list(self._int)
|
||||||
L[-1] += 1
|
L[-1] += 1
|
||||||
|
@ -1232,6 +1222,7 @@ class Decimal(object):
|
||||||
return context._raise_error(DivisionByZero, 'x / 0', sign)
|
return context._raise_error(DivisionByZero, 'x / 0', sign)
|
||||||
|
|
||||||
#OK, so neither = 0, INF or NaN
|
#OK, so neither = 0, INF or NaN
|
||||||
|
|
||||||
shouldround = context._rounding_decision == ALWAYS_ROUND
|
shouldround = context._rounding_decision == ALWAYS_ROUND
|
||||||
|
|
||||||
#If we're dividing into ints, and self < other, stop.
|
#If we're dividing into ints, and self < other, stop.
|
||||||
|
@ -1382,7 +1373,7 @@ class Decimal(object):
|
||||||
# ignored in the calling function.
|
# ignored in the calling function.
|
||||||
context = context._shallow_copy()
|
context = context._shallow_copy()
|
||||||
flags = context._ignore_flags(Rounded, Inexact)
|
flags = context._ignore_flags(Rounded, Inexact)
|
||||||
# Keep DivisionImpossible flags
|
#keep DivisionImpossible flags
|
||||||
(side, r) = self.__divmod__(other, context=context)
|
(side, r) = self.__divmod__(other, context=context)
|
||||||
|
|
||||||
if r._isnan():
|
if r._isnan():
|
||||||
|
@ -1427,8 +1418,7 @@ class Decimal(object):
|
||||||
if r > comparison or decrease and r == comparison:
|
if r > comparison or decrease and r == comparison:
|
||||||
r._sign, comparison._sign = s1, s2
|
r._sign, comparison._sign = s1, s2
|
||||||
context.prec += 1
|
context.prec += 1
|
||||||
numbsquant = len(side.__add__(Decimal(1), context=context)._int)
|
if len(side.__add__(Decimal(1), context=context)._int) >= context.prec:
|
||||||
if numbsquant >= context.prec:
|
|
||||||
context.prec -= 1
|
context.prec -= 1
|
||||||
return context._raise_error(DivisionImpossible)[1]
|
return context._raise_error(DivisionImpossible)[1]
|
||||||
context.prec -= 1
|
context.prec -= 1
|
||||||
|
@ -1463,7 +1453,7 @@ class Decimal(object):
|
||||||
context = getcontext()
|
context = getcontext()
|
||||||
return context._raise_error(InvalidContext)
|
return context._raise_error(InvalidContext)
|
||||||
elif self._isinfinity():
|
elif self._isinfinity():
|
||||||
raise OverflowError("Cannot convert infinity to long")
|
raise OverflowError, "Cannot convert infinity to long"
|
||||||
if self._exp >= 0:
|
if self._exp >= 0:
|
||||||
s = ''.join(map(str, self._int)) + '0'*self._exp
|
s = ''.join(map(str, self._int)) + '0'*self._exp
|
||||||
else:
|
else:
|
||||||
|
@ -1540,8 +1530,7 @@ class Decimal(object):
|
||||||
return ans
|
return ans
|
||||||
context._raise_error(Inexact)
|
context._raise_error(Inexact)
|
||||||
context._raise_error(Rounded)
|
context._raise_error(Rounded)
|
||||||
c = context._raise_error(Overflow, 'above Emax', ans._sign)
|
return context._raise_error(Overflow, 'above Emax', ans._sign)
|
||||||
return c
|
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def _round(self, prec=None, rounding=None, context=None):
|
def _round(self, prec=None, rounding=None, context=None):
|
||||||
|
@ -1738,9 +1727,10 @@ class Decimal(object):
|
||||||
return Infsign[sign]
|
return Infsign[sign]
|
||||||
return Decimal( (sign, (0,), 0) )
|
return Decimal( (sign, (0,), 0) )
|
||||||
|
|
||||||
# With ludicrously large exponent, just raise an overflow and return inf.
|
#with ludicrously large exponent, just raise an overflow and return inf.
|
||||||
if not modulo and n > 0 \
|
if not modulo and n > 0 and (self._exp + len(self._int) - 1) * n > context.Emax \
|
||||||
and (self._exp + len(self._int) - 1) * n > context.Emax and self:
|
and self:
|
||||||
|
|
||||||
tmp = Decimal('inf')
|
tmp = Decimal('inf')
|
||||||
tmp._sign = sign
|
tmp._sign = sign
|
||||||
context._raise_error(Rounded)
|
context._raise_error(Rounded)
|
||||||
|
@ -1826,7 +1816,7 @@ class Decimal(object):
|
||||||
|
|
||||||
if exp._isinfinity() or self._isinfinity():
|
if exp._isinfinity() or self._isinfinity():
|
||||||
if exp._isinfinity() and self._isinfinity():
|
if exp._isinfinity() and self._isinfinity():
|
||||||
return self # If both are inf, it is OK
|
return self #if both are inf, it is OK
|
||||||
if context is None:
|
if context is None:
|
||||||
context = getcontext()
|
context = getcontext()
|
||||||
return context._raise_error(InvalidOperation,
|
return context._raise_error(InvalidOperation,
|
||||||
|
@ -1858,8 +1848,7 @@ class Decimal(object):
|
||||||
|
|
||||||
if self._is_special:
|
if self._is_special:
|
||||||
if self._isinfinity():
|
if self._isinfinity():
|
||||||
return context._raise_error(InvalidOperation,
|
return context._raise_error(InvalidOperation, 'rescale with an INF')
|
||||||
'rescale with an INF')
|
|
||||||
|
|
||||||
ans = self._check_nans(context=context)
|
ans = self._check_nans(context=context)
|
||||||
if ans:
|
if ans:
|
||||||
|
@ -1971,6 +1960,7 @@ class Decimal(object):
|
||||||
ans = ans.__add__(tmp.__mul__(Decimal((0, (8,1,9), -3)),
|
ans = ans.__add__(tmp.__mul__(Decimal((0, (8,1,9), -3)),
|
||||||
context=context), context=context)
|
context=context), context=context)
|
||||||
ans._exp -= 1 + tmp.adjusted() // 2
|
ans._exp -= 1 + tmp.adjusted() // 2
|
||||||
|
|
||||||
#ans is now a linear approximation.
|
#ans is now a linear approximation.
|
||||||
|
|
||||||
Emax, Emin = context.Emax, context.Emin
|
Emax, Emin = context.Emax, context.Emin
|
||||||
|
@ -1987,7 +1977,7 @@ class Decimal(object):
|
||||||
if context.prec == maxp:
|
if context.prec == maxp:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Round to the answer's precision-- the only error can be 1 ulp.
|
#round to the answer's precision-- the only error can be 1 ulp.
|
||||||
context.prec = firstprec
|
context.prec = firstprec
|
||||||
prevexp = ans.adjusted()
|
prevexp = ans.adjusted()
|
||||||
ans = ans._round(context=context)
|
ans = ans._round(context=context)
|
||||||
|
@ -2062,13 +2052,13 @@ class Decimal(object):
|
||||||
ans = self
|
ans = self
|
||||||
c = self.__cmp__(other)
|
c = self.__cmp__(other)
|
||||||
if c == 0:
|
if c == 0:
|
||||||
# If both operands are finite and equal in numerical value
|
# if both operands are finite and equal in numerical value
|
||||||
# then an ordering is applied:
|
# then an ordering is applied:
|
||||||
#
|
#
|
||||||
# If the signs differ then max returns the operand with the
|
# if the signs differ then max returns the operand with the
|
||||||
# positive sign and min returns the operand with the negative sign
|
# positive sign and min returns the operand with the negative sign
|
||||||
#
|
#
|
||||||
# If the signs are the same then the exponent is used to select
|
# if the signs are the same then the exponent is used to select
|
||||||
# the result.
|
# the result.
|
||||||
if self._sign != other._sign:
|
if self._sign != other._sign:
|
||||||
if self._sign:
|
if self._sign:
|
||||||
|
@ -2089,7 +2079,7 @@ class Decimal(object):
|
||||||
def min(self, other, context=None):
|
def min(self, other, context=None):
|
||||||
"""Returns the smaller value.
|
"""Returns the smaller value.
|
||||||
|
|
||||||
Like min(self, other) except if one is not a number, returns
|
like min(self, other) except if one is not a number, returns
|
||||||
NaN (and signals if one is sNaN). Also rounds.
|
NaN (and signals if one is sNaN). Also rounds.
|
||||||
"""
|
"""
|
||||||
other = _convert_other(other)
|
other = _convert_other(other)
|
||||||
|
@ -2097,7 +2087,7 @@ class Decimal(object):
|
||||||
return other
|
return other
|
||||||
|
|
||||||
if self._is_special or other._is_special:
|
if self._is_special or other._is_special:
|
||||||
# If one operand is a quiet NaN and the other is number, then the
|
# if one operand is a quiet NaN and the other is number, then the
|
||||||
# number is always returned
|
# number is always returned
|
||||||
sn = self._isnan()
|
sn = self._isnan()
|
||||||
on = other._isnan()
|
on = other._isnan()
|
||||||
|
@ -2111,13 +2101,13 @@ class Decimal(object):
|
||||||
ans = self
|
ans = self
|
||||||
c = self.__cmp__(other)
|
c = self.__cmp__(other)
|
||||||
if c == 0:
|
if c == 0:
|
||||||
# If both operands are finite and equal in numerical value
|
# if both operands are finite and equal in numerical value
|
||||||
# then an ordering is applied:
|
# then an ordering is applied:
|
||||||
#
|
#
|
||||||
# If the signs differ then max returns the operand with the
|
# if the signs differ then max returns the operand with the
|
||||||
# positive sign and min returns the operand with the negative sign
|
# positive sign and min returns the operand with the negative sign
|
||||||
#
|
#
|
||||||
# If the signs are the same then the exponent is used to select
|
# if the signs are the same then the exponent is used to select
|
||||||
# the result.
|
# the result.
|
||||||
if self._sign != other._sign:
|
if self._sign != other._sign:
|
||||||
if other._sign:
|
if other._sign:
|
||||||
|
@ -2156,7 +2146,7 @@ class Decimal(object):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Support for pickling, copy, and deepcopy
|
# support for pickling, copy, and deepcopy
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return (self.__class__, (str(self),))
|
return (self.__class__, (str(self),))
|
||||||
|
|
||||||
|
@ -2170,20 +2160,19 @@ class Decimal(object):
|
||||||
return self # My components are also immutable
|
return self # My components are also immutable
|
||||||
return self.__class__(str(self))
|
return self.__class__(str(self))
|
||||||
|
|
||||||
##### Context class ##########################################################
|
##### Context class ###########################################
|
||||||
|
|
||||||
# Get rounding method function:
|
|
||||||
rounding_functions = [name for name in Decimal.__dict__.keys()
|
# get rounding method function:
|
||||||
if name.startswith('_round_')]
|
rounding_functions = [name for name in Decimal.__dict__.keys() if name.startswith('_round_')]
|
||||||
for name in rounding_functions:
|
for name in rounding_functions:
|
||||||
# Name is like _round_half_even, goes to the global ROUND_HALF_EVEN value.
|
#name is like _round_half_even, goes to the global ROUND_HALF_EVEN value.
|
||||||
globalname = name[1:].upper()
|
globalname = name[1:].upper()
|
||||||
val = globals()[globalname]
|
val = globals()[globalname]
|
||||||
Decimal._pick_rounding_function[val] = name
|
Decimal._pick_rounding_function[val] = name
|
||||||
|
|
||||||
del name, val, globalname, rounding_functions
|
del name, val, globalname, rounding_functions
|
||||||
|
|
||||||
|
|
||||||
class ContextManager(object):
|
class ContextManager(object):
|
||||||
"""Helper class to simplify Context management.
|
"""Helper class to simplify Context management.
|
||||||
|
|
||||||
|
@ -2208,13 +2197,12 @@ class ContextManager(object):
|
||||||
def __exit__(self, t, v, tb):
|
def __exit__(self, t, v, tb):
|
||||||
setcontext(self.saved_context)
|
setcontext(self.saved_context)
|
||||||
|
|
||||||
|
|
||||||
class Context(object):
|
class Context(object):
|
||||||
"""Contains the context for a Decimal instance.
|
"""Contains the context for a Decimal instance.
|
||||||
|
|
||||||
Contains:
|
Contains:
|
||||||
prec - precision (for use in rounding, division, square roots..)
|
prec - precision (for use in rounding, division, square roots..)
|
||||||
rounding - rounding type (how you round).
|
rounding - rounding type. (how you round)
|
||||||
_rounding_decision - ALWAYS_ROUND, NEVER_ROUND -- do you round?
|
_rounding_decision - ALWAYS_ROUND, NEVER_ROUND -- do you round?
|
||||||
traps - If traps[exception] = 1, then the exception is
|
traps - If traps[exception] = 1, then the exception is
|
||||||
raised when it is caused. Otherwise, a value is
|
raised when it is caused. Otherwise, a value is
|
||||||
|
@ -2255,13 +2243,9 @@ class Context(object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Show the current context."""
|
"""Show the current context."""
|
||||||
s = []
|
s = []
|
||||||
s.append(
|
s.append('Context(prec=%(prec)d, rounding=%(rounding)s, Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d' % vars(self))
|
||||||
'Context(prec=%(prec)d, rounding=%(rounding)s, Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d'
|
s.append('flags=[' + ', '.join([f.__name__ for f, v in self.flags.items() if v]) + ']')
|
||||||
% vars(self))
|
s.append('traps=[' + ', '.join([t.__name__ for t, v in self.traps.items() if v]) + ']')
|
||||||
s.append('flags=[' + ', '.join([f.__name__ for f, v
|
|
||||||
in self.flags.items() if v]) + ']')
|
|
||||||
s.append('traps=[' + ', '.join([t.__name__ for t, v
|
|
||||||
in self.traps.items() if v]) + ']')
|
|
||||||
return ', '.join(s) + ')'
|
return ', '.join(s) + ')'
|
||||||
|
|
||||||
def get_manager(self):
|
def get_manager(self):
|
||||||
|
@ -2281,10 +2265,9 @@ class Context(object):
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""Returns a deep copy from self."""
|
"""Returns a deep copy from self."""
|
||||||
nc = Context(self.prec, self.rounding, self.traps.copy(),
|
nc = Context(self.prec, self.rounding, self.traps.copy(), self.flags.copy(),
|
||||||
self.flags.copy(), self._rounding_decision,
|
self._rounding_decision, self.Emin, self.Emax,
|
||||||
self.Emin, self.Emax, self.capitals,
|
self.capitals, self._clamp, self._ignored_flags)
|
||||||
self._clamp, self._ignored_flags)
|
|
||||||
return nc
|
return nc
|
||||||
__copy__ = copy
|
__copy__ = copy
|
||||||
|
|
||||||
|
@ -2331,7 +2314,7 @@ class Context(object):
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
"""A Context cannot be hashed."""
|
"""A Context cannot be hashed."""
|
||||||
# We inherit object.__hash__, so we must deny this explicitly
|
# We inherit object.__hash__, so we must deny this explicitly
|
||||||
raise TypeError("Cannot hash a Context.")
|
raise TypeError, "Cannot hash a Context."
|
||||||
|
|
||||||
def Etiny(self):
|
def Etiny(self):
|
||||||
"""Returns Etiny (= Emin - prec + 1)"""
|
"""Returns Etiny (= Emin - prec + 1)"""
|
||||||
|
@ -2357,6 +2340,7 @@ class Context(object):
|
||||||
|
|
||||||
This will make it not round for that operation.
|
This will make it not round for that operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rounding = self._rounding_decision
|
rounding = self._rounding_decision
|
||||||
self._rounding_decision = type
|
self._rounding_decision = type
|
||||||
return rounding
|
return rounding
|
||||||
|
@ -2544,10 +2528,10 @@ class Context(object):
|
||||||
def multiply(self, a, b):
|
def multiply(self, a, b):
|
||||||
"""multiply multiplies two operands.
|
"""multiply multiplies two operands.
|
||||||
|
|
||||||
If either operand is a special value then the general rules
|
If either operand is a special value then the general rules apply.
|
||||||
apply. Otherwise, the operands are multiplied together
|
Otherwise, the operands are multiplied together ('long multiplication'),
|
||||||
('long multiplication'), resulting in a number which may be
|
resulting in a number which may be as long as the sum of the lengths
|
||||||
as long as the sum of the lengths of the two operands.
|
of the two operands.
|
||||||
|
|
||||||
>>> ExtendedContext.multiply(Decimal('1.20'), Decimal('3'))
|
>>> ExtendedContext.multiply(Decimal('1.20'), Decimal('3'))
|
||||||
Decimal("3.60")
|
Decimal("3.60")
|
||||||
|
@ -2608,8 +2592,8 @@ class Context(object):
|
||||||
1) before use.
|
1) before use.
|
||||||
|
|
||||||
If the increased precision needed for the intermediate calculations
|
If the increased precision needed for the intermediate calculations
|
||||||
exceeds the capabilities of the implementation then an Invalid
|
exceeds the capabilities of the implementation then an Invalid operation
|
||||||
operation condition is raised.
|
condition is raised.
|
||||||
|
|
||||||
If, when raising to a negative power, an underflow occurs during the
|
If, when raising to a negative power, an underflow occurs during the
|
||||||
division into 1, the operation is not halted at that point but
|
division into 1, the operation is not halted at that point but
|
||||||
|
@ -2647,7 +2631,7 @@ class Context(object):
|
||||||
return a.__pow__(b, modulo, context=self)
|
return a.__pow__(b, modulo, context=self)
|
||||||
|
|
||||||
def quantize(self, a, b):
|
def quantize(self, a, b):
|
||||||
"""Returns a value equal to 'a' (rounded), having the exponent of 'b'.
|
"""Returns a value equal to 'a' (rounded) and having the exponent of 'b'.
|
||||||
|
|
||||||
The coefficient of the result is derived from that of the left-hand
|
The coefficient of the result is derived from that of the left-hand
|
||||||
operand. It may be rounded using the current rounding setting (if the
|
operand. It may be rounded using the current rounding setting (if the
|
||||||
|
@ -2657,8 +2641,8 @@ class Context(object):
|
||||||
|
|
||||||
Unlike other operations, if the length of the coefficient after the
|
Unlike other operations, if the length of the coefficient after the
|
||||||
quantize operation would be greater than precision then an Invalid
|
quantize operation would be greater than precision then an Invalid
|
||||||
operation condition is raised. This guarantees that, unless there is
|
operation condition is raised. This guarantees that, unless there is an
|
||||||
an error condition, the exponent of the result of a quantize is always
|
error condition, the exponent of the result of a quantize is always
|
||||||
equal to that of the right-hand operand.
|
equal to that of the right-hand operand.
|
||||||
|
|
||||||
Also unlike other operations, quantize will never raise Underflow, even
|
Also unlike other operations, quantize will never raise Underflow, even
|
||||||
|
@ -2701,9 +2685,9 @@ class Context(object):
|
||||||
"""Returns the remainder from integer division.
|
"""Returns the remainder from integer division.
|
||||||
|
|
||||||
The result is the residue of the dividend after the operation of
|
The result is the residue of the dividend after the operation of
|
||||||
calculating integer division as described for divide-integer, rounded
|
calculating integer division as described for divide-integer, rounded to
|
||||||
to precision digits if necessary. The sign of the result, if non-zero,
|
precision digits if necessary. The sign of the result, if non-zero, is
|
||||||
is the same as that of the original dividend.
|
the same as that of the original dividend.
|
||||||
|
|
||||||
This operation will fail under the same conditions as integer division
|
This operation will fail under the same conditions as integer division
|
||||||
(that is, if integer division on the same two operands would fail, the
|
(that is, if integer division on the same two operands would fail, the
|
||||||
|
@ -2769,7 +2753,7 @@ class Context(object):
|
||||||
return a.same_quantum(b)
|
return a.same_quantum(b)
|
||||||
|
|
||||||
def sqrt(self, a):
|
def sqrt(self, a):
|
||||||
"""Square root of a non-negative number to context precision.
|
"""Returns the square root of a non-negative number to context precision.
|
||||||
|
|
||||||
If the result must be inexact, it is rounded using the round-half-even
|
If the result must be inexact, it is rounded using the round-half-even
|
||||||
algorithm.
|
algorithm.
|
||||||
|
@ -2851,7 +2835,6 @@ class Context(object):
|
||||||
"""
|
"""
|
||||||
return a.to_integral(context=self)
|
return a.to_integral(context=self)
|
||||||
|
|
||||||
|
|
||||||
class _WorkRep(object):
|
class _WorkRep(object):
|
||||||
__slots__ = ('sign','int','exp')
|
__slots__ = ('sign','int','exp')
|
||||||
# sign: 0 or 1
|
# sign: 0 or 1
|
||||||
|
@ -2906,9 +2889,9 @@ def _normalize(op1, op2, shouldround = 0, prec = 0):
|
||||||
other_len = len(str(other.int))
|
other_len = len(str(other.int))
|
||||||
if numdigits > (other_len + prec + 1 - tmp_len):
|
if numdigits > (other_len + prec + 1 - tmp_len):
|
||||||
# If the difference in adjusted exps is > prec+1, we know
|
# If the difference in adjusted exps is > prec+1, we know
|
||||||
# other is insignificant, so might as well put a 1 after the
|
# other is insignificant, so might as well put a 1 after the precision.
|
||||||
# precision (since this is only for addition). Also stops
|
# (since this is only for addition.) Also stops use of massive longs.
|
||||||
# use of massive longs.
|
|
||||||
extend = prec + 2 - tmp_len
|
extend = prec + 2 - tmp_len
|
||||||
if extend <= 0:
|
if extend <= 0:
|
||||||
extend = 1
|
extend = 1
|
||||||
|
@ -2944,8 +2927,7 @@ def _adjust_coefficients(op1, op2):
|
||||||
|
|
||||||
return op1, op2, adjust
|
return op1, op2, adjust
|
||||||
|
|
||||||
|
##### Helper Functions ########################################
|
||||||
##### Helper Functions #######################################################
|
|
||||||
|
|
||||||
def _convert_other(other):
|
def _convert_other(other):
|
||||||
"""Convert other to Decimal.
|
"""Convert other to Decimal.
|
||||||
|
@ -3005,7 +2987,7 @@ def _isnan(num):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
##### Setup Specific Contexts ################################################
|
##### Setup Specific Contexts ################################
|
||||||
|
|
||||||
# The default context prototype used by Context()
|
# The default context prototype used by Context()
|
||||||
# Is mutable, so that new contexts can have different default values
|
# Is mutable, so that new contexts can have different default values
|
||||||
|
@ -3038,7 +3020,7 @@ ExtendedContext = Context(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
##### Useful Constants (internal use only) ###################################
|
##### Useful Constants (internal use only) ####################
|
||||||
|
|
||||||
#Reusable defaults
|
#Reusable defaults
|
||||||
Inf = Decimal('Inf')
|
Inf = Decimal('Inf')
|
||||||
|
@ -3050,7 +3032,7 @@ Infsign = (Inf, negInf)
|
||||||
NaN = Decimal('NaN')
|
NaN = Decimal('NaN')
|
||||||
|
|
||||||
|
|
||||||
##### crud for parsing strings ################################################
|
##### crud for parsing strings #################################
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# There's an optional sign at the start, and an optional exponent
|
# There's an optional sign at the start, and an optional exponent
|
||||||
|
@ -3070,16 +3052,13 @@ _parser = re.compile(r"""
|
||||||
([eE](?P<exp>[-+]? \d+))?
|
([eE](?P<exp>[-+]? \d+))?
|
||||||
# \s*
|
# \s*
|
||||||
$
|
$
|
||||||
""", re.VERBOSE).match # Uncomment the \s* to allow leading/trailing spaces
|
""", re.VERBOSE).match #Uncomment the \s* to allow leading or trailing spaces.
|
||||||
|
|
||||||
del re
|
del re
|
||||||
|
|
||||||
|
# return sign, n, p s.t. float string value == -1**sign * n * 10**p exactly
|
||||||
|
|
||||||
def _string2exact(s):
|
def _string2exact(s):
|
||||||
"""Return sign, n, p s.t.
|
|
||||||
|
|
||||||
Float string value == -1**sign * n * 10**p exactly
|
|
||||||
"""
|
|
||||||
m = _parser(s)
|
m = _parser(s)
|
||||||
if m is None:
|
if m is None:
|
||||||
raise ValueError("invalid literal for Decimal: %r" % s)
|
raise ValueError("invalid literal for Decimal: %r" % s)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue