Search code examples
pythondecimalfractionspython-fractions

How to convert incredibly long decimals to fractions and back with high precision


I'm trying to convert very large integers to decimals, then convert those decimals to Fractions, and then convert the Fraction back to a decimal. I'm using the fractions and decimal packages to try and avoid floating point imprecision, however the accuracy still tapers off rather quickly. Is there any way to fix this / other ways of doing this?


import fractions
import decimal


def convert(exampleInt):
    power_of_10 = len(str(exampleInt))
    decimal.getcontext().prec = 10000
    exampleDecimal = decimal.Decimal(exampleInt) / (decimal.Decimal(10) ** power_of_10)
    exampleFraction = fractions.Fraction(str(exampleDecimal)).limit_denominator()
    backToDecimal = exampleFraction.numerator / decimal.Decimal(exampleFraction.denominator)
    print(f"backToDecimal: {backToDecimal}")


convert(34163457536856478543908582348965743529867234957893246783427568734742390675934285342)

Which outputs: .341634575369123189552597490138153768602695082851231192155069838....


Solution

  • It's because of calling the limit_denominator(). Also it's quite inefficient to convert using an intermediate string.

    Convert a Decimal object into a Fraction object using the constructor like the following.(It's Mark Dickinson's solution.)

    import fractions
    import decimal
    
    decimal.getcontext().prec = 100
    
    d = decimal.Decimal(34163457536856478543908582348965743529867234957893246783427568734742390675934285342)
    d = d / 10**(d.adjusted() + 1)
    
    f = fractions.Fraction(d) # This is equivalent to Fraction(*d.as_integer_ratio())
    d2 = decimal.Decimal(f.numerator) / f.denominator
    assert(d2 == d)