This task has been flagged for clarification. Code on this page in its current state may be flagged incorrect once this task has been clarified. See this page's Talk page for discussion.


The task is to write a program to transform a decimal number into a fraction in lowest terms.

It is not always possible to do this exactly. For instance, while rational numbers can be converted to decimal representation, some of them need an infinite number of digits to be represented exactly in decimal form. Namely, repeating decimals such as 1/3 = 0.333...

Because of this, the following fractions cannot be obtained (reliably) unless the language has some way of representing repeating decimals:

 67 / 74 = 0.9(054) = 0.9054054...
 14 / 27 = 0.(518) = 0.518518...

Acceptable output:

 0.9054054 → 4527027 / 5000000
 0.518518 → 259259 / 500000

Finite decimals are of course no problem:

 0.75 → 3 / 4 


'' Written in FreeBASIC
'' (no error checking, limited to 64-bit signed math)
type number as longint
#define str2num vallng
#define pow10(n) clngint(10 ^ (n))
 
function gcd(a as number, b as number) as number
    if a = 0 then return b
    return gcd(b mod a, a)
end function
 
 
function parserational(n as const string) as string
    dim as string whole, dec, num, denom
    dim as number iwhole, idec, inum, idenom, igcd
 
    '' find positions of '.', '(' and ')' in code
    dim as integer dpos, r1pos, r2pos
    dpos = instr(n & ".", ".")
    r1pos = instr(n & "(", "(")
    r2pos = instr(n & ")", ")")
 
    '' extract sections of number (whole, decimal, repeated numerator), generate '999' denominator
    whole = left(n, dpos - 1)
    dec = mid(n, dpos + 1, r1pos - dpos - 1)
    num = mid(n, r1pos + 1, r2pos - r1pos - 1)
    denom = string(len(num), "9"): if denom = "" then denom = "1"
 
    '' parse sections to integer
    iwhole = str2num(whole)
    idec = str2num(dec)
    inum = str2num(num)
    idenom = str2num(denom)
 
    '' if whole was negative, decimal and repeated sections need to be negative too
    if left(ltrim(whole), 1) = "-" then idec = -idec: inum = -inum
 
    '' add decimal part to repeated fraction, and scale down
    inum += idec * idenom
    idenom *= pow10(len(dec))
 
    '' add integer part to fraction
    inum += iwhole * idenom
 
    '' simplify fraction
    igcd = abs(gcd(inum, idenom))
    if igcd <> 0 then
        inum \= igcd
        idenom \= igcd
    end if
 
    return inum & " / " & idenom & " = " & (inum / idenom)
 
end function
 
data "0.9(054)", "0.(518)", "-.12(345)", ""
do
    dim as string n
    read n
    if n = "" then exit do
    print n & ":", parserational(n)
loop