mirror of
https://github.com/python/cpython.git
synced 2025-11-17 09:30:10 +00:00
Issue 4796: Add from_float methods to the decimal module.
This commit is contained in:
parent
0fa10b3cd5
commit
f4d8597a59
4 changed files with 201 additions and 58 deletions
|
|
@ -484,6 +484,29 @@ Decimal objects
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
.. method:: from_float(f)
|
||||||
|
|
||||||
|
Classmethod that converts a float to a decimal number, exactly.
|
||||||
|
|
||||||
|
Note `Decimal.from_float(0.1)` is not the same as `Decimal('0.1')`.
|
||||||
|
Since 0.1 is not exactly representable in binary floating point, the
|
||||||
|
value is stored as the nearest representable value which is
|
||||||
|
`0x1.999999999999ap-4`. That equivalent value in decimal is
|
||||||
|
`0.1000000000000000055511151231257827021181583404541015625`.
|
||||||
|
|
||||||
|
.. doctest::
|
||||||
|
|
||||||
|
>>> Decimal.from_float(0.1)
|
||||||
|
Decimal('0.1000000000000000055511151231257827021181583404541015625')
|
||||||
|
>>> Decimal.from_float(float('nan'))
|
||||||
|
Decimal('NaN')
|
||||||
|
>>> Decimal.from_float(float('inf'))
|
||||||
|
Decimal('Infinity')
|
||||||
|
>>> Decimal.from_float(float('-inf'))
|
||||||
|
Decimal('-Infinity')
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
.. method:: fma(other, third[, context])
|
.. method:: fma(other, third[, context])
|
||||||
|
|
||||||
Fused multiply-add. Return self*other+third with no rounding of the
|
Fused multiply-add. Return self*other+third with no rounding of the
|
||||||
|
|
@ -1007,6 +1030,26 @@ In addition to the three supplied contexts, new contexts can be created with the
|
||||||
If the argument is a string, no leading or trailing whitespace is
|
If the argument is a string, no leading or trailing whitespace is
|
||||||
permitted.
|
permitted.
|
||||||
|
|
||||||
|
.. method:: create_decimal_from_float(f)
|
||||||
|
|
||||||
|
Creates a new Decimal instance from a float *f* but rounding using *self*
|
||||||
|
as the context. Unlike the :method:`Decimal.from_float` class method,
|
||||||
|
the context precision, rounding method, flags, and traps are applied to
|
||||||
|
the conversion.
|
||||||
|
|
||||||
|
.. doctest::
|
||||||
|
|
||||||
|
>>> context = Context(prec=5, rounding=ROUND_DOWN)
|
||||||
|
>>> context.create_decimal_from_float(math.pi)
|
||||||
|
Decimal('3.1415')
|
||||||
|
>>> context = Context(prec=5, traps=[Inexact])
|
||||||
|
>>> context.create_decimal_from_float(math.pi)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
Inexact: None
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
.. method:: Etiny()
|
.. method:: Etiny()
|
||||||
|
|
||||||
Returns a value equal to ``Emin - prec + 1`` which is the minimum exponent
|
Returns a value equal to ``Emin - prec + 1`` which is the minimum exponent
|
||||||
|
|
|
||||||
162
Lib/decimal.py
162
Lib/decimal.py
|
|
@ -135,6 +135,7 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
import copy as _copy
|
import copy as _copy
|
||||||
|
import math as _math
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from collections import namedtuple as _namedtuple
|
from collections import namedtuple as _namedtuple
|
||||||
|
|
@ -242,7 +243,7 @@ class DivisionByZero(DecimalException, ZeroDivisionError):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, context, sign, *args):
|
def handle(self, context, sign, *args):
|
||||||
return _SignedInfinity[sign]
|
return _Infsign[sign]
|
||||||
|
|
||||||
class DivisionImpossible(InvalidOperation):
|
class DivisionImpossible(InvalidOperation):
|
||||||
"""Cannot perform the division adequately.
|
"""Cannot perform the division adequately.
|
||||||
|
|
@ -340,15 +341,15 @@ class Overflow(Inexact, Rounded):
|
||||||
def handle(self, context, sign, *args):
|
def handle(self, context, sign, *args):
|
||||||
if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
|
if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
|
||||||
ROUND_HALF_DOWN, ROUND_UP):
|
ROUND_HALF_DOWN, ROUND_UP):
|
||||||
return _SignedInfinity[sign]
|
return _Infsign[sign]
|
||||||
if sign == 0:
|
if sign == 0:
|
||||||
if context.rounding == ROUND_CEILING:
|
if context.rounding == ROUND_CEILING:
|
||||||
return _SignedInfinity[sign]
|
return _Infsign[sign]
|
||||||
return _dec_from_triple(sign, '9'*context.prec,
|
return _dec_from_triple(sign, '9'*context.prec,
|
||||||
context.Emax-context.prec+1)
|
context.Emax-context.prec+1)
|
||||||
if sign == 1:
|
if sign == 1:
|
||||||
if context.rounding == ROUND_FLOOR:
|
if context.rounding == ROUND_FLOOR:
|
||||||
return _SignedInfinity[sign]
|
return _Infsign[sign]
|
||||||
return _dec_from_triple(sign, '9'*context.prec,
|
return _dec_from_triple(sign, '9'*context.prec,
|
||||||
context.Emax-context.prec+1)
|
context.Emax-context.prec+1)
|
||||||
|
|
||||||
|
|
@ -653,6 +654,38 @@ class Decimal(object):
|
||||||
|
|
||||||
raise TypeError("Cannot convert %r to Decimal" % value)
|
raise TypeError("Cannot convert %r to Decimal" % value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_float(cls, f):
|
||||||
|
"""Converts a float to a decimal number, exactly.
|
||||||
|
|
||||||
|
Note that Decimal.from_float(0.1) is not the same as Decimal('0.1').
|
||||||
|
Since 0.1 is not exactly representable in binary floating point, the
|
||||||
|
value is stored as the nearest representable value which is
|
||||||
|
0x1.999999999999ap-4. The exact equivalent of the value in decimal
|
||||||
|
is 0.1000000000000000055511151231257827021181583404541015625.
|
||||||
|
|
||||||
|
>>> Decimal.from_float(0.1)
|
||||||
|
Decimal('0.1000000000000000055511151231257827021181583404541015625')
|
||||||
|
>>> Decimal.from_float(float('nan'))
|
||||||
|
Decimal('NaN')
|
||||||
|
>>> Decimal.from_float(float('inf'))
|
||||||
|
Decimal('Infinity')
|
||||||
|
>>> Decimal.from_float(-float('inf'))
|
||||||
|
Decimal('-Infinity')
|
||||||
|
>>> Decimal.from_float(-0.0)
|
||||||
|
Decimal('-0')
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(f, (int, long)): # handle integer inputs
|
||||||
|
return cls(f)
|
||||||
|
if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float
|
||||||
|
return cls(repr(f))
|
||||||
|
sign = 0 if _math.copysign(1.0, f) == 1.0 else 1
|
||||||
|
n, d = abs(f).as_integer_ratio()
|
||||||
|
k = d.bit_length() - 1
|
||||||
|
result = _dec_from_triple(sign, str(n*5**k), -k)
|
||||||
|
return result if cls is Decimal else cls(result)
|
||||||
|
|
||||||
def _isnan(self):
|
def _isnan(self):
|
||||||
"""Returns whether the number is not actually one.
|
"""Returns whether the number is not actually one.
|
||||||
|
|
||||||
|
|
@ -1171,12 +1204,12 @@ class Decimal(object):
|
||||||
if self._isinfinity():
|
if self._isinfinity():
|
||||||
if not other:
|
if not other:
|
||||||
return context._raise_error(InvalidOperation, '(+-)INF * 0')
|
return context._raise_error(InvalidOperation, '(+-)INF * 0')
|
||||||
return _SignedInfinity[resultsign]
|
return _Infsign[resultsign]
|
||||||
|
|
||||||
if other._isinfinity():
|
if other._isinfinity():
|
||||||
if not self:
|
if not self:
|
||||||
return context._raise_error(InvalidOperation, '0 * (+-)INF')
|
return context._raise_error(InvalidOperation, '0 * (+-)INF')
|
||||||
return _SignedInfinity[resultsign]
|
return _Infsign[resultsign]
|
||||||
|
|
||||||
resultexp = self._exp + other._exp
|
resultexp = self._exp + other._exp
|
||||||
|
|
||||||
|
|
@ -1226,7 +1259,7 @@ class Decimal(object):
|
||||||
return context._raise_error(InvalidOperation, '(+-)INF/(+-)INF')
|
return context._raise_error(InvalidOperation, '(+-)INF/(+-)INF')
|
||||||
|
|
||||||
if self._isinfinity():
|
if self._isinfinity():
|
||||||
return _SignedInfinity[sign]
|
return _Infsign[sign]
|
||||||
|
|
||||||
if other._isinfinity():
|
if other._isinfinity():
|
||||||
context._raise_error(Clamped, 'Division by infinity')
|
context._raise_error(Clamped, 'Division by infinity')
|
||||||
|
|
@ -1329,7 +1362,7 @@ class Decimal(object):
|
||||||
ans = context._raise_error(InvalidOperation, 'divmod(INF, INF)')
|
ans = context._raise_error(InvalidOperation, 'divmod(INF, INF)')
|
||||||
return ans, ans
|
return ans, ans
|
||||||
else:
|
else:
|
||||||
return (_SignedInfinity[sign],
|
return (_Infsign[sign],
|
||||||
context._raise_error(InvalidOperation, 'INF % x'))
|
context._raise_error(InvalidOperation, 'INF % x'))
|
||||||
|
|
||||||
if not other:
|
if not other:
|
||||||
|
|
@ -1477,7 +1510,7 @@ class Decimal(object):
|
||||||
if other._isinfinity():
|
if other._isinfinity():
|
||||||
return context._raise_error(InvalidOperation, 'INF // INF')
|
return context._raise_error(InvalidOperation, 'INF // INF')
|
||||||
else:
|
else:
|
||||||
return _SignedInfinity[self._sign ^ other._sign]
|
return _Infsign[self._sign ^ other._sign]
|
||||||
|
|
||||||
if not other:
|
if not other:
|
||||||
if self:
|
if self:
|
||||||
|
|
@ -1732,12 +1765,12 @@ class Decimal(object):
|
||||||
if not other:
|
if not other:
|
||||||
return context._raise_error(InvalidOperation,
|
return context._raise_error(InvalidOperation,
|
||||||
'INF * 0 in fma')
|
'INF * 0 in fma')
|
||||||
product = _SignedInfinity[self._sign ^ other._sign]
|
product = _Infsign[self._sign ^ other._sign]
|
||||||
elif other._exp == 'F':
|
elif other._exp == 'F':
|
||||||
if not self:
|
if not self:
|
||||||
return context._raise_error(InvalidOperation,
|
return context._raise_error(InvalidOperation,
|
||||||
'0 * INF in fma')
|
'0 * INF in fma')
|
||||||
product = _SignedInfinity[self._sign ^ other._sign]
|
product = _Infsign[self._sign ^ other._sign]
|
||||||
else:
|
else:
|
||||||
product = _dec_from_triple(self._sign ^ other._sign,
|
product = _dec_from_triple(self._sign ^ other._sign,
|
||||||
str(int(self._int) * int(other._int)),
|
str(int(self._int) * int(other._int)),
|
||||||
|
|
@ -2087,7 +2120,7 @@ class Decimal(object):
|
||||||
if not self:
|
if not self:
|
||||||
return context._raise_error(InvalidOperation, '0 ** 0')
|
return context._raise_error(InvalidOperation, '0 ** 0')
|
||||||
else:
|
else:
|
||||||
return _One
|
return _Dec_p1
|
||||||
|
|
||||||
# result has sign 1 iff self._sign is 1 and other is an odd integer
|
# result has sign 1 iff self._sign is 1 and other is an odd integer
|
||||||
result_sign = 0
|
result_sign = 0
|
||||||
|
|
@ -2109,19 +2142,19 @@ class Decimal(object):
|
||||||
if other._sign == 0:
|
if other._sign == 0:
|
||||||
return _dec_from_triple(result_sign, '0', 0)
|
return _dec_from_triple(result_sign, '0', 0)
|
||||||
else:
|
else:
|
||||||
return _SignedInfinity[result_sign]
|
return _Infsign[result_sign]
|
||||||
|
|
||||||
# Inf**(+ve or Inf) = Inf; Inf**(-ve or -Inf) = 0
|
# Inf**(+ve or Inf) = Inf; Inf**(-ve or -Inf) = 0
|
||||||
if self._isinfinity():
|
if self._isinfinity():
|
||||||
if other._sign == 0:
|
if other._sign == 0:
|
||||||
return _SignedInfinity[result_sign]
|
return _Infsign[result_sign]
|
||||||
else:
|
else:
|
||||||
return _dec_from_triple(result_sign, '0', 0)
|
return _dec_from_triple(result_sign, '0', 0)
|
||||||
|
|
||||||
# 1**other = 1, but the choice of exponent and the flags
|
# 1**other = 1, but the choice of exponent and the flags
|
||||||
# depend on the exponent of self, and on whether other is a
|
# depend on the exponent of self, and on whether other is a
|
||||||
# positive integer, a negative integer, or neither
|
# positive integer, a negative integer, or neither
|
||||||
if self == _One:
|
if self == _Dec_p1:
|
||||||
if other._isinteger():
|
if other._isinteger():
|
||||||
# exp = max(self._exp*max(int(other), 0),
|
# exp = max(self._exp*max(int(other), 0),
|
||||||
# 1-context.prec) but evaluating int(other) directly
|
# 1-context.prec) but evaluating int(other) directly
|
||||||
|
|
@ -2154,7 +2187,7 @@ class Decimal(object):
|
||||||
if (other._sign == 0) == (self_adj < 0):
|
if (other._sign == 0) == (self_adj < 0):
|
||||||
return _dec_from_triple(result_sign, '0', 0)
|
return _dec_from_triple(result_sign, '0', 0)
|
||||||
else:
|
else:
|
||||||
return _SignedInfinity[result_sign]
|
return _Infsign[result_sign]
|
||||||
|
|
||||||
# from here on, the result always goes through the call
|
# from here on, the result always goes through the call
|
||||||
# to _fix at the end of this function.
|
# to _fix at the end of this function.
|
||||||
|
|
@ -2674,9 +2707,9 @@ class Decimal(object):
|
||||||
"""
|
"""
|
||||||
# if one is negative and the other is positive, it's easy
|
# if one is negative and the other is positive, it's easy
|
||||||
if self._sign and not other._sign:
|
if self._sign and not other._sign:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if not self._sign and other._sign:
|
if not self._sign and other._sign:
|
||||||
return _One
|
return _Dec_p1
|
||||||
sign = self._sign
|
sign = self._sign
|
||||||
|
|
||||||
# let's handle both NaN types
|
# let's handle both NaN types
|
||||||
|
|
@ -2686,51 +2719,51 @@ class Decimal(object):
|
||||||
if self_nan == other_nan:
|
if self_nan == other_nan:
|
||||||
if self._int < other._int:
|
if self._int < other._int:
|
||||||
if sign:
|
if sign:
|
||||||
return _One
|
return _Dec_p1
|
||||||
else:
|
else:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if self._int > other._int:
|
if self._int > other._int:
|
||||||
if sign:
|
if sign:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
else:
|
else:
|
||||||
return _One
|
return _Dec_p1
|
||||||
return _Zero
|
return _Dec_0
|
||||||
|
|
||||||
if sign:
|
if sign:
|
||||||
if self_nan == 1:
|
if self_nan == 1:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if other_nan == 1:
|
if other_nan == 1:
|
||||||
return _One
|
return _Dec_p1
|
||||||
if self_nan == 2:
|
if self_nan == 2:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if other_nan == 2:
|
if other_nan == 2:
|
||||||
return _One
|
return _Dec_p1
|
||||||
else:
|
else:
|
||||||
if self_nan == 1:
|
if self_nan == 1:
|
||||||
return _One
|
return _Dec_p1
|
||||||
if other_nan == 1:
|
if other_nan == 1:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if self_nan == 2:
|
if self_nan == 2:
|
||||||
return _One
|
return _Dec_p1
|
||||||
if other_nan == 2:
|
if other_nan == 2:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
|
|
||||||
if self < other:
|
if self < other:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if self > other:
|
if self > other:
|
||||||
return _One
|
return _Dec_p1
|
||||||
|
|
||||||
if self._exp < other._exp:
|
if self._exp < other._exp:
|
||||||
if sign:
|
if sign:
|
||||||
return _One
|
return _Dec_p1
|
||||||
else:
|
else:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
if self._exp > other._exp:
|
if self._exp > other._exp:
|
||||||
if sign:
|
if sign:
|
||||||
return _NegativeOne
|
return _Dec_n1
|
||||||
else:
|
else:
|
||||||
return _One
|
return _Dec_p1
|
||||||
return _Zero
|
return _Dec_0
|
||||||
|
|
||||||
|
|
||||||
def compare_total_mag(self, other):
|
def compare_total_mag(self, other):
|
||||||
|
|
@ -2771,11 +2804,11 @@ class Decimal(object):
|
||||||
|
|
||||||
# exp(-Infinity) = 0
|
# exp(-Infinity) = 0
|
||||||
if self._isinfinity() == -1:
|
if self._isinfinity() == -1:
|
||||||
return _Zero
|
return _Dec_0
|
||||||
|
|
||||||
# exp(0) = 1
|
# exp(0) = 1
|
||||||
if not self:
|
if not self:
|
||||||
return _One
|
return _Dec_p1
|
||||||
|
|
||||||
# exp(Infinity) = Infinity
|
# exp(Infinity) = Infinity
|
||||||
if self._isinfinity() == 1:
|
if self._isinfinity() == 1:
|
||||||
|
|
@ -2927,15 +2960,15 @@ class Decimal(object):
|
||||||
|
|
||||||
# ln(0.0) == -Infinity
|
# ln(0.0) == -Infinity
|
||||||
if not self:
|
if not self:
|
||||||
return _NegativeInfinity
|
return _negInf
|
||||||
|
|
||||||
# ln(Infinity) = Infinity
|
# ln(Infinity) = Infinity
|
||||||
if self._isinfinity() == 1:
|
if self._isinfinity() == 1:
|
||||||
return _Infinity
|
return _Inf
|
||||||
|
|
||||||
# ln(1.0) == 0.0
|
# ln(1.0) == 0.0
|
||||||
if self == _One:
|
if self == _Dec_p1:
|
||||||
return _Zero
|
return _Dec_0
|
||||||
|
|
||||||
# ln(negative) raises InvalidOperation
|
# ln(negative) raises InvalidOperation
|
||||||
if self._sign == 1:
|
if self._sign == 1:
|
||||||
|
|
@ -3007,11 +3040,11 @@ class Decimal(object):
|
||||||
|
|
||||||
# log10(0.0) == -Infinity
|
# log10(0.0) == -Infinity
|
||||||
if not self:
|
if not self:
|
||||||
return _NegativeInfinity
|
return _negInf
|
||||||
|
|
||||||
# log10(Infinity) = Infinity
|
# log10(Infinity) = Infinity
|
||||||
if self._isinfinity() == 1:
|
if self._isinfinity() == 1:
|
||||||
return _Infinity
|
return _Inf
|
||||||
|
|
||||||
# log10(negative or -Infinity) raises InvalidOperation
|
# log10(negative or -Infinity) raises InvalidOperation
|
||||||
if self._sign == 1:
|
if self._sign == 1:
|
||||||
|
|
@ -3063,7 +3096,7 @@ class Decimal(object):
|
||||||
|
|
||||||
# logb(+/-Inf) = +Inf
|
# logb(+/-Inf) = +Inf
|
||||||
if self._isinfinity():
|
if self._isinfinity():
|
||||||
return _Infinity
|
return _Inf
|
||||||
|
|
||||||
# logb(0) = -Inf, DivisionByZero
|
# logb(0) = -Inf, DivisionByZero
|
||||||
if not self:
|
if not self:
|
||||||
|
|
@ -3220,7 +3253,7 @@ class Decimal(object):
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
if self._isinfinity() == -1:
|
if self._isinfinity() == -1:
|
||||||
return _NegativeInfinity
|
return _negInf
|
||||||
if self._isinfinity() == 1:
|
if self._isinfinity() == 1:
|
||||||
return _dec_from_triple(0, '9'*context.prec, context.Etop())
|
return _dec_from_triple(0, '9'*context.prec, context.Etop())
|
||||||
|
|
||||||
|
|
@ -3243,7 +3276,7 @@ class Decimal(object):
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
if self._isinfinity() == 1:
|
if self._isinfinity() == 1:
|
||||||
return _Infinity
|
return _Inf
|
||||||
if self._isinfinity() == -1:
|
if self._isinfinity() == -1:
|
||||||
return _dec_from_triple(1, '9'*context.prec, context.Etop())
|
return _dec_from_triple(1, '9'*context.prec, context.Etop())
|
||||||
|
|
||||||
|
|
@ -3744,6 +3777,23 @@ class Context(object):
|
||||||
"diagnostic info too long in NaN")
|
"diagnostic info too long in NaN")
|
||||||
return d._fix(self)
|
return d._fix(self)
|
||||||
|
|
||||||
|
def create_decimal_from_float(self, f):
|
||||||
|
"""Creates a new Decimal instance from a float but rounding using self
|
||||||
|
as the context.
|
||||||
|
|
||||||
|
>>> context = Context(prec=5, rounding=ROUND_DOWN)
|
||||||
|
>>> context.create_decimal_from_float(3.1415926535897932)
|
||||||
|
Decimal('3.1415')
|
||||||
|
>>> context = Context(prec=5, traps=[Inexact])
|
||||||
|
>>> context.create_decimal_from_float(3.1415926535897932)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
Inexact: None
|
||||||
|
|
||||||
|
"""
|
||||||
|
d = Decimal.from_float(f) # An exact conversion
|
||||||
|
return d._fix(self) # Apply the context rounding
|
||||||
|
|
||||||
# Methods
|
# Methods
|
||||||
def abs(self, a):
|
def abs(self, a):
|
||||||
"""Returns the absolute value of the operand.
|
"""Returns the absolute value of the operand.
|
||||||
|
|
@ -5490,15 +5540,15 @@ def _format_align(body, spec_dict):
|
||||||
##### Useful Constants (internal use only) ################################
|
##### Useful Constants (internal use only) ################################
|
||||||
|
|
||||||
# Reusable defaults
|
# Reusable defaults
|
||||||
_Infinity = Decimal('Inf')
|
_Inf = Decimal('Inf')
|
||||||
_NegativeInfinity = Decimal('-Inf')
|
_negInf = Decimal('-Inf')
|
||||||
_NaN = Decimal('NaN')
|
_NaN = Decimal('NaN')
|
||||||
_Zero = Decimal(0)
|
_Dec_0 = Decimal(0)
|
||||||
_One = Decimal(1)
|
_Dec_p1 = Decimal(1)
|
||||||
_NegativeOne = Decimal(-1)
|
_Dec_n1 = Decimal(-1)
|
||||||
|
|
||||||
# _SignedInfinity[sign] is infinity w/ that sign
|
# _Infsign[sign] is infinity w/ that sign
|
||||||
_SignedInfinity = (_Infinity, _NegativeInfinity)
|
_Infsign = (_Inf, _negInf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1361,6 +1361,55 @@ class DecimalPythonAPItests(unittest.TestCase):
|
||||||
r = d.to_integral(ROUND_DOWN)
|
r = d.to_integral(ROUND_DOWN)
|
||||||
self.assertEqual(Decimal(math.trunc(d)), r)
|
self.assertEqual(Decimal(math.trunc(d)), r)
|
||||||
|
|
||||||
|
def test_from_float(self):
|
||||||
|
|
||||||
|
class MyDecimal(Decimal):
|
||||||
|
pass
|
||||||
|
|
||||||
|
r = MyDecimal.from_float(0.1)
|
||||||
|
self.assertEqual(type(r), MyDecimal)
|
||||||
|
self.assertEqual(str(r),
|
||||||
|
'0.1000000000000000055511151231257827021181583404541015625')
|
||||||
|
bigint = 12345678901234567890123456789
|
||||||
|
self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint))
|
||||||
|
self.assert_(MyDecimal.from_float(float('nan')).is_qnan())
|
||||||
|
self.assert_(MyDecimal.from_float(float('inf')).is_infinite())
|
||||||
|
self.assert_(MyDecimal.from_float(float('-inf')).is_infinite())
|
||||||
|
self.assertEqual(str(MyDecimal.from_float(float('nan'))),
|
||||||
|
str(Decimal('NaN')))
|
||||||
|
self.assertEqual(str(MyDecimal.from_float(float('inf'))),
|
||||||
|
str(Decimal('Infinity')))
|
||||||
|
self.assertEqual(str(MyDecimal.from_float(float('-inf'))),
|
||||||
|
str(Decimal('-Infinity')))
|
||||||
|
self.assertRaises(TypeError, MyDecimal.from_float, 'abc')
|
||||||
|
for i in range(200):
|
||||||
|
x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0)
|
||||||
|
self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip
|
||||||
|
|
||||||
|
def test_create_decimal_from_float(self):
|
||||||
|
context = Context(prec=5, rounding=ROUND_DOWN)
|
||||||
|
self.assertEqual(
|
||||||
|
context.create_decimal_from_float(math.pi),
|
||||||
|
Decimal('3.1415')
|
||||||
|
)
|
||||||
|
context = Context(prec=5, rounding=ROUND_UP)
|
||||||
|
self.assertEqual(
|
||||||
|
context.create_decimal_from_float(math.pi),
|
||||||
|
Decimal('3.1416')
|
||||||
|
)
|
||||||
|
context = Context(prec=5, traps=[Inexact])
|
||||||
|
self.assertRaises(
|
||||||
|
Inexact,
|
||||||
|
context.create_decimal_from_float,
|
||||||
|
math.pi
|
||||||
|
)
|
||||||
|
self.assertEqual(repr(context.create_decimal_from_float(-0.0)),
|
||||||
|
"Decimal('-0')")
|
||||||
|
self.assertEqual(repr(context.create_decimal_from_float(1.0)),
|
||||||
|
"Decimal('1')")
|
||||||
|
self.assertEqual(repr(context.create_decimal_from_float(10)),
|
||||||
|
"Decimal('10')")
|
||||||
|
|
||||||
class ContextAPItests(unittest.TestCase):
|
class ContextAPItests(unittest.TestCase):
|
||||||
|
|
||||||
def test_pickle(self):
|
def test_pickle(self):
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ What's New in Python 2.7 alpha 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
- Issue #4817: Remove unused function PyOS_GetLastModificationTime.
|
|
||||||
|
|
||||||
- Issue #4075: Use OutputDebugStringW in Py_FatalError.
|
- Issue #4075: Use OutputDebugStringW in Py_FatalError.
|
||||||
|
|
||||||
- Issue #4797: IOError.filename was not set when _fileio.FileIO failed to open
|
- Issue #4797: IOError.filename was not set when _fileio.FileIO failed to open
|
||||||
|
|
@ -110,6 +108,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #4796: Added Decimal.from_float() and Context.create_decimal_from_float()
|
||||||
|
to the decimal module.
|
||||||
|
|
||||||
- Issue #4812: add missing underscore prefix to some internal-use-only
|
- Issue #4812: add missing underscore prefix to some internal-use-only
|
||||||
constants in the decimal module. (Dec_0 becomes _Dec_0, etc.)
|
constants in the decimal module. (Dec_0 becomes _Dec_0, etc.)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue