
__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 as _copy

import _decimal

# #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
# # Map conditions (per the spec) to signals
# _condition_map = {ConversionSyntax:InvalidOperation,
#                   DivisionImpossible:InvalidOperation,
#                   DivisionUndefined:InvalidOperation,
#                   InvalidContext:InvalidOperation}

from _decimal import DecimalException, Overflow, Underflow, \
     Clamped, DivisionByZero, Inexact, Rounded, InvalidOperation, \
     ConversionSyntax, DivisionImpossible, DivisionUndefined, \
     InvalidContext, Subnormal
from _decimal import ROUND_UP, ROUND_DOWN, ROUND_HALF_UP, \
     ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_FLOOR, \
     ROUND_CEILING, ALWAYS_ROUND, NEVER_ROUND


# ##### Useful Constants (internal use only) ####################

from _decimal import Inf, negInf, NaN

Infsign = (Inf, negInf)

##### Decimal class ###########################################

getcontext = _decimal.getcontext
setcontext = _decimal.setcontext

class Decimal(_decimal.Decimal):
    """Floating point class for decimal arithmetic."""

    # to get support for converting WorkRep instances
    def __new__(cls, value="0", context=None):
        if isinstance(value, _WorkRep):
            value = (value.sign, tuple(map(int, str(value.int))), int(value.exp))
            
        return _decimal.Decimal.__new__(cls, value, context)

    def _isnan(self):
        if self._sign in (4, 5): return 1
        if self._sign in (6, 7): return 2
        return 0

    def _isinfinity(self):
        return int(self._sign in (2, 3))

    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 __cmp__(self, other, context=None):
#         other = _convert_other(other)
#         if other is NotImplemented:
#             return 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 NotImplemented
#         return self.__cmp__(other) == 0

#     def __ne__(self, other):
#         if not isinstance(other, (Decimal, int, long)):
#             return NotImplemented
#         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)
#         if other is NotImplemented:
#             return 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 hash(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 __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 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

        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 other is NotImplemented:
            return 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)
        if other is NotImplemented:
            return 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 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 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 other is NotImplemented:
            if divmod in (0, 1):
                return NotImplemented
            return (NotImplemented, 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:
                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)
        if other is NotImplemented:
            return 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)
        if other is NotImplemented:
            return other
        return other.__divmod__(self, context=context)

    def __mod__(self, other, context=None):
        """
        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)
            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)
        if other is NotImplemented:
            return 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 other is NotImplemented:
            return 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__(-1, 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)
        if other is NotImplemented:
            return 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, -1, 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]:
                    context._raise_error(Underflow)
            else:
                if ans:
                    #Only raise subnormal if non-zero.
                    context._raise_error(Subnormal)
        else:
            Etop = context.Etop()
            if folddown and ans._exp > Etop:
                context._raise_error(Clamped)
                ans = ans._rescale(Etop, context=context)
            else:
                Emax = context.Emax
                if ans_adjusted > Emax:
                    if not ans:
                        ans = Decimal(self)
                        ans._exp = Emax
                        context._raise_error(Clamped)
                        return ans
                    context._raise_error(Inexact)
                    context._raise_error(Rounded)
                    return context._raise_error(Overflow, 'above Emax', ans._sign)
        return ans

#     def _round(self, prec=None, rounding=-1, context=None):
#         """Returns a rounded version of self.

#         You can specify the precision or rounding method.  Otherwise, the
#         context determines it.
#         """

#         if self._is_special:
#             ans = self._check_nans(context=context)
#             if ans:
#                 return ans

#             if self._isinfinity():
#                 return Decimal(self)

#         if context is None:
#             context = getcontext()

#         if rounding is None:
#             rounding = context.rounding
#         if prec is None:
#             prec = context.prec

#         if not self:
#             if prec <= 0:
#                 dig = (0,)
#                 exp = len(self._int) - prec + self._exp
#             else:
#                 dig = (0,) * prec
#                 exp = len(self._int) + self._exp - prec
#             ans = Decimal((self._sign, dig, exp))
#             context._raise_error(Rounded)
#             return ans

#         if prec == 0:
#             temp = Decimal(self)
#             temp._int = (0,)+temp._int
#             prec = 1
#         elif prec < 0:
#             exp = self._exp + len(self._int) - prec - 1
#             temp = Decimal( (self._sign, (0, 1), exp))
#             prec = 1
#         else:
#             temp = Decimal(self)

#         numdigits = len(temp._int)
#         if prec == numdigits:
#             return temp

#         # See if we need to extend precision
#         expdiff = prec - numdigits
#         if expdiff > 0:
#             tmp = list(temp._int)
#             tmp.extend([0] * expdiff)
#             ans =  Decimal( (temp._sign, tmp, temp._exp - expdiff))
#             return ans

#         #OK, but maybe all the lost digits are 0.
#         lostdigits = self._int[expdiff:]
#         if lostdigits == (0,) * len(lostdigits):
#             ans = Decimal( (temp._sign, temp._int[:prec], temp._exp - expdiff))
#             #Rounded, but not Inexact
#             context._raise_error(Rounded)
#             return ans

#         # Okay, let's round and lose data

#         this_function = getattr(temp, self._pick_rounding_function[rounding])
#         #Now we've got the rounding function

#         if prec != context.prec:
#             context = context._shallow_copy()
#             context.prec = prec
#         ans = this_function(prec, expdiff, context)
#         context._raise_error(Rounded)
#         context._raise_error(Inexact, 'Changed in rounding')

#         return ans

#     _pick_rounding_function = {}

#     def _round_down(self, prec, expdiff, context):
#         """Also known as round-towards-0, truncate."""
#         return Decimal( (self._sign, self._int[:prec], self._exp - expdiff) )

#     def _round_half_up(self, prec, expdiff, context, tmp = None):
#         """Rounds 5 up (away from 0)"""

#         if tmp is None:
#             tmp = Decimal( (self._sign,self._int[:prec], self._exp - expdiff))
#         if self._int[prec] >= 5:
#             tmp = tmp._increment(round=0, context=context)
#             if len(tmp._int) > prec:
#                 return Decimal( (tmp._sign, tmp._int[:-1], tmp._exp + 1))
#         return tmp

#     def _round_half_even(self, prec, expdiff, context):
#         """Round 5 to even, rest to nearest."""

#         tmp = Decimal( (self._sign, self._int[:prec], self._exp - expdiff))
#         half = (self._int[prec] == 5)
#         if half:
#             for digit in self._int[prec+1:]:
#                 if digit != 0:
#                     half = 0
#                     break
#         if half:
#             if self._int[prec-1] & 1 == 0:
#                 return tmp
#         return self._round_half_up(prec, expdiff, context, tmp)

#     def _round_half_down(self, prec, expdiff, context):
#         """Round 5 down"""

#         tmp = Decimal( (self._sign, self._int[:prec], self._exp - expdiff))
#         half = (self._int[prec] == 5)
#         if half:
#             for digit in self._int[prec+1:]:
#                 if digit != 0:
#                     half = 0
#                     break
#         if half:
#             return tmp
#         return self._round_half_up(prec, expdiff, context, tmp)

#     def _round_up(self, prec, expdiff, context):
#         """Rounds away from 0."""
#         tmp = Decimal( (self._sign, self._int[:prec], self._exp - expdiff) )
#         for digit in self._int[prec:]:
#             if digit != 0:
#                 tmp = tmp._increment(round=1, context=context)
#                 if len(tmp._int) > prec:
#                     return Decimal( (tmp._sign, tmp._int[:-1], tmp._exp + 1))
#                 else:
#                     return tmp
#         return tmp

#     def _round_ceiling(self, prec, expdiff, context):
#         """Rounds up (not away from 0 if negative.)"""
#         if self._sign:
#             return self._round_down(prec, expdiff, context)
#         else:
#             return self._round_up(prec, expdiff, context)

#     def _round_floor(self, prec, expdiff, context):
#         """Rounds down (not towards 0 if negative)"""
#         if not self._sign:
#             return self._round_down(prec, expdiff, context)
#         else:
#             return self._round_up(prec, expdiff, context)

    def __pow__(self, n, modulo = None, context=None):
        """Return self ** n (mod modulo)

        If modulo is None (default), don't take it mod modulo.
        """
        n = _convert_other(n)
        if n is NotImplemented:
            return n

        if context is None:
            context = getcontext()

        if self._is_special or n._is_special or n.adjusted() > 8:
            #Because the spot << doesn't work with really big exponents
            if n._isinfinity() or n.adjusted() > 8:
                return context._raise_error(InvalidOperation, 'x ** INF')

            ans = self._check_nans(n, context)
            if ans:
                return ans

        if not n._isinteger():
            return context._raise_error(InvalidOperation, 'x ** (non-integer)')

        if not self and not n:
            return context._raise_error(InvalidOperation, '0 ** 0')

        if not n:
            return Decimal(1)

        if self == Decimal(1):
            return Decimal(1)

        sign = self._sign and not n._iseven()
        n = int(n)

        if self._isinfinity():
            if modulo:
                return context._raise_error(InvalidOperation, 'INF % x')
            if n > 0:
                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:

            tmp = Decimal('inf')
            tmp._sign = sign
            context._raise_error(Rounded)
            context._raise_error(Inexact)
            context._raise_error(Overflow, 'Big power', sign)
            return tmp

        elength = len(str(abs(n)))
        firstprec = context.prec

        if not modulo and firstprec + elength + 1 > DefaultContext.Emax:
            return context._raise_error(Overflow, 'Too much precision.', sign)

        mul = Decimal(self)
        val = Decimal(1)
        context = context._shallow_copy()
        context.prec = firstprec + elength + 1
        if n < 0:
            #n is a long now, not Decimal instance
            n = -n
            mul = Decimal(1).__div__(mul, context=context)

        spot = 1
        while spot <= n:
            spot <<= 1

        spot >>= 1
        #Spot is the highest power of 2 less than n
        while spot:
            val = val.__mul__(val, context=context)
            if val._isinfinity():
                val = Infsign[sign]
                break
            if spot & n:
                val = val.__mul__(mul, context=context)
            if modulo is not None:
                val = val.__mod__(modulo, context=context)
            spot >>= 1
        context.prec = firstprec

        if context._rounding_decision == ALWAYS_ROUND:
            return val._fix(context)
        return val

    def __rpow__(self, other, context=None):
        """Swaps self/other and returns __pow__."""
        other = _convert_other(other)
        if other is NotImplemented:
            return other
        return other.__pow__(self, context=context)

#     def normalize(self, context=None):
#         """Normalize- strip trailing 0s, change anything equal to 0 to 0e0"""

#         if self._is_special:
#             ans = self._check_nans(context=context)
#             if ans:
#                 return ans

#         dup = self._fix(context)
#         if dup._isinfinity():
#             return dup

#         if not dup:
#             return Decimal( (dup._sign, (0,), 0) )
#         end = len(dup._int)
#         exp = dup._exp
#         while dup._int[end-1] == 0:
#             exp += 1
#             end -= 1
#         return Decimal( (dup._sign, dup._int[:end], exp) )


#     def quantize(self, exp, rounding=-1, context=None, watchexp=1):
#         """Quantize self so its exponent is the same as that of exp.

#         Similar to self._rescale(exp._exp) but with error checking.
#         """
#         if self._is_special or exp._is_special:
#             ans = self._check_nans(exp, context)
#             if ans:
#                 return ans

#             if exp._isinfinity() or self._isinfinity():
#                 if exp._isinfinity() and self._isinfinity():
#                     return self  #if both are inf, it is OK
#                 if context is None:
#                     context = getcontext()
#                 return context._raise_error(InvalidOperation,
#                                         'quantize with one INF')
#         return self._rescale(exp._exp, rounding, context, watchexp)

#     def same_quantum(self, other):
#         """Test whether self and other have the same exponent.

#         same as self._exp == other._exp, except NaN == sNaN
#         """
#         if self._is_special or other._is_special:
#             if self._isnan() or other._isnan():
#                 return self._isnan() and other._isnan() and True
#             if self._isinfinity() or other._isinfinity():
#                 return self._isinfinity() and other._isinfinity() and True
#         return self._exp == other._exp

    def _rescale(self, exp, rounding=-1, context=None, watchexp=1):
        """Rescales so that the exponent is exp.

        exp = exp to scale to (an integer)
        rounding = rounding version
        watchexp: if set (default) an error is returned if exp is greater
        than Emax or less than Etiny.
        """
        if context is None:
            context = getcontext()

        if self._is_special:
            if self._isinfinity():
                return context._raise_error(InvalidOperation, 'rescale with an INF')

            ans = self._check_nans(context=context)
            if ans:
                return ans

        if watchexp and (context.Emax  < exp or context.Etiny() > exp):
            return context._raise_error(InvalidOperation, 'rescale(a, INF)')

        if not self:
            ans = Decimal(self)
            ans._int = (0,)
            ans._exp = exp
            return ans

        diff = self._exp - exp
        digits = len(self._int) + diff

        if watchexp and digits > context.prec:
            return context._raise_error(InvalidOperation, 'Rescale > prec')

        tmp = Decimal(self)
        tmp._int = (0,) + tmp._int
        digits += 1

        if digits < 0:
            tmp._exp = -digits + tmp._exp
            tmp._int = (0,1)
            digits = 1
        tmp = tmp._round(digits, rounding, context)

        if tmp._int[0] == 0 and len(tmp._int) > 1:
            tmp._int = tmp._int[1:]
        tmp._exp = exp

        tmp_adjusted = tmp.adjusted()
        if tmp and tmp_adjusted < context.Emin:
            context._raise_error(Subnormal)
        elif tmp and tmp_adjusted > context.Emax:
            return context._raise_error(InvalidOperation, 'rescale(a, INF)')
        return tmp

    #def to_integral(self, rounding=None, context=None):
    #    """Rounds to the nearest integer, without raising inexact, rounded."""
    #    if self._is_special:
    #        ans = self._check_nans(context=context)
    #        if ans:
    #            return ans
    #    if self._exp >= 0:
    #        return self
    #    if context is None:
    #        context = getcontext()
    #    flags = context._ignore_flags(Rounded, Inexact)
    #    ans = self._rescale(0, rounding, context=context)
    #    context._regard_flags(flags)
    #    return ans

    def sqrt(self, context=None):
        """Return the square root of self.

        Uses a converging algorithm (Xn+1 = 0.5*(Xn + self / Xn))
        Should quadratically approach the right answer.
        """
        if self._is_special:
            ans = self._check_nans(context=context)
            if ans:
                return ans

            if self._isinfinity() and self._sign == 0:
                return Decimal(self)

        if not self:
            #exponent = self._exp / 2, using round_down.
            #if self._exp < 0:
            #    exp = (self._exp+1) // 2
            #else:
            exp = (self._exp) // 2
            if self._sign == 1:
                #sqrt(-0) = -0
                return Decimal( (1, (0,), exp))
            else:
                return Decimal( (0, (0,), exp))

        if context is None:
            context = getcontext()

        if self._sign == 1:
            return context._raise_error(InvalidOperation, 'sqrt(-x), x > 0')

        tmp = Decimal(self)

        expadd = tmp._exp // 2
        if tmp._exp & 1:
            tmp._int += (0,)
            tmp._exp = 0
        else:
            tmp._exp = 0

        context = context._shallow_copy()
        flags = context._ignore_all_flags()
        firstprec = context.prec
        context.prec = 3
        if tmp.adjusted() & 1 == 0:
            ans = Decimal( (0, (8,1,9), tmp.adjusted()  - 2) )
            ans = ans.__add__(tmp.__mul__(Decimal((0, (2,5,9), -2)),
                                          context=context), context=context)
            ans._exp -= 1 + tmp.adjusted() // 2
        else:
            ans = Decimal( (0, (2,5,9), tmp._exp + len(tmp._int)- 3) )
            ans = ans.__add__(tmp.__mul__(Decimal((0, (8,1,9), -3)),
                                          context=context), context=context)
            ans._exp -= 1 + tmp.adjusted()  // 2

        #ans is now a linear approximation.

        Emax, Emin = context.Emax, context.Emin
        context.Emax, context.Emin = DefaultContext.Emax, DefaultContext.Emin

        half = Decimal('0.5')

        maxp = firstprec + 2
        rounding = context._set_rounding(ROUND_HALF_EVEN)
        while 1:
            context.prec = min(2*context.prec - 2, maxp)
            ans = half.__mul__(ans.__add__(tmp.__div__(ans, context=context),
                                           context=context), context=context)
            if context.prec == maxp:
                break

        #round to the answer's precision-- the only error can be 1 ulp.
        context.prec = firstprec
        prevexp = ans.adjusted()
        ans = ans._round(context=context)

        #Now, check if the other last digits are better.
        context.prec = firstprec + 1
        # In case we rounded up another digit and we should actually go lower.
        if prevexp != ans.adjusted():
            ans._int += (0,)
            ans._exp -= 1


        lower = ans.__sub__(Decimal((0, (5,), ans._exp-1)), context=context)
        context._set_rounding(ROUND_UP)
        if lower.__mul__(lower, context=context) > (tmp):
            ans = ans.__sub__(Decimal((0, (1,), ans._exp)), context=context)

        else:
            upper = ans.__add__(Decimal((0, (5,), ans._exp-1)),context=context)
            context._set_rounding(ROUND_DOWN)
            if upper.__mul__(upper, context=context) < tmp:
                ans = ans.__add__(Decimal((0, (1,), ans._exp)),context=context)

        ans._exp += expadd

        context.prec = firstprec
        context.rounding = rounding
        ans = ans._fix(context)

        rounding = context._set_rounding_decision(NEVER_ROUND)
        if not ans.__mul__(ans, context=context) == self:
            # Only rounded/inexact if here.
            context._regard_flags(flags)
            context._raise_error(Rounded)
            context._raise_error(Inexact)
        else:
            #Exact answer, so let's set the exponent right.
            #if self._exp < 0:
            #    exp = (self._exp +1)// 2
            #else:
            exp = self._exp // 2
            context.prec += ans._exp - exp
            ans = ans._rescale(exp, context=context)
            context.prec = firstprec
            context._regard_flags(flags)
        context.Emax, context.Emin = Emax, Emin

        return ans._fix(context)

    def max(self, other, context=None):
        """Returns the larger value.

        like max(self, other) except if one is not a number, returns
        NaN (and signals if one is sNaN).  Also rounds.
        """
        other = _convert_other(other)
        if other is NotImplemented:
            return other

        if self._is_special or other._is_special:
            # if one operand is a quiet NaN and the other is number, then the
            # number is always returned
            sn = self._isnan()
            on = other._isnan()
            if sn or on:
                if on == 1 and sn != 2:
                    return self
                if sn == 1 and on != 2:
                    return other
                return self._check_nans(other, context)

        ans = self
        c = self.__cmp__(other)
        if c == 0:
            # 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
            # positive sign and min returns the operand with the negative sign
            #
            # if the signs are the same then the exponent is used to select
            # the result.
            if self._sign != other._sign:
                if self._sign:
                    ans = other
            elif self._exp < other._exp and not self._sign:
                ans = other
            elif self._exp > other._exp and self._sign:
                ans = other
        elif c == -1:
            ans = other

        if context is None:
            context = getcontext()
        if context._rounding_decision == ALWAYS_ROUND:
            return ans._fix(context)
        return ans

    def min(self, other, context=None):
        """Returns the smaller value.

        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)
        if other is NotImplemented:
            return other

        if self._is_special or other._is_special:
            # if one operand is a quiet NaN and the other is number, then the
            # number is always returned
            sn = self._isnan()
            on = other._isnan()
            if sn or on:
                if on == 1 and sn != 2:
                    return self
                if sn == 1 and on != 2:
                    return other
                return self._check_nans(other, context)

        ans = self
        c = self.__cmp__(other)
        if c == 0:
            # 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
            # positive sign and min returns the operand with the negative sign
            #
            # if the signs are the same then the exponent is used to select
            # the result.
            if self._sign != other._sign:
                if other._sign:
                    ans = other
            elif self._exp > other._exp and not self._sign:
                ans = other
            elif self._exp < other._exp and self._sign:
                ans = other
        elif c == 1:
            ans = other

        if context is None:
            context = getcontext()
        if context._rounding_decision == ALWAYS_ROUND:
            return ans._fix(context)
        return ans

    def _isinteger(self):
        """Returns whether self is an integer"""
        if self._exp >= 0:
            return True
        rest = self._int[self._exp:]
        return rest == (0,)*len(rest)

    def _iseven(self):
        """Returns 1 if self is even.  Assumes self is an integer."""
        if self._exp > 0:
            return 1
        return self._int[-1+self._exp] & 1 == 0

#     def adjusted(self):
#         """Return the adjusted exponent of self"""
#         try:
#             return self._exp + len(self._int) - 1
#         #If NaN or Infinity, self._exp is string
#         except TypeError:
#             return 0


##### Context class ###########################################

from _decimal import Context

# # get rounding method function:
# rounding_functions = [name for name in Decimal.__dict__.keys() if name.startswith('_round_')]
# for name in rounding_functions:
#     #name is like _round_half_even, goes to the global ROUND_HALF_EVEN value.
#     globalname = name[1:].upper()
#     val = globals()[globalname]
#     Decimal._pick_rounding_function[val] = name

# del name, val, globalname, rounding_functions

class ContextManager(object):
    """Helper class to simplify Context management.

    Sample usage:

    with decimal.ExtendedContext:
        s = ...
    return +s # Convert result to normal precision

    with decimal.getcontext() as ctx:
        ctx.prec += 2
        s = ...
    return +s

    """
    def __init__(self, new_context):
        self.new_context = new_context
    def __enter__(self):
        self.saved_context = getcontext()
        setcontext(self.new_context)
        return self.new_context
    def __exit__(self, t, v, tb):
        setcontext(self.saved_context)


from _decimal import BasicContext, ExtendedContext, \
     DefaultContext

class _WorkRep(object):
    __slots__ = ('sign','int','exp')
    # sign: 0 or 1
    # int:  int or long
    # exp:  None, int, or string

    def __init__(self, value=None):
        if value is None:
            self.sign = None
            self.int = 0
            self.exp = None
        elif isinstance(value, Decimal):
            self.sign = value._sign
            cum = 0
            for digit  in value._int:
                cum = cum * 10 + digit
            self.int = cum
            self.exp = value._exp
        else:
            # assert isinstance(value, tuple)
            self.sign = value[0]
            self.int = value[1]
            self.exp = value[2]

    def __repr__(self):
        return "(%r, %r, %r)" % (self.sign, self.int, self.exp)

    __str__ = __repr__


def _normalize(op1, op2, shouldround = 0, prec = 0):
    """Normalizes op1, op2 to have the same exp and length of coefficient.

    Done during addition.
    """
    # Yes, the exponent is a long, but the difference between exponents
    # must be an int-- otherwise you'd get a big memory problem.
    numdigits = int(op1.exp - op2.exp)
    if numdigits < 0:
        numdigits = -numdigits
        tmp = op2
        other = op1
    else:
        tmp = op1
        other = op2


    if shouldround and numdigits > prec + 1:
        # Big difference in exponents - check the adjusted exponents
        tmp_len = len(str(tmp.int))
        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.

            extend = prec + 2 - tmp_len
            if extend <= 0:
                extend = 1
            tmp.int *= 10 ** extend
            tmp.exp -= extend
            other.int = 1
            other.exp = tmp.exp
            return op1, op2

    tmp.int *= 10 ** numdigits
    tmp.exp -= numdigits
    return op1, op2

def _adjust_coefficients(op1, op2):
    """Adjust op1, op2 so that op2.int * 10 > op1.int >= op2.int.

    Returns the adjusted op1, op2 as well as the change in op1.exp-op2.exp.

    Used on _WorkRep instances during division.
    """
    adjust = 0
    #If op1 is smaller, make it larger
    while op2.int > op1.int:
        op1.int *= 10
        op1.exp -= 1
        adjust += 1

    #If op2 is too small, make it larger
    while op1.int >= (10 * op2.int):
        op2.int *= 10
        op2.exp -= 1
        adjust -= 1

    return op1, op2, adjust

##### Helper Functions ########################################

def _convert_other(other):
    """Convert other to Decimal.

    Verifies that it's ok to use in an implicit construction.
    """
    if isinstance(other, Decimal):
        return other
    if isinstance(other, (int, long)):
        return Decimal(other)
    return NotImplemented

_infinity_map = {
    'inf' : 1,
    'infinity' : 1,
    '+inf' : 1,
    '+infinity' : 1,
    '-inf' : -1,
    '-infinity' : -1
}

def _isinfinity(num):
    """Determines whether a string or float is infinity.

    +1 for negative infinity; 0 for finite ; +1 for positive infinity
    """
    num = str(num).lower()
    return _infinity_map.get(num, 0)

def _isnan(num):
    """Determines whether a string or float is NaN

    (1, sign, diagnostic info as string) => NaN
    (2, sign, diagnostic info as string) => sNaN
    0 => not a NaN
    """
    num = str(num).lower()
    if not num:
        return 0

    #get the sign, get rid of trailing [+-]
    sign = 0
    if num[0] == '+':
        num = num[1:]
    elif num[0] == '-':  #elif avoids '+-nan'
        num = num[1:]
        sign = 1

    if num.startswith('nan'):
        if len(num) > 3 and not num[3:].isdigit(): #diagnostic info
            return 0
        return (1, sign, num[3:].lstrip('0'))
    if num.startswith('snan'):
        if len(num) > 4 and not num[4:].isdigit():
            return 0
        return (2, sign, num[4:].lstrip('0'))
    return 0

