Skip to content

Instantly share code, notes, and snippets.

@ngocongcan
Last active May 17, 2019 03:47
Show Gist options
  • Save ngocongcan/0aeef02bd0b9ff6ad9149505c844951a to your computer and use it in GitHub Desktop.
Save ngocongcan/0aeef02bd0b9ff6ad9149505c844951a to your computer and use it in GitHub Desktop.
Converting exactly decimal to fraction
class FractionHelper {
/*
* https://en.wikipedia.org/wiki/Continued_fraction
* Using this format instead float number (0.001) to avoid inaccurate value
* https://stackoverflow.com/questions/812815/php-intval-and-floor-return-value-that-is-too-low
*/
const TOLERANCE = 1.e-4;
const PATTERN_FROM_STRING = '#^(-?\d+)(?:(?: (\d+))?/(\d+))?$#';
public static function decimal2Fraction($x) {
if(is_null($x)) return null;
if(floor($x) - $x == 0) return floor($x);
$isNegative = $x < 0 ? -1 : 1 ;
$x = abs($x);
$tolerance = self::TOLERANCE;
$h1 = 1; $h2 = 0;
$k1 = 0; $k2 = 1;
$b = 1/$x;
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($x - $h1/$k1) >= ($x * $tolerance));
$numerator = (int) $h1 * $isNegative;
$denominator = (int) $k1;
if ($numerator === $denominator) {
return '1';
}
if (-1*$numerator === $denominator) {
return '-1';
}
if (1 === $denominator) {
return (string) $numerator;
}
if (abs($numerator) > abs($denominator)) {
$whole = floor(abs($numerator) / $denominator);
if ($numerator < 0) {
$whole *= -1;
}
return sprintf('%d %d/%d',
$whole,
abs($numerator % $denominator),
$denominator
);
}
return sprintf('%d/%d',
$numerator,
$denominator
);
}
public static function fractionString2Decimal($string) {
if (preg_match(self::PATTERN_FROM_STRING, trim($string), $matches)) {
if (2 === count($matches)) {
// whole number
return floatval($matches[1]);
} else {
// either x y/z or x/y
if ($matches[2]) {
// x y/z
return (intval($matches[1]) + (intval($matches[2])/ intval($matches[3])) );
}
// x/y
return (intval($matches[1])/ intval($matches[3]));
}
}
return floatval($string);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment