Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP convert decimal into fraction and back?

I want the user to be able to type in a fraction like:

 1/2
 2 1/4
 3

And convert it into its corresponding decimal, to be saved in MySQL, that way I can order by it and do other comparisons to it.

But I need to be able to convert the decimal back to a fraction when showing to the user

so basically I need a function that will convert fraction string to decimal:

fraction_to_decimal("2 1/4");// return 2.25

and a function that can convert a decimal to a faction string:

decimal_to_fraction(.5); // return "1/2"

How can I do this?

like image 634
JD Isaacks Avatar asked Dec 23 '09 17:12

JD Isaacks


People also ask

How do you change a decimal back to a fraction?

Decimals can be written in fraction form. To convert a decimal to a fraction, place the decimal number over its place value. For example, in 0.6, the six is in the tenths place, so we place 6 over 10 to create the equivalent fraction, 6/10. If needed, simplify the fraction.

How do you find the decimal of a number?

To convert a percentage to a decimal, divide by 100. So 25% is 25/100, or 0.25. To convert a decimal to a percentage, multiply by 100 (just move the decimal point 2 places to the right). For example, 0.065 = 6.5% and 3.75 = 375%.

How do I round to 2 decimal places in PHP?

Example #1 round() examples php echo round(3.4); // 3 echo round(3.5); // 4 echo round(3.6); // 4 echo round(3.6, 0); // 4 echo round(1.95583, 2); // 1.96 echo round(1241757, -3); // 1242000 echo round(5.045, 2); // 5.05 echo round(5.055, 2); // 5.06 ?>


4 Answers

Sometimes you need to find a way to do it and rounding is acceptable. So if you decide what range of rounding works out for you you can build a function like this. To convert a decimal into the fraction that it most closely matches. You can extend the accuracy by adding more denominators to be tested.

function decToFraction($float) {
    // 1/2, 1/4, 1/8, 1/16, 1/3 ,2/3, 3/4, 3/8, 5/8, 7/8, 3/16, 5/16, 7/16,
    // 9/16, 11/16, 13/16, 15/16
    $whole = floor ( $float );
    $decimal = $float - $whole;
    $leastCommonDenom = 48; // 16 * 3;
    $denominators = array (2, 3, 4, 8, 16, 24, 48 );
    $roundedDecimal = round ( $decimal * $leastCommonDenom ) / $leastCommonDenom;
    if ($roundedDecimal == 0)
        return $whole;
    if ($roundedDecimal == 1)
        return $whole + 1;
    foreach ( $denominators as $d ) {
        if ($roundedDecimal * $d == floor ( $roundedDecimal * $d )) {
            $denom = $d;
            break;
        }
    }
    return ($whole == 0 ? '' : $whole) . " " . ($roundedDecimal * $denom) . "/" . $denom;
}
like image 108
mmcconkie Avatar answered Oct 24 '22 22:10

mmcconkie


I think I'd store the string representation too, as, once you run the math, you're not getting it back!

And, here's a quick-n-dirty compute function, no guarantees:

$input = '1 1/2';
$fraction = array('whole' => 0);
preg_match('/^((?P<whole>\d+)(?=\s))?(\s*)?(?P<numerator>\d+)\/(?P<denominator>\d+)$/', $input, $fraction);
$result = $fraction['whole'] + $fraction['numerator']/$fraction['denominator'];
print_r($result);die;

Oh, for completeness, add a check to make sure $fraction['denominator'] != 0.

like image 31
Derek Illchuk Avatar answered Oct 24 '22 23:10

Derek Illchuk


To can use PEAR's Math_Fraction class for some of your needs

<?php

include "Math/Fraction.php";

$fr = new Math_Fraction(1,2);


// print as a string
// output: 1/2
echo $fr->toString();

// print as float
// output: 0.5
echo $fr->toFloat();

?>
like image 39
codaddict Avatar answered Oct 24 '22 22:10

codaddict


Here is a solution that first determines a valid fraction (although not necessarily the simplest fraction). So 0.05 -> 5/100. It then determines the greatest common divisor of the numerator and denominator to reduce it down to the simplest fraction, 1/20.

function decimal_to_fraction($fraction) {
  $base = floor($fraction);
  $fraction -= $base;
  if( $fraction == 0 ) return $base;
  list($ignore, $numerator) = preg_split('/\./', $fraction, 2);
  $denominator = pow(10, strlen($numerator));
  $gcd = gcd($numerator, $denominator);
  $fraction = ($numerator / $gcd) . '/' . ($denominator / $gcd);
  if( $base > 0 ) {
    return $base . ' ' . $fraction;
  } else {
    return $fraction;
  }
}

# Borrowed from: http://www.php.net/manual/en/function.gmp-gcd.php#69189
function gcd($a,$b) {
  return ($a % $b) ? gcd($b,$a % $b) : $b;
}

This includes a pure PHP implementation of the gcd although if you are sure the gmp module is installed you could use the one that comes with gcd.

As many others have noted you need to use rational numbers. So if you convert 1/7 to a decimal then try to convert it back to a decimal you will be out of luck because the precision lost will prevent it from getting back to 1/7. For my purposes this is acceptable since all the numbers I am dealing with (standard measurements) are rational numbers anyway.

like image 30
Eric Anderson Avatar answered Oct 25 '22 00:10

Eric Anderson