[Python-checkins] r55125 - in python/branches/decimal-branch/Lib: decimal.py test/test_decimal.py
facundo.batista
python-checkins at python.org
Fri May 4 21:07:02 CEST 2007
Author: facundo.batista
Date: Fri May 4 21:06:58 2007
New Revision: 55125
Modified:
python/branches/decimal-branch/Lib/decimal.py
python/branches/decimal-branch/Lib/test/test_decimal.py
Log:
All the new operations were added to the decimal module, with docstring
and some examples, but no code. Also the corresponding name changes were
added to test_decimal. Right now, all the tests that are not ok, just
fail, no error.
We're entering now in the phase of actually code the new operations.
Modified: python/branches/decimal-branch/Lib/decimal.py
==============================================================================
--- python/branches/decimal-branch/Lib/decimal.py (original)
+++ python/branches/decimal-branch/Lib/decimal.py Fri May 4 21:06:58 2007
@@ -627,7 +627,7 @@
self._sign, self._int, self._exp = _string2exact(value)
except ValueError:
self._is_special = True
- return context._raise_error(ConversionSyntax,
+ return context._raise_error(ConversionSyntax,
"non parseable string")
return self
@@ -1650,7 +1650,7 @@
# # See if we need to extend precision
expdiff = prec - numdigits
-
+
# not allowing subnormal for quantize
if fromQuantize and (forceExp - context.Emax) > context.prec:
context._raise_error(InvalidOperation, "Quantize doesn't allow subnormal")
@@ -1709,7 +1709,7 @@
context._raise_error(Rounded)
context._raise_error(Inexact, 'Changed in rounding')
return ans
-
+
if len(ans._int) > origprec:
context._raise_error(InvalidOperation, 'Beyond guarded precision')
return NaN
@@ -1801,8 +1801,13 @@
if context is None:
context = getcontext()
+ if n._exp == 0 and n._sign == 0 and len(n._int) > context.prec:
+ return context._raise_error(InvalidContext)
-# # FIXME: study if this finally disappears...
+# # FIXME: this block code was against the new handling of Infinities
+# # I think we could remove them safely, do not know what the "n.adjusted()>8"
+# # actually means, so I won't be sure until all the tests passes ok.
+# # . Facundo
# if self._is_special or n._is_special:# or n.adjusted() > 8:
# # Because the spot << doesn't work with really big exponents
# if n._isinfinity() or n.adjusted() > 8:
@@ -1812,9 +1817,13 @@
if ans:
return ans
- if not self:
- if not n:
+ if not n:
+ if self:
+ return Decimal(1) # something ** 0
+ else:
return context._raise_error(InvalidOperation, '0 ** 0')
+
+ if not self:
if n._sign == 0:
zero = Decimal(0)
if n._iseven():
@@ -1830,39 +1839,29 @@
else:
return negInf
- if not n:
- return Decimal(1)
-
- # FIXME: Reduce the following to something more readable
+ self_inf = self._isinfinity()
+ n_inf = n._isinfinity()
if self == Decimal(1):
- if n._isinfinity():
+ if n_inf:
context._raise_error(Inexact)
context._raise_error(Rounded)
digits = (1,)+(0,)*(context.prec-1)
return Decimal((0, digits, -context.prec+1))
return Decimal(1)
- if self._isinfinity() == -1 and n._isinfinity():
+ if self_inf == -1 and n_inf:
return context._raise_error(InvalidOperation, '-Inf ** +-Inf')
- if self._isinfinity() == 1:
- if n._isinfinity() == 1:
- return Inf
- if n._isinfinity() == -1:
- return Decimal(0)
-
- if self._isinfinity() == 1:
+
+ if self_inf:
if modulo:
return context._raise_error(InvalidOperation, 'INF % x')
if not n:
return Decimal(1)
+ if self_inf == 1:
if n._sign == 1:
return Decimal(0)
return Inf
- if self._isinfinity() == -1:
- if modulo:
- return context._raise_error(InvalidOperation, '-INF % x')
- if not n:
- return Decimal(1)
+ if self_inf == -1:
if abs(n) < 1:
return context._raise_error(InvalidOperation, '-INF ** -1<n<1')
if n._sign == 0:
@@ -1875,16 +1874,14 @@
else:
return Decimal((1, (0,), 0))
- if n._isinfinity() == 1:
- if self._sign == 1:
- return context._raise_error(InvalidOperation, '-num ** Inf')
+ if n_inf and self._sign == 1:
+ return context._raise_error(InvalidOperation, '-num ** Inf')
+ if n_inf == 1:
if self < 1:
return Decimal(0)
else:
return Inf
- if n._isinfinity() == -1:
- if self._sign == 1:
- return context._raise_error(InvalidOperation, '-num ** -Inf')
+ if n_inf == -1:
if self > 1:
return Decimal(0)
else:
@@ -2052,7 +2049,7 @@
return context._raise_error(InvalidOperation, 'rescale(a, INF)')
return tmp
- def to_integral(self, rounding=None, context=None):
+ def to_integral_value(self, rounding=None, context=None):
"""Rounds to the nearest integer, without raising inexact, rounded."""
if self._is_special:
ans = self._check_nans(context=context)
@@ -2067,6 +2064,9 @@
context._regard_flags(flags)
return ans
+ # the method name changed, but we provide also the old one, for compatibility
+ to_integral = to_integral_value
+
def sqrt(self, context=None):
"""Return the square root of self.
@@ -2309,6 +2309,154 @@
except TypeError:
return 0
+ def canonical(self, context=None):
+ """Returns the same Decimal object.
+
+ As we do not have different encodings for the same number, the
+ received object already is in it's canonical form.
+ """
+
+ def compare_signal(self, other, context=None):
+ """Compares self to the other operand numerically.
+
+ It's pretty much like compare(), but all NaNs signal, with signaling
+ NaNs taking precedence over quiet NaNs.
+ """
+
+ def compare_total(self, other, context=None):
+ """Compares self to other using the abstract representations.
+
+ This is not like the standard compare, which use their numerical
+ value. Note that a total ordering is defined for all possible abstract
+ representations.
+ """
+
+ def compare_total_mag (self, other, context=None):
+ """Compares self to other using abstract repr., ignoring sign.
+
+ Like compare_total, but with operand's sign ignored and assumed to be 0.
+ """
+
+ def copy_abs(self, context=None):
+ """Returns a copy with the sign set to 0. """
+
+ def copy_negate(self, context=None):
+ """Returns a copy with the sign inverted."""
+
+ def copy_sign(self, other, context=None):
+ """Returns self with the sign of other."""
+
+ def exp(self, context=None):
+ """Returns e ** self."""
+
+ def is_canonical(self, context=None):
+ """Returns 1 if self is canonical; otherwise returns 0."""
+
+ def is_finite(self, context=None):
+ """Returns 1 if self is finite, otherwise returns 0.
+
+ For it to be finite, it must be neither infinite nor a NaN.
+ """
+
+ def is_infinite(self, context=None):
+ """Returns 1 if self is an Infinite, otherwise returns 0."""
+
+ def is_nan(self, context=None):
+ """Returns 1 if self is qNaN or sNaN, otherwise returns 0."""
+
+ def is_normal(self, context=None):
+ """Returns 1 if self is a normal number, otherwise returns 0."""
+
+ def is_qnan(self, context=None):
+ """Returns 1 if self is a quiet NaN, otherwise returns 0."""
+
+ def is_signed(self, context=None):
+ """Returns 1 if self is negative, otherwise returns 0."""
+
+ def is_snan(self, context=None):
+ """Returns 1 if self is a signaling NaN, otherwise returns 0."""
+
+ def is_subnormal(self, context=None):
+ """Returns 1 if self is subnormal, otherwise returns 0."""
+
+ def is_zero(self, context=None):
+ """Returns 1 if self is a zero, otherwise returns 0."""
+
+ def ln(self, context=None):
+ """Returns the natural (base e) logarithm of self."""
+
+ def log10(self, context=None):
+ """Returns the base 10 logarithm of self."""
+
+ def logb(self, context=None):
+ """ Returns the exponent of the magnitude of self's MSD.
+
+ The result is the integer which is the exponent of the magnitude
+ of the most significant digit of self (as though it were truncated
+ to a single digit while maintaining the value of that digit and
+ without limiting the resulting exponent).
+ """
+
+ def logical_and(self, other, context=None):
+ """Applies an 'and' operation between self and other's digits."""
+
+ def logical_invert(self, context=None):
+ """Invert all its digits."""
+
+ def logical_or(self, other, context=None):
+ """Applies an 'or' operation between self and other's digits."""
+
+ def logical_xor(self, other, context=None):
+ """Applies an 'xor' operation between self and other's digits."""
+
+ def max_mag(self, other, context=None):
+ """Compares the values numerically with their sign ignored."""
+
+ def min_mag(self, other, context=None):
+ """Compares the values numerically with their sign ignored."""
+
+ def next_minus(self, context=None):
+ """Returns the largest representable number smaller than itself."""
+
+ def next_plus(self, context=None):
+ """Returns the smallest representable number larger than itself."""
+
+ def next_toward(self, other, context=None):
+ """Returns the number closest to itself, in direction towards other.
+
+ The result is the closest to self representable number (but not
+ self) that is in the direction towards other, unless the both have
+ the same value.
+ """
+
+ def number_class(self, context=None):
+ """Returns an indication of the class of self.
+
+ The class is one of the following strings:
+ -sNaN
+ -NaN
+ -Infinity
+ -Normal
+ -Subnormal
+ -Zero
+ +Zero
+ +Subnormal
+ +Normal
+ +Infinity
+ """
+
+ def radix(self, context=None):
+ """Just returns 10, as this is Decimal, :)"""
+ return Decimal(10)
+
+ def rotate(self, other, context=None):
+ """Returns a rotated copy of self, value-of-other times."""
+
+ def scaleb (self, other, context=None):
+ """Returns self operand after adding the second value to its exp."""
+
+ def shift(self, other, context=None):
+ """Returns a shifted copy of self, value-of-other times."""
# Support for pickling, copy, and deepcopy
def __reduce__(self):
return (self.__class__, (str(self),))
@@ -2557,6 +2705,17 @@
def _apply(self, a):
return str(a._fix(self))
+ def canonical(self, a):
+ """Returns the same Decimal object.
+
+ As we do not have different encodings for the same number, the
+ received object already is in it's canonical form.
+
+ >>> ExtendedContext.canonical(Decimal('2.50'))
+ Decimal('2.50')
+ """
+ return a.canonical(context=self)
+
def compare(self, a, b):
"""Compares values numerically.
@@ -2586,6 +2745,90 @@
"""
return a.compare(b, context=self)
+ def compare_signal(self, a, b):
+ """Compares the values of the two operands numerically.
+
+ It's pretty much like compare(), but all NaNs signal, with signaling
+ NaNs taking precedence over quiet NaNs.
+ """
+ return a.compare_signal(b, context=self)
+
+ def compare_total(self, a, b):
+ """Compares two operands using their abstract representation.
+
+ This is not like the standard compare, which use their numerical
+ value. Note that a total ordering is defined for all possible abstract
+ representations.
+
+ >>> ExtendedContext.compare_total(Decimal('12.73'), Decimal('127.9'))
+ Decimal('-1')
+ >>> ExtendedContext.compare_total(Decimal('-127'), Decimal('12'))
+ Decimal('-1')
+ >>> ExtendedContext.compare_total(Decimal('12.30'), Decimal('12.3'))
+ Decimal('-1')
+ >>> ExtendedContext.compare_total(Decimal('12.30'), Decimal('12.30'))
+ Decimal('0')
+ >>> ExtendedContext.compare_total(Decimal('12.3'), Decimal('12.300'))
+ Decimal('1')
+ >>> ExtendedContext.compare_total(Decimal('12.3'), Decimal('NaN'))
+ Decimal('-1')
+ """
+ return a.compare_total(b, context=self)
+
+ def compare_total_mag (self, a, b):
+ """Compares two operands using their abstract representation ignoring sign.
+
+ Like compare_total, but with operand's sign ignored and assumed to be 0.
+ """
+ return a.compare_total_mag (b, context=self)
+
+ def copy_abs(self, a):
+ """Returns a copy of the operand with the sign set to 0.
+
+ >>> ExtendedContext.copy_abs(Decimal('2.1'))
+ Decimal('2.1')
+ >>> ExtendedContext.copy_abs(Decimal('-100'))
+ Decimal('100')
+ """
+ return a.copy_abs(context=self)
+
+ def copy_decimal(self, a):
+ """Returns a copy of the decimal objet.
+
+ >>> ExtendedContext.copy_decimal(Decimal('2.1'))
+ Decimal('2.1')
+ >>> ExtendedContext.copy_decimal(Decimal('-1.00'))
+ Decimal('-1.00')
+ """
+ return a
+
+ def copy_negate(self, a):
+ """Returns a copy of the operand with the sign inverted.
+
+ >>> ExtendedContext.copy_negate(Decimal('101.5'))
+ Decimal('-101.5')
+ >>> ExtendedContext.copy_negate(Decimal('-101.5'))
+ Decimal('101.5')
+ """
+ return a.copy_negate(context=self)
+
+ def copy_sign(self, a, b):
+ """Copys the second operand's sign to the first one.
+
+ In detail, it returns a copy of the first operand with the sign
+ equal to the sign of the second operand.
+
+ >>> ExtendedContext.copy_sign(Decimal( '1.50'), Decimal('7.33'))
+ Decimal('1.50')
+ >>> ExtendedContext.copy_sign(Decimal('-1.50'), Decimal('7.33'))
+ Decimal('1.50')
+ >>> ExtendedContext.copy_sign(Decimal( '1.50'), Decimal('-7.33'))
+ Decimal('-1.50')
+ >>> ExtendedContext.copy_sign(Decimal('-1.50'), Decimal('-7.33'))
+ Decimal('-1.50')
+ """
+ return a.copy_sign(b, context=self)
+
def divide(self, a, b):
"""Decimal division in a specified context.
@@ -2627,6 +2870,300 @@
def divmod(self, a, b):
return a.__divmod__(b, context=self)
+ def exp(self, a):
+ """Returns e ** a.
+
+ >>> ExtendedContext.exp(Decimal('-Infinity'))
+ Decimal('0')
+ >>> ExtendedContext.exp(Decimal('-1'))
+ Decimal('0.367879441')
+ >>> ExtendedContext.exp(Decimal('0'))
+ Decimal('1')
+ >>> ExtendedContext.exp(Decimal('1'))
+ Decimal('2.71828183')
+ >>> ExtendedContext.exp(Decimal('0.693147181'))
+ Decimal('2.00000000')
+ >>> ExtendedContext.exp(Decimal('+Infinity'))
+ Decimal('Inf')
+ """
+ return a.exp(context=self)
+
+ def fma(self, a, b, c):
+ """Returns a multiplied by b, plus c.
+
+ The first two operands are multiplied together, using multiply,
+ the third operand is then added to the result of that
+ multiplication, using add, all with only one final rounding.
+
+ >>> ExtendedContext.fma(Decimal('3'), Decimal('5'), Decimal('7'))
+ Decimal('22')
+ >>> ExtendedContext.fma(Decimal('3'), Decimal('-5'), Decimal('7'))
+ Decimal('-8')
+ >>> ExtendedContext.fma(Decimal('888565290'), Decimal('1557.96930'), Decimal('-86087.7578'))
+ Decimal('1.38435736E+12')
+ """
+
+ def is_canonical(self, a):
+ """Returns 1 if the operand is canonical; otherwise returns 0.
+
+ >>> ExtendedContext.is_canonical(Decimal('2.50'))
+ Decimal('1')
+ """
+ return a.is_canonical(context=self)
+
+ def is_finite(self, a):
+ """Returns 1 if the operand is finite, otherwise returns 0.
+
+ For it to be finite, it must be neither infinite nor a NaN.
+
+ >>> ExtendedContext.is_finite(Decimal('2.50'))
+ Decimal('1')
+ >>> ExtendedContext.is_finite(Decimal('-0.3'))
+ Decimal('1')
+ >>> ExtendedContext.is_finite(Decimal('0'))
+ Decimal('1')
+ >>> ExtendedContext.is_finite(Decimal('Inf'))
+ Decimal('0')
+ >>> ExtendedContext.is_finite(Decimal('NaN'))
+ Decimal('0')
+ """
+ return a.is_finite(context=self)
+
+ def is_infinite(self, a):
+ """Returns 1 if the operand is an Infinite, otherwise returns 0.
+
+ >>> ExtendedContext.is_infinite(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_infinite(Decimal('-Inf'))
+ Decimal('1')
+ >>> ExtendedContext.is_infinite(Decimal('NaN'))
+ Decimal('0')
+ """
+ return a.is_infinite(context=self)
+
+ def is_nan(self, a):
+ """Returns 1 if the operand is qNaN or sNaN, otherwise returns 0.
+
+ >>> ExtendedContext.is_nan(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_nan(Decimal('NaN'))
+ Decimal('1')
+ >>> ExtendedContext.is_nan(Decimal('-sNaN'))
+ Decimal('1')
+ """
+ return a.is_nan(context=self)
+
+ def is_normal(self, a):
+ """Returns 1 if the operand is a normal number, otherwise returns 0.
+
+ >>> ExtendedContext.is_normal(Decimal('2.50'))
+ Decimal('1')
+ >>> ExtendedContext.is_normal(Decimal('0.1E-999'))
+ Decimal('0')
+ >>> ExtendedContext.is_normal(Decimal('0.00'))
+ Decimal('0')
+ >>> ExtendedContext.is_normal(Decimal('-Inf'))
+ Decimal('0')
+ >>> ExtendedContext.is_normal(Decimal('NaN'))
+ Decimal('0')
+ """
+ return a.is_normal(context=self)
+
+ def is_qnan(self, a):
+ """Returns 1 if the operand is a quiet NaN, otherwise returns 0.
+
+ >>> ExtendedContext.is_qnan(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_qnan(Decimal('NaN'))
+ Decimal('1')
+ >>> ExtendedContext.is_qnan(Decimal('sNaN'))
+ Decimal('0')
+ """
+ return a.is_qnan(context=self)
+
+ def is_signed(self, a):
+ """Returns 1 if the operand is negative, otherwise returns 0.
+
+ >>> ExtendedContext.is_signed(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_signed(Decimal('-12'))
+ Decimal('1')
+ >>> ExtendedContext.is_signed(Decimal('-0'))
+ Decimal('1')
+ """
+ return a.is_signed(context=self)
+
+ def is_snan(self, a):
+ """Returns 1 if the operand is a signaling NaN, otherwise returns 0.
+
+ >>> ExtendedContext.is_snan(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_snan(Decimal('NaN'))
+ Decimal('0')
+ >>> ExtendedContext.is_snan(Decimal('sNaN'))
+ Decimal('1')
+ """
+ return a.is_snan(context=self)
+
+ def is_subnormal(self, a):
+ """Returns 1 if the operand is subnormal, otherwise returns 0.
+
+ >>> ExtendedContext.is_subnormal(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_subnormal(Decimal('0.1E-999'))
+ Decimal('1')
+ >>> ExtendedContext.is_subnormal(Decimal('0.00'))
+ Decimal('0')
+ >>> ExtendedContext.is_subnormal(Decimal('-Inf'))
+ Decimal('0')
+ >>> ExtendedContext.is_subnormal(Decimal('NaN'))
+ Decimal('0')
+ """
+ return a.is_subnormal(context=self)
+
+ def is_zero(self, a):
+ """Returns 1 if the operand is a zero, otherwise returns 0.
+
+ >>> ExtendedContext.is_zero(Decimal('0'))
+ Decimal('1')
+ >>> ExtendedContext.is_zero(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.is_zero(Decimal('-0E+2'))
+ Decimal('1')
+ """
+ return a.is_zero(context=self)
+
+ def ln(self, a):
+ """Returns the natural (base e) logarithm of the operand.
+
+ >>> ExtendedContext.ln(Decimal('0'))
+ Decimal('-Inf')
+ >>> ExtendedContext.ln(Decimal('1.000'))
+ Decimal('0')
+ >>> ExtendedContext.ln(Decimal('2.71828183'))
+ Decimal('1.00000000')
+ >>> ExtendedContext.ln(Decimal('10'))
+ Decimal('2.30258509')
+ >>> ExtendedContext.ln(Decimal('+Infinity'))
+ Decimal('Inf')
+ """
+ return a.ln(context=self)
+
+ def log10(self, a):
+ """Returns the base 10 logarithm of the operand.
+
+ >>> ExtendedContext.log10(Decimal('0'))
+ Decimal('-In')
+ >>> ExtendedContext.log10(Decimal('0.001'))
+ Decimal('-3')
+ >>> ExtendedContext.log10(Decimal('1.000'))
+ Decimal('0')
+ >>> ExtendedContext.log10(Decimal('2'))
+ Decimal('0.301029996')
+ >>> ExtendedContext.log10(Decimal('10'))
+ Decimal('1')
+ >>> ExtendedContext.log10(Decimal('70'))
+ Decimal('1.84509804')
+ >>> ExtendedContext.log10(Decimal('+Infinity'))
+ Decimal('Inf')
+ """
+ return a.log10(context=self)
+
+ def logb(self, a):
+ """ Returns the exponent of the magnitude of the operand's MSD.
+
+ The result is the integer which is the exponent of the magnitude
+ of the most significant digit of the operand (as though the
+ operand were truncated to a single digit while maintaining the
+ value of that digit and without limiting the resulting exponent).
+
+ >>> ExtendedContext.logb(Decimal('250'))
+ Decimal('2')
+ >>> ExtendedContext.logb(Decimal('2.50'))
+ Decimal('0')
+ >>> ExtendedContext.logb(Decimal('0.03'))
+ Decimal('-2')
+ >>> ExtendedContext.logb(Decimal('0'))
+ Decimal('-Inf')
+ """
+ return a.logb(context=self)
+
+ def logical_and(self, a, b):
+ """Applies the logical operation 'and' between each operand's digits.
+
+ The operands must be both logical numbers.
+
+ >>> ExtendedContext.logical_and(Decimal('0'), Decimal('0'))
+ Decimal('0')
+ >>> ExtendedContext.logical_and(Decimal('0'), Decimal('1'))
+ Decimal('0')
+ >>> ExtendedContext.logical_and(Decimal('1'), Decimal('0'))
+ Decimal('0')
+ >>> ExtendedContext.logical_and(Decimal('1'), Decimal('1'))
+ Decimal('1')
+ >>> ExtendedContext.logical_and(Decimal('1100'), Decimal('1010'))
+ Decimal('1000')
+ >>> ExtendedContext.logical_and(Decimal('1111'), Decimal('10'))
+ Decimal('10')
+ """
+ return a.logical_and(b, context=self)
+
+ def logical_invert(self, a):
+ """Invert all the digits in the operand.
+
+ The operand must be a logical number.
+
+ >>> ExtendedContext.logical_invert(Decimal('0'))
+ Decimal('111111111')
+ >>> ExtendedContext.logical_invert(Decimal('1'))
+ Decimal('111111110')
+ >>> ExtendedContext.logical_invert(Decimal('111111111'))
+ Decimal('0')
+ >>> ExtendedContext.logical_invert(Decimal('101010101'))
+ Decimal('10101010')
+ """
+ return a.logical_invert(context=self)
+
+ def logical_or(self, a, b):
+ """Applies the logical operation 'or' between each operand's digits.
+
+ The operands must be both logical numbers.
+
+ >>> ExtendedContext.logical_or(Decimal('0'), Decimal('0'))
+ Decimal('0')
+ >>> ExtendedContext.logical_or(Decimal('0'), Decimal('1'))
+ Decimal('1')
+ >>> ExtendedContext.logical_or(Decimal('1'), Decimal('0'))
+ Decimal('1')
+ >>> ExtendedContext.logical_or(Decimal('1'), Decimal('1'))
+ Decimal('1')
+ >>> ExtendedContext.logical_or(Decimal('1100'), Decimal('1010'))
+ Decimal('1110')
+ >>> ExtendedContext.logical_or(Decimal('1110'), Decimal('10'))
+ Decimal('1110')
+ """
+ return a.logical_or(b, context=self)
+
+ def logical_xor(self, a, b):
+ """Applies the logical operation 'xor' between each operand's digits.
+
+ The operands must be both logical numbers.
+
+ >>> ExtendedContext.logical_xor(Decimal('0'), Decimal('0'))
+ Decimal('0')
+ >>> ExtendedContext.logical_xor(Decimal('0'), Decimal('1'))
+ Decimal('1')
+ >>> ExtendedContext.logical_xor(Decimal('1'), Decimal('0'))
+ Decimal('1')
+ >>> ExtendedContext.logical_xor(Decimal('1'), Decimal('1'))
+ Decimal('0')
+ >>> ExtendedContext.logical_xor(Decimal('1100'), Decimal('1010'))
+ Decimal('110')
+ >>> ExtendedContext.logical_xor(Decimal('1111'), Decimal('10'))
+ Decimal('1101')
+ """
+ return a.logical_xor(b, context=self)
+
def max(self, a,b):
"""max compares two values numerically and returns the maximum.
@@ -2647,6 +3184,10 @@
"""
return a.max(b, context=self)
+ def max_mag(self, a, b):
+ """Compares the values numerically with their sign ignored."""
+ return a.max_mag(b, context=self)
+
def min(self, a,b):
"""min compares two values numerically and returns the minimum.
@@ -2667,6 +3208,10 @@
"""
return a.min(b, context=self)
+ def min_mag(self, a, b):
+ """Compares the values numerically with their sign ignored."""
+ return a.min_mag(b, context=self)
+
def minus(self, a):
"""Minus corresponds to unary prefix minus in Python.
@@ -2702,6 +3247,59 @@
"""
return a.__mul__(b, context=self)
+ def next_minus(self, a):
+ """Returns the largest representable number smaller than a.
+
+ >>> ExtendedContext.next_minus(Decimal('1'))
+ Decimal('0.999999999')
+ >>> ExtendedContext.next_minus(Decimal('1E-1007'))
+ Decimal('0E-1007')
+ >>> ExtendedContext.next_minus(Decimal('-1.00000003'))
+ Decimal('-1.00000004')
+ >>> ExtendedContext.next_minus(Decimal('Infinity'))
+ Decimal('9.99999999E+999')
+ """
+ return a.next_minus(context=self)
+
+ def next_plus(self, a):
+ """Returns the smallest representable number larger than a.
+
+ >>> ExtendedContext.next_plus(Decimal('1'))
+ Decimal('1.00000001')
+ >>> ExtendedContext.next_plus(Decimal('-1E-1007'))
+ Decimal('-0E-1007')
+ >>> ExtendedContext.next_plus(Decimal('-1.00000003'))
+ Decimal('-1.00000002')
+ >>> ExtendedContext.next_plus(Decimal('-Infinity'))
+ Decimal('-9.99999999E+999')
+ """
+ return a.next_plus(context=self)
+
+ def next_toward(self, a, b):
+ """Returns the number closest to a, in direction towards b.
+
+ The result is the closest representable number from the first
+ operand (but not the first operand) that is in the direction
+ towards the second operand, unless the operands have the same
+ value.
+
+ >>> ExtendedContext.next_toward(Decimal('1'), Decimal('2'))
+ Decimal('1.00000001')
+ >>> ExtendedContext.next_toward(Decimal('-1E-1007'), Decimal('1'))
+ Decimal('-0E-1007')
+ >>> ExtendedContext.next_toward(Decimal('-1.00000003'), Decimal('0'))
+ Decimal('-1.00000002')
+ >>> ExtendedContext.next_toward(Decimal('1'), Decimal('0'))
+ Decimal('0.999999999')
+ >>> ExtendedContext.next_toward(Decimal('1E-1007'), Decimal('-100'))
+ Decimal('0E-1007')
+ >>> ExtendedContext.next_toward(Decimal('-1.00000003'), Decimal('-10'))
+ Decimal('-1.00000004')
+ >>> ExtendedContext.next_toward(Decimal('0.00'), Decimal('-0.0000'))
+ Decimal('-0.00')
+ """
+ return a.next_toward(b, context=self)
+
def normalize(self, a):
"""normalize reduces an operand to its simplest form.
@@ -2723,6 +3321,50 @@
"""
return a.normalize(context=self)
+ def number_class(self, a):
+ """Returns an indication of the class of the operand.
+
+ The class is one of the following strings:
+ -sNaN
+ -NaN
+ -Infinity
+ -Normal
+ -Subnormal
+ -Zero
+ +Zero
+ +Subnormal
+ +Normal
+ +Infinity
+
+ >>> ExtendedContext.number_class(Decimal('Infinity'))
+ "+Infinity"
+ >>> ExtendedContext.number_class(Decimal('1E-10'))
+ "+Normal"
+ >>> ExtendedContext.number_class(Decimal('2.50'))
+ "+Normal"
+ >>> ExtendedContext.number_class(Decimal('0.1E-999'))
+ "+Subnormal"
+ >>> ExtendedContext.number_class(Decimal('0'))
+ "+Zero"
+ >>> ExtendedContext.number_class(Decimal('-0'))
+ "-Zero"
+ >>> ExtendedContext.number_class(Decimal('-0.1E-999'))
+ "-Subnormal"
+ >>> ExtendedContext.number_class(Decimal('-1E-10'))
+ "-Normal"
+ >>> ExtendedContext.number_class(Decimal('-2.50'))
+ "-Normal"
+ >>> ExtendedContext.number_class(Decimal('-Infinity'))
+ "-Infinity"
+ >>> ExtendedContext.number_class(Decimal('NaN'))
+ "NaN"
+ >>> ExtendedContext.number_class(Decimal('-NaN'))
+ "NaN"
+ >>> ExtendedContext.number_class(Decimal('sNaN'))
+ "sNaN"
+ """
+ return a.number_class(context=self)
+
def plus(self, a):
"""Plus corresponds to unary prefix plus in Python.
@@ -2748,7 +3390,7 @@
1) before use.
If the increased precision needed for the intermediate calculations
- exceeds the capabilities of the implementation then an Invalid
+ exceeds the capabilities of the implementation then an Invalid
operation condition is raised.
If, when raising to a negative power, an underflow occurs during the
@@ -2837,12 +3479,20 @@
"""
return a.quantize(b, context=self)
+ def radix(self):
+ """Just returns 10, as this is Decimal, :)
+
+ >>> ExtendedContext.radix()
+ Decimal('10')
+ """
+ return Decimal(10)
+
def remainder(self, a, b):
"""Returns the remainder from integer division.
The result is the residue of the dividend after the operation of
calculating integer division as described for divide-integer, rounded
- to precision digits if necessary. The sign of the result, if
+ to precision digits if necessary. The sign of the result, if
non-zero, is the same as that of the original dividend.
This operation will fail under the same conditions as integer division
@@ -2891,6 +3541,28 @@
"""
return a.remainder_near(b, context=self)
+ def rotate(self, a, b):
+ """Returns a rotated copy of a, b times.
+
+ The coefficient of the result is a rotated copy of the digits in
+ the coefficient of the first operand. The number of places of
+ rotation is taken from the absolute value of the second operand,
+ with the rotation being to the left if the second operand is
+ positive or to the right otherwise.
+
+ >>> ExtendedContext.rotate(Decimal('34'), Decimal('8'))
+ Decimal('400000003')
+ >>> ExtendedContext.rotate(Decimal('12'), Decimal('9'))
+ Decimal('12')
+ >>> ExtendedContext.rotate(Decimal('123456789'), Decimal('-2'))
+ Decimal('891234567')
+ >>> ExtendedContext.rotate(Decimal('123456789'), Decimal('0'))
+ Decimal('123456789')
+ >>> ExtendedContext.rotate(Decimal('123456789'), Decimal('+2'))
+ Decimal('345678912')
+ """
+ return a.rotate(b, context=self)
+
def same_quantum(self, a, b):
"""Returns True if the two operands have the same exponent.
@@ -2908,6 +3580,41 @@
"""
return a.same_quantum(b)
+ def scaleb (self, a, b):
+ """Returns the first operand after adding the second value its exp.
+
+ >>> ExtendedContext.scaleb(Decimal('7.50'), Decimal('-2'))
+ Decimal('0.0750')
+ >>> ExtendedContext.scaleb(Decimal('7.50'), Decimal('0'))
+ Decimal('7.50')
+ >>> ExtendedContext.scaleb(Decimal('7.50'), Decimal('3'))
+ Decimal('7.50E+3')
+ """
+ return a.scaleb (b, context=self)
+
+ def shift(self, a, b):
+ """Returns a shifted copy of a, b times.
+
+ The coefficient of the result is a shifted copy of the digits
+ in the coefficient of the first operand. The number of places
+ to shift is taken from the absolute value of the second operand,
+ with the shift being to the left if the second operand is
+ positive or to the right otherwise. Digits shifted into the
+ coefficient are zeros.
+
+ >>> ExtendedContext.shift(Decimal('34'), Decimal('8'))
+ Decimal('400000000')
+ >>> ExtendedContext.shift(Decimal('12'), Decimal('9'))
+ Decimal('0')
+ >>> ExtendedContext.shift(Decimal('123456789'), Decimal('-2'))
+ Decimal('1234567')
+ >>> ExtendedContext.shift(Decimal('123456789'), Decimal('0'))
+ Decimal('123456789')
+ >>> ExtendedContext.shift(Decimal('123456789'), Decimal('+2'))
+ Decimal('345678900')
+ """
+ return a.shift(b, context=self)
+
def sqrt(self, a):
"""Square root of a non-negative number to context precision.
@@ -2965,7 +3672,35 @@
a = self._raise_error(ConversionSyntax)
return a.__str__(context=self)
- def to_integral(self, a):
+ def to_integral_exact(self, a):
+ """Rounds to an integer.
+
+ When the operand has a negative exponent, the result is the same
+ as using the quantize() operation using the given operand as the
+ left-hand-operand, 1E+0 as the right-hand-operand, and the precision
+ of the operand as the precision setting; Inexact and Rounded flags
+ are allowed in this operation. The rounding mode is taken from the
+ context.
+
+ >>> ExtendedContext.to_integral_exact(Decimal('2.1'))
+ Decimal('2')
+ >>> ExtendedContext.to_integral_exact(Decimal('100'))
+ Decimal('100')
+ >>> ExtendedContext.to_integral_exact(Decimal('100.0'))
+ Decimal('100')
+ >>> ExtendedContext.to_integral_exact(Decimal('101.5'))
+ Decimal('102')
+ >>> ExtendedContext.to_integral_exact(Decimal('-101.5'))
+ Decimal('-102')
+ >>> ExtendedContext.to_integral_exact(Decimal('10E+5'))
+ Decimal('1.0E+6')
+ >>> ExtendedContext.to_integral_exact(Decimal('7.89E+77'))
+ Decimal('7.89E+77')
+ >>> ExtendedContext.to_integral_exact(Decimal('-Inf'))
+ Decimal('-Infinity')
+ """
+
+ def to_integral_value(self, a):
"""Rounds to an integer.
When the operand has a negative exponent, the result is the same
@@ -2974,24 +3709,27 @@
of the operand as the precision setting, except that no flags will
be set. The rounding mode is taken from the context.
- >>> ExtendedContext.to_integral(Decimal('2.1'))
+ >>> ExtendedContext.to_integral_value(Decimal('2.1'))
Decimal("2")
- >>> ExtendedContext.to_integral(Decimal('100'))
+ >>> ExtendedContext.to_integral_value(Decimal('100'))
Decimal("100")
- >>> ExtendedContext.to_integral(Decimal('100.0'))
+ >>> ExtendedContext.to_integral_value(Decimal('100.0'))
Decimal("100")
- >>> ExtendedContext.to_integral(Decimal('101.5'))
+ >>> ExtendedContext.to_integral_value(Decimal('101.5'))
Decimal("102")
- >>> ExtendedContext.to_integral(Decimal('-101.5'))
+ >>> ExtendedContext.to_integral_value(Decimal('-101.5'))
Decimal("-102")
- >>> ExtendedContext.to_integral(Decimal('10E+5'))
+ >>> ExtendedContext.to_integral_value(Decimal('10E+5'))
Decimal("1.0E+6")
- >>> ExtendedContext.to_integral(Decimal('7.89E+77'))
+ >>> ExtendedContext.to_integral_value(Decimal('7.89E+77'))
Decimal("7.89E+77")
- >>> ExtendedContext.to_integral(Decimal('-Inf'))
+ >>> ExtendedContext.to_integral_value(Decimal('-Inf'))
Decimal("-Infinity")
"""
- return a.to_integral(context=self)
+ return a.to_integral_value(context=self)
+
+ # the method name changed, but we provide also the old one, for compatibility
+ to_integral = to_integral_value
class _WorkRep(object):
__slots__ = ('sign','int','exp')
@@ -3048,7 +3786,7 @@
if numdigits > (other_len + prec + 1 - tmp_len):
# If the difference in adjusted exps is > prec+1, we know
# other is insignificant, so might as well put a 1 after the
- # precision (since this is only for addition). Also stops
+ # precision (since this is only for addition). Also stops
# use of massive longs.
extend = prec + 2 - tmp_len
@@ -3216,7 +3954,7 @@
def _string2exact(s):
"""Return sign, n, p s.t.
-
+
Float string value == -1**sign * n * 10**p exactly
"""
m = _parser(s)
Modified: python/branches/decimal-branch/Lib/test/test_decimal.py
==============================================================================
--- python/branches/decimal-branch/Lib/test/test_decimal.py (original)
+++ python/branches/decimal-branch/Lib/test/test_decimal.py Fri May 4 21:06:58 2007
@@ -99,11 +99,28 @@
nameAdapter = {'toeng':'to_eng_string',
'tosci':'to_sci_string',
'samequantum':'same_quantum',
- 'tointegral':'to_integral',
+ 'tointegral':'to_integral_value',
+ 'tointegralx':'to_integral_exact',
'remaindernear':'remainder_near',
'divideint':'divide_int',
'squareroot':'sqrt',
'apply':'_apply',
+ 'class':'number_class',
+ 'comparetotal':'compare_total',
+ 'comparetotmag':'compare_total_mag',
+ 'copyabs':'copy_abs',
+ 'copy':'copy_decimal',
+ 'copynegate':'copy_negate',
+ 'copysign':'copy_sign',
+ 'and':'logical_and',
+ 'or':'logical_or',
+ 'xor':'logical_xor',
+ 'invert':'logical_invert',
+ 'maxmag':'max_mag',
+ 'minmag':'min_mag',
+ 'nextminus':'next_minus',
+ 'nextplus':'next_plus',
+ 'nexttoward':'next_toward',
}
class DecimalTest(unittest.TestCase):
@@ -948,7 +965,7 @@
d1 = Decimal('-25e55')
b1 = Decimal('-25e55')
- d2 = Decimal('33e-33')
+ d2 = Decimal('33e+33')
b2 = Decimal('33e-33')
def checkSameDec(operation, useOther=False):
More information about the Python-checkins
mailing list