Conversione decimale float in frazione

Sto cercando di convertire i calcoli inseriti dagli utenti con risultati decimali in frazioni. Per esempio; 66.6666666667 in 66 2/3. Qualche indicazione? Grazie in anticipo

Le frazioni continue possono essere utilizzate per trovare approssimazioni razionali a numbers reali che sono "migliori" in senso stretto. Ecco una function PHP che trova un'approssimazione razionale a un determinato numero (positivo) in virgola mobile con un errore relativo inferiore a $tolerance :

 <?php function 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/3 printf("%s\n", float2rat(sqrt(2))); # 1393/985 printf("%s\n", float2rat(0.43212)); # 748/1731 

Ho scritto altro su questo algorithm e perché funziona, e anche una demo JavaScript qui: http://jonisalonen.com/2012/converting-decimal-numbers-to-ratios/

Codice Python convertito in risposta da @ APerson241 a PHP

 <?php function farey($v, $lim) { // No error checking on args. lim = maximum denominator. // Results are arrays(numerator, denominator); arrays(1, 0) is 'infinity'. if($v < 0) { list($n, $d) = farey(-$v, $lim); return arrays(-$n, $d); } $z = $lim - $lim; // Get a "zero of the right type" for the denominator list($lower, $upper) = arrays(arrays($z, $z+1), arrays($z+1, $z)); while(true) { $mediant = arrays(($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 

Le frazioni Farey possono essere abbastanza utili in questo caso.

Possono essere utilizzati per convertire qualsiasi decimale in una frazione con il minimo denominatore ansible.

Scusa – Non ho un prototipo in PHP, quindi eccone uno 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 

Basato sulla risposta di @ Joni, ecco cosa ho usato per estrarre l'integer numero.

 function convert_decimal_to_fraction($decimal){ $big_fraction = float2rat($decimal); $num_arrays = explode('/', $big_fraction); $numerator = $num_arrays[0]; $denominator = $num_arrays[1]; $whole_number = floor( $numerator / $denominator ); $numerator = $numerator % $denominator; if($numerator == 0){ return $whole_number; }else if ($whole_number == 0){ return $numerator . '/' . $denominator; }else{ return $whole_number . ' ' . $numerator . '/' . $denominator; } } function 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"; } 

Ecco il mio approccio a questo problema, funziona bene con i numbers razionali. http://www.carlosabundis.com/2014/03/25/converting-decimals-to-fractions-with-php-v2/

  function dec2fracso($dec){ //Negative number flag. $num=$dec; if($num<0){ $neg=true; }else{ $neg=false; } //Extracts 2 strings from input number $decarr=explode('.',(string)$dec); //Checks for divided by zero input. if($decarr[1]==0){ $decarr[1]=1; $fraccion[0]=$decarr[0]; $fraccion[1]=$decarr[1]; return $fraccion; } //Calculates the divisor before simplification. $long=strlen($decarr[1]); $div="1"; for($x=0;$x<$long;$x++){ $div.="0"; } //Gets the greatest common divisor. $x=(int)$decarr[1]; $y=(int)$div; $gcd=gmp_strval(gmp_gcd($x,$y)); //Calculates the result and fills the arrays with the correct sign. if($neg){ $fraccion[0]=((abs($decarr[0])*($y/$gcd))+($x/$gcd))*(-1); }else{ $fraccion[0]=(abs($decarr[0])*($y/$gcd))+($x/$gcd); } $fraccion[1]=($y/$gcd); return $fraccion; }