62 lines
1.7 KiB
Text
62 lines
1.7 KiB
Text
'' 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
|