I needed to convert floating point numbers to int/int fractions. Python technically has this functionality, but has issues with rounding errors:
>>> (0.1+0.2).as_integer_ratio()
(1351079888211149, 4503599627370496)
This is what I wrote and I was wondering whether it could be further improved for performance?
def as_fraction(number: float, accuracy: float) -> (int, int):
whole, x = divmod(number, 1)
if not x:
return int(whole), 1
n = 1
while True:
d = int(n/x)
if n/d-x < accuracy:
return int(whole)*d+n, d
d += 1
if x-n/d < accuracy:
return int(whole)*d+n, d
n += 1
0.1+0.2
is actually0.30000000000000004
, right? Which happens to be exactly1351079888211149 / 4503599627370496
, so it's your function which has issues with rounding errors. Unless I misunderstood your question. In either case, your function returns the wrong result for0.1+0.2
with accuracy0.0000000000000001
. With finer accuracy, it doesn't even return a result (in a reasonable time). \$\endgroup\$0.1+0.2 != 0.3
, the problem is that my program receives0.30000000000000004
as input and needs to read it as0.3
(rounding errors add up over time, causing problems), but fractions such as1/7
prevent me from simply usinground(x)
\$\endgroup\$0.3
? But I agree that this function will hopefully in most cases reduce rounding errors, if the user of that function is aware of the implications. \$\endgroup\$accuracy
. I believe that for other numerators it should also work correctly? \$\endgroup\$as_integer_ratio
versus your function, and choose the one which better fits your needs – the one which gives better overall results for your application. \$\endgroup\$