How to convert floating point number to ratio of integers in python with high accuracy?

536 Views Asked by At

QUESTION:

I would like to convert floats into a ratio of integers in simplest form. (Not a duplicate of this question, see "EDIT" below). For example, 0.1 = 1, 10, 0.66666... = 2, 3, etc. In the code snippet below, I try doing this for x = 0.1, 0.2, ..., 1.0 using this default function; the method only works successfully for x = 0.5 and x = 1.0. Why does this algorithm fail for other values of x and what is a better method to do this? In case it is relevant, my use-case will be for dx ~ 0.0005 = x[1] - x[0] for 0.0005 < x 10.0.

CODE:

import numpy as np

f = np.vectorize(lambda x : x.as_integer_ratio())

x = np.arange(0.1, 1.1, 0.1)
nums, dens = f(x)
for xi, numerator, denominator in zip(x, nums, dens):
    print("\n .. {} = {} / {}\n".format(xi, numerator, denominator))

OUTPUT:

 .. 0.1 = 3602879701896397 / 36028797018963968


 .. 0.2 = 3602879701896397 / 18014398509481984


 .. 0.30000000000000004 = 1351079888211149 / 4503599627370496


 .. 0.4 = 3602879701896397 / 9007199254740992


 .. 0.5 = 1 / 2


 .. 0.6 = 5404319552844595 / 9007199254740992


 .. 0.7000000000000001 = 6305039478318695 / 9007199254740992


 .. 0.8 = 3602879701896397 / 4503599627370496


 .. 0.9 = 8106479329266893 / 9007199254740992


 .. 1.0 = 1 / 1

EDIT:

This is not really a duplicate. Both methods of the accepted answer in the original question fail a basic use-case from my MWE. To show that the Fraction module gives the same error:

import numpy as np
from fractions import Fraction

f = np.vectorize(lambda x : Fraction(x))

x = np.arange(0.1, 1.1, 0.1)
y = f(x)
print(y)

## OUTPUT
[Fraction(3602879701896397, 36028797018963968)
 Fraction(3602879701896397, 18014398509481984)
 Fraction(1351079888211149, 4503599627370496)
 Fraction(3602879701896397, 9007199254740992) Fraction(1, 2)
 Fraction(5404319552844595, 9007199254740992)
 Fraction(6305039478318695, 9007199254740992)
 Fraction(3602879701896397, 4503599627370496)
 Fraction(8106479329266893, 9007199254740992) Fraction(1, 1)]
0

There are 0 best solutions below