The decimal number 2.5 can also be written as the fraction 5 / 2. 19.2 becomes 96 / 5. 0.24 becomes 6 / 25. Etcetera. So how can you do this programmatically? Well, it turns out a naive solution can be obtained pretty quickly.
The idea is pretty straightforward. It comes from the observation that for any fraction f = x / y, increasing the value of x will increase the value of f and increasing the value of y will decrease the value of f. Both x and y must be at least 1. So now, if we want to find the fraction for some number n, we start with fraction f = x / y with x = 1 and y = 1. If f is smaller than n, we increase x by one. If f is larger than n, we increase y by one. We do this until f = n, at which point we have rewritten n as a fraction x / y.
The code is as simple as the description of the algorithm:
public static Tuple<int, int> GetFraction(double number)
{
var numerator = 1.0;
var denominator = 1.0;
var tmp = numerator / denominator;
while (Math.Abs(tmp - number) > 0.0000001)
{
if (tmp < number)
{
numerator++;
}
else
{
denominator++;
numerator = Math.Floor(number * denominator);
}
tmp = numerator / denominator;
}
return Tuple.Create(Convert.ToInt32(numerator), Convert.ToInt32(denominator));
}
The only difference in the code above is it does not check for equality of f and n, but instead aims to approach the value of n within a certain precision. This is done to counter inaccuracies in floating point arithmetic. Note the current precision is selected arbitrarily and is probably rather conservative. The code also has an optimization step where after incrementing y it sets x to be the highest value it can be under this y without f becoming more than n. After all, if we have some n and some y then we know that because f = x / y = n we have x = n * y. But because n * y can be a decimal number, we take the floor, which is a lower bound for x.