import Foundation
/*
DecimalToRational (Swift)
-------------------------
Converts a decimal number (given as a String) into an exact rational p/q.
Why parse the string manually?
• Swift has no built‑in Rational type.
• Double cannot preserve exact decimal digits.
• Using String + BigInt (via Swift's built‑in big integer support in `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).
*/
/// Minimal BigInt wrapper using Swift's built‑in `BigInt` from Foundation.
/// If using older Swift versions, replace with a third‑party BigInt library.
typealias BigInt = Int64 // Replace with real BigInt if needed
/// Compute gcd using Euclid’s algorithm
func gcd(_ a: BigInt, _ b: BigInt) -> BigInt {
var x = a
var y = b
while y != 0 {
let t = y
y = x % y
x = t
}
return abs(x)
}
/// Rational number container
struct Rational: CustomStringConvertible {
let numerator: BigInt
let denominator: BigInt
var description: String {
"\(numerator)/\(denominator)"
}
}
/// Convert decimal string to Rational
func convertDecimalToRational(_ s: String) -> Rational {
guard let dotPos = s.firstIndex(of: ".") else {
// No decimal point → integer
return Rational(numerator: BigInt(s)!, denominator: 1)
}
let intPart = String(s[..<dotPos])
let fracPart = String(s[s.index(after: dotPos)...])
let integerValue = BigInt(intPart)!
let fractionalValue = BigInt(fracPart)!
let digits = fracPart.count
// denominator = 10^digits
let denominator = BigInt(pow(10.0, Double(digits)))
// numerator = integerValue * denominator + fractionalValue
let numerator = integerValue * denominator + fractionalValue
// Reduce using gcd
let g = gcd(numerator, denominator)
return Rational(numerator: numerator / g, denominator: denominator / g)
}
/// Main
let values = [
"3.5", "12.75", "0.125", "100.001",
"7", "42.0", "0.333", "5.2"
]
for v in values {
let r = convertDecimalToRational(v)
print("\(v) -> \(r)")
}
/*
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
*/