use num_bigint::BigInt;
use num_integer::Integer;
/*
DecimalToRational (Rust)
------------------------
Converts a decimal number (given as a string) into an exact rational p/q.
Why parse the string manually?
• Rust has no built‑in rational type in std.
• f64 cannot preserve exact decimal digits.
• Using BigInt ensures perfect accuracy.
• The num crate provides BigInt + gcd helpers.
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.
*/
#[derive(Debug)]
struct Rational {
numerator: BigInt,
denominator: BigInt,
}
fn convert_decimal_to_rational(s: &str) -> Rational {
if let Some(dot_pos) = s.find('.') {
// Split into integer and fractional parts
let int_part: &str = &s[..dot_pos];
let frac_part: &str = &s[dot_pos + 1..];
let integer_value: BigInt = int_part.parse().unwrap();
let fractional_value: BigInt = frac_part.parse().unwrap();
let digits: usize = frac_part.len();
// denominator = 10^digits
let denominator: BigInt = BigInt::from(10u32).pow(digits as u32);
// numerator = integerValue * denominator + fractionalValue
let numerator: BigInt = integer_value * &denominator + fractional_value;
// Reduce using gcd
let g: BigInt = numerator.gcd(&denominator);
let numerator = numerator / &g;
let denominator = denominator / &g;
Rational { numerator, denominator }
} else {
// No decimal point → integer
let numerator: BigInt = s.parse().unwrap();
let denominator: BigInt = BigInt::from(1);
Rational { numerator, denominator }
}
}
fn main() {
let values: [&str; 8] = [
"3.5", "12.75", "0.125", "100.001",
"7", "42.0", "0.333", "5.2",
];
for v in values {
let r: Rational = convert_decimal_to_rational(v);
println!("{} -> {}/{}", 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
*/