0

I was given a task to find a way to make a function to turn floats into fractions as accurate as possible, and by sheer brute forcing, i created a function like this

def isclose(a, b, tolerance):
    return abs(a-b) <= tolerance


def fraction(a, factor=0, tol=0.01):
    while True:
        factor += 1
        a_rounded = int(round(a*factor))
        if isclose(a*factor, a_rounded, tol):
            break
    if factor == 1:
        return a_rounded
    else:
        return "{}/{}".format(a_rounded, factor)

Is there a more efficient way to do it, without having to rely on external modules? I can't use modules, as I'm trying to implement this to micropython, which doesn't have the fractions library.

  • IEEE-754 floating-point numbers (other than special encodings like NaNs and infinities) are already fractions, where the denominator is a power of two (for binary floating-point) or power of ten (for decimal floating point). – njuffa Aug 21 '20 at 22:10

2 Answers2

0

The algorithm I'm using is to take the decimal, put it over a power of 10 (3.25 turns into 25/100), multiply the whole number by the new denominator (3 * 100), add that onto the decimal (300 + 25), and put it over the denominator (325/100).

If you don't need to simplify, this will suffice:

def float_to_frac(flt):
    integer, decimal = str(flt).split(".")
    denominator = 10 ** len(decimal)
    numerator = int(integer) * denominator + int(decimal)
    return f"{numerator}/{denominator}"

If you need to simplify, the only way I know of is through brute force:

def float_to_frac(flt):
    integer, decimal = str(flt).split(".")
    denominator = 10 ** len(decimal)
    numerator = int(integer) * denominator + int(decimal)
    for factor in range(2, min(numerator, denominator) + 1):
        if (numerator // factor == numerator / factor) and (denominator // factor == denominator / factor):
            numerator /= factor
            denominator /= factor
    return f"{numerator}/{denominator}"
Elan-R
  • 434
  • 2
  • 6
  • the brute force method seems less accurate then mine, for example 0.3 is 3/10 is right, but with 0.33, 1/3 which mine generates is more accurate than 33/100 – Eren Yaegar Aug 21 '20 at 17:47
  • But 1/3 isn't the same as 0.33. 1/3 is 0.33333..., which is less accurate than 33/100 which is exactly 0.33. – Elan-R Aug 21 '20 at 17:52
  • even with 0.333333333333333, your program hangs and produces 3333333333.../1000000000... – Eren Yaegar Aug 21 '20 at 17:57
  • Yes, that's what it's meant to do. Turn a rational float into a fraction. – Elan-R Aug 21 '20 at 18:05
0

If you can’t use python libraries, you might be able to use c libraries with micropython:

https://github.com/lvgl/lv_binding_micropython

See the section regarding “Binding other C Libraries”

There’s a bit of code here as well, with a well regarded solution should you be able to implement the c code:

How to convert floats to human-readable fractions?

Mr No
  • 83
  • 1
  • 8