Here is the algorithm that I use. It's an iterative process that works as follows:
- The initial approximation for the numerator is 1 and the denominator is 1 divided by the fraction portion of the floating point value. For example, when converting 0.06 to a fraction, the denominator = 1/0.06 = 16.66666667 (rounded to 17), thus the initial approximation is 1/17.
- The difference between the floating point value and the the current approximation is computed. For the example, the difference is 1/17 - 0.06 = 0.058824 - 0.06 = -0.001176.
- If the absolute value of the difference is less than the defined tolerance (i.e. 0.000005), then the iteration is terminated.
- Use the difference computed in step 2 to improve approximation of fraction. This is done by converting the difference into a fraction and adding (or subtracting) to the current approximation. In the example, a negative difference indicates a low approximation -- thus difference needs to be added to current approximation. The difference fraction is the numerator = 1 and denominator = 1/0.001176 = 850 -- difference in fraction from is 1/850. The new approximation will be (1/17) + (1/850) = (850*1 + 17*1)/(850*17) = 867/14450.
- Repeat steps 2 to 4 until solution found.
- After solution found, the fraction can be reduced. For example, 867/14450 is exactly 0.06 and the iteration process is terminated. 867/14450 can be reduced to 3/50.
Some features of this method are:
- If the resulting fraction is 1/anything, the first approximation will be exact. For example, converting 0.25 to fraction, the first approximation will be 1/4. Thus further iterations are not needed.
- In majority (> 80%) of 1,000,000 test cases, convergence occurs in 2 iteration or less.
- For all test cases, the maximum number of iterations was 3.
I posted the code for this algorithm on github -- https://github.com/tnbezue/fraction