/*
convertDecimalToRational($s)
-----------------------------
Converts a decimal number (given as a string) into an exact rational p/q.
Why parse the string?
• PHP has no built‑in rational type.
• Floats cannot preserve exact decimal digits.
• Using strings + integers ensures perfect accuracy.
Algorithm:
1. Look for a decimal point.
2. If none → integer → numerator = n, denominator = 1.
3. Otherwise:
Example: "12.345"
integer part = 12
fractional part = 345
digits = 3
numerator = integer_part * 10^digits + fractional_part
denominator = 10^digits
4. Reduce using gcd (Euclid’s algorithm).
*/
function gcd(int $a, int $b): int {
// Euclid's algorithm
while ($b !== 0) {
$t = $b;
$b = $a % $b;
$a = $t;
}
return abs($a);
}
function convertDecimalToRational(string $s): array {
$dotPos = strpos($s, '.');
if ($dotPos === false) {
// No decimal point → integer
return [intval($s), 1];
}
// Split into integer and fractional parts
$intPart = substr($s, 0, $dotPos);
$fracPart = substr($s, $dotPos + 1);
$integerValue = intval($intPart);
$fractionalValue = intval($fracPart);
$digits = strlen($fracPart);
// Build denominator = 10^digits
$denominator = 10 ** $digits;
// Build numerator
$numerator = $integerValue * $denominator + $fractionalValue;
// Reduce fraction
$g = gcd($numerator, $denominator);
$numerator /= $g;
$denominator /= $g;
return [$numerator, $denominator];
}
/*
Main
*/
$values = [
"3.5", "12.75", "0.125", "100.001",
"7", "42.0", "0.333", "5.2"
];
foreach ($values as $v) {
[$num, $den] = convertDecimalToRational($v);
echo "$v -> $num/$den\n";
}
/*
run:
3.5 -> 7/2
12.75 -> 51/4
0.125 -> 1/8
100.001 -> 100001/1000
7 -> 7/1
42.0 -> 42/1
0.333 -> 333/1000
5.2 -> 26/5
*/