/lib-python/2.7/decimal.py
Python | 6192 lines | 6160 code | 4 blank | 28 comment | 9 complexity | 028979387d621e04a0406f71310817e0 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- # Copyright (c) 2004 Python Software Foundation.
- # All rights reserved.
- # Written by Eric Price <eprice at tjhsst.edu>
- # and Facundo Batista <facundo at taniquetil.com.ar>
- # and Raymond Hettinger <python at rcn.com>
- # and Aahz <aahz at pobox.com>
- # and Tim Peters
- # This module is currently Py2.3 compatible and should be kept that way
- # unless a major compelling advantage arises. IOW, 2.3 compatibility is
- # strongly preferred, but not guaranteed.
- # Also, this module should be kept in sync with the latest updates of
- # the IBM specification as it evolves. Those updates will be treated
- # as bug fixes (deviation from the spec is a compatibility, usability
- # bug) and will be backported. At this point the spec is stabilizing
- # and the updates are becoming fewer, smaller, and less significant.
- """
- This is a Py2.3 implementation of decimal floating point arithmetic based on
- the General Decimal Arithmetic Specification:
- http://speleotrove.com/decimal/decarith.html
- and IEEE standard 854-1987:
- www.cs.berkeley.edu/~ejr/projects/754/private/drafts/854-1987/dir.html
- Decimal floating point has finite precision with arbitrarily large bounds.
- The purpose of this module is to support arithmetic using familiar
- "schoolhouse" rules and to avoid some of the tricky representation
- issues associated with binary floating point. The package is especially
- useful for financial applications or for contexts where users have
- expectations that are at odds with binary floating point (for instance,
- in binary floating point, 1.00 % 0.1 gives 0.09999999999999995 instead
- of the expected Decimal('0.00') returned by decimal floating point).
- Here are some examples of using the decimal module:
- >>> from decimal import *
- >>> setcontext(ExtendedContext)
- >>> Decimal(0)
- Decimal('0')
- >>> Decimal('1')
- Decimal('1')
- >>> Decimal('-.0123')
- Decimal('-0.0123')
- >>> Decimal(123456)
- Decimal('123456')
- >>> Decimal('123.45e12345678901234567890')
- Decimal('1.2345E+12345678901234567892')
- >>> Decimal('1.33') + Decimal('1.27')
- Decimal('2.60')
- >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41')
- Decimal('-2.20')
- >>> dig = Decimal(1)
- >>> print dig / Decimal(3)
- 0.333333333
- >>> getcontext().prec = 18
- >>> print dig / Decimal(3)
- 0.333333333333333333
- >>> print dig.sqrt()
- 1
- >>> print Decimal(3).sqrt()
- 1.73205080756887729
- >>> print Decimal(3) ** 123
- 4.85192780976896427E+58
- >>> inf = Decimal(1) / Decimal(0)
- >>> print inf
- Infinity
- >>> neginf = Decimal(-1) / Decimal(0)
- >>> print neginf
- -Infinity
- >>> print neginf + inf
- NaN
- >>> print neginf * inf
- -Infinity
- >>> print dig / 0
- Infinity
- >>> getcontext().traps[DivisionByZero] = 1
- >>> print dig / 0
- Traceback (most recent call last):
- ...
- ...
- ...
- DivisionByZero: x / 0
- >>> c = Context()
- >>> c.traps[InvalidOperation] = 0
- >>> print c.flags[InvalidOperation]
- 0
- >>> c.divide(Decimal(0), Decimal(0))
- Decimal('NaN')
- >>> c.traps[InvalidOperation] = 1
- >>> print c.flags[InvalidOperation]
- 1
- >>> c.flags[InvalidOperation] = 0
- >>> print c.flags[InvalidOperation]
- 0
- >>> print c.divide(Decimal(0), Decimal(0))
- Traceback (most recent call last):
- ...
- ...
- ...
- InvalidOperation: 0 / 0
- >>> print c.flags[InvalidOperation]
- 1
- >>> c.flags[InvalidOperation] = 0
- >>> c.traps[InvalidOperation] = 0
- >>> print c.divide(Decimal(0), Decimal(0))
- NaN
- >>> print c.flags[InvalidOperation]
- 1
- >>>
- """
- __all__ = [
- # Two major classes
- 'Decimal', 'Context',
- # Contexts
- 'DefaultContext', 'BasicContext', 'ExtendedContext',
- # Exceptions
- 'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero',
- 'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow',
- # Constants for use in setting up contexts
- 'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING',
- 'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP',
- # Functions for manipulating contexts
- 'setcontext', 'getcontext', 'localcontext'
- ]
- __version__ = '1.70' # Highest version of the spec this complies with
- import copy as _copy
- import math as _math
- import numbers as _numbers
- try:
- from collections import namedtuple as _namedtuple
- DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent')
- except ImportError:
- DecimalTuple = lambda *args: args
- # Rounding
- ROUND_DOWN = 'ROUND_DOWN'
- ROUND_HALF_UP = 'ROUND_HALF_UP'
- ROUND_HALF_EVEN = 'ROUND_HALF_EVEN'
- ROUND_CEILING = 'ROUND_CEILING'
- ROUND_FLOOR = 'ROUND_FLOOR'
- ROUND_UP = 'ROUND_UP'
- ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
- ROUND_05UP = 'ROUND_05UP'
- # Errors
- class DecimalException(ArithmeticError):
- """Base exception class.
- Used exceptions derive from this.
- If an exception derives from another exception besides this (such as
- Underflow (Inexact, Rounded, Subnormal) that indicates that it is only
- 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 not 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):
- pass
- class Clamped(DecimalException):
- """Exponent of a 0 changed to fit bounds.
- This occurs and signals clamped if the exponent of a result has been
- altered in order to fit the constraints of a specific concrete
- representation. This may occur when the exponent of a zero result would
- be outside the bounds of a representation, or when a large normal
- number would have an encoded exponent that cannot be represented. In
- this latter case, the exponent is reduced to fit and the corresponding
- number of zero digits are appended to the coefficient ("fold-down").
- """
- class InvalidOperation(DecimalException):
- """An invalid operation was performed.
- Various bad things cause this:
- Something creates a signaling NaN
- -INF + INF
- 0 * (+-)INF
- (+-)INF / (+-)INF
- x % 0
- (+-)INF % x
- x._rescale( non-integer )
- sqrt(-x) , x > 0
- 0 ** 0
- x ** (non-integer)
- x ** (+-)INF
- An operand is invalid
- The result of the operation after these is a quiet positive NaN,
- except when the cause is a signaling NaN, in which case the result is
- also a quiet NaN, but with the original sign, and an optional
- diagnostic information.
- """
- def handle(self, context, *args):
- if args:
- ans = _dec_from_triple(args[0]._sign, args[0]._int, 'n', True)
- return ans._fix_nan(context)
- return _NaN
- class ConversionSyntax(InvalidOperation):
- """Trying to convert badly formed string.
- This occurs and signals invalid-operation if an string is being
- 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 _NaN
- class DivisionByZero(DecimalException, ZeroDivisionError):
- """Division by 0.
- This occurs and signals division-by-zero if division of a finite number
- by zero was attempted (during a divide-integer or divide operation, or a
- power operation with negative right-hand operand), and the dividend was
- not zero.
- The result of the operation is [sign,inf], where sign is the exclusive
- 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, *args):
- return _SignedInfinity[sign]
- class DivisionImpossible(InvalidOperation):
- """Cannot perform the division adequately.
- This occurs and signals invalid-operation if the integer result of a
- 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
- class DivisionUndefined(InvalidOperation, ZeroDivisionError):
- """Undefined result of division.
- This occurs and signals invalid-operation if division by zero was
- attempted (during a divide-integer, divide, or remainder operation), and
- the dividend is also zero. The result is [0,qNaN].
- """
- def handle(self, context, *args):
- return _NaN
- class Inexact(DecimalException):
- """Had to round, losing information.
- This occurs and signals inexact whenever the result of an operation is
- not exact (that is, it needed to be rounded and any discarded digits
- were non-zero), or if an overflow or underflow condition occurs. The
- result in all cases is unchanged.
- The inexact signal may be tested (or trapped) to determine if a given
- operation (or sequence of operations) was inexact.
- """
- class InvalidContext(InvalidOperation):
- """Invalid context. Unknown rounding, for example.
- This occurs and signals invalid-operation if an invalid context was
- detected during an operation. This can occur if contexts are not checked
- on creation and either the precision exceeds the capability of the
- underlying concrete representation or an unknown or unsupported rounding
- 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).
- This occurs and signals rounded whenever the result of an operation is
- rounded (that is, some zero or non-zero digits were discarded from the
- coefficient), or if an overflow or underflow condition occurs. The
- result in all cases is unchanged.
- The rounded signal may be tested (or trapped) to determine if a given
- operation (or sequence of operations) caused a loss of precision.
- """
- class Subnormal(DecimalException):
- """Exponent < Emin before rounding.
- This occurs and signals subnormal whenever the result of a conversion or
- operation is subnormal (that is, its adjusted exponent is less than
- Emin, before any rounding). The result in all cases is unchanged.
- The subnormal signal may be tested (or trapped) to determine if a given
- or operation (or sequence of operations) yielded a subnormal result.
- """
- class Overflow(Inexact, Rounded):
- """Numerical overflow.
- This occurs and signals overflow if the adjusted exponent of a result
- (from a conversion or from an operation that is not an attempt to divide
- by zero), after rounding, would be greater than the largest value that
- can be handled by the implementation (the value Emax).
- The result depends on the rounding mode:
- For round-half-up and round-half-even (and for round-half-down and
- round-up, if implemented), the result of the operation is [sign,inf],
- where sign is the sign of the intermediate result. For round-down, the
- result is the largest finite number that can be represented in the
- current precision, with the sign of the intermediate result. For
- round-ceiling, the result is the same as for round-down if the sign of
- the intermediate result is 1, or is [0,inf] otherwise. For round-floor,
- the result is the same as for round-down if the sign of the intermediate
- 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):
- return _SignedInfinity[sign]
- if sign == 0:
- if context.rounding == ROUND_CEILING:
- return _SignedInfinity[sign]
- return _dec_from_triple(sign, '9'*context.prec,
- context.Emax-context.prec+1)
- if sign == 1:
- if context.rounding == ROUND_FLOOR:
- return _SignedInfinity[sign]
- return _dec_from_triple(sign, '9'*context.prec,
- context.Emax-context.prec+1)
- class Underflow(Inexact, Rounded, Subnormal):
- """Numerical underflow with result rounded to 0.
- This occurs and signals underflow if a result is inexact and the
- adjusted exponent of the result would be smaller (more negative) than
- the smallest value that can be handled by the implementation (the value
- Emin). That is, the result is both inexact and subnormal.
- The result after an underflow will be a subnormal number rounded, if
- necessary, so that its exponent is not less than Etiny. This may result
- in 0 with the sign of the intermediate result and an exponent of Etiny.
- In all cases, Inexact, Rounded, and Subnormal will also be raised.
- """
- # List of public traps and flags
- _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
- Underflow, InvalidOperation, Subnormal]
- # Map conditions (per the spec) to signals
- _condition_map = {ConversionSyntax:InvalidOperation,
- DivisionImpossible:InvalidOperation,
- DivisionUndefined:InvalidOperation,
- InvalidContext:InvalidOperation}
- ##### 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.
- try:
- import threading
- except ImportError:
- # Python was compiled without threads; create a mock object instead
- import sys
- class MockThreading(object):
- def local(self, sys=sys):
- return sys.modules[__name__]
- threading = MockThreading()
- del sys, MockThreading
- 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.
- if hasattr(threading.currentThread(), '__decimal_context__'):
- del threading.currentThread().__decimal_context__
- def setcontext(context):
- """Set this thread's context to context."""
- if context in (DefaultContext, BasicContext, ExtendedContext):
- context = context.copy()
- context.clear_flags()
- threading.currentThread().__decimal_context__ = context
- def getcontext():
- """Returns this thread's context.
- If this thread does not yet have a context, returns
- a new context and sets this thread's context.
- New contexts are copies of DefaultContext.
- """
- try:
- return threading.currentThread().__decimal_context__
- except AttributeError:
- context = Context()
- threading.currentThread().__decimal_context__ = context
- return context
- else:
- local = threading.local()
- if hasattr(local, '__decimal_context__'):
- del local.__decimal_context__
- def getcontext(_local=local):
- """Returns this thread's context.
- If this thread does not yet have a context, returns
- a new context and sets this thread's context.
- New contexts are copies of DefaultContext.
- """
- try:
- return _local.__decimal_context__
- except AttributeError:
- context = Context()
- _local.__decimal_context__ = context
- return context
- def setcontext(context, _local=local):
- """Set this thread's context to context."""
- if context in (DefaultContext, BasicContext, ExtendedContext):
- context = context.copy()
- context.clear_flags()
- _local.__decimal_context__ = context
- del threading, local # Don't contaminate the namespace
- def localcontext(ctx=None):
- """Return a context manager for a copy of the supplied context
- Uses a copy of the current context if no context is specified
- The returned context manager creates a local decimal context
- in a with statement:
- def sin(x):
- with localcontext() as ctx:
- ctx.prec += 2
- # Rest of sin calculation algorithm
- # uses a precision 2 greater than normal
- return +s # Convert result to normal precision
- def sin(x):
- with localcontext(ExtendedContext):
- # Rest of sin calculation algorithm
- # uses the Extended Context from the
- # General Decimal Arithmetic Specification
- return +s # Convert result to normal context
- >>> setcontext(DefaultContext)
- >>> print getcontext().prec
- 28
- >>> with localcontext():
- ... ctx = getcontext()
- ... ctx.prec += 2
- ... print ctx.prec
- ...
- 30
- >>> with localcontext(ExtendedContext):
- ... print getcontext().prec
- ...
- 9
- >>> print getcontext().prec
- 28
- """
- if ctx is None: ctx = getcontext()
- return _ContextManager(ctx)
- ##### Decimal class #######################################################
- class Decimal(object):
- """Floating point class for decimal arithmetic."""
- __slots__ = ('_exp','_int','_sign', '_is_special')
- # Generally, the value of the Decimal instance is given by
- # (-1)**_sign * _int * 10**_exp
- # Special values are signified by _is_special == True
- # We're immutable, so use __new__ not __init__
- def __new__(cls, value="0", context=None):
- """Create a decimal point instance.
- >>> Decimal('3.14') # string input
- Decimal('3.14')
- >>> Decimal((0, (3, 1, 4), -2)) # tuple (sign, digit_tuple, exponent)
- Decimal('3.14')
- >>> Decimal(314) # int or long
- Decimal('314')
- >>> Decimal(Decimal(314)) # another decimal instance
- Decimal('314')
- >>> Decimal(' 3.14 \\n') # leading and trailing whitespace okay
- Decimal('3.14')
- """
- # Note that the coefficient, self._int, is actually stored as
- # a string rather than as a tuple of digits. This speeds up
- # the "digits to integer" and "integer to digits" conversions
- # that are used in almost every arithmetic operation on
- # Decimals. This is an internal detail: the as_tuple function
- # and the Decimal constructor still deal with tuples of
- # digits.
- self = object.__new__(cls)
- # From a string
- # REs insist on real strings, so we can too.
- if isinstance(value, basestring):
- m = _parser(value.strip())
- if m is None:
- if context is None:
- context = getcontext()
- return context._raise_error(ConversionSyntax,
- "Invalid literal for Decimal: %r" % value)
- if m.group('sign') == "-":
- self._sign = 1
- else:
- self._sign = 0
- intpart = m.group('int')
- if intpart is not None:
- # finite number
- fracpart = m.group('frac') or ''
- exp = int(m.group('exp') or '0')
- self._int = str(int(intpart+fracpart))
- self._exp = exp - len(fracpart)
- self._is_special = False
- else:
- diag = m.group('diag')
- if diag is not None:
- # NaN
- self._int = str(int(diag or '0')).lstrip('0')
- if m.group('signal'):
- self._exp = 'N'
- else:
- self._exp = 'n'
- else:
- # infinity
- self._int = '0'
- self._exp = 'F'
- self._is_special = True
- return self
- # From an integer
- if isinstance(value, (int,long)):
- if value >= 0:
- self._sign = 0
- else:
- self._sign = 1
- self._exp = 0
- self._int = str(abs(value))
- self._is_special = False
- return self
- # From another decimal
- if isinstance(value, Decimal):
- self._exp = value._exp
- self._sign = value._sign
- self._int = value._int
- self._is_special = value._is_special
- return self
- # From an internal working value
- if isinstance(value, _WorkRep):
- self._sign = value.sign
- self._int = str(value.int)
- self._exp = int(value.exp)
- self._is_special = False
- return self
- # tuple/list conversion (possibly from as_tuple())
- if isinstance(value, (list,tuple)):
- if len(value) != 3:
- raise ValueError('Invalid tuple size in creation of Decimal '
- 'from list or tuple. The list or tuple '
- 'should have exactly three elements.')
- # process sign. The isinstance test rejects floats
- if not (isinstance(value[0], (int, long)) and value[0] in (0,1)):
- raise ValueError("Invalid sign. The first value in the tuple "
- "should be an integer; either 0 for a "
- "positive number or 1 for a negative number.")
- self._sign = value[0]
- if value[2] == 'F':
- # infinity: value[1] is ignored
- self._int = '0'
- self._exp = value[2]
- self._is_special = True
- else:
- # process and validate the digits in value[1]
- digits = []
- for digit in value[1]:
- if isinstance(digit, (int, long)) and 0 <= digit <= 9:
- # skip leading zeros
- if digits or digit != 0:
- digits.append(digit)
- else:
- raise ValueError("The second value in the tuple must "
- "be composed of integers in the range "
- "0 through 9.")
- if value[2] in ('n', 'N'):
- # NaN: digits form the diagnostic
- self._int = ''.join(map(str, digits))
- self._exp = value[2]
- self._is_special = True
- elif isinstance(value[2], (int, long)):
- # finite number: digits give the coefficient
- self._int = ''.join(map(str, digits or [0]))
- self._exp = value[2]
- self._is_special = False
- else:
- raise ValueError("The third value in the tuple must "
- "be an integer, or one of the "
- "strings 'F', 'n', 'N'.")
- return self
- if isinstance(value, float):
- value = Decimal.from_float(value)
- self._exp = value._exp
- self._sign = value._sign
- self._int = value._int
- self._is_special = value._is_special
- return self
- raise TypeError("Cannot convert %r to Decimal" % value)
- # @classmethod, but @decorator is not valid Python 2.3 syntax, so
- # don't use it (see notes on Py2.3 compatibility at top of file)
- def from_float(cls, f):
- """Converts a float to a decimal number, exactly.
- Note that Decimal.from_float(0.1) is not the same as Decimal('0.1').
- Since 0.1 is not exactly representable in binary floating point, the
- value is stored as the nearest representable value which is
- 0x1.999999999999ap-4. The exact equivalent of the value in decimal
- is 0.1000000000000000055511151231257827021181583404541015625.
- >>> Decimal.from_float(0.1)
- Decimal('0.1000000000000000055511151231257827021181583404541015625')
- >>> Decimal.from_float(float('nan'))
- Decimal('NaN')
- >>> Decimal.from_float(float('inf'))
- Decimal('Infinity')
- >>> Decimal.from_float(-float('inf'))
- Decimal('-Infinity')
- >>> Decimal.from_float(-0.0)
- Decimal('-0')
- """
- if isinstance(f, (int, long)): # handle integer inputs
- return cls(f)
- if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float
- return cls(repr(f))
- if _math.copysign(1.0, f) == 1.0:
- sign = 0
- else:
- sign = 1
- n, d = abs(f).as_integer_ratio()
- k = d.bit_length() - 1
- result = _dec_from_triple(sign, str(n*5**k), -k)
- if cls is Decimal:
- return result
- else:
- return cls(result)
- from_float = classmethod(from_float)
- def _isnan(self):
- """Returns whether the number is not actually one.
- 0 if a number
- 1 if NaN
- 2 if sNaN
- """
- if self._is_special:
- exp = self._exp
- if exp == 'n':
- return 1
- elif exp == 'N':
- return 2
- return 0
- def _isinfinity(self):
- """Returns whether the number is infinite
- 0 if finite or not a number
- 1 if +INF
- -1 if -INF
- """
- if self._exp == 'F':
- if self._sign:
- return -1
- return 1
- return 0
- def _check_nans(self, other=None, context=None):
- """Returns whether the number is not actually one.
- if self, other are sNaN, signal
- if self, other are NaN return nan
- return 0
- Done before operations.
- """
- self_is_nan = self._isnan()
- if other is None:
- other_is_nan = False
- else:
- other_is_nan = other._isnan()
- if self_is_nan or other_is_nan:
- if context is None:
- context = getcontext()
- if self_is_nan == 2:
- return context._raise_error(InvalidOperation, 'sNaN',
- self)
- if other_is_nan == 2:
- return context._raise_error(InvalidOperation, 'sNaN',
- other)
- if self_is_nan:
- return self._fix_nan(context)
- return other._fix_nan(context)
- return 0
- def _compare_check_nans(self, other, context):
- """Version of _check_nans used for the signaling comparisons
- compare_signal, __le__, __lt__, __ge__, __gt__.
- Signal InvalidOperation if either self or other is a (quiet
- or signaling) NaN. Signaling NaNs take precedence over quiet
- NaNs.
- Return 0 if neither operand is a NaN.
- """
- if context is None:
- context = getcontext()
- if self._is_special or other._is_special:
- if self.is_snan():
- return context._raise_error(InvalidOperation,
- 'comparison involving sNaN',
- self)
- elif other.is_snan():
- return context._raise_error(InvalidOperation,
- 'comparison involving sNaN',
- other)
- elif self.is_qnan():
- return context._raise_error(InvalidOperation,
- 'comparison involving NaN',
- self)
- elif other.is_qnan():
- return context._raise_error(InvalidOperation,
- 'comparison involving NaN',
- other)
- return 0
- def __nonzero__(self):
- """Return True if self is nonzero; otherwise return False.
- NaNs and infinities are considered nonzero.
- """
- return self._is_special or self._int != '0'
- def _cmp(self, other):
- """Compare the two non-NaN decimal instances self and other.
- Returns -1 if self < other, 0 if self == other and 1
- if self > other. This routine is for internal use only."""
- if self._is_special or other._is_special:
- self_inf = self._isinfinity()
- other_inf = other._isinfinity()
- if self_inf == other_inf:
- return 0
- elif self_inf < other_inf:
- return -1
- else:
- return 1
- # check for zeros; Decimal('0') == Decimal('-0')
- if not self:
- if not other:
- return 0
- else:
- return -((-1)**other._sign)
- if not other:
- return (-1)**self._sign
- # If different signs, neg one is less
- if other._sign < self._sign:
- return -1
- if self._sign < other._sign:
- return 1
- self_adjusted = self.adjusted()
- other_adjusted = other.adjusted()
- if self_adjusted == other_adjusted:
- self_padded = self._int + '0'*(self._exp - other._exp)
- other_padded = other._int + '0'*(other._exp - self._exp)
- if self_padded == other_padded:
- return 0
- elif self_padded < other_padded:
- return -(-1)**self._sign
- else:
- return (-1)**self._sign
- elif self_adjusted > other_adjusted:
- return (-1)**self._sign
- else: # self_adjusted < other_adjusted
- return -((-1)**self._sign)
- # Note: The Decimal standard doesn't cover rich comparisons for
- # Decimals. In particular, the specification is silent on the
- # subject of what should happen for a comparison involving a NaN.
- # We take the following approach:
- #
- # == comparisons involving a quiet NaN always return False
- # != comparisons involving a quiet NaN always return True
- # == or != comparisons involving a signaling NaN signal
- # InvalidOperation, and return False or True as above if the
- # InvalidOperation is not trapped.
- # <, >, <= and >= comparisons involving a (quiet or signaling)
- # NaN signal InvalidOperation, and return False if the
- # InvalidOperation is not trapped.
- #
- # This behavior is designed to conform as closely as possible to
- # that specified by IEEE 754.
- def __eq__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- if self._check_nans(other, context):
- return False
- return self._cmp(other) == 0
- def __ne__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- if self._check_nans(other, context):
- return True
- return self._cmp(other) != 0
- def __lt__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- ans = self._compare_check_nans(other, context)
- if ans:
- return False
- return self._cmp(other) < 0
- def __le__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- ans = self._compare_check_nans(other, context)
- if ans:
- return False
- return self._cmp(other) <= 0
- def __gt__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- ans = self._compare_check_nans(other, context)
- if ans:
- return False
- return self._cmp(other) > 0
- def __ge__(self, other, context=None):
- other = _convert_other(other, allow_float=True)
- if other is NotImplemented:
- return other
- ans = self._compare_check_nans(other, context)
- if ans:
- return False
- return self._cmp(other) >= 0
- def compare(self, other, context=None):
- """Compares one to another.
- -1 => a < b
- 0 => a = b
- 1 => a > b
- NaN => one is NaN
- Like __cmp__, but returns Decimal instances.
- """
- other = _convert_other(other, raiseit=True)
- # Compare(NaN, NaN) = NaN
- if (self._is_special or other and other._is_special):
- ans = self._check_nans(other, context)
- if ans:
- return ans
- return Decimal(self._cmp(other))
- def __hash__(self):
- """x.__hash__() <==> hash(x)"""
- # Decimal integers must hash the same as the ints
- #
- # The hash of a nonspecial noninteger Decimal must depend only
- # on the value of that Decimal, and not on its representation.
- # For example: hash(Decimal('100E-1')) == hash(Decimal('10')).
- # Equality comparisons involving signaling nans can raise an
- # exception; since equality checks are implicitly and
- # unpredictably used when checking set and dict membership, we
- # prevent signaling nans from being used as set elements or
- # dict keys by making __hash__ raise an exception.
- if self._is_special:
- if self.is_snan():
- raise TypeError('Cannot hash a signaling NaN value.')
- elif self.is_nan():
- # 0 to match hash(float('nan'))
- return 0
- else:
- # values chosen to match hash(float('inf')) and
- # hash(float('-inf')).
- if self._sign:
- return -271828
- else:
- return 314159
- # In Python 2.7, we're allowing comparisons (but not
- # arithmetic operations) between floats and Decimals; so if
- # a Decimal instance is exactly representable as a float then
- # its hash should match that of the float.
- self_as_float = float(self)
- if Decimal.from_float(self_as_float) == self:
- return hash(self_as_float)
- if self._isinteger():
- op = _WorkRep(self.to_integral_value())
- # to make computation feasible for Decimals with large
- # exponent, we use the fact that hash(n) == hash(m) for
- # any two nonzero integers n and m such that (i) n and m
- # have the same sign, and (ii) n is congruent to m modulo
- # 2**64-1. So we can replace hash((-1)**s*c*10**e) with
- # hash((-1)**s*c*pow(10, e, 2**64-1).
- return hash((-1)**op.sign*op.int*pow(10, op.exp, 2**64-1))
- # The value of a nonzero nonspecial Decimal instance is
- # faithfully represented by the triple consisting of its sign,
- # its adjusted exponent, and its coefficient with trailing
- # zeros removed.
- return hash((self._sign,
- self._exp+len(self._int),
- self._int.rstrip('0')))
- def as_tuple(self):
- """Represents the number as a triple tuple.
- To show the internals exactly as they are.
- """
- return DecimalTuple(self._sign, tuple(map(int, self._int)), self._exp)
- def __repr__(self):
- """Represents the number as an instance of Decimal."""
- # Invariant: eval(repr(d)) == d
- return "Decimal('%s')" % str(self)
- def __str__(self, eng=False, context=None):
- """Return string representation of the number in scientific notation.
- Captures all of the information in the underlying representation.
- """
- sign = ['', '-'][self._sign]
- if self._is_special:
- if self._exp == 'F':
- return sign + 'Infinity'
- elif self._exp == 'n':
- return sign + 'NaN' + self._int
- else: # self._exp == 'N'
- return sign + 'sNaN' + self._int
- # number of digits of self._int to left of decimal point
- leftdigits = self._exp + len(self._int)
- # dotplace is number of digits of self._int to the left of the
- # decimal point in the mantissa of the output string (that is,
- # after adjusting the exponent)
- if self._exp <= 0 and leftdigits > -6:
- # no exponent required
- dotplace = leftdigits
- elif not eng:
- # usual scientific notation: 1 digit on left of the point
- dotplace = 1
- elif self._int == '0':
- # engineering notation, zero
- dotplace = (leftdigits + 1) % 3 - 1
- else:
- # engineering notation, nonzero
- dotplace = (leftdigits - 1) % 3 + 1
- if dotplace <= 0:
- intpart = '0'
- fracpart = '.' + '0'*(-dotplace) + self._int
- elif dotplace >= len(self._int):
- intpart = self._int+'0'*(dotplace-len(self._int))
- fracpart = ''
- else:
- intpart = self._int[:dotplace]
- fracpart = '.' + self._int[dotplace:]
- if leftdigits == dotplace:
- exp = ''
- else:
- if context is None:
- context = getcontext()
- exp = ['e', 'E'][context.capitals] + "%+d" % (leftdigits-dotplace)
- return sign + intpart + fracpart + exp
- def to_eng_string(self, context=None):
- """Convert to engineering-type string.
- Engineering notation has an exponent which is a multiple of 3, so there
- are up to 3 digits left of the decimal place.
- Same rules for when in exponential and when as a value as in __str__.
- """
- return self.__str__(eng=True, context=context)
- def __neg__(self, context=None):
- """Returns a copy with the sign switched.
- Rounds, if it has reason.
- """
- if self._is_special:
- ans = self._check_nans(context=context)
- if ans:
- return ans
- if context is None:
- context = getcontext()
- if not self and context.rounding != ROUND_FLOOR:
- # -Decimal('0') is Decimal('0'), not Decimal('-0'), except
- # in ROUND_FLOOR rounding mode.
- ans = self.copy_abs()
- else:
- ans = self.copy_negate()
- return ans._fix(context)
- def __pos__(self, context=None):
- """Returns a copy, unless it is a sNaN.
- Rounds the number (if more then precision digits)
- """
- if self._is_special:
- ans = self._check_nans(context=context)
- if ans:
- return ans
- if context is None:
- context = getcontext()
- if not self and context.rounding != ROUND_FLOOR:
- # + (-0) = 0, except in ROUND_FLOOR rounding mode.
- ans = self.copy_abs()
- else:
- ans = Decimal(self)
- return ans._fix(context)
- def __abs__(self, round=True, context=None):
- """Returns the absolute value of self.
- If the keyword argument 'round' is false, do not round. The
- expression self.__abs__(round=False) is equivalent to
- self.copy_abs().
- """
- if not round:
- return self.copy_abs()
- if self._is_special:
- ans = self._check_nans(context=context)
- if ans:
- return ans
- if self._sign:
- ans = self.__neg__(context=context)
- else:
- ans = self.__pos__(context=context)
- return ans
- def __add__(self, other, context=None):
- """Returns self + other.
- -INF + INF (or the reverse) cause InvalidOperation errors.
- """
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- if context is None:
- context = getcontext()
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return ans
- if self._isinfinity():
- # 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
- 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.
- negativezero = 1
- if not self and not other:
- sign = min(self._sign, other._sign)
- if negativezero:
- sign = 1
- ans = _dec_from_triple(sign, '0', exp)
- ans = ans._fix(context)
- return ans
- if not self:
- exp = max(exp, other._exp - context.prec-1)
- ans = other._rescale(exp, context.rounding)
- ans = ans._fix(context)
- return ans
- if not other:
- exp = max(exp, self._exp - context.prec-1)
- ans = self._rescale(exp, context.rounding)
- ans = ans._fix(context)
- return ans
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- op1, op2 = _normalize(op1, op2, context.prec)
- result = _WorkRep()
- if op1.sign != op2.sign:
- # Equal and opposite
- if op1.int == op2.int:
- ans = _dec_from_triple(negativezero, '0', exp)
- ans = ans._fix(context)
- return ans
- if op1.int < op2.int:
- op1, op2 = op2, op1
- # 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.
- elif op1.sign == 1:
- result.sign = 1
- op1.sign, op2.sign = (0, 0)
- else:
- result.sign = 0
- # Now, op1 > abs(op2) > 0
- if op2.sign == 0:
- result.int = op1.int + op2.int
- else:
- result.int = op1.int - op2.int
- result.exp = op1.exp
- ans = Decimal(result)
- ans = ans._fix(context)
- return ans
- __radd__ = __add__
- def __sub__(self, other, context=None):
- """Return self - other"""
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context=context)
- if ans:
- return ans
- # self - other is computed as self + other.copy_negate()
- return self.__add__(other.copy_negate(), context=context)
- def __rsub__(self, other, context=None):
- """Return other - self"""
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- return other.__sub__(self, context=context)
- def __mul__(self, other, context=None):
- """Return self * other.
- (+-) INF * 0 (or its reverse) raise InvalidOperation.
- """
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- if context is None:
- context = getcontext()
- resultsign = self._sign ^ other._sign
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return ans
- if self._isinfinity():
- if not other:
- return context._raise_error(InvalidOperation, '(+-)INF * 0')
- return _SignedInfinity[resultsign]
- if other._isinfinity():
- if not self:
- return context._raise_error(InvalidOperation, '0 * (+-)INF')
- return _SignedInfinity[resultsign]
- resultexp = self._exp + other._exp
- # Special case for multiplying by zero
- if not self or not other:
- ans = _dec_from_triple(resultsign, '0', resultexp)
- # Fixing in case the exponent is out of bounds
- ans = ans._fix(context)
- return ans
- # Special case for multiplying by power of 10
- if self._int == '1':
- ans = _dec_from_triple(resultsign, other._int, resultexp)
- ans = ans._fix(context)
- return ans
- if other._int == '1':
- ans = _dec_from_triple(resultsign, self._int, resultexp)
- ans = ans._fix(context)
- return ans
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- ans = _dec_from_triple(resultsign, str(op1.int * op2.int), resultexp)
- ans = ans._fix(context)
- return ans
- __rmul__ = __mul__
- def __truediv__(self, other, context=None):
- """Return self / other."""
- other = _convert_other(other)
- if other is NotImplemented:
- return NotImplemented
- if context is None:
- context = getcontext()
- sign = self._sign ^ other._sign
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return ans
- if self._isinfinity() and other._isinfinity():
- return context._raise_error(InvalidOperation, '(+-)INF/(+-)INF')
- if self._isinfinity():
- return _SignedInfinity[sign]
- if other._isinfinity():
- context._raise_error(Clamped, 'Division by infinity')
- return _dec_from_triple(sign, '0', context.Etiny())
- # Special cases for zeroes
- if not other:
- if not self:
- return context._raise_error(DivisionUndefined, '0 / 0')
- return context._raise_error(DivisionByZero, 'x / 0', sign)
- if not self:
- exp = self._exp - other._exp
- coeff = 0
- else:
- # OK, so neither = 0, INF or NaN
- shift = len(other._int) - len(self._int) + context.prec + 1
- exp = self._exp - other._exp - shift
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- if shift >= 0:
- coeff, remainder = divmod(op1.int * 10**shift, op2.int)
- else:
- coeff, remainder = divmod(op1.int, op2.int * 10**-shift)
- if remainder:
- # result is not exact; adjust to ensure correct rounding
- if coeff % 5 == 0:
- coeff += 1
- else:
- # result is exact; get as close to ideal exponent as possible
- ideal_exp = self._exp - other._exp
- while exp < ideal_exp and coeff % 10 == 0:
- coeff //= 10
- exp += 1
- ans = _dec_from_triple(sign, str(coeff), exp)
- return ans._fix(context)
- def _divide(self, other, context):
- """Return (self // other, self % other), to context.prec precision.
- Assumes that neither self nor other is a NaN, that self is not
- infinite and that other is nonzero.
- """
- sign = self._sign ^ other._sign
- if other._isinfinity():
- ideal_exp = self._exp
- else:
- ideal_exp = min(self._exp, other._exp)
- expdiff = self.adjusted() - other.adjusted()
- if not self or other._isinfinity() or expdiff <= -2:
- return (_dec_from_triple(sign, '0', 0),
- self._rescale(ideal_exp, context.rounding))
- if expdiff <= context.prec:
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- if op1.exp >= op2.exp:
- op1.int *= 10**(op1.exp - op2.exp)
- else:
- op2.int *= 10**(op2.exp - op1.exp)
- q, r = divmod(op1.int, op2.int)
- if q < 10**context.prec:
- return (_dec_from_triple(sign, str(q), 0),
- _dec_from_triple(self._sign, str(r), ideal_exp))
- # Here the quotient is too large to be representable
- ans = context._raise_error(DivisionImpossible,
- 'quotient too large in //, % or divmod')
- return ans, ans
- def __rtruediv__(self, other, context=None):
- """Swaps self/other and returns __truediv__."""
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- return other.__truediv__(self, context=context)
- __div__ = __truediv__
- __rdiv__ = __rtruediv__
- def __divmod__(self, other, context=None):
- """
- Return (self // other, self % other)
- """
- other = _convert_other(other)
- if other is NotImplemented:
- return other
- if context is None:
- context = getcontext()
- ans = self._check_nans(other, context)
- if ans:
- return (ans, ans)
- sign = self._sign ^ other._sign
- if self._isinfinity():
- if other._isinfinity():
- ans = context._raise_error(InvalidOperation, 'divmod(INF, INF)')
- return ans, ans
- else:
- return (_SignedInfinity[sign],
- context._raise_error(InvalidOperation, 'INF % x'))
- if not other:
- if not self:
- ans = context._raise_error(DivisionUnde…
Large files files are truncated, but you can click here to view the full file