Simplify float conversion recipe.
This commit is contained in:
parent
65baa34115
commit
66cb7d4bd8
|
@ -1516,39 +1516,29 @@ Q. Is there a way to convert a regular float to a :class:`Decimal`?
|
|||
|
||||
A. Yes, all binary floating point numbers can be exactly expressed as a
|
||||
Decimal. An exact conversion may take more precision than intuition would
|
||||
suggest, so trapping :const:`Inexact` will signal a need for more precision::
|
||||
suggest, so we trap :const:`Inexact` to signal a need for more precision::
|
||||
|
||||
def floatToDecimal(f):
|
||||
"Convert a floating point number to a Decimal with no loss of information"
|
||||
# Transform (exactly) a float to a mantissa (0.5 <= abs(m) < 1.0) and an
|
||||
# exponent. Double the mantissa until it is an integer. Use the integer
|
||||
# mantissa and exponent to compute an equivalent Decimal. If this cannot
|
||||
# be done exactly, then retry with more precision.
|
||||
def float_to_decimal(f):
|
||||
"Convert a floating point number to a Decimal with no loss of information"
|
||||
n, d = f.as_integer_ratio()
|
||||
with localcontext() as ctx:
|
||||
ctx.traps[Inexact] = True
|
||||
while True:
|
||||
try:
|
||||
return Decimal(n) / Decimal(d)
|
||||
except Inexact:
|
||||
ctx.prec += 1
|
||||
|
||||
mantissa, exponent = math.frexp(f)
|
||||
while mantissa != int(mantissa):
|
||||
mantissa *= 2.0
|
||||
exponent -= 1
|
||||
mantissa = int(mantissa)
|
||||
>>> float_to_decimal(math.pi)
|
||||
Decimal("3.141592653589793115997963468544185161590576171875")
|
||||
|
||||
oldcontext = getcontext()
|
||||
setcontext(Context(traps=[Inexact]))
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
return mantissa * Decimal(2) ** exponent
|
||||
except Inexact:
|
||||
getcontext().prec += 1
|
||||
finally:
|
||||
setcontext(oldcontext)
|
||||
|
||||
Q. Why isn't the :func:`floatToDecimal` routine included in the module?
|
||||
Q. Why isn't the :func:`float_to_decimal` routine included in the module?
|
||||
|
||||
A. There is some question about whether it is advisable to mix binary and
|
||||
decimal floating point. Also, its use requires some care to avoid the
|
||||
representation issues associated with binary floating point::
|
||||
|
||||
>>> floatToDecimal(1.1)
|
||||
>>> float_to_decimal(1.1)
|
||||
Decimal("1.100000000000000088817841970012523233890533447265625")
|
||||
|
||||
Q. Within a complex calculation, how can I make sure that I haven't gotten a
|
||||
|
|
Loading…
Reference in New Issue