@@ -1626,47 +1626,53 @@ def _fix(self, context):
16261626 exp_min = len (self ._int ) + self ._exp - context .prec
16271627 if exp_min > Etop :
16281628 # overflow: exp_min > Etop iff self.adjusted() > Emax
1629+ ans = context ._raise_error (Overflow , 'above Emax' , self ._sign )
16291630 context ._raise_error (Inexact )
16301631 context ._raise_error (Rounded )
1631- return context ._raise_error (Overflow , 'above Emax' , self ._sign )
1632+ return ans
1633+
16321634 self_is_subnormal = exp_min < Etiny
16331635 if self_is_subnormal :
1634- context ._raise_error (Subnormal )
16351636 exp_min = Etiny
16361637
16371638 # round if self has too many digits
16381639 if self ._exp < exp_min :
1639- context ._raise_error (Rounded )
16401640 digits = len (self ._int ) + self ._exp - exp_min
16411641 if digits < 0 :
16421642 self = _dec_from_triple (self ._sign , '1' , exp_min - 1 )
16431643 digits = 0
1644- this_function = getattr ( self , self ._pick_rounding_function [context .rounding ])
1645- changed = this_function (digits )
1644+ rounding_method = self ._pick_rounding_function [context .rounding ]
1645+ changed = getattr ( self , rounding_method ) (digits )
16461646 coeff = self ._int [:digits ] or '0'
1647- if changed == 1 :
1647+ if changed > 0 :
16481648 coeff = str (int (coeff )+ 1 )
1649- ans = _dec_from_triple (self ._sign , coeff , exp_min )
1649+ if len (coeff ) > context .prec :
1650+ coeff = coeff [:- 1 ]
1651+ exp_min += 1
16501652
1653+ # check whether the rounding pushed the exponent out of range
1654+ if exp_min > Etop :
1655+ ans = context ._raise_error (Overflow , 'above Emax' , self ._sign )
1656+ else :
1657+ ans = _dec_from_triple (self ._sign , coeff , exp_min )
1658+
1659+ # raise the appropriate signals, taking care to respect
1660+ # the precedence described in the specification
1661+ if changed and self_is_subnormal :
1662+ context ._raise_error (Underflow )
1663+ if self_is_subnormal :
1664+ context ._raise_error (Subnormal )
16511665 if changed :
16521666 context ._raise_error (Inexact )
1653- if self_is_subnormal :
1654- context ._raise_error (Underflow )
1655- if not ans :
1656- # raise Clamped on underflow to 0
1657- context ._raise_error (Clamped )
1658- elif len (ans ._int ) == context .prec + 1 :
1659- # we get here only if rescaling rounds the
1660- # cofficient up to exactly 10**context.prec
1661- if ans ._exp < Etop :
1662- ans = _dec_from_triple (ans ._sign ,
1663- ans ._int [:- 1 ], ans ._exp + 1 )
1664- else :
1665- # Inexact and Rounded have already been raised
1666- ans = context ._raise_error (Overflow , 'above Emax' ,
1667- self ._sign )
1667+ context ._raise_error (Rounded )
1668+ if not ans :
1669+ # raise Clamped on underflow to 0
1670+ context ._raise_error (Clamped )
16681671 return ans
16691672
1673+ if self_is_subnormal :
1674+ context ._raise_error (Subnormal )
1675+
16701676 # fold down if _clamp == 1 and self has too few digits
16711677 if context ._clamp == 1 and self ._exp > Etop :
16721678 context ._raise_error (Clamped )
@@ -2293,6 +2299,7 @@ def __pow__(self, other, modulo=None, context=None):
22932299 # from here on, the result always goes through the call
22942300 # to _fix at the end of this function.
22952301 ans = None
2302+ exact = False
22962303
22972304 # crude test to catch cases of extreme overflow/underflow. If
22982305 # log10(self)*other >= 10**bound and bound >= len(str(Emax))
@@ -2317,6 +2324,7 @@ def __pow__(self, other, modulo=None, context=None):
23172324 ans = self ._power_exact (other , context .prec + 1 )
23182325 if ans is not None and result_sign == 1 :
23192326 ans = _dec_from_triple (1 , ans ._int , ans ._exp )
2327+ exact = True
23202328
23212329 # usual case: inexact result, x**y computed directly as exp(y*log(x))
23222330 if ans is None :
@@ -2339,24 +2347,55 @@ def __pow__(self, other, modulo=None, context=None):
23392347
23402348 ans = _dec_from_triple (result_sign , str (coeff ), exp )
23412349
2342- # the specification says that for non-integer other we need to
2343- # raise Inexact, even when the result is actually exact. In
2344- # the same way, we need to raise Underflow here if the result
2345- # is subnormal. (The call to _fix will take care of raising
2346- # Rounded and Subnormal, as usual.)
2347- if not other ._isinteger ():
2348- context ._raise_error (Inexact )
2349- # pad with zeros up to length context.prec+1 if necessary
2350+ # unlike exp, ln and log10, the power function respects the
2351+ # rounding mode; no need to switch to ROUND_HALF_EVEN here
2352+
2353+ # There's a difficulty here when 'other' is not an integer and
2354+ # the result is exact. In this case, the specification
2355+ # requires that the Inexact flag be raised (in spite of
2356+ # exactness), but since the result is exact _fix won't do this
2357+ # for us. (Correspondingly, the Underflow signal should also
2358+ # be raised for subnormal results.) We can't directly raise
2359+ # these signals either before or after calling _fix, since
2360+ # that would violate the precedence for signals. So we wrap
2361+ # the ._fix call in a temporary context, and reraise
2362+ # afterwards.
2363+ if exact and not other ._isinteger ():
2364+ # pad with zeros up to length context.prec+1 if necessary; this
2365+ # ensures that the Rounded signal will be raised.
23502366 if len (ans ._int ) <= context .prec :
2351- expdiff = context .prec + 1 - len (ans ._int )
2367+ expdiff = context .prec + 1 - len (ans ._int )
23522368 ans = _dec_from_triple (ans ._sign , ans ._int + '0' * expdiff ,
23532369 ans ._exp - expdiff )
2354- if ans .adjusted () < context .Emin :
2355- context ._raise_error (Underflow )
23562370
2357- # unlike exp, ln and log10, the power function respects the
2358- # rounding mode; no need to use ROUND_HALF_EVEN here
2359- ans = ans ._fix (context )
2371+ # create a copy of the current context, with cleared flags/traps
2372+ newcontext = context .copy ()
2373+ newcontext .clear_flags ()
2374+ for exception in _signals :
2375+ newcontext .traps [exception ] = 0
2376+
2377+ # round in the new context
2378+ ans = ans ._fix (newcontext )
2379+
2380+ # raise Inexact, and if necessary, Underflow
2381+ newcontext ._raise_error (Inexact )
2382+ if newcontext .flags [Subnormal ]:
2383+ newcontext ._raise_error (Underflow )
2384+
2385+ # propagate signals to the original context; _fix could
2386+ # have raised any of Overflow, Underflow, Subnormal,
2387+ # Inexact, Rounded, Clamped. Overflow needs the correct
2388+ # arguments. Note that the order of the exceptions is
2389+ # important here.
2390+ if newcontext .flags [Overflow ]:
2391+ context ._raise_error (Overflow , 'above Emax' , ans ._sign )
2392+ for exception in Underflow , Subnormal , Inexact , Rounded , Clamped :
2393+ if newcontext .flags [exception ]:
2394+ context ._raise_error (exception )
2395+
2396+ else :
2397+ ans = ans ._fix (context )
2398+
23602399 return ans
23612400
23622401 def __rpow__ (self , other , context = None ):
@@ -2450,14 +2489,15 @@ def quantize(self, exp, rounding=None, context=None, watchexp=True):
24502489 'quantize result has too many digits for current context' )
24512490
24522491 # raise appropriate flags
2492+ if ans and ans .adjusted () < context .Emin :
2493+ context ._raise_error (Subnormal )
24532494 if ans ._exp > self ._exp :
2454- context ._raise_error (Rounded )
24552495 if ans != self :
24562496 context ._raise_error (Inexact )
2457- if ans and ans .adjusted () < context .Emin :
2458- context ._raise_error (Subnormal )
2497+ context ._raise_error (Rounded )
24592498
2460- # call to fix takes care of any necessary folddown
2499+ # call to fix takes care of any necessary folddown, and
2500+ # signals Clamped if necessary
24612501 ans = ans ._fix (context )
24622502 return ans
24632503
@@ -2556,10 +2596,10 @@ def to_integral_exact(self, rounding=None, context=None):
25562596 context = getcontext ()
25572597 if rounding is None :
25582598 rounding = context .rounding
2559- context ._raise_error (Rounded )
25602599 ans = self ._rescale (0 , rounding )
25612600 if ans != self :
25622601 context ._raise_error (Inexact )
2602+ context ._raise_error (Rounded )
25632603 return ans
25642604
25652605 def to_integral_value (self , rounding = None , context = None ):
@@ -3439,13 +3479,13 @@ def next_toward(self, other, context=None):
34393479 context ._raise_error (Overflow ,
34403480 'Infinite result from next_toward' ,
34413481 ans ._sign )
3442- context ._raise_error (Rounded )
34433482 context ._raise_error (Inexact )
3483+ context ._raise_error (Rounded )
34443484 elif ans .adjusted () < context .Emin :
34453485 context ._raise_error (Underflow )
34463486 context ._raise_error (Subnormal )
3447- context ._raise_error (Rounded )
34483487 context ._raise_error (Inexact )
3488+ context ._raise_error (Rounded )
34493489 # if precision == 1 then we don't raise Clamped for a
34503490 # result 0E-Etiny.
34513491 if not ans :
0 commit comments