/*
convertDecimalToRational(s)
---------------------------
Converts a decimal number (given as a string) into an exact rational p/q.
Why parse the string manually?
• JavaScript has no built‑in rational type.
• Number (IEEE‑754 float) cannot preserve exact decimal digits.
• Using strings + BigInt 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(a, b) {
// Euclid's algorithm using BigInt
while (b !== 0n) {
const t = b;
b = a % b;
a = t;
}
return a < 0n ? -a : a; // ensure positive gcd
}
function convertDecimalToRational(s) {
const dotPos = s.indexOf(".");
if (dotPos === -1) {
// No decimal point → integer
return {
numerator: BigInt(s),
denominator: 1n
};
}
// Split into integer and fractional parts
const intPart = s.slice(0, dotPos);
const fracPart = s.slice(dotPos + 1);
const integerValue = BigInt(intPart);
const fractionalValue = BigInt(fracPart);
const digits = fracPart.length;
// Build denominator = 10^digits
const denominator = 10n ** BigInt(digits);
// Build numerator
const numerator = integerValue * denominator + fractionalValue;
// Reduce using gcd
const g = gcd(numerator, denominator);
return {
numerator: numerator / g,
denominator: denominator / g
};
}
/*
Main
*/
const values = [
"3.5", "12.75", "0.125", "100.001",
"7", "42.0", "0.333", "5.2"
];
for (const v of values) {
const r = convertDecimalToRational(v);
console.log(`${v} -> ${r.numerator}/${r.denominator}`);
}
/*
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
*/