User:NXTBoy/Scripts/Fraction
From Legacy Roblox Wiki
< User:NXTBoy | Scripts
local Fraction = {} Fraction.new = function(num, denom) return setmetatable({ numerator = num or 0, denominator = denom or 0 }, Fraction):simplify() end Fraction.toFloat = function(self) return self.numerator / self.denominator end Fraction.simplify = function(self) for i = 2, self.q do while self.p % i == 0 and self.q % i == 0 do self.p = self.p / i self.q = self.q / i end end return self end -- Metatable bits and pieces Fraction.__index = function(self, k) if k == "p" or k == "top" then return self.numerator elseif k == "q" or k == "bottom" then return self.denominator else return Fraction[k] end end Fraction.__tostring = function(self) return self.p.."/"..self.q end Fraction.__unm = function(self) return Fraction.new( -self.p, self.q ) end Fraction.__pow = function(a, b) if getmetatable(a) == Fraction and getmetatable(b) == Fraction then return a:toFloat() ^ b:toFloat() elseif getmetatable(a) == Fraction and type(b) == "number" then return Fraction.new( a.p ^ b, a.q ^ b ) elseif type(a) == "number" and getmetatable(b) == Fraction then return a ^ b:toFloat() else error(string.format("attempt to raise a %s to the power of a %s", type(a), type(b)), 2) end end Fraction.__add = function(a, b) if getmetatable(a) == Fraction and getmetatable(b) == Fraction then return Fraction.new( a.p * b.q + a.q * b.p, a.q * b.q ) elseif getmetatable(a) == Fraction and type(b) == "number" then return Fraction.new( a.p + b * a.q, a.q ) elseif type(a) == "number" and getmetatable(b) == Fraction then return Fraction.new( b.p + a * b.q, b.q ) else error(string.format("attempt to add a %s to a %s", type(a), type(b)), 2) end end Fraction.__sub = function(a, b) if getmetatable(a) == Fraction and getmetatable(b) == Fraction then return Fraction.new( a.p * b.q - a.q * b.p, a.q * b.q ) elseif getmetatable(a) == Fraction and type(b) == "number" then return Fraction.new( a.p - b * a.q, a.q ) elseif type(a) == "number" and getmetatable(b) == Fraction then return Fraction.new( b.p - a * b.q, b.q ) else error(string.format("attempt to subtract a %s from a %s", type(a), type(b)), 2) end end Fraction.__mul = function(a, b) if getmetatable(a) == Fraction and getmetatable(b) == Fraction then return Fraction.new( a.p * b.p, a.q * b.q ) elseif getmetatable(a) == Fraction and type(b) == "number" then return Fraction.new( a.p * b, a.q ) elseif type(a) == "number" and getmetatable(b) == Fraction then return Fraction.new( a * b.p, b.q ) else error(string.format("attempt to multiply a %s by a %s", type(a), type(b)), 2) end end Fraction.__div = function(a, b) if getmetatable(a) == Fraction and getmetatable(b) == Fraction then return Fraction.new( a.p * b.q, a.q * b.p ) elseif getmetatable(a) == Fraction and type(b) == "number" then return Fraction.new( a.p, a.q * b ) elseif type(a) == "number" and getmetatable(b) == Fraction then return Fraction.new( a * b.q, b.p ) else error(string.format("attempt to divide a %s by a %s", type(a), type(b)), 2) end end --Important bit Fraction.fromFloat = function(input, maxDenominator) maxDenominator = maxDenominator or 1e99 local f0 = Fraction.new(1, 0) local f1 = Fraction.new(math.floor(input), 1) local f2 local r = input % 1 local next_cf while math.abs(r) >= 0.0001 do r = 1 / r next_cf = math.floor(r) f2 = Fraction.new( next_cf * f1.p + f0.p, next_cf * f1.q + f0.q ) -- Limit the numerator and denominator to be 256 or less if f2.q > maxDenominator then break end -- remember the last two fractions f0 = f1 f1 = f2 r = r - next_cf end return f1 end
Using it:
print(Fraction.fromFloat(1/3) + Fraction.fromFloat(1/2)) --5/6 print(Fraction.new(1, 6) + Fraction.new(1, 3)) --1/2 print(Fraction.fromFloat(math.pi, 100)) --22/7