/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/site-packages/win32com/decimal_23.py
Python | 3047 lines | 3011 code | 4 blank | 32 comment | 3 complexity | a3cbe3594d683069d0339d36026b6260 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- # <win32com>
- # This is a clone of Python 2.4's 'decimal' module. It will only be used when
- # 'import decimal' fails - so is likely to be used in Python 2.3.
- # </win32com>
- # 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:
- www2.hursley.ibm.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 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,
- 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',
- # Functions for manipulating contexts
- 'setcontext', 'getcontext'
- ]
- import copy
- #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'
- #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
- 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 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
- """
- def handle(self, context, *args):
- if args:
- 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.
- 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 (0, (0,), 'n') #Passed to something which uses a tuple.
- 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, double = None, *args):
- if double is not None:
- return (Infsign[sign],)*2
- return Infsign[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, 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, tup=None, *args):
- if tup is not None:
- return (NaN, NaN) #for 0 %0, 0 // 0
- 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.
- """
- pass
- 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.
- """
- pass
- 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.
- """
- pass
- 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 Infsign[sign]
- if sign == 0:
- if context.rounding == ROUND_CEILING:
- return Infsign[sign]
- return Decimal((sign, (9,)*context.prec,
- context.Emax-context.prec+1))
- if sign == 1:
- if context.rounding == ROUND_FLOOR:
- return Infsign[sign]
- return Decimal( (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:
- 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
- ##### 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 input (sign, digit_tuple, exponent)
- Decimal("3.14")
- >>> Decimal(314) # int or long
- Decimal("314")
- >>> Decimal(Decimal(314)) # another decimal instance
- Decimal("314")
- """
- self = object.__new__(cls)
- self._is_special = False
- # From an internal working value
- if isinstance(value, _WorkRep):
- self._sign = value.sign
- self._int = tuple(map(int, str(value.int)))
- self._exp = int(value.exp)
- 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 integer
- if isinstance(value, (int,long)):
- if value >= 0:
- self._sign = 0
- else:
- self._sign = 1
- self._exp = 0
- self._int = tuple(map(int, str(abs(value))))
- return self
- # tuple/list conversion (possibly from as_tuple())
- if isinstance(value, (list,tuple)):
- if len(value) != 3:
- raise ValueError, 'Invalid arguments'
- if value[0] not in (0,1):
- 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."
- self._sign = value[0]
- self._int = tuple(value[1])
- if value[2] in ('F','n','N'):
- self._exp = value[2]
- self._is_special = True
- else:
- self._exp = int(value[2])
- return self
- if isinstance(value, float):
- raise TypeError("Cannot convert float to Decimal. " +
- "First convert the float to a string")
- # Other argument types may require the context during interpretation
- if context is None:
- context = getcontext()
- # From a string
- # REs insist on real strings, so we can too.
- if isinstance(value, basestring):
- if _isinfinity(value):
- self._exp = 'F'
- self._int = (0,)
- self._is_special = True
- if _isinfinity(value) == 1:
- self._sign = 0
- else:
- self._sign = 1
- return self
- if _isnan(value):
- sig, sign, diag = _isnan(value)
- self._is_special = True
- 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
- self._exp = 'N' #sNaN
- self._sign = sign
- 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)
- return self
- raise TypeError("Cannot convert %r to Decimal" % value)
- 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',
- 1, self)
- if other_is_nan == 2:
- return context._raise_error(InvalidOperation, 'sNaN',
- 1, other)
- if self_is_nan:
- return self
- return other
- return 0
- def __nonzero__(self):
- """Is the number non-zero?
- 0 if self == 0
- 1 if self != 0
- """
- if self._is_special:
- return 1
- return sum(self._int) != 0
- def __cmp__(self, other, context=None):
- other = _convert_other(other)
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return 1 # Comparison involving NaN's always reports self > other
- # INF = INF
- return cmp(self._isinfinity(), other._isinfinity())
- if not self and not other:
- return 0 #If both 0, sign comparison isn't certain.
- #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 and \
- self._int + (0,)*(self._exp - other._exp) == \
- other._int + (0,)*(other._exp - self._exp):
- 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:
- return -((-1)**self._sign)
- # Need to round, so make sure we have a valid context
- if context is None:
- context = getcontext()
- context = context._shallow_copy()
- rounding = context._set_rounding(ROUND_UP) #round away from 0
- flags = context._ignore_all_flags()
- res = self.__sub__(other, context=context)
- context._regard_flags(*flags)
- context.rounding = rounding
- if not res:
- return 0
- elif res._sign:
- return -1
- return 1
- def __eq__(self, other):
- if not isinstance(other, (Decimal, int, long)):
- return False
- return self.__cmp__(other) == 0
- def __ne__(self, other):
- if not isinstance(other, (Decimal, int, long)):
- return True
- 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)
- #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, context))
- def __hash__(self):
- """x.__hash__() <==> hash(x)"""
- # Decimal integers must hash the same as the ints
- # Non-integer decimals are normalized and hashed as strings
- # Normalization assures that hast(100E-1) == hash(10)
- if self._is_special:
- if self._isnan():
- raise TypeError('Cannot hash a NaN value.')
- return hash(str(self))
- i = int(self)
- if self == Decimal(i):
- return hash(i)
- assert self.__nonzero__() # '-0' handled by integer case
- return hash(str(self.normalize()))
- def as_tuple(self):
- """Represents the number as a triple tuple.
- To show the internals exactly as they are.
- """
- return (self._sign, 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 = 0, context=None):
- """Return string representation of the number in scientific notation.
- Captures all of the information in the underlying representation.
- """
- if self._isnan():
- minus = '-'*self._sign
- if self._int == (0,):
- info = ''
- else:
- info = ''.join(map(str, self._int))
- if self._isnan() == 2:
- return minus + 'sNaN' + info
- return minus + 'NaN' + info
- if self._isinfinity():
- minus = '-'*self._sign
- return minus + 'Infinity'
- if context is None:
- context = getcontext()
- 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
- s = '-'*self._sign + '0.' + '0'*(abs(self._exp))
- return s
- #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)
- else:
- s = '0'
- if exp != 0:
- if context.capitals:
- s += 'E'
- else:
- s += 'e'
- if exp > 0:
- s += '+' #0.0e+3, not 0.0e3
- s += str(exp)
- s = '-'*self._sign + s
- return s
- if eng:
- dotplace = (leftdigits-1)%3+1
- adjexp = leftdigits -1 - (leftdigits-1)%3
- else:
- adjexp = leftdigits-1
- dotplace = 1
- if self._exp == 0:
- pass
- elif self._exp < 0 and adjexp >= 0:
- tmp.insert(leftdigits, '.')
- elif self._exp < 0 and adjexp >= -6:
- tmp[0:0] = ['0'] * int(-leftdigits)
- tmp.insert(0, '0.')
- else:
- if numdigits > dotplace:
- tmp.insert(dotplace, '.')
- elif numdigits < dotplace:
- tmp.extend(['0']*(dotplace-numdigits))
- if adjexp:
- if not context.capitals:
- tmp.append('e')
- else:
- tmp.append('E')
- if adjexp > 0:
- tmp.append('+')
- tmp.append(str(adjexp))
- if eng:
- while tmp[0:1] == ['0']:
- tmp[0:1] = []
- if len(tmp) == 0 or tmp[0] == '.' or tmp[0].lower() == 'e':
- tmp[0:0] = ['0']
- if self._sign:
- tmp.insert(0, '-')
- return ''.join(tmp)
- 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=1, 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 not self:
- # -Decimal('0') is Decimal('0'), not Decimal('-0')
- sign = 0
- elif self._sign:
- sign = 0
- else:
- sign = 1
- if context is None:
- context = getcontext()
- if context._rounding_decision == ALWAYS_ROUND:
- return Decimal((sign, self._int, self._exp))._fix(context)
- return Decimal( (sign, self._int, self._exp))
- 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
- sign = self._sign
- if not self:
- # + (-0) = 0
- sign = 0
- if context is None:
- context = getcontext()
- if context._rounding_decision == ALWAYS_ROUND:
- ans = self._fix(context)
- else:
- ans = Decimal(self)
- ans._sign = sign
- return ans
- def __abs__(self, round=1, context=None):
- """Returns the absolute value of self.
- If the second argument is 0, do not round.
- """
- if self._is_special:
- ans = self._check_nans(context=context)
- if ans:
- return ans
- if not round:
- if context is None:
- context = getcontext()
- context = context._shallow_copy()
- context._set_rounding_decision(NEVER_ROUND)
- 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 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
- 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.
- negativezero = 1
- if not self and not other:
- sign = min(self._sign, other._sign)
- if negativezero:
- sign = 1
- return Decimal( (sign, (0,), exp))
- if not self:
- exp = max(exp, other._exp - context.prec-1)
- ans = other._rescale(exp, watchexp=0, context=context)
- if shouldround:
- ans = ans._fix(context)
- return ans
- if not other:
- exp = max(exp, self._exp - context.prec-1)
- ans = self._rescale(exp, watchexp=0, context=context)
- if shouldround:
- ans = ans._fix(context)
- return ans
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- op1, op2 = _normalize(op1, op2, shouldround, context.prec)
- result = _WorkRep()
- if op1.sign != op2.sign:
- # Equal and opposite
- if op1.int == op2.int:
- if exp < context.Etiny():
- exp = context.Etiny()
- context._raise_error(Clamped)
- return Decimal((negativezero, (0,), exp))
- 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)
- if shouldround:
- ans = ans._fix(context)
- return ans
- __radd__ = __add__
- def __sub__(self, other, context=None):
- """Return self + (-other)"""
- other = _convert_other(other)
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context=context)
- if ans:
- return ans
- # -Decimal(0) = Decimal(0), which we don't want since
- # (-0 - 0 = -0 + (-0) = -0, but -0 + 0 = 0.)
- # so we change the sign directly to a copy
- tmp = Decimal(other)
- tmp._sign = 1-tmp._sign
- return self.__add__(tmp, context=context)
- def __rsub__(self, other, context=None):
- """Return other + (-self)"""
- other = _convert_other(other)
- tmp = Decimal(self)
- tmp._sign = 1 - tmp._sign
- return other.__add__(tmp, context=context)
- def _increment(self, round=1, context=None):
- """Special case of add, adding 1eExponent
- Since it is common, (rounding, for example) this adds
- (sign)*one E self._exp to the number more efficiently than add.
- For example:
- Decimal('5.624e10')._increment() == Decimal('5.625e10')
- """
- if self._is_special:
- ans = self._check_nans(context=context)
- if ans:
- return ans
- return Decimal(self) # Must be infinite, and incrementing makes no difference
- L = list(self._int)
- L[-1] += 1
- spot = len(L)-1
- while L[spot] == 10:
- L[spot] = 0
- if spot == 0:
- L[0:0] = [1]
- break
- L[spot-1] += 1
- spot -= 1
- ans = Decimal((self._sign, L, self._exp))
- if context is None:
- context = getcontext()
- if round and context._rounding_decision == ALWAYS_ROUND:
- ans = ans._fix(context)
- return ans
- def __mul__(self, other, context=None):
- """Return self * other.
- (+-) INF * 0 (or its reverse) raise InvalidOperation.
- """
- other = _convert_other(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 Infsign[resultsign]
- if other._isinfinity():
- if not self:
- return context._raise_error(InvalidOperation, '0 * (+-)INF')
- return Infsign[resultsign]
- resultexp = self._exp + other._exp
- shouldround = context._rounding_decision == ALWAYS_ROUND
- # Special case for multiplying by zero
- if not self or not other:
- ans = Decimal((resultsign, (0,), resultexp))
- if shouldround:
- #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 = Decimal((resultsign, other._int, resultexp))
- if shouldround:
- ans = ans._fix(context)
- return ans
- if other._int == (1,):
- ans = Decimal((resultsign, self._int, resultexp))
- if shouldround:
- ans = ans._fix(context)
- return ans
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- ans = Decimal( (resultsign, map(int, str(op1.int * op2.int)), resultexp))
- if shouldround:
- ans = ans._fix(context)
- return ans
- __rmul__ = __mul__
- def __div__(self, other, context=None):
- """Return self / other."""
- return self._divide(other, context=context)
- __truediv__ = __div__
- def _divide(self, other, divmod = 0, context=None):
- """Return a / b, to context.prec precision.
- divmod:
- 0 => true division
- 1 => (a //b, a%b)
- 2 => a //b
- 3 => a%b
- Actually, if divmod is 2 or 3 a tuple is returned, but errors for
- computing the other value are not raised.
- """
- other = _convert_other(other)
- 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:
- if divmod:
- return (ans, ans)
- return ans
- if self._isinfinity() and other._isinfinity():
- if divmod:
- return (context._raise_error(InvalidOperation,
- '(+-)INF // (+-)INF'),
- context._raise_error(InvalidOperation,
- '(+-)INF % (+-)INF'))
- return context._raise_error(InvalidOperation, '(+-)INF/(+-)INF')
- if self._isinfinity():
- if divmod == 1:
- return (Infsign[sign],
- context._raise_error(InvalidOperation, 'INF % x'))
- elif divmod == 2:
- return (Infsign[sign], NaN)
- elif divmod == 3:
- return (Infsign[sign],
- context._raise_error(InvalidOperation, 'INF % x'))
- return Infsign[sign]
- if other._isinfinity():
- if divmod:
- return (Decimal((sign, (0,), 0)), Decimal(self))
- context._raise_error(Clamped, 'Division by infinity')
- return Decimal((sign, (0,), context.Etiny()))
- # Special cases for zeroes
- if not self and not other:
- if divmod:
- return context._raise_error(DivisionUndefined, '0 / 0', 1)
- return context._raise_error(DivisionUndefined, '0 / 0')
- if not self:
- if divmod:
- otherside = Decimal(self)
- otherside._exp = min(self._exp, other._exp)
- return (Decimal((sign, (0,), 0)), otherside)
- exp = self._exp - other._exp
- if exp < context.Etiny():
- exp = context.Etiny()
- context._raise_error(Clamped, '0e-x / y')
- if exp > context.Emax:
- exp = context.Emax
- context._raise_error(Clamped, '0e+x / y')
- return Decimal( (sign, (0,), exp) )
- if not other:
- if divmod:
- return context._raise_error(DivisionByZero, 'divmod(x,0)',
- sign, 1)
- 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.
- #self.__abs__(0) does not round.
- if divmod and (self.__abs__(0, context) < other.__abs__(0, context)):
- if divmod == 1 or divmod == 3:
- exp = min(self._exp, other._exp)
- ans2 = self._rescale(exp, context=context, watchexp=0)
- if shouldround:
- ans2 = ans2._fix(context)
- return (Decimal( (sign, (0,), 0) ),
- ans2)
- elif divmod == 2:
- #Don't round the mod part, if we don't need it.
- return (Decimal( (sign, (0,), 0) ), Decimal(self))
- op1 = _WorkRep(self)
- op2 = _WorkRep(other)
- op1, op2, adjust = _adjust_coefficients(op1, op2)
- res = _WorkRep( (sign, 0, (op1.exp - op2.exp)) )
- if divmod and res.exp > context.prec + 1:
- return context._raise_error(DivisionImpossible)
- prec_limit = 10 ** context.prec
- while 1:
- while op2.int <= op1.int:
- res.int += 1
- op1.int -= op2.int
- if res.exp == 0 and divmod:
- if res.int >= prec_limit and shouldround:
- return context._raise_error(DivisionImpossible)
- otherside = Decimal(op1)
- frozen = context._ignore_all_flags()
- exp = min(self._exp, other._exp)
- otherside = otherside._rescale(exp, context=context, watchexp=0)
- context._regard_flags(*frozen)
- if shouldround:
- otherside = otherside._fix(context)
- return (Decimal(res), otherside)
- if op1.int == 0 and adjust >= 0 and not divmod:
- break
- if res.int >= prec_limit and shouldround:
- if divmod:
- return context._raise_error(DivisionImpossible)
- shouldround=1
- # Really, the answer is a bit higher, so adding a one to
- # the end will make sure the rounding is right.
- if op1.int != 0:
- res.int *= 10
- res.int += 1
- res.exp -= 1
- break
- res.int *= 10
- res.exp -= 1
- adjust += 1
- op1.int *= 10
- op1.exp -= 1
- if res.exp == 0 and divmod and op2.int > op1.int:
- #Solves an error in precision. Same as a previous block.
- if res.int >= prec_limit and shouldround:
- return context._raise_error(DivisionImpossible)
- otherside = Decimal(op1)
- frozen = context._ignore_all_flags()
- exp = min(self._exp, other._exp)
- otherside = otherside._rescale(exp, context=context)
- context._regard_flags(*frozen)
- return (Decimal(res), otherside)
- ans = Decimal(res)
- if shouldround:
- ans = ans._fix(context)
- return ans
- def __rdiv__(self, other, context=None):
- """Swaps self/other and returns __div__."""
- other = _convert_other(other)
- return other.__div__(self, context=context)
- __rtruediv__ = __rdiv__
- def __divmod__(self, other, context=None):
- """
- (self // other, self % other)
- """
- return self._divide(other, 1, context)
- def __rdivmod__(self, other, context=None):
- """Swaps self/other and returns __divmod__."""
- other = _convert_other(other)
- return other.__divmod__(self, context=context)
- def __mod__(self, other, context=None):
- """
- self % other
- """
- other = _convert_other(other)
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return ans
- if self and not other:
- return context._raise_error(InvalidOperation, 'x % 0')
- return self._divide(other, 3, context)[1]
- def __rmod__(self, other, context=None):
- """Swaps self/other and returns __mod__."""
- other = _convert_other(other)
- return other.__mod__(self, context=context)
- def remainder_near(self, other, context=None):
- """
- Remainder nearest to 0- abs(remainder-near) <= other/2
- """
- other = _convert_other(other)
- if self._is_special or other._is_special:
- ans = self._check_nans(other, context)
- if ans:
- return ans
- if self and not other:
- return context._raise_error(InvalidOperation, 'x % 0')
- if context is None:
- context = getcontext()
- # If DivisionImpossible causes an error, do not leave Rounded/Inexact
- # ignored in the calling function.
- context = context._shallow_copy()
- flags = context._ignore_flags(Rounded, Inexact)
- #keep DivisionImpossible flags
- (side, r) = self.__divmod__(other, context=context)
- if r._isnan():
- context._regard_flags(*flags)
- return r
- context = context._shallow_copy()
- rounding = context._set_rounding_decision(NEVER_ROUND)
- if other._sign:
- comparison = other.__div__(Decimal(-2), context=context)
- else:
- comparison = other.__div__(Decimal(2), context=context)
- context._set_rounding_decision(rounding)
- context._regard_flags(*flags)
- s1, s2 = r._sign, comparison._sign
- r._sign, comparison._sign = 0, 0
- if r < comparison:
- r._sign, comparison._sign = s1, s2
- #Get flags now
- self.__divmod__(other, context=context)
- return r._fix(context)
- r._sign, comparison._sign = s1, s2
- rounding = context._set_rounding_decision(NEVER_ROUND)
- (side, r) = self.__divmod__(other, context=context)
- context._set_rounding_decision(rounding)
- if r._isnan():
- return r
- decrease = not side._iseven()
- rounding = context._set_rounding_decision(NEVER_ROUND)
- side = side.__abs__(context=context)
- context._set_rounding_decision(rounding)
- s1, s2 = r._sign, comparison._sign
- r._sign, comparison._sign = 0, 0
- 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:
- context.prec -= 1
- return context._raise_error(DivisionImpossible)[1]
- context.prec -= 1
- if self._sign == other._sign:
- r = r.__sub__(other, context=context)
- else:
- r = r.__add__(other, context=context)
- else:
- r._sign, comparison._sign = s1, s2
- return r._fix(context)
- def __floordiv__(self, other, context=None):
- """self // other"""
- return self._divide(other, 2, context)[0]
- def __rfloordiv__(self, other, context=None):
- """Swaps self/other and returns __floordiv__."""
- other = _convert_other(other)
- return other.__floordiv__(self, context=context)
- def __float__(self):
- """Float representation."""
- return float(str(self))
- def __int__(self):
- """Converts self to an int, truncating if necessary."""
- if self._is_special:
- if self._isnan():
- context = getcontext()
- return context._raise_error(InvalidContext)
- elif self._isinfinity():
- raise OverflowError, "Cannot convert infinity to long"
- if self._exp >= 0:
- s = ''.join(map(str, self._int)) + '0'*self._exp
- else:
- s = ''.join(map(str, self._int))[:self._exp]
- if s == '':
- s = '0'
- sign = '-'*self._sign
- return int(sign + s)
- def __long__(self):
- """Converts to a long.
- Equivalent to long(int(self))
- """
- return long(self.__int__())
- def _fix(self, context):
- """Round if it is necessary to keep self within prec precision.
- Rounds and fixes the exponent. Does not raise on a sNaN.
- Arguments:
- self - Decimal instance
- context - context used.
- """
- if self._is_special:
- return self
- if context is None:
- context = getcontext()
- prec = context.prec
- ans = self._fixexponents(context)
- if len(ans._int) > prec:
- ans = ans._round(prec, context=context)
- ans = ans._fixexponents(context)
- return ans
- def _fixexponents(self, context):
- """Fix the exponents and return a copy with the exponent in bounds.
- Only call if known to not be a special value.
- """
- folddown = context._clamp
- Emin = context.Emin
- ans = self
- ans_adjusted = ans.adjusted()
- if ans_adjusted < Emin:
- Etiny = context.Etiny()
- if ans._exp < Etiny:
- if not ans:
- ans = Decimal(self)
- ans._exp = Etiny
- context._raise_error(Clamped)
- return ans
- ans = ans._rescale(Etiny, context=context)
- #It isn't zero, and exp < Emin => subnormal
- context._raise_error(Subnormal)
- if context.flags[Inexact]:
- …
Large files files are truncated, but you can click here to view the full file