RosettaCodeData/Task/Convert-decimal-number-to-rational/FreeBASIC/convert-decimal-number-to-rational.basic
2023-07-01 13:44:08 -04:00

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