mirror of https://github.com/python/cpython
Made the various is_* operations return booleans. This was discussed
with Cawlishaw by mail, and he basically confirmed that to these is_* operations, there's no need to return Decimal(0) and Decimal(1) if the language supports the False and True booleans. Also added a few tests for the these functions in extra.decTest, since they are mostly untested (apart from the doctests). Thanks Mark Dickinson
This commit is contained in:
parent
31ba8480d8
commit
1a191df14d
207
Lib/decimal.py
207
Lib/decimal.py
|
@ -679,14 +679,11 @@ class Decimal(object):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
"""Is the number non-zero?
|
"""Return True if self is nonzero; otherwise return False.
|
||||||
|
|
||||||
0 if self == 0
|
NaNs and infinities are considered nonzero.
|
||||||
1 if self != 0
|
|
||||||
"""
|
"""
|
||||||
if self._is_special:
|
return self._is_special or self._int[0] != 0
|
||||||
return True
|
|
||||||
return sum(self._int) != 0
|
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
other = _convert_other(other)
|
other = _convert_other(other)
|
||||||
|
@ -2239,15 +2236,18 @@ class Decimal(object):
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def same_quantum(self, other):
|
def same_quantum(self, other):
|
||||||
"""Test whether self and other have the same exponent.
|
"""Return True if self and other have the same exponent; otherwise
|
||||||
|
return False.
|
||||||
|
|
||||||
same as self._exp == other._exp, except NaN == sNaN
|
If either operand is a special value, the following rules are used:
|
||||||
|
* return True if both operands are infinities
|
||||||
|
* return True if both operands are NaNs
|
||||||
|
* otherwise, return False.
|
||||||
"""
|
"""
|
||||||
|
other = _convert_other(other, raiseit=True)
|
||||||
if self._is_special or other._is_special:
|
if self._is_special or other._is_special:
|
||||||
if self._isnan() or other._isnan():
|
return (self.is_nan() and other.is_nan() or
|
||||||
return self._isnan() and other._isnan() and True
|
self.is_infinite() and other.is_infinite())
|
||||||
if self._isinfinity() or other._isinfinity():
|
|
||||||
return self._isinfinity() and other._isinfinity() and True
|
|
||||||
return self._exp == other._exp
|
return self._exp == other._exp
|
||||||
|
|
||||||
def _rescale(self, exp, rounding):
|
def _rescale(self, exp, rounding):
|
||||||
|
@ -2730,84 +2730,60 @@ class Decimal(object):
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def is_canonical(self):
|
def is_canonical(self):
|
||||||
"""Returns 1 if self is canonical; otherwise returns 0."""
|
"""Return True if self is canonical; otherwise return False.
|
||||||
return Dec_p1
|
|
||||||
|
Currently, the encoding of a Decimal instance is always
|
||||||
|
canonical, so this method returns True for any Decimal.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
def is_finite(self):
|
def is_finite(self):
|
||||||
"""Returns 1 if self is finite, otherwise returns 0.
|
"""Return True if self is finite; otherwise return False.
|
||||||
|
|
||||||
For it to be finite, it must be neither infinite nor a NaN.
|
A Decimal instance is considered finite if it is neither
|
||||||
|
infinite nor a NaN.
|
||||||
"""
|
"""
|
||||||
if self._is_special:
|
return not self._is_special
|
||||||
return Dec_0
|
|
||||||
else:
|
|
||||||
return Dec_p1
|
|
||||||
|
|
||||||
def is_infinite(self):
|
def is_infinite(self):
|
||||||
"""Returns 1 if self is an Infinite, otherwise returns 0."""
|
"""Return True if self is infinite; otherwise return False."""
|
||||||
if self._isinfinity():
|
return self._exp == 'F'
|
||||||
return Dec_p1
|
|
||||||
else:
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_nan(self):
|
def is_nan(self):
|
||||||
"""Returns 1 if self is qNaN or sNaN, otherwise returns 0."""
|
"""Return True if self is a qNaN or sNaN; otherwise return False."""
|
||||||
if self._isnan():
|
return self._exp in ('n', 'N')
|
||||||
return Dec_p1
|
|
||||||
else:
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_normal(self, context=None):
|
def is_normal(self, context=None):
|
||||||
"""Returns 1 if self is a normal number, otherwise returns 0."""
|
"""Return True if self is a normal number; otherwise return False."""
|
||||||
if self._is_special:
|
if self._is_special or not self:
|
||||||
return Dec_0
|
return False
|
||||||
if not self:
|
|
||||||
return Dec_0
|
|
||||||
if context is None:
|
if context is None:
|
||||||
context = getcontext()
|
context = getcontext()
|
||||||
if context.Emin <= self.adjusted() <= context.Emax:
|
return context.Emin <= self.adjusted() <= context.Emax
|
||||||
return Dec_p1
|
|
||||||
else:
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_qnan(self):
|
def is_qnan(self):
|
||||||
"""Returns 1 if self is a quiet NaN, otherwise returns 0."""
|
"""Return True if self is a quiet NaN; otherwise return False."""
|
||||||
if self._isnan() == 1:
|
return self._exp == 'n'
|
||||||
return Dec_p1
|
|
||||||
else:
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_signed(self):
|
def is_signed(self):
|
||||||
"""Returns 1 if self is negative, otherwise returns 0."""
|
"""Return True if self is negative; otherwise return False."""
|
||||||
return Decimal(self._sign)
|
return self._sign == 1
|
||||||
|
|
||||||
def is_snan(self):
|
def is_snan(self):
|
||||||
"""Returns 1 if self is a signaling NaN, otherwise returns 0."""
|
"""Return True if self is a signaling NaN; otherwise return False."""
|
||||||
if self._isnan() == 2:
|
return self._exp == 'N'
|
||||||
return Dec_p1
|
|
||||||
else:
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_subnormal(self, context=None):
|
def is_subnormal(self, context=None):
|
||||||
"""Returns 1 if self is subnormal, otherwise returns 0."""
|
"""Return True if self is subnormal; otherwise return False."""
|
||||||
if self._is_special:
|
if self._is_special or not self:
|
||||||
return Dec_0
|
return False
|
||||||
if not self:
|
|
||||||
return Dec_0
|
|
||||||
if context is None:
|
if context is None:
|
||||||
context = getcontext()
|
context = getcontext()
|
||||||
|
return self.adjusted() < context.Emin
|
||||||
r = self._exp + len(self._int)
|
|
||||||
if r <= context.Emin:
|
|
||||||
return Dec_p1
|
|
||||||
return Dec_0
|
|
||||||
|
|
||||||
def is_zero(self):
|
def is_zero(self):
|
||||||
"""Returns 1 if self is a zero, otherwise returns 0."""
|
"""Return True if self is a zero; otherwise return False."""
|
||||||
if self:
|
return not self._is_special and self._int[0] == 0
|
||||||
return Dec_0
|
|
||||||
else:
|
|
||||||
return Dec_p1
|
|
||||||
|
|
||||||
def _ln_exp_bound(self):
|
def _ln_exp_bound(self):
|
||||||
"""Compute a lower bound for the adjusted exponent of self.ln().
|
"""Compute a lower bound for the adjusted exponent of self.ln().
|
||||||
|
@ -3871,138 +3847,145 @@ class Context(object):
|
||||||
return a.fma(b, c, context=self)
|
return a.fma(b, c, context=self)
|
||||||
|
|
||||||
def is_canonical(self, a):
|
def is_canonical(self, a):
|
||||||
"""Returns 1 if the operand is canonical; otherwise returns 0.
|
"""Return True if the operand is canonical; otherwise return False.
|
||||||
|
|
||||||
|
Currently, the encoding of a Decimal instance is always
|
||||||
|
canonical, so this method returns True for any Decimal.
|
||||||
|
|
||||||
>>> ExtendedContext.is_canonical(Decimal('2.50'))
|
>>> ExtendedContext.is_canonical(Decimal('2.50'))
|
||||||
Decimal("1")
|
True
|
||||||
"""
|
"""
|
||||||
return Dec_p1
|
return a.is_canonical()
|
||||||
|
|
||||||
def is_finite(self, a):
|
def is_finite(self, a):
|
||||||
"""Returns 1 if the operand is finite, otherwise returns 0.
|
"""Return True if the operand is finite; otherwise return False.
|
||||||
|
|
||||||
For it to be finite, it must be neither infinite nor a NaN.
|
A Decimal instance is considered finite if it is neither
|
||||||
|
infinite nor a NaN.
|
||||||
|
|
||||||
>>> ExtendedContext.is_finite(Decimal('2.50'))
|
>>> ExtendedContext.is_finite(Decimal('2.50'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_finite(Decimal('-0.3'))
|
>>> ExtendedContext.is_finite(Decimal('-0.3'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_finite(Decimal('0'))
|
>>> ExtendedContext.is_finite(Decimal('0'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_finite(Decimal('Inf'))
|
>>> ExtendedContext.is_finite(Decimal('Inf'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_finite(Decimal('NaN'))
|
>>> ExtendedContext.is_finite(Decimal('NaN'))
|
||||||
Decimal("0")
|
False
|
||||||
"""
|
"""
|
||||||
return a.is_finite()
|
return a.is_finite()
|
||||||
|
|
||||||
def is_infinite(self, a):
|
def is_infinite(self, a):
|
||||||
"""Returns 1 if the operand is an Infinite, otherwise returns 0.
|
"""Return True if the operand is infinite; otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_infinite(Decimal('2.50'))
|
>>> ExtendedContext.is_infinite(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_infinite(Decimal('-Inf'))
|
>>> ExtendedContext.is_infinite(Decimal('-Inf'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_infinite(Decimal('NaN'))
|
>>> ExtendedContext.is_infinite(Decimal('NaN'))
|
||||||
Decimal("0")
|
False
|
||||||
"""
|
"""
|
||||||
return a.is_infinite()
|
return a.is_infinite()
|
||||||
|
|
||||||
def is_nan(self, a):
|
def is_nan(self, a):
|
||||||
"""Returns 1 if the operand is qNaN or sNaN, otherwise returns 0.
|
"""Return True if the operand is a qNaN or sNaN;
|
||||||
|
otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_nan(Decimal('2.50'))
|
>>> ExtendedContext.is_nan(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_nan(Decimal('NaN'))
|
>>> ExtendedContext.is_nan(Decimal('NaN'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_nan(Decimal('-sNaN'))
|
>>> ExtendedContext.is_nan(Decimal('-sNaN'))
|
||||||
Decimal("1")
|
True
|
||||||
"""
|
"""
|
||||||
return a.is_nan()
|
return a.is_nan()
|
||||||
|
|
||||||
def is_normal(self, a):
|
def is_normal(self, a):
|
||||||
"""Returns 1 if the operand is a normal number, otherwise returns 0.
|
"""Return True if the operand is a normal number;
|
||||||
|
otherwise return False.
|
||||||
|
|
||||||
>>> c = ExtendedContext.copy()
|
>>> c = ExtendedContext.copy()
|
||||||
>>> c.Emin = -999
|
>>> c.Emin = -999
|
||||||
>>> c.Emax = 999
|
>>> c.Emax = 999
|
||||||
>>> c.is_normal(Decimal('2.50'))
|
>>> c.is_normal(Decimal('2.50'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> c.is_normal(Decimal('0.1E-999'))
|
>>> c.is_normal(Decimal('0.1E-999'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_normal(Decimal('0.00'))
|
>>> c.is_normal(Decimal('0.00'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_normal(Decimal('-Inf'))
|
>>> c.is_normal(Decimal('-Inf'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_normal(Decimal('NaN'))
|
>>> c.is_normal(Decimal('NaN'))
|
||||||
Decimal("0")
|
False
|
||||||
"""
|
"""
|
||||||
return a.is_normal(context=self)
|
return a.is_normal(context=self)
|
||||||
|
|
||||||
def is_qnan(self, a):
|
def is_qnan(self, a):
|
||||||
"""Returns 1 if the operand is a quiet NaN, otherwise returns 0.
|
"""Return True if the operand is a quiet NaN; otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_qnan(Decimal('2.50'))
|
>>> ExtendedContext.is_qnan(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_qnan(Decimal('NaN'))
|
>>> ExtendedContext.is_qnan(Decimal('NaN'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_qnan(Decimal('sNaN'))
|
>>> ExtendedContext.is_qnan(Decimal('sNaN'))
|
||||||
Decimal("0")
|
False
|
||||||
"""
|
"""
|
||||||
return a.is_qnan()
|
return a.is_qnan()
|
||||||
|
|
||||||
def is_signed(self, a):
|
def is_signed(self, a):
|
||||||
"""Returns 1 if the operand is negative, otherwise returns 0.
|
"""Return True if the operand is negative; otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_signed(Decimal('2.50'))
|
>>> ExtendedContext.is_signed(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_signed(Decimal('-12'))
|
>>> ExtendedContext.is_signed(Decimal('-12'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_signed(Decimal('-0'))
|
>>> ExtendedContext.is_signed(Decimal('-0'))
|
||||||
Decimal("1")
|
True
|
||||||
"""
|
"""
|
||||||
return a.is_signed()
|
return a.is_signed()
|
||||||
|
|
||||||
def is_snan(self, a):
|
def is_snan(self, a):
|
||||||
"""Returns 1 if the operand is a signaling NaN, otherwise returns 0.
|
"""Return True if the operand is a signaling NaN;
|
||||||
|
otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_snan(Decimal('2.50'))
|
>>> ExtendedContext.is_snan(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_snan(Decimal('NaN'))
|
>>> ExtendedContext.is_snan(Decimal('NaN'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_snan(Decimal('sNaN'))
|
>>> ExtendedContext.is_snan(Decimal('sNaN'))
|
||||||
Decimal("1")
|
True
|
||||||
"""
|
"""
|
||||||
return a.is_snan()
|
return a.is_snan()
|
||||||
|
|
||||||
def is_subnormal(self, a):
|
def is_subnormal(self, a):
|
||||||
"""Returns 1 if the operand is subnormal, otherwise returns 0.
|
"""Return True if the operand is subnormal; otherwise return False.
|
||||||
|
|
||||||
>>> c = ExtendedContext.copy()
|
>>> c = ExtendedContext.copy()
|
||||||
>>> c.Emin = -999
|
>>> c.Emin = -999
|
||||||
>>> c.Emax = 999
|
>>> c.Emax = 999
|
||||||
>>> c.is_subnormal(Decimal('2.50'))
|
>>> c.is_subnormal(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_subnormal(Decimal('0.1E-999'))
|
>>> c.is_subnormal(Decimal('0.1E-999'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> c.is_subnormal(Decimal('0.00'))
|
>>> c.is_subnormal(Decimal('0.00'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_subnormal(Decimal('-Inf'))
|
>>> c.is_subnormal(Decimal('-Inf'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> c.is_subnormal(Decimal('NaN'))
|
>>> c.is_subnormal(Decimal('NaN'))
|
||||||
Decimal("0")
|
False
|
||||||
"""
|
"""
|
||||||
return a.is_subnormal(context=self)
|
return a.is_subnormal(context=self)
|
||||||
|
|
||||||
def is_zero(self, a):
|
def is_zero(self, a):
|
||||||
"""Returns 1 if the operand is a zero, otherwise returns 0.
|
"""Return True if the operand is a zero; otherwise return False.
|
||||||
|
|
||||||
>>> ExtendedContext.is_zero(Decimal('0'))
|
>>> ExtendedContext.is_zero(Decimal('0'))
|
||||||
Decimal("1")
|
True
|
||||||
>>> ExtendedContext.is_zero(Decimal('2.50'))
|
>>> ExtendedContext.is_zero(Decimal('2.50'))
|
||||||
Decimal("0")
|
False
|
||||||
>>> ExtendedContext.is_zero(Decimal('-0E+2'))
|
>>> ExtendedContext.is_zero(Decimal('-0E+2'))
|
||||||
Decimal("1")
|
True
|
||||||
"""
|
"""
|
||||||
return a.is_zero()
|
return a.is_zero()
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -95,35 +95,61 @@ RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings.
|
||||||
|
|
||||||
# Name adapter to be able to change the Decimal and Context
|
# Name adapter to be able to change the Decimal and Context
|
||||||
# interface without changing the test files from Cowlishaw
|
# interface without changing the test files from Cowlishaw
|
||||||
nameAdapter = {'toeng':'to_eng_string',
|
nameAdapter = {'and':'logical_and',
|
||||||
'tosci':'to_sci_string',
|
|
||||||
'samequantum':'same_quantum',
|
|
||||||
'tointegral':'to_integral_value',
|
|
||||||
'tointegralx':'to_integral_exact',
|
|
||||||
'remaindernear':'remainder_near',
|
|
||||||
'divideint':'divide_int',
|
|
||||||
'squareroot':'sqrt',
|
|
||||||
'apply':'_apply',
|
'apply':'_apply',
|
||||||
'class':'number_class',
|
'class':'number_class',
|
||||||
'comparesig':'compare_signal',
|
'comparesig':'compare_signal',
|
||||||
'comparetotal':'compare_total',
|
'comparetotal':'compare_total',
|
||||||
'comparetotmag':'compare_total_mag',
|
'comparetotmag':'compare_total_mag',
|
||||||
'copyabs':'copy_abs',
|
|
||||||
'copy':'copy_decimal',
|
'copy':'copy_decimal',
|
||||||
|
'copyabs':'copy_abs',
|
||||||
'copynegate':'copy_negate',
|
'copynegate':'copy_negate',
|
||||||
'copysign':'copy_sign',
|
'copysign':'copy_sign',
|
||||||
'and':'logical_and',
|
'divideint':'divide_int',
|
||||||
'or':'logical_or',
|
|
||||||
'xor':'logical_xor',
|
|
||||||
'invert':'logical_invert',
|
'invert':'logical_invert',
|
||||||
|
'iscanonical':'is_canonical',
|
||||||
|
'isfinite':'is_finite',
|
||||||
|
'isinfinite':'is_infinite',
|
||||||
|
'isnan':'is_nan',
|
||||||
|
'isnormal':'is_normal',
|
||||||
|
'isqnan':'is_qnan',
|
||||||
|
'issigned':'is_signed',
|
||||||
|
'issnan':'is_snan',
|
||||||
|
'issubnormal':'is_subnormal',
|
||||||
|
'iszero':'is_zero',
|
||||||
'maxmag':'max_mag',
|
'maxmag':'max_mag',
|
||||||
'minmag':'min_mag',
|
'minmag':'min_mag',
|
||||||
'nextminus':'next_minus',
|
'nextminus':'next_minus',
|
||||||
'nextplus':'next_plus',
|
'nextplus':'next_plus',
|
||||||
'nexttoward':'next_toward',
|
'nexttoward':'next_toward',
|
||||||
|
'or':'logical_or',
|
||||||
'reduce':'normalize',
|
'reduce':'normalize',
|
||||||
|
'remaindernear':'remainder_near',
|
||||||
|
'samequantum':'same_quantum',
|
||||||
|
'squareroot':'sqrt',
|
||||||
|
'toeng':'to_eng_string',
|
||||||
|
'tointegral':'to_integral_value',
|
||||||
|
'tointegralx':'to_integral_exact',
|
||||||
|
'tosci':'to_sci_string',
|
||||||
|
'xor':'logical_xor',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The following functions return True/False rather than a Decimal instance
|
||||||
|
|
||||||
|
LOGICAL_FUNCTIONS = (
|
||||||
|
'is_canonical',
|
||||||
|
'is_finite',
|
||||||
|
'is_infinite',
|
||||||
|
'is_nan',
|
||||||
|
'is_normal',
|
||||||
|
'is_qnan',
|
||||||
|
'is_signed',
|
||||||
|
'is_snan',
|
||||||
|
'is_subnormal',
|
||||||
|
'is_zero',
|
||||||
|
'same_quantum',
|
||||||
|
)
|
||||||
|
|
||||||
# For some operations (currently exp, ln, log10, power), the decNumber
|
# For some operations (currently exp, ln, log10, power), the decNumber
|
||||||
# reference implementation imposes additional restrictions on the
|
# reference implementation imposes additional restrictions on the
|
||||||
# context and operands. These restrictions are not part of the
|
# context and operands. These restrictions are not part of the
|
||||||
|
@ -321,7 +347,7 @@ class DecimalTest(unittest.TestCase):
|
||||||
print "--", self.context
|
print "--", self.context
|
||||||
try:
|
try:
|
||||||
result = str(funct(*vals))
|
result = str(funct(*vals))
|
||||||
if fname == 'same_quantum':
|
if fname in LOGICAL_FUNCTIONS:
|
||||||
result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
|
result = str(int(eval(result))) # 'True', 'False' -> '1', '0'
|
||||||
except Signals, error:
|
except Signals, error:
|
||||||
self.fail("Raised %s in %s" % (error, s))
|
self.fail("Raised %s in %s" % (error, s))
|
||||||
|
|
Loading…
Reference in New Issue