package main
import (
"fmt"
"math/big"
"strings"
)
/*
convertDecimalToRational(s string)
----------------------------------
Converts a decimal number (given as a string) into an exact rational p/q.
Why parse the string manually?
• Go has no built‑in rational type.
• float64 cannot preserve exact decimal digits.
• Using strings + big.Int 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).
*/
// gcd computes the greatest common divisor using Euclid’s algorithm.
func gcd(a, b *big.Int) *big.Int {
zero := big.NewInt(0)
tmp := new(big.Int)
for b.Cmp(zero) != 0 {
tmp.Set(b)
b.Mod(a, b)
a.Set(tmp)
}
if a.Sign() < 0 {
a.Neg(a)
}
return a
}
// convertDecimalToRational converts a decimal string into numerator/denominator.
func convertDecimalToRational(s string) (*big.Int, *big.Int) {
dotPos := strings.Index(s, ".")
if dotPos == -1 {
// No decimal point → integer
n := new(big.Int)
n.SetString(s, 10)
return n, big.NewInt(1)
}
intPart := s[:dotPos]
fracPart := s[dotPos+1:]
integerValue := new(big.Int)
integerValue.SetString(intPart, 10)
fractionalValue := new(big.Int)
fractionalValue.SetString(fracPart, 10)
digits := len(fracPart)
// denominator = 10^digits
denominator := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(digits)), nil)
// numerator = integerValue * denominator + fractionalValue
numerator := new(big.Int).Mul(integerValue, denominator)
numerator.Add(numerator, fractionalValue)
// Reduce fraction
g := gcd(new(big.Int).Set(numerator), new(big.Int).Set(denominator))
numerator.Div(numerator, g)
denominator.Div(denominator, g)
return numerator, denominator
}
func main() {
values := []string{
"3.5", "12.75", "0.125", "100.001",
"7", "42.0", "0.333", "5.2",
}
for _, v := range values {
num, den := convertDecimalToRational(v)
fmt.Printf("%s -> %s/%s\n", v, num.String(), den.String())
}
}
/*
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
*/