mirror of
https://github.com/python/cpython.git
synced 2025-09-17 06:06:25 +00:00
Moved Rational._binary_float_to_ratio() to float.as_integer_ratio() because
it's useful outside of rational numbers. This is my first C code that had to do anything significant. Please be more careful when looking over it.
This commit is contained in:
parent
56eadd9d0d
commit
3ea7b41b58
3 changed files with 180 additions and 56 deletions
|
@ -25,60 +25,6 @@ def gcd(a, b):
|
|||
return a
|
||||
|
||||
|
||||
def _binary_float_to_ratio(x):
|
||||
"""x -> (top, bot), a pair of ints s.t. x = top/bot.
|
||||
|
||||
The conversion is done exactly, without rounding.
|
||||
bot > 0 guaranteed.
|
||||
Some form of binary fp is assumed.
|
||||
Pass NaNs or infinities at your own risk.
|
||||
|
||||
>>> _binary_float_to_ratio(10.0)
|
||||
(10, 1)
|
||||
>>> _binary_float_to_ratio(0.0)
|
||||
(0, 1)
|
||||
>>> _binary_float_to_ratio(-.25)
|
||||
(-1, 4)
|
||||
"""
|
||||
# XXX Move this to floatobject.c with a name like
|
||||
# float.as_integer_ratio()
|
||||
|
||||
if x == 0:
|
||||
return 0, 1
|
||||
f, e = math.frexp(x)
|
||||
signbit = 1
|
||||
if f < 0:
|
||||
f = -f
|
||||
signbit = -1
|
||||
assert 0.5 <= f < 1.0
|
||||
# x = signbit * f * 2**e exactly
|
||||
|
||||
# Suck up CHUNK bits at a time; 28 is enough so that we suck
|
||||
# up all bits in 2 iterations for all known binary double-
|
||||
# precision formats, and small enough to fit in an int.
|
||||
CHUNK = 28
|
||||
top = 0
|
||||
# invariant: x = signbit * (top + f) * 2**e exactly
|
||||
while f:
|
||||
f = math.ldexp(f, CHUNK)
|
||||
digit = trunc(f)
|
||||
assert digit >> CHUNK == 0
|
||||
top = (top << CHUNK) | digit
|
||||
f = f - digit
|
||||
assert 0.0 <= f < 1.0
|
||||
e = e - CHUNK
|
||||
assert top
|
||||
|
||||
# Add in the sign bit.
|
||||
top = signbit * top
|
||||
|
||||
# now x = top * 2**e exactly; fold in 2**e
|
||||
if e>0:
|
||||
return (top * 2**e, 1)
|
||||
else:
|
||||
return (top, 2 ** -e)
|
||||
|
||||
|
||||
_RATIONAL_FORMAT = re.compile(
|
||||
r'^\s*(?P<sign>[-+]?)(?P<num>\d+)'
|
||||
r'(?:/(?P<denom>\d+)|\.(?P<decimal>\d+))?\s*$')
|
||||
|
@ -163,7 +109,7 @@ class Rational(RationalAbc):
|
|||
(cls.__name__, f, type(f).__name__))
|
||||
if math.isnan(f) or math.isinf(f):
|
||||
raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
|
||||
return cls(*_binary_float_to_ratio(f))
|
||||
return cls(*f.as_integer_ratio())
|
||||
|
||||
@classmethod
|
||||
def from_decimal(cls, dec):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue