359 lines
7.6 KiB
Lua
359 lines
7.6 KiB
Lua
-- class table
|
|
Big = {
|
|
m = 0,
|
|
e = 0
|
|
}
|
|
|
|
-- metatable
|
|
BigMeta = {}
|
|
BigMeta.__index = Big
|
|
|
|
--- Create a new Big number
|
|
--
|
|
-- numbers are stored in the form `m * 10 ^ e`
|
|
function Big:new(m, e)
|
|
if type(m) == "table" then
|
|
return setmetatable({m = m.m, e = m.e}, BigMeta):normalized()
|
|
end
|
|
if e == nil then e = 0 end
|
|
|
|
if type(m) == "string" then
|
|
return Big.parse(m)
|
|
end
|
|
|
|
return setmetatable({m = m, e = e}, BigMeta):normalized()
|
|
end
|
|
|
|
function Big:normalize()
|
|
if self.m == 0 then
|
|
self.e = 0
|
|
else
|
|
local n_log = math.floor(math.log(math.abs(self.m), 10))
|
|
self.m = self.m / 10 ^ n_log
|
|
self.e = self.e + n_log
|
|
self.e = math.floor(self.e)
|
|
end
|
|
end
|
|
|
|
function Big:normalized()
|
|
if (tostring(self.e) == "nan" or tostring(self.e) == "inf") then
|
|
self.m = 0/0
|
|
self.e = 10^1000
|
|
return self
|
|
end
|
|
self:normalize()
|
|
return self
|
|
end
|
|
|
|
function Big:add(b)
|
|
if type(b) == "number" then b = Big:new(b) end
|
|
local delta = b.e - self.e
|
|
|
|
if delta > 14 then return b end
|
|
if delta < -14 then return self end
|
|
|
|
return Big:new(self.m + b.m * 10 ^ delta, self.e):normalized()
|
|
end
|
|
|
|
function BigMeta.__add(b1, b2)
|
|
if type(b1) == "number" then return Big:new(b1) + b2 end
|
|
return b1:add(b2)
|
|
end
|
|
|
|
function Big:sub(b)
|
|
if type(b) == "number" then b = Big:new(b) end
|
|
local nb = Big:new(b.m * -1, b.e) --negate b
|
|
return self:add(nb)
|
|
end
|
|
|
|
function BigMeta.__sub(b1, b2)
|
|
if type(b1) == "number" then return Big:new(b1) - b2 end
|
|
return b1:sub(b2)
|
|
end
|
|
|
|
function Big:mul(b)
|
|
if type(b) == "number" then b = Big:new(b) end
|
|
return Big:new(self.m * b.m, self.e + b.e):normalized()
|
|
end
|
|
|
|
function BigMeta.__mul(b1, b2)
|
|
if type(b1) == "number" then return Big:new(b1) * b2 end
|
|
return b1:mul(b2)
|
|
end
|
|
|
|
function Big:div(b)
|
|
if type(b) == "number" then b = Big:new(b) end
|
|
return Big:new(self.m / b.m, self.e - b.e):normalized()
|
|
end
|
|
|
|
function BigMeta.__div(b1, b2)
|
|
if type(b1) == "number" then return Big:new(b1) / b2 end
|
|
return b1:div(b2)
|
|
end
|
|
|
|
function Big:mod(other)
|
|
other = Big:create(other)
|
|
if (other:eq(R.ZERO)) then
|
|
Big:create(R.ZERO)
|
|
end
|
|
if (self.sign*other.sign == -1) then
|
|
return self:abs():mod(other:abs()):neg()
|
|
end
|
|
if (self.sign==-1) then
|
|
return self:abs():mod(other:abs())
|
|
end
|
|
return self:sub(self:div(other):floor():mul(other))
|
|
end
|
|
|
|
function Big:negate()
|
|
return self:mul(Big:new(-1))
|
|
end
|
|
|
|
function BigMeta.__unm(b1)
|
|
return b1:negate()
|
|
end
|
|
|
|
function Big:log10()
|
|
-- The default value of 0 is to make Balatro happy...
|
|
if self.e == nan and self.m == nan then return 0 end
|
|
if self:lte(Big:new(0)) then return 0 end
|
|
return self.e + math.log(self.m, 10)
|
|
end
|
|
|
|
function Big:log(base)
|
|
-- The default value of 0 is to make Balatro happy...
|
|
if self.e == nan and self.m == nan then return 0 end
|
|
if self:lte(Big:new(0)) then return 0 end
|
|
return self:log10() / math.log(base, 10)
|
|
end
|
|
|
|
function Big:ln()
|
|
return self:log(math.exp(1))
|
|
end
|
|
|
|
function Big:ld()
|
|
return self:log(2)
|
|
end
|
|
|
|
function Big:pow(pow)
|
|
-- faster than self:eq(Big:new(0))
|
|
if self.m == 0 and self.e == 0 then
|
|
return Big:new(0)
|
|
end
|
|
local log = self:log10()
|
|
local new_log = log * pow
|
|
return Big:new(10 ^ (new_log % 1), math.floor(new_log)):normalized()
|
|
end
|
|
|
|
function BigMeta.__pow(b1, n)
|
|
if type(n) == "table" then n = n:to_number() end
|
|
if type(b1) ~= "table" then b1 = Big:new(b1) end
|
|
return b1:pow(n)
|
|
end
|
|
|
|
function Big.exp(n)
|
|
return Big:new(math.exp(1)):pow(n)
|
|
end
|
|
|
|
function Big:recp()
|
|
return self:pow(-1)
|
|
end
|
|
|
|
function Big:sqrt()
|
|
return self:pow(0.5)
|
|
end
|
|
|
|
function Big:cbrt()
|
|
return self:pow(1 / 3)
|
|
end
|
|
|
|
function Big:round()
|
|
if self.e > 100 then return self end
|
|
local num = self:to_number()
|
|
if num % 1 < 0.5 then
|
|
return Big:new(math.floor(num))
|
|
else
|
|
return Big:new(math.ceil(num))
|
|
end
|
|
end
|
|
|
|
function Big:floor()
|
|
if self.e > 100 then return self end
|
|
return Big:new(math.floor(self:to_number()))
|
|
end
|
|
|
|
function Big:ceil()
|
|
if self.e > 100 then return self end
|
|
return Big:new(math.ceil(self:to_number()))
|
|
end
|
|
|
|
function Big:floor_m(digits)
|
|
if self.e > 100 then return self end
|
|
return Big:new(math.floor(self.m * 10 ^ digits) / 10 ^ digits, self.e)
|
|
end
|
|
|
|
function Big:ceil_m(digits)
|
|
if self.e > 100 then return self end
|
|
return Big:new(math.ceil(self.m * 10 ^ digits) / 10 ^ digits, self.e)
|
|
end
|
|
|
|
function Big:sin()
|
|
return Big:new(math.sin(self:to_number()))
|
|
end
|
|
|
|
function Big:asin()
|
|
return Big:new(math.asin(self:to_number()))
|
|
end
|
|
|
|
function Big:cos()
|
|
return Big:new(math.cos(self:to_number()))
|
|
end
|
|
|
|
function Big:acos()
|
|
return Big:new(math.acos(self:to_number()))
|
|
end
|
|
|
|
function Big:tan()
|
|
return Big:new(math.tan(self:to_number()))
|
|
end
|
|
|
|
function Big:is_positive()
|
|
return self.m >= 0
|
|
end
|
|
|
|
function Big:is_negative()
|
|
return self.m < 0
|
|
end
|
|
|
|
function Big:is_naneinf()
|
|
return tostring(self.m) == "nan" and (tostring(self.e) == "nan" or tostring(self.e) == "inf")
|
|
end
|
|
|
|
function Big:compare(b)
|
|
b = Big:new(b)
|
|
if self.m == b.m and self.e == b.e then
|
|
return 0
|
|
end
|
|
|
|
if self:is_positive() and b:is_negative() then
|
|
return 1
|
|
end
|
|
if self:is_negative() and b:is_positive() then
|
|
return -1
|
|
end
|
|
|
|
if self.e > b.e then return 1 end
|
|
if self.e < b.e then return -1 end
|
|
|
|
if self:is_positive() and self.m > b.m then return 1 end
|
|
if self:is_positive() and self.m < b.m then return -1 end
|
|
if self:is_negative() and self.m > b.m then return -1 end
|
|
if self:is_negative() and self.m < b.m then return 1 end
|
|
end
|
|
|
|
function Big:gt(b)
|
|
return self:compare(b) == 1
|
|
end
|
|
|
|
function Big:gte(b)
|
|
return self:compare(b) >= 0
|
|
end
|
|
|
|
function Big:lt(b)
|
|
return self:compare(b) == -1
|
|
end
|
|
|
|
function BigMeta.__lt(b1, b2)
|
|
if b2:is_naneinf() then
|
|
return true
|
|
end
|
|
if b1:is_naneinf() then
|
|
return false
|
|
end
|
|
return b1:lt(b2)
|
|
end
|
|
|
|
function Big:lte(b)
|
|
return self:compare(b) <= 0
|
|
end
|
|
|
|
function BigMeta.__le(b1, b2)
|
|
if b2:is_naneinf() then
|
|
return true
|
|
end
|
|
if b1:is_naneinf() then
|
|
return false
|
|
end
|
|
return b1:lte(b2)
|
|
end
|
|
|
|
function Big:gt(b)
|
|
return self:compare(b) == 1
|
|
end
|
|
|
|
function Big:eq(b)
|
|
return self:compare(b) == 0
|
|
end
|
|
|
|
function BigMeta.__eq(b1, b2)
|
|
return b1:eq(b2)
|
|
end
|
|
|
|
function Big:neq(b)
|
|
return self:compare(b) ~= 0
|
|
end
|
|
|
|
function Big:to_string()
|
|
return self.m.."e"..self.e
|
|
end
|
|
|
|
function Big:to_number()
|
|
return self.m * 10 ^ self.e
|
|
end
|
|
|
|
function BigMeta.__tostring(b)
|
|
return number_format(b)
|
|
end
|
|
|
|
function Big.parse(str)
|
|
local to_n = tonumber(str)
|
|
if to_n ~= nil and to_n < math.huge then
|
|
return Big:new(to_n):normalized()
|
|
end
|
|
|
|
local parts = {}
|
|
for m, e in str:gmatch("(.+)e(.+)") do
|
|
parts = {m, e}
|
|
end
|
|
return Big:new(tonumber(parts[1]), math.floor(tonumber(parts[2]))):normalized()
|
|
end
|
|
|
|
function BigMeta.__concat(a, b)
|
|
a = Big:create(a)
|
|
return tostring(a) .. tostring(b)
|
|
end
|
|
|
|
--Adding things OmegaNum has that this doesn't...
|
|
R = {}
|
|
|
|
R.ZERO = 0
|
|
R.ONE = 1
|
|
R.E = math.exp(1)
|
|
R.LN2 = math.log(2, R.E)
|
|
R.LN10 = math.log(10, R.E)
|
|
R.LOG2E = math.log(R.E, 2)
|
|
R.LOG10E = math.log(R.E, 0)
|
|
R.PI = math.pi
|
|
R.SQRT1_2 = math.sqrt(0.5)
|
|
R.SQRT2 = math.sqrt(2)
|
|
R.MAX_SAFE_INTEGER=9007199254740991
|
|
R.MIN_SAFE_INTEGER=-9007199254740992
|
|
R.MAX_DISP_INTEGER=1000000
|
|
R.NaN=0/0
|
|
R.NEGATIVE_INFINITY = -1/0
|
|
R.POSITIVE_INFINITY = 1/0
|
|
R.E_MAX_SAFE_INTEGER="e"..tostring(R.MAX_SAFE_INTEGER)
|
|
R.EE_MAX_SAFE_INTEGER="ee"..tostring(R.MAX_SAFE_INTEGER)
|
|
R.TETRATED_MAX_SAFE_INTEGER="10^^"..tostring(R.MAX_SAFE_INTEGER)
|
|
|
|
return Big |