This works by calling a rationalization function r() with a starting denominator of 1. The function begins incrementing a numerator, and checking at every increment whether the resulting number, when rounded to the same number of digits as the original, has the same string representation as the original. Once the numerator has been incremented so much that the result is greater than the original, the function increments the denominator and calls itself.
This of course uses much more code, but I think the spirit of the problem exonerates this bare-bones approach; for all we know, the internal rationalize() functions of modern languages have lots of internal loops.