mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +00:00
Faster _fix function, and some reordering for a more elegant
coding. Thanks Mark Dickinson.
This commit is contained in:
parent
62edb71556
commit
2ec7415db5
1 changed files with 47 additions and 52 deletions
|
|
@ -1077,29 +1077,6 @@ class Decimal(object):
|
||||||
|
|
||||||
return other.__sub__(self, context=context)
|
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):
|
def __mul__(self, other, context=None):
|
||||||
"""Return self * other.
|
"""Return self * other.
|
||||||
|
|
||||||
|
|
@ -1540,8 +1517,18 @@ class Decimal(object):
|
||||||
# round if self has too many digits
|
# round if self has too many digits
|
||||||
if self._exp < exp_min:
|
if self._exp < exp_min:
|
||||||
context._raise_error(Rounded)
|
context._raise_error(Rounded)
|
||||||
ans = self._rescale(exp_min, context.rounding)
|
digits = len(self._int) + self._exp - exp_min
|
||||||
if ans != self:
|
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)
|
context._raise_error(Inexact)
|
||||||
if self_is_subnormal:
|
if self_is_subnormal:
|
||||||
context._raise_error(Underflow)
|
context._raise_error(Underflow)
|
||||||
|
|
@ -1574,66 +1561,68 @@ class Decimal(object):
|
||||||
# for each of the rounding functions below:
|
# for each of the rounding functions below:
|
||||||
# self is a finite, nonzero Decimal
|
# self is a finite, nonzero Decimal
|
||||||
# prec is an integer satisfying 0 <= prec < len(self._int)
|
# 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):
|
def _round_down(self, prec):
|
||||||
"""Also known as round-towards-0, truncate."""
|
"""Also known as round-towards-0, truncate."""
|
||||||
newexp = self._exp + len(self._int) - prec
|
if _all_zeros(self._int, prec):
|
||||||
return _dec_from_triple(self._sign, self._int[:prec] or '0', newexp)
|
return 0
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
|
||||||
def _round_up(self, prec):
|
def _round_up(self, prec):
|
||||||
"""Rounds away from 0."""
|
"""Rounds away from 0."""
|
||||||
newexp = self._exp + len(self._int) - prec
|
return -self._round_down(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
|
|
||||||
|
|
||||||
def _round_half_up(self, prec):
|
def _round_half_up(self, prec):
|
||||||
"""Rounds 5 up (away from 0)"""
|
"""Rounds 5 up (away from 0)"""
|
||||||
if self._int[prec] in '56789':
|
if self._int[prec] in '56789':
|
||||||
return self._round_up(prec)
|
return 1
|
||||||
|
elif _all_zeros(self._int, prec):
|
||||||
|
return 0
|
||||||
else:
|
else:
|
||||||
return self._round_down(prec)
|
return -1
|
||||||
|
|
||||||
def _round_half_down(self, prec):
|
def _round_half_down(self, prec):
|
||||||
"""Round 5 down"""
|
"""Round 5 down"""
|
||||||
if self._int[prec] == '5':
|
if _exact_half(self._int, prec):
|
||||||
for digit in self._int[prec+1:]:
|
return -1
|
||||||
if digit != '0':
|
else:
|
||||||
break
|
return self._round_half_up(prec)
|
||||||
else:
|
|
||||||
return self._round_down(prec)
|
|
||||||
return self._round_half_up(prec)
|
|
||||||
|
|
||||||
def _round_half_even(self, prec):
|
def _round_half_even(self, prec):
|
||||||
"""Round 5 to even, rest to nearest."""
|
"""Round 5 to even, rest to nearest."""
|
||||||
if prec and self._int[prec-1] in '13579':
|
if _exact_half(self._int, prec) and \
|
||||||
return self._round_half_up(prec)
|
(prec == 0 or self._int[prec-1] in '02468'):
|
||||||
|
return -1
|
||||||
else:
|
else:
|
||||||
return self._round_half_down(prec)
|
return self._round_half_up(prec)
|
||||||
|
|
||||||
def _round_ceiling(self, prec):
|
def _round_ceiling(self, prec):
|
||||||
"""Rounds up (not away from 0 if negative.)"""
|
"""Rounds up (not away from 0 if negative.)"""
|
||||||
if self._sign:
|
if self._sign:
|
||||||
return self._round_down(prec)
|
return self._round_down(prec)
|
||||||
else:
|
else:
|
||||||
return self._round_up(prec)
|
return -self._round_down(prec)
|
||||||
|
|
||||||
def _round_floor(self, prec):
|
def _round_floor(self, prec):
|
||||||
"""Rounds down (not towards 0 if negative)"""
|
"""Rounds down (not towards 0 if negative)"""
|
||||||
if not self._sign:
|
if not self._sign:
|
||||||
return self._round_down(prec)
|
return self._round_down(prec)
|
||||||
else:
|
else:
|
||||||
return self._round_up(prec)
|
return -self._round_down(prec)
|
||||||
|
|
||||||
def _round_05up(self, prec):
|
def _round_05up(self, prec):
|
||||||
"""Round down unless digit prec-1 is 0 or 5."""
|
"""Round down unless digit prec-1 is 0 or 5."""
|
||||||
if prec == 0 or self._int[prec-1] in '05':
|
if prec and self._int[prec-1] not in '05':
|
||||||
return self._round_up(prec)
|
|
||||||
else:
|
|
||||||
return self._round_down(prec)
|
return self._round_down(prec)
|
||||||
|
else:
|
||||||
|
return -self._round_down(prec)
|
||||||
|
|
||||||
def fma(self, other, third, context=None):
|
def fma(self, other, third, context=None):
|
||||||
"""Fused multiply-add.
|
"""Fused multiply-add.
|
||||||
|
|
@ -2290,7 +2279,11 @@ class Decimal(object):
|
||||||
self = _dec_from_triple(self._sign, '1', exp-1)
|
self = _dec_from_triple(self._sign, '1', exp-1)
|
||||||
digits = 0
|
digits = 0
|
||||||
this_function = getattr(self, self._pick_rounding_function[rounding])
|
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):
|
def to_integral_exact(self, rounding=None, context=None):
|
||||||
"""Rounds to a nearby integer.
|
"""Rounds to a nearby integer.
|
||||||
|
|
@ -5198,6 +5191,8 @@ _parser = re.compile(r""" # A numeric string consists of:
|
||||||
$
|
$
|
||||||
""", re.VERBOSE | re.IGNORECASE).match
|
""", re.VERBOSE | re.IGNORECASE).match
|
||||||
|
|
||||||
|
_all_zeros = re.compile('0*$').match
|
||||||
|
_exact_half = re.compile('50*$').match
|
||||||
del re
|
del re
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue