Converting float decimal to fraction Converting float decimal to fraction php php

Converting float decimal to fraction


Continued fractions can be used to find rational approximations to real numbers that are "best" in a strict sense. Here's a PHP function that finds a rational approximation to a given (positive) floating point number with a relative error less than $tolerance:

<?phpfunction float2rat($n, $tolerance = 1.e-6) {    $h1=1; $h2=0;    $k1=0; $k2=1;    $b = 1/$n;    do {        $b = 1/$b;        $a = floor($b);        $aux = $h1; $h1 = $a*$h1+$h2; $h2 = $aux;        $aux = $k1; $k1 = $a*$k1+$k2; $k2 = $aux;        $b = $b-$a;    } while (abs($n-$h1/$k1) > $n*$tolerance);    return "$h1/$k1";}printf("%s\n", float2rat(66.66667)); # 200/3printf("%s\n", float2rat(sqrt(2)));  # 1393/985printf("%s\n", float2rat(0.43212));  # 748/1731

I have written more about this algorithm and why it works, and even a JavaScript demo here: https://web.archive.org/web/20180731235708/http://jonisalonen.com/2012/converting-decimal-numbers-to-ratios/


Farey fractions can be quite useful in this case.

They can be used to convert any decimal into a fraction with the lowest possible denominator.

Sorry - I don't have a prototype in PHP, so here's one in Python:

def farey(v, lim):    """No error checking on args.  lim = maximum denominator.        Results are (numerator, denominator); (1, 0) is 'infinity'."""    if v < 0:        n, d = farey(-v, lim)        return (-n, d)    z = lim - lim   # Get a "zero of the right type" for the denominator    lower, upper = (z, z+1), (z+1, z)    while True:        mediant = (lower[0] + upper[0]), (lower[1] + upper[1])        if v * mediant[1] > mediant[0]:            if lim < mediant[1]:                return upper            lower = mediant        elif v * mediant[1] == mediant[0]:            if lim >= mediant[1]:                return mediant            if lower[1] < upper[1]:                return lower            return upper        else:            if lim < mediant[1]:                return lower            upper = mediant


Converted Python code in answer from @APerson241 to PHP

<?phpfunction farey($v, $lim) {    // No error checking on args.  lim = maximum denominator.    // Results are array(numerator, denominator); array(1, 0) is 'infinity'.    if($v < 0) {        list($n, $d) = farey(-$v, $lim);        return array(-$n, $d);    }    $z = $lim - $lim;   // Get a "zero of the right type" for the denominator    list($lower, $upper) = array(array($z, $z+1), array($z+1, $z));    while(true) {        $mediant = array(($lower[0] + $upper[0]), ($lower[1] + $upper[1]));        if($v * $mediant[1] > $mediant[0]) {            if($lim < $mediant[1])                 return $upper;            $lower = $mediant;        }        else if($v * $mediant[1] == $mediant[0]) {            if($lim >= $mediant[1])                return $mediant;            if($lower[1] < $upper[1])                return $lower;            return $upper;        }        else {            if($lim < $mediant[1])                return $lower;            $upper = $mediant;        }    }}// Example use:$f = farey(66.66667, 10);echo $f[0], '/', $f[1], "\n"; # 200/3$f = farey(sqrt(2), 1000);echo $f[0], '/', $f[1], "\n";  # 1393/985$f = farey(0.43212, 2000);echo $f[0], '/', $f[1], "\n";  # 748/1731