summaryrefslogtreecommitdiffstats
path: root/Lib/_pydecimal.py
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2015-12-28 22:02:02 (GMT)
committerStefan Krah <skrah@bytereef.org>2015-12-28 22:02:02 (GMT)
commit53f2e0ad45e41c007f714e077ccf11643651ef28 (patch)
treec00ffd5dd955b9685de5c1a12fd014745b22f361 /Lib/_pydecimal.py
parentac1e7f6983ef4f0feef6389d458544bf924f6965 (diff)
downloadcpython-53f2e0ad45e41c007f714e077ccf11643651ef28.zip
cpython-53f2e0ad45e41c007f714e077ccf11643651ef28.tar.gz
cpython-53f2e0ad45e41c007f714e077ccf11643651ef28.tar.bz2
Issue #25928: Add Decimal.as_integer_ratio(). Python parts and docs by
Mark Dickinson.
Diffstat (limited to 'Lib/_pydecimal.py')
-rw-r--r--Lib/_pydecimal.py52
1 files changed, 52 insertions, 0 deletions
diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
index 05ba4ee..eb7bba8 100644
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -1010,6 +1010,58 @@ class Decimal(object):
"""
return DecimalTuple(self._sign, tuple(map(int, self._int)), self._exp)
+ def as_integer_ratio(self):
+ """Express a finite Decimal instance in the form n / d.
+
+ Returns a pair (n, d) of integers. When called on an infinity
+ or NaN, raises OverflowError or ValueError respectively.
+
+ >>> Decimal('3.14').as_integer_ratio()
+ (157, 50)
+ >>> Decimal('-123e5').as_integer_ratio()
+ (-12300000, 1)
+ >>> Decimal('0.00').as_integer_ratio()
+ (0, 1)
+
+ """
+ if self._is_special:
+ if self.is_nan():
+ raise ValueError("Cannot pass NaN "
+ "to decimal.as_integer_ratio.")
+ else:
+ raise OverflowError("Cannot pass infinity "
+ "to decimal.as_integer_ratio.")
+
+ if not self:
+ return 0, 1
+
+ # Find n, d in lowest terms such that abs(self) == n / d;
+ # we'll deal with the sign later.
+ n = int(self._int)
+ if self._exp >= 0:
+ # self is an integer.
+ n, d = n * 10**self._exp, 1
+ else:
+ # Find d2, d5 such that abs(self) = n / (2**d2 * 5**d5).
+ d5 = -self._exp
+ while d5 > 0 and n % 5 == 0:
+ n //= 5
+ d5 -= 1
+
+ # (n & -n).bit_length() - 1 counts trailing zeros in binary
+ # representation of n (provided n is nonzero).
+ d2 = -self._exp
+ shift2 = min((n & -n).bit_length() - 1, d2)
+ if shift2:
+ n >>= shift2
+ d2 -= shift2
+
+ d = 5**d5 << d2
+
+ if self._sign:
+ n = -n
+ return n, d
+
def __repr__(self):
"""Represents the number as an instance of Decimal."""
# Invariant: eval(repr(d)) == d