C, 233 ===== 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. Note that this doesn't work for an input of "0." because that is not a standard way to write a float, so when it re-writes the float to string, the result will never be a "0.". The specs want a function that returns values instead of just printing to screen, hence the argument-passing. Code (ungolfed): void r(char* x, int* a, int* b) { int i = -1; char z[32]; double v =atof(x); while(1) { i++; double y = ((double)i)/((double)(*b)); double w; sprintf(z, "%.*f", strlen(strchr(x,'.'))-1, y); if(strcmp(x, z)==0) { *a = i; return; } w = atof(z); if(w > v) { (*b)++; r(x, a, b); return; } } } Usage: #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char* argv[]) { int num; int denom = 1; // start with a denominator of 1 r(argv[1], &num, &denom); printf("%d/%d\n", num, denom); return 0; } Golfed code: typedef double D; void r(char*x,int*a,int*b){int i=-1;char z[32];D v=atof(x);while(1){i++;D y=((D)i)/((D)(*b));D w;sprintf(z,"%.*f",strlen(strchr(x,'.'))-1,y);if(!strcmp(x,z)){*a=i;return;}w=atof(z);if(w>v){(*b)++;r(x,a,b);return;}}}