3

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....

Einsneins
  • 43
  • 3

1 Answers1

4

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)
relent95
  • 3,703
  • 1
  • 14
  • 17
  • You shouldn't need `as_integer_ratio` here; just `fractions.Fraction(d)` should be enough to convert a `decimal.Decimal` instance `d` to a `fractions.Fraction` instance with the exact same value. – Mark Dickinson Jan 06 '23 at 19:21
  • 1
    Thanks @Mark Dickinson, I updated the answer. – relent95 Jan 07 '23 at 10:44