Index: Lib/decimal.py =================================================================== --- Lib/decimal.py (revision 80686) +++ Lib/decimal.py (working copy) @@ -1664,47 +1664,53 @@ exp_min = len(self._int) + self._exp - context.prec if exp_min > Etop: # overflow: exp_min > Etop iff self.adjusted() > Emax + ans = context._raise_error(Overflow, 'above Emax', self._sign) context._raise_error(Inexact) context._raise_error(Rounded) - return context._raise_error(Overflow, 'above Emax', self._sign) + return ans + self_is_subnormal = exp_min < Etiny if self_is_subnormal: - context._raise_error(Subnormal) exp_min = Etiny # round if self has too many digits if self._exp < exp_min: - context._raise_error(Rounded) digits = len(self._int) + self._exp - exp_min if digits < 0: self = _dec_from_triple(self._sign, '1', exp_min-1) digits = 0 - this_function = getattr(self, self._pick_rounding_function[context.rounding]) - changed = this_function(digits) + rounding_method = self._pick_rounding_function[context.rounding] + changed = getattr(self, rounding_method)(digits) coeff = self._int[:digits] or '0' - if changed == 1: + if changed > 0: coeff = str(int(coeff)+1) - ans = _dec_from_triple(self._sign, coeff, exp_min) + if len(coeff) > context.prec: + coeff = coeff[:-1] + exp_min += 1 + # check whether the rounding pushed the exponent out of range + if exp_min > Etop: + ans = context._raise_error(Overflow, 'above Emax', self._sign) + else: + ans = _dec_from_triple(self._sign, coeff, exp_min) + + # raise the appropriate signals, taking care to respect + # the precedence described in the specification + if changed and self_is_subnormal: + context._raise_error(Underflow) + if self_is_subnormal: + context._raise_error(Subnormal) if changed: context._raise_error(Inexact) - if self_is_subnormal: - context._raise_error(Underflow) - if not ans: - # raise Clamped on underflow to 0 - context._raise_error(Clamped) - elif len(ans._int) == context.prec+1: - # we get here only if rescaling rounds the - # cofficient up to exactly 10**context.prec - if ans._exp < Etop: - ans = _dec_from_triple(ans._sign, - ans._int[:-1], ans._exp+1) - else: - # Inexact and Rounded have already been raised - ans = context._raise_error(Overflow, 'above Emax', - self._sign) + context._raise_error(Rounded) + if not ans: + # raise Clamped on underflow to 0 + context._raise_error(Clamped) return ans + if self_is_subnormal: + context._raise_error(Subnormal) + # fold down if _clamp == 1 and self has too few digits if context._clamp == 1 and self._exp > Etop: context._raise_error(Clamped) Index: Lib/test/test_decimal.py =================================================================== --- Lib/test/test_decimal.py (revision 80686) +++ Lib/test/test_decimal.py (working copy) @@ -42,6 +42,12 @@ # Useful Test Constant Signals = tuple(getcontext().flags.keys()) +# Signals ordered with respect to precedence: when an operation +# produces multiple signals, signals occurring later in the list +# should be handled before those occurring earlier in the list. +OrderedSignals = (Clamped, Rounded, Inexact, Subnormal, + Underflow, Overflow, DivisionByZero, InvalidOperation) + # Tests are built around these assumed context defaults. # test_main() restores the original context. def init(): @@ -352,6 +358,25 @@ else: self.fail("Did not raise %s in %s" % (error, s)) self.context.traps[error] = 0 + + # as above, but add traps cumulatively, to check precedence + ordered_errors = [e for e in OrderedSignals if e in theirexceptions] + for error in ordered_errors: + self.context.traps[error] = 1 + try: + funct(*vals) + except error: + pass + except Signals, e: + self.fail("Raised %s in %s; expected %s" % + (type(e), s, error)) + else: + self.fail("Did not raise %s in %s" % (error, s)) + # reset traps + for error in ordered_errors: + self.context.traps[error] = 0 + + if DEBUG: print "--", self.context try: