-- fraction library -- f1/lua is the usage example local num=require("num") local gcd=num.gcd local Fr = {} local mt = {} local function setmt(t,mt) -- set meta-table if mt then t.mt = mt setmetatable(t,mt) else if t.mt then setmetatable(t,t.mt) end end end local function dup(t) -- create new table from t local tn tn = {} for k,v in pairs(t) do if type(v)=="table" then tn[k] = dup(v) setmt(tn[k]) else tn[k] = v end end return tn end function Fr.tostring(x) -- function in Fr if x[1]==0 then return "0" end if x[2] < 0 then x[1],x[2] = -x[1], -x[2] end if x[2]==1 then return fmt("%d",x[1]) end return fmt("%d/%d",x[1],x[2]) end mt.__tostring = Fr.tostring function Fr.new(a,b) -- function in Fr if b==nil then b=1 end local f={a,b} setmt(f,mt) return f end local function fix(x) if type(x)=="number" then return {x,1} end return x end local function fr_add(x,y) if type(x)=="number" then x = {x,1} end if type(y)=="number" then y = {y,1} end local a,b,z a = x[1]*y[2] + x[2]*y[1] b = x[2]*y[2] c = gcd(a,b) z = {a//c,b//c} setmt(z,mt) return z end mt.__add = fr_add local function fr_neg(x) local z={} if type(x)=="number" then z[1] = -x z[2] = 1 else z[1] = -x[1] z[2] = x[2] end setmt(z,mt) return z end mt.__unm = fr_neg local function fr_sub(x,y) local z = fr_neg(y) setmt(z,mt) return fr_add(x,z) end mt.__sub = fr_sub local function fr_mul(x,y) if type(x)=="number" then x = {x,1} end if type(y)=="number" then y = {y,1} end local a,b,z a = x[1]*y[1] b = x[2]*y[2] c = gcd(a,b) z = {a//c,b//c} setmt(z,mt) return z end mt.__mul = fr_mul local function fr_inv(x) if type(x)=="number" then return {1,x} end return {x[2],x[1]} end local function fr_div(x,y) return fr_mul(x, fr_inv(y)) end mt.__div = fr_div -- Lua has no __inv local function fr_abs(x) local t = {abs(x[1]),abs(x[2])} setmt(t,mt) return t end local function fr_eq(x,y) if type(x)=="number" then x = {x,1} end if type(y)=="number" then y = {y,1} end return x[1]*y[2]==x[2]*y[1] end mt.__eq = fr_eq local function fr_lt(x,y) if x == 0 then return y[1]*y[2] > 0 end if y == 0 then return x[1]*x[2] < 0 end if type(x)=="number" then x = {x,1} end if type(y)=="number" then y = {y,1} end return x[1]*y[2]-x[2]*y[1] < 0 end mt.__lt = fr_lt local function fr_le(x,y) if x == 0 then return y[1]*y[2] >= 0 end if y == 0 then return x[1]*x[2] <= 0 end if type(x)=="number" then x = {x,1} end if type(y)=="number" then y = {y,1} end return x[1]*y[2]-x[2]*y[1] <= 0 end mt.__le = fr_le return { Fr=Fr, mt=mt, setmt=setmt, dup=dup, fr_abs=fr_abs, }