954,568 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Function to convert decimal to fraction?

Hi. I need a function which will convert a decimal to a fraction, so that I can put in

echo dec2frac(1.75);


and it'll output 1 3/4.

Any suggestions?

Thanks

calebcook
Junior Poster in Training
66 posts since Jun 2011
Reputation Points: 10
Solved Threads: 4
 

Hmm. I'm no maths expert, but decimal -> fraction is difficult(!). The other direction is fine as you're just dividing and can approximate by specifying a level of precision. Irrational numbers exist, so how the hell do you approximate that? E.g. PI.

Are you going to end up with things like 1234561/8346172 ?

There may be a ready made library or function for this, but I've never seen one.

I think you need to set an acceptable level of precision for a float value, say 5 decimal places - you can do this with something like round(). Then multiply this by 100000 to make an integer.

You could do something like this to give a silly answer:

$num = 0.354675898; // from input
$precision = 5;
$pnum = round($num,$precision);
$denominator = pow(10,$precision);
$numerator = $pnum * $denominator;

echo $numerator . "/" . $denominator;


Before outputting though, I'd have a loop, where I'd test the numerator and denominator with division against prime numbers. If the remainder of each is 0 - do the division - adjust both numbers and go again until division by 2 doesn't work.

If you stick to 5 d.p., you need divisors (primes) from below 500,000 (* I think *). There's a list of primes here: http://primes.utm.edu/lists/small/100000.txt

Can't help thinking that you could check for a smaller set of primes depending on the size of the numerator. Yes, I'm sure you could.

BTW, perhaps it's obvious, but take off numbers to the left of the decimal point before all this!

diafol
Rhod Gilbert Fan (ardav)
Moderator
7,792 posts since Oct 2006
Reputation Points: 1,170
Solved Threads: 1,080
 

I found this code:

<?php
$decimal = $_GET['decimal'];

list ($whole, $numerator, $denominator, $top_heavy) = convert($decimal); 
function num2frac($decimal) {

  function convert ($decimal) { 
	if ($decimal == 0) { 
	  $whole = 0; 
	  $numerator = 0; 
	  $denominator = 1; 
	  $top_heavy = 0; 
	} 

	else { 
	  $sign = 1; 
	  if ($decimal < 0) { 
		$sign = -1; 
	  } 

	  if (floor(abs($decimal)) == 0) { 
		$whole = 0; 
		$conversion = abs($decimal); 
	  } 
	  else { 
		$whole = floor(abs($decimal)); 
		$conversion = abs($decimal); 
	  } 

	  $power = 1; 
	  $flag = 0; 
	  while ($flag == 0) { 
		$argument = $conversion * $power; 
		if ($argument == floor($argument)) { 
		  $flag = 1; 
		} 
		else { 
		  $power = $power * 10; 
		} 
	  } 

	  $numerator = $conversion * $power; 
	  $denominator = $power; 

	  $hcf = euclid ($numerator, $denominator); 

	  $numerator = $numerator/$hcf; 
	  $denominator = $denominator/$hcf; 
	  $whole = $sign * $whole; 
	  $top_heavy = $sign * $numerator; 

	  $numerator = abs($top_heavy) - (abs($whole) * $denominator); 

	  if (($whole == 0) && ($sign == -1)) { 
		$numerator = $numerator * $sign; 
	  } 


	} 
	return array($whole, $numerator, $denominator, $top_heavy); 
  } 



   function euclid ($number_one, $number_two) { 

	  if (($number_one == 0) or ($number_two == 0)) { 
	  $hcf = 1; 
	  return $hcf; 
	  } 
	  else { 
		 if ($number_one < $number_two) { 
		 $buffer = $number_one; 
		 $number_one = $number_two; 
		 $number_two = $buffer; 
		 } 

		 $dividend = $number_one; 
		 $divisor = $number_two; 
		 $remainder = $dividend; 

		 while ($remainder > 0) { 
		   if ((floor($dividend/$divisor)) == ($dividend/$divisor)) { 
		   $quotient = $dividend/$divisor; 
		   $remainder = 0; 
		   } 
		   else { 
		   $quotient = floor($dividend/$divisor); 
		   $remainder = $dividend - ($quotient * $divisor); 
		   } 
		   $hcf = $divisor; 
		   $dividend = $divisor; 
		   $divisor = $remainder; 
		 } 


	} 
   return $hcf; 
   }
?>


However, to display the value you need to use this code:

<?php 
//echo "Whole number = " . $whole . "";
if ($decimal > "" && $whole > 0 && $fraction == ""){echo "
" . $decimal . '"' . " is equal to " .$whole . " " . $numerator . "/" . $denominator . '"';
}
elseif ($decimal > ""  && $fraction == "") {echo "" . $decimal . '"' . " is equal to " . $numerator . "/" . $denominator . '"';
}
?>


How do I display the value simply by writing:

echo convert(0.75);


or something like that?

Thanks!

calebcook
Junior Poster in Training
66 posts since Jun 2011
Reputation Points: 10
Solved Threads: 4
 

Sorry, it's Friday night. Nose began to bleed when wife asked me if I wanted Guinness or Felinfoel beer... :)

diafol
Rhod Gilbert Fan (ardav)
Moderator
7,792 posts since Oct 2006
Reputation Points: 1,170
Solved Threads: 1,080
 

OK, I was intrigued by this, so I had a few Guinesses...

<?php
function dec2frac($dec,$prec){
	if(is_float($dec) && strlen(abs($dec)) < 10 && is_int($prec) && $prec > 1 && $prec < 10){
		$answer = "";
		if(abs($dec) > 1){
			$br = explode('.', $dec);
			$dec = '0.' . $br[1];
			$int = "<strong style=\"color: red;\">{$br[0]}</strong>" . " ";
		}else{
			$int = "";
		}
		$pnum = round($dec,$prec);
		$denominator = pow(10,$prec);
		$numerator = $pnum * $denominator;
		$p = array(10,5,2);
		$answer .= $numerator . "/" . $denominator . "";
		foreach($p as $div){
		a:
			if($numerator % $div == 0 && $denominator % $div == 0){
				$numerator = $numerator/$div;
				$denominator = 	$denominator/$div;
				$answer .= "= " . $int . $numerator . "/" . $denominator . "";
				goto a;
			}
		}
		return $int . $answer;
	}
	return "Input data was not valid: the value to check must be a number and be limited to 10 places and the level of precision must be an integer between 1 and 9";
}

echo dec2frac(2.7552,5);


Anyway, the code gives:2 75520/100000
= 2 15104/20000
= 2 7552/10000
= 2 3776/5000
= 2 1888/2500
= 2 944/1250
= 2 472/625

The code's got a horrible 'goto' in it, but I couldn't be arsed to write a recursive. :(

If you don't want to show the steps, change

$answer .= "= " . $int . $numerator . "/" . $denominator . "";


to

$answer = $numerator . "/" . $denominator;
diafol
Rhod Gilbert Fan (ardav)
Moderator
7,792 posts since Oct 2006
Reputation Points: 1,170
Solved Threads: 1,080
 

While reading ardav solution I thought another solution. Maybe is not clean but it should work:

<?php
function convert($number)
{
	$reverse = strpos(strrev($number),'.');
	$number = (strpos($number,'0') == '0') ? str_replace('0','',$number) : $number;
	
	$n1 = str_replace('.','',$number);
	$n2 = pow('10',$reverse);
	
	$a = gmp_gcd($n1,$n2);
	$b = gmp_strval($a); # display greatest common divisor
	
	return $n1 / $b . "/" . $n2 / $b . "\n";
}

echo convert('0.75');
?>

bye :)

cereal
Master Poster
709 posts since Aug 2007
Reputation Points: 214
Solved Threads: 120
 
While reading ardav solution I thought another solution. Maybe is not clean but it should work:

Now that's nice. But I couldn't get it to work. You need to download the extension from: http://gmplib.org/#DOWNLOAD

I never knew these functions existed. That makes it extremely straightforward. Wasted about 15 minutes with my hack job. :(

diafol
Rhod Gilbert Fan (ardav)
Moderator
7,792 posts since Oct 2006
Reputation Points: 1,170
Solved Threads: 1,080
 

On my opinion it's never a waste of time :)
Your solution does the job without GMP extension, in some situations you can't install what you want, so that's perfect.

cereal
Master Poster
709 posts since Aug 2007
Reputation Points: 214
Solved Threads: 120
 

Thanks ardav! The code works great!

(@cereal: Thanks as well!) :)

calebcook
Junior Poster in Training
66 posts since Jun 2011
Reputation Points: 10
Solved Threads: 4
 

just for completeness:
change

foreach($p as $div){
		a:
			if($numerator % $div == 0 && $denominator % $div == 0){
				$numerator = $numerator/$div;
				$denominator = 	$denominator/$div;
				$answer .= "= " . $int . $numerator . "/" . $denominator . "";
				goto a;
			}
		}


to

foreach($p as $div){
		while($numerator % $div == 0 && $denominator % $div == 0){
				$numerator = $numerator/$div;
				$denominator = 	$denominator/$div;
				$answer .= "= " . $int . $numerator . "/" . $denominator . "";
			}
		}


that gets rid of that awful goto.

diafol
Rhod Gilbert Fan (ardav)
Moderator
7,792 posts since Oct 2006
Reputation Points: 1,170
Solved Threads: 1,080
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You
View similar articles that have also been tagged: