mirror of
https://github.com/python/cpython.git
synced 2025-07-29 06:05:00 +00:00
General clean-up. Lot of margin corrections, comments, some typos.
Exceptions now are raised in the new style. And a mockup class is now also new style. Thanks Santiago Pereson.
This commit is contained in:
parent
8341aac123
commit
59c5884b4c
1 changed files with 170 additions and 159 deletions
135
Lib/decimal.py
135
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 the module is to support arithmetic using familiar
|
||||
"schoolhouse" rules and to avoid the some of tricky representation
|
||||
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,
|
||||
|
@ -379,7 +379,7 @@ _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
|
||||
|
@ -392,7 +392,7 @@ try:
|
|||
except ImportError:
|
||||
# Python was compiled without threads; create a mock object instead
|
||||
import sys
|
||||
class MockThreading:
|
||||
class MockThreading(object):
|
||||
def local(self, sys=sys):
|
||||
return sys.modules[__name__]
|
||||
threading = MockThreading()
|
||||
|
@ -502,7 +502,7 @@ def localcontext(ctx=None):
|
|||
return _ContextManager(ctx)
|
||||
|
||||
|
||||
##### Decimal class ###########################################
|
||||
##### Decimal class #######################################################
|
||||
|
||||
class Decimal(object):
|
||||
"""Floating point class for decimal arithmetic."""
|
||||
|
@ -518,7 +518,7 @@ class Decimal(object):
|
|||
|
||||
>>> Decimal('3.14') # string input
|
||||
Decimal("3.14")
|
||||
>>> Decimal((0, (3, 1, 4), -2)) # tuple input (sign, digit_tuple, exponent)
|
||||
>>> Decimal((0, (3, 1, 4), -2)) # tuple (sign, digit_tuple, exponent)
|
||||
Decimal("3.14")
|
||||
>>> Decimal(314) # int or long
|
||||
Decimal("314")
|
||||
|
@ -557,13 +557,13 @@ 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])
|
||||
if value[2] in ('F','n','N'):
|
||||
|
@ -611,7 +611,8 @@ class Decimal(object):
|
|||
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)
|
||||
|
@ -762,7 +763,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:
|
||||
|
@ -1096,7 +1097,8 @@ class Decimal(object):
|
|||
if ans:
|
||||
return ans
|
||||
|
||||
return Decimal(self) # Must be infinite, and incrementing makes no difference
|
||||
# Must be infinite, and incrementing makes no difference
|
||||
return Decimal(self)
|
||||
|
||||
L = list(self._int)
|
||||
L[-1] += 1
|
||||
|
@ -1265,7 +1267,6 @@ class Decimal(object):
|
|||
return context._raise_error(DivisionByZero, 'x / 0', sign)
|
||||
|
||||
# OK, so neither = 0, INF or NaN
|
||||
|
||||
shouldround = context._rounding_decision == ALWAYS_ROUND
|
||||
|
||||
# If we're dividing into ints, and self < other, stop.
|
||||
|
@ -1416,7 +1417,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():
|
||||
|
@ -1461,7 +1462,8 @@ class Decimal(object):
|
|||
if r > comparison or decrease and r == comparison:
|
||||
r._sign, comparison._sign = s1, s2
|
||||
context.prec += 1
|
||||
if len(side.__add__(Decimal(1), context=context)._int) >= context.prec:
|
||||
numbsquant = len(side.__add__(Decimal(1), context=context)._int)
|
||||
if numbsquant >= context.prec:
|
||||
context.prec -= 1
|
||||
return context._raise_error(DivisionImpossible)[1]
|
||||
context.prec -= 1
|
||||
|
@ -1496,7 +1498,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:
|
||||
|
@ -1573,7 +1575,8 @@ class Decimal(object):
|
|||
return ans
|
||||
context._raise_error(Inexact)
|
||||
context._raise_error(Rounded)
|
||||
return context._raise_error(Overflow, 'above Emax', ans._sign)
|
||||
c = context._raise_error(Overflow, 'above Emax', ans._sign)
|
||||
return c
|
||||
return ans
|
||||
|
||||
def _round(self, prec=None, rounding=None, context=None):
|
||||
|
@ -1770,9 +1773,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
|
||||
|
@ -1801,7 +1805,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():
|
||||
|
@ -2005,7 +2009,6 @@ class Decimal(object):
|
|||
ans._exp -= 1 + tmp.adjusted() // 2
|
||||
|
||||
# ans is now a linear approximation.
|
||||
|
||||
Emax, Emin = context.Emax, context.Emin
|
||||
context.Emax, context.Emin = DefaultContext.Emax, DefaultContext.Emin
|
||||
|
||||
|
@ -2020,7 +2023,7 @@ 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)
|
||||
|
@ -2081,7 +2084,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()
|
||||
|
@ -2095,13 +2098,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:
|
||||
|
@ -2122,7 +2125,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)
|
||||
|
@ -2130,7 +2133,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()
|
||||
|
@ -2144,13 +2147,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:
|
||||
|
@ -2189,7 +2192,7 @@ class Decimal(object):
|
|||
except TypeError:
|
||||
return 0
|
||||
|
||||
# support for pickling, copy, and deepcopy
|
||||
# Support for pickling, copy, and deepcopy
|
||||
def __reduce__(self):
|
||||
return (self.__class__, (str(self),))
|
||||
|
||||
|
@ -2203,11 +2206,12 @@ 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_')]
|
||||
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.
|
||||
globalname = name[1:].upper()
|
||||
|
@ -2236,7 +2240,7 @@ class Context(object):
|
|||
|
||||
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
|
||||
|
@ -2277,9 +2281,13 @@ 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))
|
||||
names = [f.__name__ for f, v in self.flags.items() if v]
|
||||
s.append('flags=[' + ', '.join(names) + ']')
|
||||
names = [t.__name__ for t, v in self.traps.items() if v]
|
||||
s.append('traps=[' + ', '.join(names) + ']')
|
||||
return ', '.join(s) + ')'
|
||||
|
||||
def clear_flags(self):
|
||||
|
@ -2296,9 +2304,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
|
||||
|
||||
|
@ -2345,7 +2353,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)"""
|
||||
|
@ -2623,8 +2631,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
|
||||
|
@ -2662,7 +2670,7 @@ class Context(object):
|
|||
return a.__pow__(b, modulo, context=self)
|
||||
|
||||
def quantize(self, a, b):
|
||||
"""Returns a value equal to 'a' (rounded) and having the exponent of 'b'.
|
||||
"""Returns a value equal to 'a' (rounded), 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
|
||||
|
@ -2672,8 +2680,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
|
||||
|
@ -2716,9 +2724,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
|
||||
|
@ -2784,7 +2792,7 @@ class Context(object):
|
|||
return a.same_quantum(b)
|
||||
|
||||
def sqrt(self, a):
|
||||
"""Returns the square root of a non-negative number to context precision.
|
||||
"""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.
|
||||
|
@ -2920,8 +2928,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:
|
||||
|
@ -2958,7 +2967,7 @@ def _adjust_coefficients(op1, op2):
|
|||
|
||||
return op1, op2, adjust
|
||||
|
||||
##### Helper Functions ########################################
|
||||
##### Helper Functions ####################################################
|
||||
|
||||
def _convert_other(other):
|
||||
"""Convert other to Decimal.
|
||||
|
@ -2999,7 +3008,7 @@ 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:]
|
||||
|
@ -3018,7 +3027,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
|
||||
|
@ -3051,7 +3060,7 @@ ExtendedContext = Context(
|
|||
)
|
||||
|
||||
|
||||
##### Useful Constants (internal use only) ####################
|
||||
##### Useful Constants (internal use only) ################################
|
||||
|
||||
# Reusable defaults
|
||||
Inf = Decimal('Inf')
|
||||
|
@ -3063,7 +3072,7 @@ 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
|
||||
|
@ -3087,9 +3096,11 @@ _parser = re.compile(r"""
|
|||
|
||||
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…
Add table
Add a link
Reference in a new issue