diff options
| author | Facundo Batista <facundobatista@gmail.com> | 2007-12-03 17:55:00 (GMT) | 
|---|---|---|
| committer | Facundo Batista <facundobatista@gmail.com> | 2007-12-03 17:55:00 (GMT) | 
| commit | 2ec7415db5ad63c4e4b27ee793214071454f6fe5 (patch) | |
| tree | 18f0e65379a300110f9f16a92dd2eb41febf8d21 /Lib/decimal.py | |
| parent | 62edb71556d26f924a0e2e949af9cd3c211dea23 (diff) | |
| download | cpython-2ec7415db5ad63c4e4b27ee793214071454f6fe5.zip cpython-2ec7415db5ad63c4e4b27ee793214071454f6fe5.tar.gz cpython-2ec7415db5ad63c4e4b27ee793214071454f6fe5.tar.bz2  | |
Faster _fix function, and some reordering for a more elegant
coding. Thanks Mark Dickinson.
Diffstat (limited to 'Lib/decimal.py')
| -rw-r--r-- | Lib/decimal.py | 99 | 
1 files changed, 47 insertions, 52 deletions
diff --git a/Lib/decimal.py b/Lib/decimal.py index c503d2f..0ce9a34 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -1077,29 +1077,6 @@ class Decimal(object):          return other.__sub__(self, context=context) -    def _increment(self): -        """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. - -        Assumes that self is nonspecial. - -        For example: -        Decimal('5.624e10')._increment() == Decimal('5.625e10') -        """ -        L = map(int, 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 -        return _dec_from_triple(self._sign, "".join(map(str, L)), self._exp) -      def __mul__(self, other, context=None):          """Return self * other. @@ -1540,8 +1517,18 @@ class Decimal(object):          # round if self has too many digits          if self._exp < exp_min:              context._raise_error(Rounded) -            ans = self._rescale(exp_min, context.rounding) -            if ans != self: +            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) +            coeff = self._int[:digits] or '0' +            if changed == 1: +                coeff = str(int(coeff)+1) +            ans = _dec_from_triple(self._sign, coeff, exp_min) + +            if changed:                  context._raise_error(Inexact)                  if self_is_subnormal:                      context._raise_error(Underflow) @@ -1574,66 +1561,68 @@ class Decimal(object):      # for each of the rounding functions below:      #   self is a finite, nonzero Decimal      #   prec is an integer satisfying 0 <= prec < len(self._int) -    # the rounded result will have exponent self._exp + len(self._int) - prec; +    # +    # each function returns either -1, 0, or 1, as follows: +    #   1 indicates that self should be rounded up (away from zero) +    #   0 indicates that self should be truncated, and that all the +    #     digits to be truncated are zeros (so the value is unchanged) +    #  -1 indicates that there are nonzero digits to be truncated      def _round_down(self, prec):          """Also known as round-towards-0, truncate.""" -        newexp = self._exp + len(self._int) - prec -        return _dec_from_triple(self._sign, self._int[:prec] or '0', newexp) +        if _all_zeros(self._int, prec): +            return 0 +        else: +            return -1      def _round_up(self, prec):          """Rounds away from 0.""" -        newexp = self._exp + len(self._int) - prec -        tmp = _dec_from_triple(self._sign, self._int[:prec] or '0', newexp) -        for digit in self._int[prec:]: -            if digit != '0': -                return tmp._increment() -        return tmp +        return -self._round_down(prec)      def _round_half_up(self, prec):          """Rounds 5 up (away from 0)"""          if self._int[prec] in '56789': -            return self._round_up(prec) +            return 1 +        elif _all_zeros(self._int, prec): +            return 0          else: -            return self._round_down(prec) +            return -1      def _round_half_down(self, prec):          """Round 5 down""" -        if self._int[prec] == '5': -            for digit in self._int[prec+1:]: -                if digit != '0': -                    break -            else: -                return self._round_down(prec) -        return self._round_half_up(prec) +        if _exact_half(self._int, prec): +            return -1 +        else: +            return self._round_half_up(prec)      def _round_half_even(self, prec):          """Round 5 to even, rest to nearest.""" -        if prec and self._int[prec-1] in '13579': -            return self._round_half_up(prec) +        if _exact_half(self._int, prec) and \ +                (prec == 0 or self._int[prec-1] in '02468'): +            return -1          else: -            return self._round_half_down(prec) +            return self._round_half_up(prec)      def _round_ceiling(self, prec):          """Rounds up (not away from 0 if negative.)"""          if self._sign:              return self._round_down(prec)          else: -            return self._round_up(prec) +            return -self._round_down(prec)      def _round_floor(self, prec):          """Rounds down (not towards 0 if negative)"""          if not self._sign:              return self._round_down(prec)          else: -            return self._round_up(prec) +            return -self._round_down(prec)      def _round_05up(self, prec):          """Round down unless digit prec-1 is 0 or 5.""" -        if prec == 0 or self._int[prec-1] in '05': -            return self._round_up(prec) -        else: +        if prec and self._int[prec-1] not in '05':              return self._round_down(prec) +        else: +            return -self._round_down(prec)      def fma(self, other, third, context=None):          """Fused multiply-add. @@ -2290,7 +2279,11 @@ class Decimal(object):              self = _dec_from_triple(self._sign, '1', exp-1)              digits = 0          this_function = getattr(self, self._pick_rounding_function[rounding]) -        return this_function(digits) +        changed = this_function(digits) +        coeff = self._int[:digits] or '0' +        if changed == 1: +            coeff = str(int(coeff)+1) +        return _dec_from_triple(self._sign, coeff, exp)      def to_integral_exact(self, rounding=None, context=None):          """Rounds to a nearby integer. @@ -5198,6 +5191,8 @@ _parser = re.compile(r"""     # A numeric string consists of:      $  """, re.VERBOSE | re.IGNORECASE).match +_all_zeros = re.compile('0*$').match +_exact_half = re.compile('50*$').match  del re  | 
