Fast conversion of numbers to numerator/denominator pairs

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Aug 23 23:30:47 EDT 2013


I have a need to convert arbitrary non-complex numbers into numerator/
denominator pairs. Numbers could be ints, floats, Fractions or Decimals. 
For example:

2 => (2, 1)
0.25 => (1, 4)
Fraction(2, 3) => (2, 3)
Decimal("0.5") => (1, 2)


The first three cases are easy and fast:

# ints and Fractions
number.numerator, number.denominator

# floats are a little slower
number.as_integer_ratio()


But Decimals are unfortunately slower. MUCH slower, about 40 times slower 
than Fractions in Python 3.3:

tmp = Fraction.from_decimal(number)
(tmp.numerator, tmp.denominator)


This ends up being the bottleneck in my code: once you include the 
scaffolding code to select the right conversion method, processing a 
large list of Decimals is about fifty times slower than large lists of 
floats or fractions.

Is there a fast way to convert a Decimal into a pair of numbers numerator/
denominator? It *must* be exact, but it doesn't have to be simplest form. 
For example, Decimal("0.5") => (5, 10) would be okay, although (1, 2) 
would be preferred.


I've tried this function:

def convert(d):
    sign, digits, exp = d.as_tuple()
    num = int(''.join([str(digit) for digit in digits]))
    if sign: num = -num
    return num, 10**-exp


which is faster, but not fast enough. Any suggestions?


-- 
Steven



More information about the Python-list mailing list