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
315
Lib/decimal.py
315
Lib/decimal.py
|
@ -29,8 +29,8 @@ and IEEE standard 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
|
||||
The purpose of the module is to support arithmetic using familiar
|
||||
"schoolhouse" rules and to avoid the some of 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,
|
||||
|
@ -136,7 +136,7 @@ __all__ = [
|
|||
|
||||
import copy as _copy
|
||||
|
||||
# Rounding
|
||||
#Rounding
|
||||
ROUND_DOWN = 'ROUND_DOWN'
|
||||
ROUND_HALF_UP = 'ROUND_HALF_UP'
|
||||
ROUND_HALF_EVEN = 'ROUND_HALF_EVEN'
|
||||
|
@ -145,11 +145,11 @@ ROUND_FLOOR = 'ROUND_FLOOR'
|
|||
ROUND_UP = 'ROUND_UP'
|
||||
ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
|
||||
|
||||
# Rounding decision (not part of the public API)
|
||||
#Rounding decision (not part of the public API)
|
||||
NEVER_ROUND = 'NEVER_ROUND' # Round in division (non-divmod), sqrt ONLY
|
||||
ALWAYS_ROUND = 'ALWAYS_ROUND' # Every operation rounds at end.
|
||||
|
||||
# Errors
|
||||
#Errors
|
||||
|
||||
class DecimalException(ArithmeticError):
|
||||
"""Base exception class.
|
||||
|
@ -160,17 +160,17 @@ class DecimalException(ArithmeticError):
|
|||
called if the others are present. This isn't actually used for
|
||||
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
|
||||
from DecimalException.
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
|
@ -185,7 +185,6 @@ class Clamped(DecimalException):
|
|||
this latter case, the exponent is reduced to fit and the corresponding
|
||||
number of zero digits are appended to the coefficient ("fold-down").
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidOperation(DecimalException):
|
||||
|
@ -208,11 +207,10 @@ class InvalidOperation(DecimalException):
|
|||
"""
|
||||
def handle(self, context, *args):
|
||||
if args:
|
||||
if args[0] == 1: # sNaN, must drop 's' but keep diagnostics
|
||||
if args[0] == 1: #sNaN, must drop 's' but keep diagnostics
|
||||
return Decimal( (args[1]._sign, args[1]._int, 'n') )
|
||||
return NaN
|
||||
|
||||
|
||||
class ConversionSyntax(InvalidOperation):
|
||||
"""Trying to convert badly formed string.
|
||||
|
||||
|
@ -220,9 +218,9 @@ class ConversionSyntax(InvalidOperation):
|
|||
converted to a number and it does not conform to the numeric string
|
||||
syntax. The result is [0,qNaN].
|
||||
"""
|
||||
def handle(self, context, *args):
|
||||
return (0, (0,), 'n') # Passed to something which uses a tuple.
|
||||
|
||||
def handle(self, context, *args):
|
||||
return (0, (0,), 'n') #Passed to something which uses a tuple.
|
||||
|
||||
class DivisionByZero(DecimalException, ZeroDivisionError):
|
||||
"""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
|
||||
-0, for power.
|
||||
"""
|
||||
|
||||
def handle(self, context, sign, double = None, *args):
|
||||
if double is not None:
|
||||
return (Infsign[sign],)*2
|
||||
return Infsign[sign]
|
||||
|
||||
|
||||
class DivisionImpossible(InvalidOperation):
|
||||
"""Cannot perform the division adequately.
|
||||
|
||||
|
@ -249,10 +247,10 @@ class DivisionImpossible(InvalidOperation):
|
|||
divide-integer or remainder operation had too many digits (would be
|
||||
longer than precision). The result is [0,qNaN].
|
||||
"""
|
||||
|
||||
def handle(self, context, *args):
|
||||
return (NaN, NaN)
|
||||
|
||||
|
||||
class DivisionUndefined(InvalidOperation, ZeroDivisionError):
|
||||
"""Undefined result of division.
|
||||
|
||||
|
@ -260,12 +258,12 @@ class DivisionUndefined(InvalidOperation, ZeroDivisionError):
|
|||
attempted (during a divide-integer, divide, or remainder operation), and
|
||||
the dividend is also zero. The result is [0,qNaN].
|
||||
"""
|
||||
|
||||
def handle(self, context, tup=None, *args):
|
||||
if tup is not None:
|
||||
return (NaN, NaN) # For 0 %0, 0 // 0
|
||||
return (NaN, NaN) #for 0 %0, 0 // 0
|
||||
return NaN
|
||||
|
||||
|
||||
class Inexact(DecimalException):
|
||||
"""Had to round, losing information.
|
||||
|
||||
|
@ -279,7 +277,6 @@ class Inexact(DecimalException):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidContext(InvalidOperation):
|
||||
"""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
|
||||
the values are required to be used. The result is [0,qNaN].
|
||||
"""
|
||||
|
||||
def handle(self, context, *args):
|
||||
return NaN
|
||||
|
||||
|
||||
class Rounded(DecimalException):
|
||||
"""Number got rounded (not necessarily changed during rounding).
|
||||
|
||||
|
@ -307,7 +304,6 @@ class Rounded(DecimalException):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Subnormal(DecimalException):
|
||||
"""Exponent < Emin before rounding.
|
||||
|
||||
|
@ -320,7 +316,6 @@ class Subnormal(DecimalException):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Overflow(Inexact, Rounded):
|
||||
"""Numerical overflow.
|
||||
|
||||
|
@ -342,6 +337,7 @@ class Overflow(Inexact, Rounded):
|
|||
result is 0, or is [1,inf] otherwise. In all cases, Inexact and Rounded
|
||||
will also be raised.
|
||||
"""
|
||||
|
||||
def handle(self, context, sign, *args):
|
||||
if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
|
||||
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.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# List of public traps and flags
|
||||
_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
|
||||
|
@ -385,34 +379,32 @@ _condition_map = {ConversionSyntax:InvalidOperation,
|
|||
DivisionUndefined:InvalidOperation,
|
||||
InvalidContext:InvalidOperation}
|
||||
|
||||
##### Context Functions #####################################################
|
||||
##### 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.currentThread() 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.
|
||||
# mock threading object with threading.local() returning the module namespace.
|
||||
|
||||
try:
|
||||
import threading
|
||||
except ImportError:
|
||||
# Python was compiled without threads; create a mock object instead
|
||||
import sys
|
||||
class MockThreading(object):
|
||||
class MockThreading:
|
||||
def local(self, sys=sys):
|
||||
return sys.modules[__name__]
|
||||
threading = MockThreading()
|
||||
del sys, MockThreading
|
||||
|
||||
|
||||
try:
|
||||
threading.local
|
||||
|
||||
except AttributeError:
|
||||
|
||||
# To fix reloading, force it to create a new context
|
||||
# Old contexts have different exceptions in their dicts, making problems.
|
||||
#To fix reloading, force it to create a new context
|
||||
#Old contexts have different exceptions in their dicts, making problems.
|
||||
if hasattr(threading.currentThread(), '__decimal_context__'):
|
||||
del threading.currentThread().__decimal_context__
|
||||
|
||||
|
@ -467,7 +459,7 @@ else:
|
|||
del threading, local # Don't contaminate the namespace
|
||||
|
||||
|
||||
##### Decimal class ##########################################################
|
||||
##### Decimal class ###########################################
|
||||
|
||||
class Decimal(object):
|
||||
"""Floating point class for decimal arithmetic."""
|
||||
|
@ -483,7 +475,7 @@ class Decimal(object):
|
|||
|
||||
>>> Decimal('3.14') # string input
|
||||
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(314) # int or long
|
||||
Decimal("314")
|
||||
|
@ -522,13 +514,12 @@ class Decimal(object):
|
|||
# tuple/list conversion (possibly from as_tuple())
|
||||
if isinstance(value, (list,tuple)):
|
||||
if len(value) != 3:
|
||||
raise ValueError('Invalid arguments')
|
||||
raise ValueError, 'Invalid arguments'
|
||||
if value[0] not in (0,1):
|
||||
raise ValueError('Invalid sign')
|
||||
raise ValueError, 'Invalid sign'
|
||||
for digit in value[1]:
|
||||
if not isinstance(digit, (int,long)) or digit < 0:
|
||||
raise ValueError("The second value in the tuple must be "+
|
||||
"composed of non negative integer elements.")
|
||||
raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
|
||||
|
||||
self._sign = value[0]
|
||||
self._int = tuple(value[1])
|
||||
|
@ -562,23 +553,22 @@ class Decimal(object):
|
|||
if _isnan(value):
|
||||
sig, sign, diag = _isnan(value)
|
||||
self._is_special = True
|
||||
if len(diag) > context.prec: # Diagnostic info too long
|
||||
if len(diag) > context.prec: #Diagnostic info too long
|
||||
self._sign, self._int, self._exp = \
|
||||
context._raise_error(ConversionSyntax)
|
||||
return self
|
||||
if sig == 1:
|
||||
self._exp = 'n' #qNaN
|
||||
else: # sig == 2
|
||||
else: #sig == 2
|
||||
self._exp = 'N' #sNaN
|
||||
self._sign = sign
|
||||
self._int = tuple(map(int, diag)) # Diagnostic info
|
||||
self._int = tuple(map(int, diag)) #Diagnostic info
|
||||
return self
|
||||
try:
|
||||
self._sign, self._int, self._exp = _string2exact(value)
|
||||
except ValueError:
|
||||
self._is_special = True
|
||||
self._sign, self._int, self._exp = \
|
||||
context._raise_error(ConversionSyntax)
|
||||
self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
|
||||
return self
|
||||
|
||||
raise TypeError("Cannot convert %r to Decimal" % value)
|
||||
|
@ -667,9 +657,9 @@ class Decimal(object):
|
|||
return cmp(self._isinfinity(), other._isinfinity())
|
||||
|
||||
if not self and not other:
|
||||
return 0 # If both 0, sign comparison isn't certain.
|
||||
return 0 #If both 0, sign comparison isn't certain.
|
||||
|
||||
# If different signs, neg one is less
|
||||
#If different signs, neg one is less
|
||||
if other._sign < self._sign:
|
||||
return -1
|
||||
if self._sign < other._sign:
|
||||
|
@ -680,7 +670,7 @@ class Decimal(object):
|
|||
if self_adjusted == other_adjusted and \
|
||||
self._int + (0,)*(self._exp - other._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:
|
||||
return (-1)**self._sign
|
||||
elif self_adjusted < other_adjusted and other._int[0] != 0:
|
||||
|
@ -691,7 +681,7 @@ class Decimal(object):
|
|||
context = getcontext()
|
||||
|
||||
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()
|
||||
res = self.__sub__(other, context=context)
|
||||
|
@ -729,7 +719,7 @@ class Decimal(object):
|
|||
if other is NotImplemented:
|
||||
return other
|
||||
|
||||
# Compare(NaN, NaN) = NaN
|
||||
#compare(NaN, NaN) = NaN
|
||||
if (self._is_special or other and other._is_special):
|
||||
ans = self._check_nans(other, context)
|
||||
if ans:
|
||||
|
@ -790,11 +780,11 @@ class Decimal(object):
|
|||
tmp = map(str, self._int)
|
||||
numdigits = len(self._int)
|
||||
leftdigits = self._exp + numdigits
|
||||
if eng and not self: # self = 0eX wants 0[.0[0]]eY, not [[0]0]0eY
|
||||
if self._exp < 0 and self._exp >= -6: # short, no need for e/E
|
||||
if eng and not self: #self = 0eX wants 0[.0[0]]eY, not [[0]0]0eY
|
||||
if self._exp < 0 and self._exp >= -6: #short, no need for e/E
|
||||
s = '-'*self._sign + '0.' + '0'*(abs(self._exp))
|
||||
return s
|
||||
# exp is closest mult. of 3 >= self._exp
|
||||
#exp is closest mult. of 3 >= self._exp
|
||||
exp = ((self._exp - 1)// 3 + 1) * 3
|
||||
if exp != self._exp:
|
||||
s = '0.'+'0'*(exp - self._exp)
|
||||
|
@ -806,7 +796,7 @@ class Decimal(object):
|
|||
else:
|
||||
s += 'e'
|
||||
if exp > 0:
|
||||
s += '+' # 0.0e+3, not 0.0e3
|
||||
s += '+' #0.0e+3, not 0.0e3
|
||||
s += str(exp)
|
||||
s = '-'*self._sign + s
|
||||
return s
|
||||
|
@ -946,19 +936,19 @@ class Decimal(object):
|
|||
return ans
|
||||
|
||||
if self._isinfinity():
|
||||
# If both INF, same sign => same as both, opposite => error.
|
||||
#If both INF, same sign => same as both, opposite => error.
|
||||
if self._sign != other._sign and other._isinfinity():
|
||||
return context._raise_error(InvalidOperation, '-INF + INF')
|
||||
return Decimal(self)
|
||||
if other._isinfinity():
|
||||
return Decimal(other) # Can't both be infinity here
|
||||
return Decimal(other) #Can't both be infinity here
|
||||
|
||||
shouldround = context._rounding_decision == ALWAYS_ROUND
|
||||
|
||||
exp = min(self._exp, other._exp)
|
||||
negativezero = 0
|
||||
if context.rounding == ROUND_FLOOR and self._sign != other._sign:
|
||||
# If the answer is 0, the sign should be negative, in this case.
|
||||
#If the answer is 0, the sign should be negative, in this case.
|
||||
negativezero = 1
|
||||
|
||||
if not self and not other:
|
||||
|
@ -993,19 +983,19 @@ class Decimal(object):
|
|||
return Decimal((negativezero, (0,), exp))
|
||||
if op1.int < op2.int:
|
||||
op1, op2 = op2, op1
|
||||
# OK, now abs(op1) > abs(op2)
|
||||
#OK, now abs(op1) > abs(op2)
|
||||
if op1.sign == 1:
|
||||
result.sign = 1
|
||||
op1.sign, op2.sign = op2.sign, op1.sign
|
||||
else:
|
||||
result.sign = 0
|
||||
# So we know the sign, and op1 > 0.
|
||||
#So we know the sign, and op1 > 0.
|
||||
elif op1.sign == 1:
|
||||
result.sign = 1
|
||||
op1.sign, op2.sign = (0, 0)
|
||||
else:
|
||||
result.sign = 0
|
||||
# Now, op1 > abs(op2) > 0
|
||||
#Now, op1 > abs(op2) > 0
|
||||
|
||||
if op2.sign == 0:
|
||||
result.int = op1.int + op2.int
|
||||
|
@ -1062,8 +1052,8 @@ class Decimal(object):
|
|||
ans = self._check_nans(context=context)
|
||||
if 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[-1] += 1
|
||||
|
@ -1119,7 +1109,7 @@ class Decimal(object):
|
|||
if not self or not other:
|
||||
ans = Decimal((resultsign, (0,), resultexp))
|
||||
if shouldround:
|
||||
# Fixing in case the exponent is out of bounds
|
||||
#Fixing in case the exponent is out of bounds
|
||||
ans = ans._fix(context)
|
||||
return ans
|
||||
|
||||
|
@ -1138,7 +1128,7 @@ class Decimal(object):
|
|||
op1 = _WorkRep(self)
|
||||
op2 = _WorkRep(other)
|
||||
|
||||
ans = Decimal((resultsign, map(int, str(op1.int * op2.int)), resultexp))
|
||||
ans = Decimal( (resultsign, map(int, str(op1.int * op2.int)), resultexp))
|
||||
if shouldround:
|
||||
ans = ans._fix(context)
|
||||
|
||||
|
@ -1231,11 +1221,12 @@ class Decimal(object):
|
|||
sign, 1)
|
||||
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
|
||||
|
||||
# If we're dividing into ints, and self < other, stop.
|
||||
# self.__abs__(0) does not round.
|
||||
#If we're dividing into ints, and self < other, stop.
|
||||
#self.__abs__(0) does not round.
|
||||
if divmod and (self.__abs__(0, context) < other.__abs__(0, context)):
|
||||
|
||||
if divmod == 1 or divmod == 3:
|
||||
|
@ -1247,7 +1238,7 @@ class Decimal(object):
|
|||
ans2)
|
||||
|
||||
elif divmod == 2:
|
||||
# Don't round the mod part, if we don't need it.
|
||||
#Don't round the mod part, if we don't need it.
|
||||
return (Decimal( (sign, (0,), 0) ), Decimal(self))
|
||||
|
||||
op1 = _WorkRep(self)
|
||||
|
@ -1296,7 +1287,7 @@ class Decimal(object):
|
|||
op1.exp -= 1
|
||||
|
||||
if res.exp == 0 and divmod and op2.int > op1.int:
|
||||
# Solves an error in precision. Same as a previous block.
|
||||
#Solves an error in precision. Same as a previous block.
|
||||
|
||||
if res.int >= prec_limit and shouldround:
|
||||
return context._raise_error(DivisionImpossible)
|
||||
|
@ -1382,7 +1373,7 @@ class Decimal(object):
|
|||
# ignored in the calling function.
|
||||
context = context._shallow_copy()
|
||||
flags = context._ignore_flags(Rounded, Inexact)
|
||||
# Keep DivisionImpossible flags
|
||||
#keep DivisionImpossible flags
|
||||
(side, r) = self.__divmod__(other, context=context)
|
||||
|
||||
if r._isnan():
|
||||
|
@ -1405,7 +1396,7 @@ class Decimal(object):
|
|||
|
||||
if r < comparison:
|
||||
r._sign, comparison._sign = s1, s2
|
||||
# Get flags now
|
||||
#Get flags now
|
||||
self.__divmod__(other, context=context)
|
||||
return r._fix(context)
|
||||
r._sign, comparison._sign = s1, s2
|
||||
|
@ -1427,8 +1418,7 @@ class Decimal(object):
|
|||
if r > comparison or decrease and r == comparison:
|
||||
r._sign, comparison._sign = s1, s2
|
||||
context.prec += 1
|
||||
numbsquant = len(side.__add__(Decimal(1), context=context)._int)
|
||||
if numbsquant >= context.prec:
|
||||
if len(side.__add__(Decimal(1), context=context)._int) >= context.prec:
|
||||
context.prec -= 1
|
||||
return context._raise_error(DivisionImpossible)[1]
|
||||
context.prec -= 1
|
||||
|
@ -1463,7 +1453,7 @@ class Decimal(object):
|
|||
context = getcontext()
|
||||
return context._raise_error(InvalidContext)
|
||||
elif self._isinfinity():
|
||||
raise OverflowError("Cannot convert infinity to long")
|
||||
raise OverflowError, "Cannot convert infinity to long"
|
||||
if self._exp >= 0:
|
||||
s = ''.join(map(str, self._int)) + '0'*self._exp
|
||||
else:
|
||||
|
@ -1517,13 +1507,13 @@ class Decimal(object):
|
|||
context._raise_error(Clamped)
|
||||
return ans
|
||||
ans = ans._rescale(Etiny, context=context)
|
||||
# It isn't zero, and exp < Emin => subnormal
|
||||
#It isn't zero, and exp < Emin => subnormal
|
||||
context._raise_error(Subnormal)
|
||||
if context.flags[Inexact]:
|
||||
context._raise_error(Underflow)
|
||||
else:
|
||||
if ans:
|
||||
# Only raise subnormal if non-zero.
|
||||
#Only raise subnormal if non-zero.
|
||||
context._raise_error(Subnormal)
|
||||
else:
|
||||
Etop = context.Etop()
|
||||
|
@ -1540,8 +1530,7 @@ class Decimal(object):
|
|||
return ans
|
||||
context._raise_error(Inexact)
|
||||
context._raise_error(Rounded)
|
||||
c = context._raise_error(Overflow, 'above Emax', ans._sign)
|
||||
return c
|
||||
return context._raise_error(Overflow, 'above Emax', ans._sign)
|
||||
return ans
|
||||
|
||||
def _round(self, prec=None, rounding=None, context=None):
|
||||
|
@ -1601,18 +1590,18 @@ class Decimal(object):
|
|||
ans = Decimal( (temp._sign, tmp, temp._exp - expdiff))
|
||||
return ans
|
||||
|
||||
# OK, but maybe all the lost digits are 0.
|
||||
#OK, but maybe all the lost digits are 0.
|
||||
lostdigits = self._int[expdiff:]
|
||||
if lostdigits == (0,) * len(lostdigits):
|
||||
ans = Decimal( (temp._sign, temp._int[:prec], temp._exp - expdiff))
|
||||
# Rounded, but not Inexact
|
||||
#Rounded, but not Inexact
|
||||
context._raise_error(Rounded)
|
||||
return ans
|
||||
|
||||
# Okay, let's round and lose data
|
||||
|
||||
this_function = getattr(temp, self._pick_rounding_function[rounding])
|
||||
# Now we've got the rounding function
|
||||
#Now we've got the rounding function
|
||||
|
||||
if prec != context.prec:
|
||||
context = context._shallow_copy()
|
||||
|
@ -1708,7 +1697,7 @@ class Decimal(object):
|
|||
context = getcontext()
|
||||
|
||||
if self._is_special or n._is_special or n.adjusted() > 8:
|
||||
# Because the spot << doesn't work with really big exponents
|
||||
#Because the spot << doesn't work with really big exponents
|
||||
if n._isinfinity() or n.adjusted() > 8:
|
||||
return context._raise_error(InvalidOperation, 'x ** INF')
|
||||
|
||||
|
@ -1738,9 +1727,10 @@ class Decimal(object):
|
|||
return Infsign[sign]
|
||||
return Decimal( (sign, (0,), 0) )
|
||||
|
||||
# With ludicrously large exponent, just raise an overflow and return inf.
|
||||
if not modulo and n > 0 \
|
||||
and (self._exp + len(self._int) - 1) * n > context.Emax and self:
|
||||
#with ludicrously large exponent, just raise an overflow and return inf.
|
||||
if not modulo and n > 0 and (self._exp + len(self._int) - 1) * n > context.Emax \
|
||||
and self:
|
||||
|
||||
tmp = Decimal('inf')
|
||||
tmp._sign = sign
|
||||
context._raise_error(Rounded)
|
||||
|
@ -1759,7 +1749,7 @@ class Decimal(object):
|
|||
context = context._shallow_copy()
|
||||
context.prec = firstprec + elength + 1
|
||||
if n < 0:
|
||||
# n is a long now, not Decimal instance
|
||||
#n is a long now, not Decimal instance
|
||||
n = -n
|
||||
mul = Decimal(1).__div__(mul, context=context)
|
||||
|
||||
|
@ -1768,7 +1758,7 @@ class Decimal(object):
|
|||
spot <<= 1
|
||||
|
||||
spot >>= 1
|
||||
# Spot is the highest power of 2 less than n
|
||||
#Spot is the highest power of 2 less than n
|
||||
while spot:
|
||||
val = val.__mul__(val, context=context)
|
||||
if val._isinfinity():
|
||||
|
@ -1826,7 +1816,7 @@ class Decimal(object):
|
|||
|
||||
if exp._isinfinity() or 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:
|
||||
context = getcontext()
|
||||
return context._raise_error(InvalidOperation,
|
||||
|
@ -1858,8 +1848,7 @@ class Decimal(object):
|
|||
|
||||
if self._is_special:
|
||||
if self._isinfinity():
|
||||
return context._raise_error(InvalidOperation,
|
||||
'rescale with an INF')
|
||||
return context._raise_error(InvalidOperation, 'rescale with an INF')
|
||||
|
||||
ans = self._check_nans(context=context)
|
||||
if ans:
|
||||
|
@ -1931,13 +1920,13 @@ class Decimal(object):
|
|||
return Decimal(self)
|
||||
|
||||
if not self:
|
||||
# exponent = self._exp / 2, using round_down.
|
||||
# if self._exp < 0:
|
||||
#exponent = self._exp / 2, using round_down.
|
||||
#if self._exp < 0:
|
||||
# exp = (self._exp+1) // 2
|
||||
# else:
|
||||
#else:
|
||||
exp = (self._exp) // 2
|
||||
if self._sign == 1:
|
||||
# sqrt(-0) = -0
|
||||
#sqrt(-0) = -0
|
||||
return Decimal( (1, (0,), exp))
|
||||
else:
|
||||
return Decimal( (0, (0,), exp))
|
||||
|
@ -1971,7 +1960,8 @@ class Decimal(object):
|
|||
ans = ans.__add__(tmp.__mul__(Decimal((0, (8,1,9), -3)),
|
||||
context=context), context=context)
|
||||
ans._exp -= 1 + tmp.adjusted() // 2
|
||||
# ans is now a linear approximation.
|
||||
|
||||
#ans is now a linear approximation.
|
||||
|
||||
Emax, Emin = context.Emax, context.Emin
|
||||
context.Emax, context.Emin = DefaultContext.Emax, DefaultContext.Emin
|
||||
|
@ -1987,12 +1977,12 @@ class Decimal(object):
|
|||
if context.prec == maxp:
|
||||
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
|
||||
prevexp = ans.adjusted()
|
||||
ans = ans._round(context=context)
|
||||
|
||||
# Now, check if the other last digits are better.
|
||||
#Now, check if the other last digits are better.
|
||||
context.prec = firstprec + 1
|
||||
# In case we rounded up another digit and we should actually go lower.
|
||||
if prevexp != ans.adjusted():
|
||||
|
@ -2024,10 +2014,10 @@ class Decimal(object):
|
|||
context._raise_error(Rounded)
|
||||
context._raise_error(Inexact)
|
||||
else:
|
||||
# Exact answer, so let's set the exponent right.
|
||||
# if self._exp < 0:
|
||||
#Exact answer, so let's set the exponent right.
|
||||
#if self._exp < 0:
|
||||
# exp = (self._exp +1)// 2
|
||||
# else:
|
||||
#else:
|
||||
exp = self._exp // 2
|
||||
context.prec += ans._exp - exp
|
||||
ans = ans._rescale(exp, context=context)
|
||||
|
@ -2062,13 +2052,13 @@ class Decimal(object):
|
|||
ans = self
|
||||
c = self.__cmp__(other)
|
||||
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:
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
if self._sign != other._sign:
|
||||
if self._sign:
|
||||
|
@ -2089,7 +2079,7 @@ class Decimal(object):
|
|||
def min(self, other, context=None):
|
||||
"""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.
|
||||
"""
|
||||
other = _convert_other(other)
|
||||
|
@ -2097,7 +2087,7 @@ class Decimal(object):
|
|||
return other
|
||||
|
||||
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
|
||||
sn = self._isnan()
|
||||
on = other._isnan()
|
||||
|
@ -2111,13 +2101,13 @@ class Decimal(object):
|
|||
ans = self
|
||||
c = self.__cmp__(other)
|
||||
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:
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
if self._sign != other._sign:
|
||||
if other._sign:
|
||||
|
@ -2152,11 +2142,11 @@ class Decimal(object):
|
|||
"""Return the adjusted exponent of self"""
|
||||
try:
|
||||
return self._exp + len(self._int) - 1
|
||||
# If NaN or Infinity, self._exp is string
|
||||
#If NaN or Infinity, self._exp is string
|
||||
except TypeError:
|
||||
return 0
|
||||
|
||||
# Support for pickling, copy, and deepcopy
|
||||
# support for pickling, copy, and deepcopy
|
||||
def __reduce__(self):
|
||||
return (self.__class__, (str(self),))
|
||||
|
||||
|
@ -2170,20 +2160,19 @@ class Decimal(object):
|
|||
return self # My components are also immutable
|
||||
return self.__class__(str(self))
|
||||
|
||||
##### Context class ##########################################################
|
||||
##### Context class ###########################################
|
||||
|
||||
# Get rounding method function:
|
||||
rounding_functions = [name for name in Decimal.__dict__.keys()
|
||||
if name.startswith('_round_')]
|
||||
|
||||
# get rounding method function:
|
||||
rounding_functions = [name for name in Decimal.__dict__.keys() if name.startswith('_round_')]
|
||||
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()
|
||||
val = globals()[globalname]
|
||||
Decimal._pick_rounding_function[val] = name
|
||||
|
||||
del name, val, globalname, rounding_functions
|
||||
|
||||
|
||||
class ContextManager(object):
|
||||
"""Helper class to simplify Context management.
|
||||
|
||||
|
@ -2208,13 +2197,12 @@ class ContextManager(object):
|
|||
def __exit__(self, t, v, tb):
|
||||
setcontext(self.saved_context)
|
||||
|
||||
|
||||
class Context(object):
|
||||
"""Contains the context for a Decimal instance.
|
||||
|
||||
Contains:
|
||||
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?
|
||||
traps - If traps[exception] = 1, then the exception is
|
||||
raised when it is caused. Otherwise, a value is
|
||||
|
@ -2255,13 +2243,9 @@ class Context(object):
|
|||
def __repr__(self):
|
||||
"""Show the current context."""
|
||||
s = []
|
||||
s.append(
|
||||
'Context(prec=%(prec)d, rounding=%(rounding)s, Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d'
|
||||
% vars(self))
|
||||
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]) + ']')
|
||||
s.append('Context(prec=%(prec)d, rounding=%(rounding)s, Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d' % vars(self))
|
||||
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) + ')'
|
||||
|
||||
def get_manager(self):
|
||||
|
@ -2281,10 +2265,9 @@ class Context(object):
|
|||
|
||||
def copy(self):
|
||||
"""Returns a deep copy from self."""
|
||||
nc = Context(self.prec, self.rounding, self.traps.copy(),
|
||||
self.flags.copy(), self._rounding_decision,
|
||||
self.Emin, self.Emax, self.capitals,
|
||||
self._clamp, self._ignored_flags)
|
||||
nc = Context(self.prec, self.rounding, self.traps.copy(), self.flags.copy(),
|
||||
self._rounding_decision, self.Emin, self.Emax,
|
||||
self.capitals, self._clamp, self._ignored_flags)
|
||||
return nc
|
||||
__copy__ = copy
|
||||
|
||||
|
@ -2298,16 +2281,16 @@ class Context(object):
|
|||
"""
|
||||
error = _condition_map.get(condition, condition)
|
||||
if error in self._ignored_flags:
|
||||
# Don't touch the flag
|
||||
#Don't touch the flag
|
||||
return error().handle(self, *args)
|
||||
|
||||
self.flags[error] += 1
|
||||
if not self.traps[error]:
|
||||
# The errors define how to handle themselves.
|
||||
#The errors define how to handle themselves.
|
||||
return condition().handle(self, *args)
|
||||
|
||||
# Errors should only be risked on copies of the context
|
||||
# self._ignored_flags = []
|
||||
#self._ignored_flags = []
|
||||
raise error, explanation
|
||||
|
||||
def _ignore_all_flags(self):
|
||||
|
@ -2331,7 +2314,7 @@ class Context(object):
|
|||
def __hash__(self):
|
||||
"""A Context cannot be hashed."""
|
||||
# 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):
|
||||
"""Returns Etiny (= Emin - prec + 1)"""
|
||||
|
@ -2357,6 +2340,7 @@ class Context(object):
|
|||
|
||||
This will make it not round for that operation.
|
||||
"""
|
||||
|
||||
rounding = self._rounding_decision
|
||||
self._rounding_decision = type
|
||||
return rounding
|
||||
|
@ -2385,7 +2369,7 @@ class Context(object):
|
|||
d = Decimal(num, context=self)
|
||||
return d._fix(self)
|
||||
|
||||
# Methods
|
||||
#Methods
|
||||
def abs(self, a):
|
||||
"""Returns the absolute value of the operand.
|
||||
|
||||
|
@ -2544,10 +2528,10 @@ class Context(object):
|
|||
def multiply(self, a, b):
|
||||
"""multiply multiplies two operands.
|
||||
|
||||
If either operand is a special value then the general rules
|
||||
apply. Otherwise, the operands are multiplied together
|
||||
('long multiplication'), resulting in a number which may be
|
||||
as long as the sum of the lengths of the two operands.
|
||||
If either operand is a special value then the general rules apply.
|
||||
Otherwise, the operands are multiplied together ('long multiplication'),
|
||||
resulting in a number which may be as long as the sum of the lengths
|
||||
of the two operands.
|
||||
|
||||
>>> ExtendedContext.multiply(Decimal('1.20'), Decimal('3'))
|
||||
Decimal("3.60")
|
||||
|
@ -2608,8 +2592,8 @@ class Context(object):
|
|||
1) before use.
|
||||
|
||||
If the increased precision needed for the intermediate calculations
|
||||
exceeds the capabilities of the implementation then an Invalid
|
||||
operation condition is raised.
|
||||
exceeds the capabilities of the implementation then an Invalid operation
|
||||
condition is raised.
|
||||
|
||||
If, when raising to a negative power, an underflow occurs during the
|
||||
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)
|
||||
|
||||
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
|
||||
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
|
||||
quantize operation would be greater than precision then an Invalid
|
||||
operation condition is raised. This guarantees that, unless there is
|
||||
an error condition, the exponent of the result of a quantize is always
|
||||
operation condition is raised. This guarantees that, unless there is an
|
||||
error condition, the exponent of the result of a quantize is always
|
||||
equal to that of the right-hand operand.
|
||||
|
||||
Also unlike other operations, quantize will never raise Underflow, even
|
||||
|
@ -2701,9 +2685,9 @@ class Context(object):
|
|||
"""Returns the remainder from integer division.
|
||||
|
||||
The result is the residue of the dividend after the operation of
|
||||
calculating integer division as described for divide-integer, rounded
|
||||
to precision digits if necessary. The sign of the result, if non-zero,
|
||||
is the same as that of the original dividend.
|
||||
calculating integer division as described for divide-integer, rounded to
|
||||
precision digits if necessary. The sign of the result, if non-zero, is
|
||||
the same as that of the original dividend.
|
||||
|
||||
This operation will fail under the same conditions as integer division
|
||||
(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)
|
||||
|
||||
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
|
||||
algorithm.
|
||||
|
@ -2851,7 +2835,6 @@ class Context(object):
|
|||
"""
|
||||
return a.to_integral(context=self)
|
||||
|
||||
|
||||
class _WorkRep(object):
|
||||
__slots__ = ('sign','int','exp')
|
||||
# sign: 0 or 1
|
||||
|
@ -2906,9 +2889,9 @@ def _normalize(op1, op2, shouldround = 0, prec = 0):
|
|||
other_len = len(str(other.int))
|
||||
if numdigits > (other_len + prec + 1 - tmp_len):
|
||||
# If the difference in adjusted exps is > prec+1, we know
|
||||
# other is insignificant, so might as well put a 1 after the
|
||||
# precision (since this is only for addition). Also stops
|
||||
# use of massive longs.
|
||||
# other is insignificant, so might as well put a 1 after the precision.
|
||||
# (since this is only for addition.) Also stops use of massive longs.
|
||||
|
||||
extend = prec + 2 - tmp_len
|
||||
if extend <= 0:
|
||||
extend = 1
|
||||
|
@ -2930,13 +2913,13 @@ def _adjust_coefficients(op1, op2):
|
|||
Used on _WorkRep instances during division.
|
||||
"""
|
||||
adjust = 0
|
||||
# If op1 is smaller, make it larger
|
||||
#If op1 is smaller, make it larger
|
||||
while op2.int > op1.int:
|
||||
op1.int *= 10
|
||||
op1.exp -= 1
|
||||
adjust += 1
|
||||
|
||||
# If op2 is too small, make it larger
|
||||
#If op2 is too small, make it larger
|
||||
while op1.int >= (10 * op2.int):
|
||||
op2.int *= 10
|
||||
op2.exp -= 1
|
||||
|
@ -2944,8 +2927,7 @@ def _adjust_coefficients(op1, op2):
|
|||
|
||||
return op1, op2, adjust
|
||||
|
||||
|
||||
##### Helper Functions #######################################################
|
||||
##### Helper Functions ########################################
|
||||
|
||||
def _convert_other(other):
|
||||
"""Convert other to Decimal.
|
||||
|
@ -2986,16 +2968,16 @@ def _isnan(num):
|
|||
if not num:
|
||||
return 0
|
||||
|
||||
# get the sign, get rid of trailing [+-]
|
||||
#get the sign, get rid of trailing [+-]
|
||||
sign = 0
|
||||
if num[0] == '+':
|
||||
num = num[1:]
|
||||
elif num[0] == '-': # elif avoids '+-nan'
|
||||
elif num[0] == '-': #elif avoids '+-nan'
|
||||
num = num[1:]
|
||||
sign = 1
|
||||
|
||||
if num.startswith('nan'):
|
||||
if len(num) > 3 and not num[3:].isdigit(): # diagnostic info
|
||||
if len(num) > 3 and not num[3:].isdigit(): #diagnostic info
|
||||
return 0
|
||||
return (1, sign, num[3:].lstrip('0'))
|
||||
if num.startswith('snan'):
|
||||
|
@ -3005,7 +2987,7 @@ def _isnan(num):
|
|||
return 0
|
||||
|
||||
|
||||
##### Setup Specific Contexts ################################################
|
||||
##### Setup Specific Contexts ################################
|
||||
|
||||
# The default context prototype used by Context()
|
||||
# Is mutable, so that new contexts can have different default values
|
||||
|
@ -3038,19 +3020,19 @@ ExtendedContext = Context(
|
|||
)
|
||||
|
||||
|
||||
##### Useful Constants (internal use only) ###################################
|
||||
##### Useful Constants (internal use only) ####################
|
||||
|
||||
# Reusable defaults
|
||||
#Reusable defaults
|
||||
Inf = Decimal('Inf')
|
||||
negInf = Decimal('-Inf')
|
||||
|
||||
# Infsign[sign] is infinity w/ that sign
|
||||
#Infsign[sign] is infinity w/ that sign
|
||||
Infsign = (Inf, negInf)
|
||||
|
||||
NaN = Decimal('NaN')
|
||||
|
||||
|
||||
##### crud for parsing strings ################################################
|
||||
##### crud for parsing strings #################################
|
||||
import re
|
||||
|
||||
# There's an optional sign at the start, and an optional exponent
|
||||
|
@ -3070,16 +3052,13 @@ _parser = re.compile(r"""
|
|||
([eE](?P<exp>[-+]? \d+))?
|
||||
# \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
|
||||
|
||||
# return sign, n, p s.t. float string value == -1**sign * n * 10**p exactly
|
||||
|
||||
def _string2exact(s):
|
||||
"""Return sign, n, p s.t.
|
||||
|
||||
Float string value == -1**sign * n * 10**p exactly
|
||||
"""
|
||||
m = _parser(s)
|
||||
if m is None:
|
||||
raise ValueError("invalid literal for Decimal: %r" % s)
|
||||
|
|
Loading…
Reference in New Issue