balatro-mods/Talisman/big-num/omeganum.lua
2025-01-19 15:01:49 +08:00

1340 lines
36 KiB
Lua

--OmegaNum port by Mathguy
Big = {
array = {},
sign = 1
}
maxArrow = 1e3
OmegaMeta = {}
OmegaMeta.__index = Big
external = true
omegaNumError = "[OmegaNumError] "
invalidArgument = omegaNumError .. "Invalid argument: "
isOmegaNum = "/^[-\\+]*(Infinity|NaN|(10(\\^+|\\{[1-9]\\d*\\})|\\(10(\\^+|\\{[1-9]\\d*\\})\\)\\^[1-9]\\d* )*((\\d+(\\.\\d*)?|\\d*\\.\\d+)?([Ee][-\\+]*))*(0|\\d+(\\.\\d*)?|\\d*\\.\\d+))$/"
MAX_SAFE_INTEGER = 9007199254740991
MAX_E = math.log(MAX_SAFE_INTEGER, 10)
LONG_STRING_MIN_LENGTH = 17
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=MAX_SAFE_INTEGER
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)
--------------make the numbers look good----------------------
function thousands_format(number)
return string.format("%.2f", number)
end
function AThousandNotation(n, places)
local raw = string.format("%." .. places .."f", n)
local result = ""
local comma = string.find(raw, "%.")
if comma == nil then
comma = #raw
else
comma = comma - 1
end
for i = 1, #raw do
result = result .. string.sub(raw, i, i)
if (comma - i) % 3 == 0 and i < comma then
result = result .. ","
end
end
return result
end
------------------------------------------------------
function Big:new(arr)
return setmetatable({array = arr, sign = 1}, OmegaMeta):normalize()
end
function Big:isNaN()
return self.array[1] ~= self.array[1]
end
function Big:isInfinite()
return (self.array[1] == R.POSITIVE_INFINITY) or (self.array[1] == R.NEGATIVE_INFINITY)
end
function Big:isFinite()
return (not self:isInfinite() and not self:isNaN())
end
function Big:isint()
if (self.sign==-1) then
return self:abs():isint()
end
if (self:gt(R.MAX_SAFE_INTEGER)) then
return true;
end
local num = self:to_number()
return (math.floor(num) == num);
end
function Big:compareTo(other)
other = Big:create(other)
if ((self.array[1] ~= self.array[1]) or (other.array[1] ~= other.array[1])) then
return R.NaN;
end
if ((self.array[1]==R.POSITIVE_INFINITY) and (other.array[1]~=R.POSITIVE_INFINITY)) then
return self.sign
end
if ((self.array[1]~=R.POSITIVE_INFINITY) and (other.array[1]==R.POSITIVE_INFINITY)) then
return other.sign
end
if ((#self.array==1) and (self.array[1]==0) and (#other.array==1) and (other.array[1]==0)) then
return 0
end
if (self.sign~=other.sign) then
return self.sign
end
local m = self.sign;
local r = nil;
if (#self.array>#other.array) then
r = 1;
elseif (#self.array<#other.array) then
r = -1;
else
for i=#self.array,1,-1 do
if (self.array[i]>other.array[i]) then
r = 1;
break;
elseif (self.array[i]<other.array[i]) then
r = -1
break
end
r = r or 0;
end
end
return r * m;
end
function Big:lt(other)
return self:compareTo(other) < 0
end
function Big:gt(other)
return self:compareTo(other) > 0
end
function Big:lte(other)
return self:compareTo(other) <= 0
end
function Big:gte(other)
return self:compareTo(other) >= 0
end
function Big:eq(other)
return self:compareTo(other) == 0
end
function Big:neg()
local x = self:clone();
x.sign = x.sign * -1;
return x;
end
function Big:abs()
local x = self:clone();
x.sign = 1;
return x;
end
function Big:min(other)
if (self:lt(other)) then
return self:clone()
else
return Big:create(other)
end
end
function Big:max(other)
if (self:gt(other)) then
return self:clone()
else
return Big:create(other)
end
end
function Big:normalize()
local b = nil
local x = self
if ((x.array == nil) or (type(x.array) ~= "table") or (#x.array == 0)) then
x.array = {0}
end
if (#x.array == 1) and (x.array[1] == 0) then
x.sign = 1
return x
end
if (#x.array == 1) and (x.array[1] < 0) then
x.sign = -1
x.array[1] = -x.array[1]
end
if ((x.sign~=1) and (x.sign~=-1)) then
-- if (typeof x.sign!="number") x.sign=Number(x.sign);
if (x.sign < 0) then
x.sign = -1;
else
x.sign = 1;
end
end
local l = 0
for i ,j in pairs(x.array) do
if i > l then
l = i
end
end
for i=1,l do
local e = x.array[i];
if ((e == nil)) then
x.array[i] = 0
e = 0
end
if (e ~= e) then
x.array={R.NaN};
return x;
end
if (e == R.POSITIVE_INFINITY) or (e == R.NEGATIVE_INFINITY) then
x.array = {R.POSITIVE_INFINITY};
return x;
end
if (i ~= 1) then
x.array[i]=math.floor(e)
end
end
local doOnce = true
while (doOnce or b) do
-- if (OmegaNum.debug>=OmegaNum.ALL) console.log(x.toString());
b=false;
while ((#x.array ~= 0) and (x.array[#x.array]==0)) do
x.array[#x.array] = nil;
b=true;
end
if (x.array[1] > R.MAX_DISP_INTEGER) then --modified, should make printed values easier to display
x.array[2]=(x.array[2] or 0) + 1;
x.array[1]= math.log(x.array[1], 10);
b=true;
end
while ((x.array[1] < math.log(R.MAX_DISP_INTEGER,10)) and ((x.array[2] ~= nil) and (x.array[2] ~= 0))) do
x.array[1] = math.pow(10,x.array[1], 10);
x.array[2] = x.array[2] - 1
b=true;
end
-- if ((#x.array>2) and ((x.array[2] == nil) or (x.array[2] == 0))) then
-- local i = 3
-- while (x.array[i] == nil) or (x.array[i] == 0) do
-- i = i + 1
-- end
-- x.array[i-1]=x.array[1];
-- x.array[1]=1;
-- x.array[i] = x.array[i] - 1
-- b=true;
-- end
doOnce = false;
l = #x.array
for i=1,l do
if (x.array[i]>R.MAX_SAFE_INTEGER) then
x.array[i+1]=(x.array[i+1] or 0)+1;
x.array[1]=x.array[i]+1;
for j=2,i do
x.array[j]=0;
end
b=true;
end
end
end
if (#x.array == 0) then
x.array = {0}
end
return x;
end
function Big:toString()
if (self.sign==-1) then
return "-" .. self:abs():toString()
end
if (self.array[1] ~= self.array[1]) then
return "NaN"
end
-- if (!isFinite(this.array[0])) return "Infinity";
local s = "";
if (#self.array>=2) then
for i=#self.array,3,-1 do
local q = nil
if (i >= 6) then
q = "{"..(i-1).."}"
else
q = string.rep("^", i-1)
end
if (self.array[i]>1) then
s = s .."(10" .. q .. ")^" .. AThousandNotation(self.array[i], 0) .. " "
elseif (self.array[i]==1) then
s= s .."10" .. q;
end
end
end
if (self.array[2] == nil) or (self.array[2] == 0) then
if (self.array[1] <= 9e9) then
s = s .. AThousandNotation(self.array[1], 2)
else
local exponent = math.floor(math.log(self.array[1], 10))
local mantissa = math.floor((self.array[1] / (10^exponent))*100)/100
s = s .. AThousandNotation(mantissa, 2) .. "e" .. AThousandNotation(exponent, 0)
end
elseif (self.array[2]<3) then
s = s .. string.rep("e", self.array[2]-1) .. AThousandNotation(math.pow(10,self.array[1]-math.floor(self.array[1])), 2) .. "e" .. AThousandNotation(math.floor(self.array[1]), 0);
elseif (self.array[2]<8) then
s = s .. string.rep("e", self.array[2]) .. AThousandNotation(self.array[1], 0)
else
s = s .. "(10^)^" .. AThousandNotation(self.array[2], 0) .. " " .. AThousandNotation(self.array[1],0)
end
return s
end
function log10LongString(str)
return math.log(tonumber(string.sub(str, 1, LONG_STRING_MIN_LENGTH)), 10)+(string.len(str)- LONG_STRING_MIN_LENGTH);
end
function Big:parse(input)
-- if (typeof input!="string") throw Error(invalidArgument+"Expected String");
-- var isJSON=false;
-- if (typeof input=="string"&&(input[0]=="["||input[0]=="{")){
-- try {
-- JSON.parse(input);
-- }finally{
-- isJSON=true;
-- }
-- }
-- if (isJSON){
-- return OmegaNum.fromJSON(input);
-- }
local x = Big:new({0})
-- if (!isOmegaNum.test(input)){
-- console.warn(omegaNumError+"Malformed input: "+input);
-- x.array=[NaN];
-- return x;
-- }
local negateIt = false
while ((string.sub(input, 1, 1)=="-") or (string.sub(input, 1, 1)=="+")) do
if (string.sub(input, 1, 1)=="-") then
negateIt = not negateIt
end
input = string.sub(input, 2);
end
if (input=="NaN") or (input=="nan") then
x.array = {R.NaN}
elseif (input=="Infinity") or (input=="inf") then
x.array = {R.POSITIVE_INFINITY}
else
local a = 0
local b = 0
local c = 0
local d = 0
local i = 0
while (string.len(input) > 0) do
local passTest = false
if true then
local j = 1
if string.sub(input, 1, 1) == "(" then
j = j + 1
end
if (string.sub(input, j, j+1) == "10") and ((string.sub(input, j+2, j+2) == "^") or (string.sub(input, j+2, j+2) == "{")) then
passTest = true
end
end
if (passTest) then
if (string.sub(input, 1, 1) == "(") then
input = string.sub(input, 2);
end
local arrows = -1;
if (string.sub(input, 3, 3)=="^") then
arrows = 3
while (string.sub(input, arrows, arrows) == "^") do
arrows = arrows + 1
end
arrows = arrows - 3
a = arrows
b = arrows + 2;
else
a = 1
while (string.sub(input, a, a) ~= "}") do
a = a + 1
end
arrows=tonumber(string.sub(input, 4, a - 1))+1;
b = a + 1
end
--[[if (arrows >= maxArrow) then
-- console.warn("Number too large to reasonably handle it: tried to "+arrows.add(2)+"-ate.");
x.array = {R.POSITIVE_INFINITY};
break;
end--]]
input = string.sub(input, b + 1);
if (string.sub(input, 1, 1) == ")") then
a = 1
while (string.sub(input, a, a) ~= " ") do
a = a + 1
end
c = tonumber(string.sub(input, 3, a - 1));
input = string.sub(input, a+1);
else
c = 1
end
if (arrows==1) then
x.array[2] = (x.array[2] or 0) + c;
elseif (arrows==2) then
a = x.array[2] or 0;
b = x.array[1] or 0;
if (b>=1e10) then
a = a + 1
end
if (b>=10) then
a = a + 1
end
x.array[1]=a;
x.array[2]=0;
x.array[3]=(x.array[3] or 0)+c;
else
a=x.array[arrows] or 0;
b=x.array[arrows-1] or 0;
if (b>=10) then
a = a + 1
end
for i=1, arrows do
x.array[i] = 0;
end
x.array[1]=a;
x.array[arrows+1] = (x.array[arrows+1] or 0) + c;
end
else
break
end
end
a = {""}
while (string.len(input) > 0) do
if ((string.sub(input, 1, 1) == "e") or (string.sub(input, 1, 1) == "E")) then
a[#a + 1] = ""
else
a[#a] = a[#a] .. string.sub(input, 1, 1)
end
input = string.sub(input, 2);
end
if a[#a] == "" then
a[#a] = nil
end
b={x.array[1],0};
c=1;
for i=#a, 1, -1 do
if ((b[1] < MAX_E) and (b[2]==0)) then
b[1] = math.pow(10,c*b[1]);
elseif (c==-1) then
if (b[2]==0) then
b[1]=math.pow(10,c*b[1]);
elseif ((b[2]==1) and (b[1]<=308)) then
b[1] = math.pow(10,c*math.pow(10,b[1]));
else
b[1]=0;
end
b[2]=0;
else
b[2] = b[2] + 1;
end
local decimalPointPos = 1;
while ((string.sub(a[i], decimalPointPos, decimalPointPos) ~= ".") and (decimalPointPos <= #a[i])) do
decimalPointPos = decimalPointPos + 1
end
if decimalPointPos == #a[i] + 1 then
decimalPointPos = -1
end
local intPartLen = -1
if (decimalPointPos == -1) then
intPartLen = #a[i] + 1
else
intPartLen = decimalPointPos
end
if (b[2] == 0) then
if (intPartLen - 1 >= LONG_STRING_MIN_LENGTH) then
b[1] = math.log10(b[1]) + log10LongString(string.sub(a[i], 1, intPartLen - 1))
b[2] = 1;
elseif ((a[i] ~= nil) and (a[i] ~= "")) then
b[1] = b[1] * tonumber(a[i]);
end
else
d=-1
if (intPartLen - 1 >= LONG_STRING_MIN_LENGTH) then
d = log10LongString(string.sub(a[i], 1,intPartLen - 1))
else
if (a[i] ~= nil) and (a[i] ~= "") and (tonumber(a[i]) ~= nil) then
d = math.log(tonumber(a[i]), 10)
else
d = 0
end
end
if (b[2]==1) then
b[1] = b[1] + d;
elseif ((b[2]==2) and (b[1]<MAX_E+math.log(d, 10))) then
b[1] = b[1] + math.log(1+math.pow(10,Math.log10(d)-b[0]), 10);
end
end
if ((b[1]<MAX_E) and (b[2] ~= 0) and (b[2] ~= nil)) then
b[1]=math.pow(10,b[1]);
b[2] = b[2] - 1;
elseif (b[1]>MAX_SAFE_INTEGER) then
b[1] = math.log(b[1], 10);
b[2] = b[2] + 1;
end
end
x.array[1]= b[1];
x.array[2]= (x.array[2] or 0) + b[2];
end
if (negateIt) then
x.sign = x.sign * -1
end
x:normalize();
return x;
end
function Big:to_number()
-- //console.log(this.array);
if (self.sign==-1) then
return -1*(self:neg():to_number());
end
if ((#self.array>=2) and ((self.array[2]>=2) or (self.array[2]==1) and (self.array[1]>308))) then
return R.POSITIVE_INFINITY;
end
if (#self.array >= 3) and ((self.array[1] >= 3) or (self.array[2] >= 1) or (self.array[3] >= 1)) then
return R.POSITIVE_INFINITY;
end
if (#self.array >= 4) and ((self.array[1] > 1) or (self.array[2] >= 1) or (self.array[3] >= 1)) then
for i = 4, #self.array do
if self.array[i] > 0 then
return R.POSITIVE_INFINITY;
end
end
end
if (type(self.array[1]) == "table") then
self.array[1] = self.array[1]:to_number()
end
if (self.array[2]==1) then
return math.pow(10,self.array[1]);
end
return self.array[1];
end
function Big:floor()
if (self:isint()) then
return self:clone()
end
return Big:create(math.floor(self:to_number()));
end
function Big:ceil()
if (self:isint()) then
return self:clone()
end
return Big:create(math.ceil(self:to_number()));
end
function Big:clone()
local newArr = {}
for i, j in ipairs(self.array) do
newArr[i] = j
end
local result = Big:new(newArr)
result.sign = self.sign
return result
end
function Big:create(input)
if ((type(input) == "number")) then
return Big:new({input})
elseif ((type(input) == "string")) then
return Big:parse(input)
elseif ((type(input) == "table") and getmetatable(input) == OmegaMeta) then
return input:clone()
else
return Big:new(input)
end
end
function Big:add(other)
local x = self:clone()
other = Big:create(other)
-- if (OmegaNum.debug>=OmegaNum.NORMAL){
-- console.log(this+"+"+other);
-- if (!debugMessageSent) console.warn(omegaNumError+"Debug output via 'debug' is being deprecated and will be removed in the future!"),debugMessageSent=true;
-- }
if (x.sign==-1) then
return x:neg():add(other:neg()):neg()
end
if (other.sign==-1) then
return x:sub(other:neg());
end
if (x:eq(R.ZERO)) then
return other;
end
if (other:eq(R.ZERO)) then
return x;
end
if (x:isNaN() or other:isNaN() or (x:isInfinite() and other:isInfinite() and x:eq(other:neg()))) then
return Big:create(R.NaN);
end
if (x:isInfinite()) then
return x;
end
if (other:isInfinite()) then
return other;
end
local p=x:min(other);
local q=x:max(other);
local t = -1;
if (p.array[2] == 2) and not p:gt(R.E_MAX_SAFE_INTEGER) then
p.array[2] = 1
p.array[1] = 10 ^ p.array[1]
end
if (q.array[2] == 2) and not q:gt(R.E_MAX_SAFE_INTEGER) then
q.array[2] = 1
q.array[1] = 10 ^ q.array[1]
end
if (q:gt(R.E_MAX_SAFE_INTEGER) or q:div(p):gt(R.MAX_SAFE_INTEGER)) then
t = q;
elseif (q.array[2] == nil) or (q.array[2] == 0) then
t= Big:create(x:to_number()+other:to_number());
elseif (q.array[2]==1) then
if (p.array[2] ~= nil) and (p.array[2] ~= 0) then
a = p.array[1]
else
a = math.log(p.array[1], 10)
end
t = Big:new({a+math.log(math.pow(10,q.array[1]-a)+1, 10),1});
end
p = nil
q = nil
return t;
end
function Big:sub(other)
local x = self:clone()
other = Big:create(other)
-- if (OmegaNum.debug>=OmegaNum.NORMAL) console.log(x+"-"+other);
if (x.sign==-1) then
return x:neg():sub(other:neg()):neg()
end
if (other.sign==-1) then
return x:add(other:neg())
end
if (x:eq(other)) then
return Big:create(R.ZERO)
end
if (other:eq(R.ZERO)) then
return x;
end
if (x:isNaN() or other:isNaN() or (x:isInfinite() and other:isInfinite() and x:eq(other:neg()))) then
return Big:create(R.NaN)
end
if (x:isInfinite()) then
return x
end
if (other:isInfinite()) then
return other:neg()
end
local p = x:min(other);
local q = x:max(other);
local n = other:gt(x);
local t = -1;
if (p.array[2] == 2) and not p:gt(R.E_MAX_SAFE_INTEGER) then
p.array[2] = 1
p.array[1] = 10 ^ p.array[1]
end
if (q.array[2] == 2) and not q:gt(R.E_MAX_SAFE_INTEGER) then
q.array[2] = 1
q.array[1] = 10 ^ q.array[1]
end
if (q:gt(R.E_MAX_SAFE_INTEGER) or q:div(p):gt(R.MAX_SAFE_INTEGER)) then
t = q;
if n then
t = t:neg()
else
t = t
end
elseif (q.array[2] == nil) or (q.array[2] == 0) then
t = Big:create(x:to_number()-other:to_number());
elseif (q.array[2]==1) then
if (p.array[2] ~= nil) and (p.array[2] ~= 0) then
a = p.array[1]
else
a = math.log(p.array[1], 10)
end
t = Big:new({a+math.log(math.pow(10,q.array[1]-a)-1, 10),1});
if n then
t = t:neg()
else
t = t
end
end
p = nil
q = nil
return t;
end
function Big:div(other)
local x = self:clone();
other = Big:create(other);
-- if (OmegaNum.debug>=OmegaNum.NORMAL) then
-- console.log(x+"/"+other);
if (x.sign*other.sign==-1) then
return x:abs():div(other:abs()):neg()
end
if (x.sign==-1) then
return x:abs():div(other:abs())
end
if (x:isNaN() or other:isNaN() or (x:isInfinite() and other:isInfinite() and x:eq(other:neg()))) then
return Big:create(R.NaN)
end
if (other:eq(R.ZERO)) then
Big:create(R.POSITIVE_INFINITY)
end
if (other:eq(R.ONE)) then
return x:clone()
end
if (x:eq(other)) then
return Big:create(R.ONE)
end
if (x:isInfinite()) then
return x
end
if (other:isInfinite()) then
return Big:create(R.ZERO)
end
if (x:max(other):gt(R.EE_MAX_SAFE_INTEGER)) then
if x:gt(other) then
return x:clone()
else
return Big:create(R.ZERO)
end
end
local n = x:to_number()/other:to_number();
if (n<=MAX_SAFE_INTEGER) then
return Big:create(n)
end
local pw = Big:create(10):pow(x:log10():sub(other:log10()))
local fp = pw:floor()
if (pw:sub(fp):lt(Big:create(1e-9))) then
return fp
end
return pw
end
function Big:mul(other)
local x = self:clone();
other = Big:create(other);
-- if (OmegaNum.debug>=OmegaNum.NORMAL) console.log(x+"*"+other);
if (x.sign*other.sign==-1) then
return x:abs():mul(other:abs()):neg()
end
if (x.sign==-1) then
return x:abs():mul(other:abs())
end
if (x:isNaN() or other:isNaN() or (x:isInfinite() and other:isInfinite() and x:eq(other:neg()))) then
return Big:create(R.NaN)
end
if (other:eq(R.ZERO)) then
return Big:create(R.ZERO)
end
if (other:eq(R.ONE)) then
return x:clone()
end
if (x:isInfinite()) then
return x
end
if (other:isInfinite()) then
return other
end
if (x:max(other):gt(R.EE_MAX_SAFE_INTEGER)) then
return x:max(other)
end
local n = x:to_number()*other:to_number()
if (n<=MAX_SAFE_INTEGER) then
return Big:create(n)
end
return Big:create(10):pow(x:log10():add(other:log10()));
end
function Big:rec()
if (self:isNaN() or self:eq(R.ZERO)) then
return Big:create(R.NaN)
end
if (self:abs():gt("2e323")) then
return Big:create(R.ZERO)
end
return Big:create(R.ONE):div(self)
end
function Big:logBase(base)
if base == nil then
base = Big:create(R.E)
end
return self:log10():div(base:log10())
end
function Big:log10()
local x = self:clone();
-- if (OmegaNum.debug>=OmegaNum.NORMAL) console.log("log"+this);
if (x:lt(R.ZERO)) then
return Big:create(R.NaN)
end
if (x:eq(R.ZERO)) then
return Big:create(R.NEGATIVE_INFINITY)
end
if (x:lte(R.MAX_SAFE_INTEGER)) then
return Big:create(math.log(x:to_number(), 10))
end
if (not x:isFinite()) then
return x;
end
if (x:gt(R.TETRATED_MAX_SAFE_INTEGER)) then
return x;
end
x.array[2] = x.array[2] - 1;
return x:normalize()
end
function Big:ln()
base = Big:create(R.E)
return self:log10():div(base:log10())
end
function Big:pow(other)
other = Big:create(other);
-- if (OmegaNum.debug>=OmegaNum.NORMAL) console.log(this+"^"+other);
if (other:eq(R.ZERO)) then
return Big:create(R.ONE)
end
if (other:eq(R.ONE)) then
return self:clone()
end
if (other:lt(R.ZERO)) then
return self:pow(other:neg()):rec()
end
if (self:lt(R.ZERO) and other:isint()) then
if (other:mod(2):lt(R.ONE)) then
return self:abs():pow(other)
end
return self:abs():pow(other):neg()
end
if (self:lt(R.ZERO)) then
return Big:create(R.NaN)
end
if (self:eq(R.ONE)) then
return Big:create(R.ONE)
end
if (self:eq(R.ZERO)) then
return Big:create(R.ZERO)
end
if (self:max(other):gt(R.TETRATED_MAX_SAFE_INTEGER)) then
return self:max(other);
end
if (self:eq(10)) then
if (other:gt(R.ZERO)) then
other.array[2] = (other.array[2] or 0) + 1;
other:normalize();
return other;
else
return Big:create(math.pow(10,other:to_number()));
end
end
if (other:lt(R.ONE)) then
return self:root(other:rec())
end
local n = math.pow(self:to_number(),other:to_number())
if (n<=MAX_SAFE_INTEGER) then
return Big:create(n);
end
return Big:create(10):pow(self:log10():mul(other));
end
function Big:exp()
return Big:create(R.E, self)
end
function Big:root(other)
other = Big:create(other)
-- if (OmegaNum.debug>=OmegaNum.NORMAL) console.log(this+"root"+other);
if (other:eq(R.ONE)) then
return self:clone()
end
if (other:lt(R.ZERO)) then
return self:root(other:neg()):rec()
end
if (other:lt(R.ONE)) then
return self:pow(other:rec())
end
if (self:lt(R.ZERO) and other:isint() and other:mod(2):eq(R.ONE)) then
return self:neg():root(other):neg()
end
if (self:lt(R.ZERO)) then
return Big:create(R.NaN)
end
if (self:eq(R.ONE)) then
return Big:create(R.ONE)
end
if (self:eq(R.ZERO)) then
return Big:create(R.ZERO)
end
if (self:max(other):gt(R.TETRATED_MAX_SAFE_INTEGER)) then
if self:gt(other) then
return self:clone()
else
Big:create(R.ZERO)
end
end
return Big:create(10):pow(self:log10():div(other));
end
function Big:slog(base)
if base == nil then
base = 10
end
local x = Big:create(self)
base = Big:create(base)
if (x:isNaN() or base:isNaN() or (x:isInfinite() and base:isInfinite())) then
return Big:create(R.NaN)
end
if (x:isInfinite()) then
return x;
end
if (base:isInfinite()) then
return Big:create(R.ZERO)
end
if (x:lt(R.ZERO)) then
return Big:create(-R.ONE)
end
if (x:lt(R.ONE)) then
return Big:create(R.ZERO)
end
if (x:eq(base)) then
return Big:create(R.ONE)
end
if (base:lt(math.exp(1/R.E))) then
local a = base:tetrate(1/0)
if (x:eq(a)) then
return Big:create(R.POSITIVE_INFINITY)
end
if (x:gt(a)) then
return Big:create(R.NaN)
end
end
if (x:max(base):gt("10^^^" .. R.MAX_SAFE_INTEGER)) then
if (x:gt(base)) then
return x;
end
return Big:create(R.ZERO)
end
if (x:max(base):gt(R.TETRATED_MAX_SAFE_INTEGER)) then
if x:gt(base) then
x.array[3] = x.array[3] - 1
x:normalize()
return x:sub(x.array[2])
end
return Big:create(R.ZERO)
end
local r = 0
local t = (x.array[2] or 0) - (base.array[2] or 0)
if (t > 3) then
local l = t - 3
r = r + l
x.array[2] = x.array[2] - l
end
for i = 0, 99 do
if x:lt(R.ZERO) then
x = base:pow(x)
r = r - 1
elseif (x:lte(R.ONE)) then
return Big:create(r + x:to_number() - 1)
else
r = r + 1
x = x:logBase(base)
end
end
if (x:gt(10)) then
return Big:create(r)
end
end
function Big:tetrate(other)
local t = self:clone()
other = Big:create(other)
local negln = nil
if (t:isNaN() or other:isNaN()) then
return Big:create(R.NaN)
end
if (other:isInfinite() and other.sign > 0) then
negln = t:ln():neg()
return negln:lambertw():div(negln)
end
if (other:lte(-2)) then
return Big:create(R.NaN)
end
if (t:eq(R.ZERO)) then
if (other:eq(R.ZERO)) then
return Big:create(R.NaN)
end
if (other:mod(2):eq(R.ZERO)) then
return Big:create(R.ZERO)
end
return Big:create(R.ONE)
end
if (t:eq(R.ONE)) then
if (other:eq(-1)) then
return Big:create(R.NaN)
end
return Big:create(R.ONE)
end
if (other:eq(-1)) then
return Big:create(R.ZERO)
end
if other:eq(R.ZERO) then
return Big:create(R.ONE)
end
if other:eq(R.ONE) then
return t
end
if other:eq(2) then
return t:pow(t)
end
if t:eq(2) then
if other:eq(3) then
return Big:create({16})
end
if other:eq(4) then
return Big:create({65536})
end
end
local m = t:max(other)
if (m:gt(Big:create("10^^^" .. tostring(R.MAX_SAFE_INTEGER)))) then
return m
end
if (m:gt(R.TETRATED_MAX_SAFE_INTEGER) or other:gt(MAX_SAFE_INTEGER)) then
if (t:lt(math.exp(1/R.E))) then
negln = t:ln():neg()
return negln:lambertw():div(negln)
end
local j = t:slog(10):add(other)
j.array[3]=(j.array[3] or 0) + 1
j:normalize()
return j
end
local y = other:to_number()
local f = math.floor(y)
local r = t:pow(y-f)
local l = Big:create(R.NaN)
local i = 0
local m = Big:create(R.E_MAX_SAFE_INTEGER)
while ((f ~= 0) and r:lt(m) and (i < 100)) do
if (f > 0) then
r = t:pow(r)
if (l:eq(r)) then
f = 0
break
end
l = r
f = f - 1
else
r = r:logBase(t)
if (l:eq(r)) then
f = 0
break
end
l = r
f = f + 1
end
end
if ((i == 100) or t:lt(math.exp(1/R.E))) then
f = 0
end
r.array[2] = (r.array[2] or 0) + f
r:normalize()
return r;
end
function Big:arrow(arrows, other)
local t = self:clone()
arrows = Big:create(arrows)
if (not arrows:isint() or arrows:lt(R.ZERO)) then
return Big:create(R.NaN)
end
if arrows:eq(R.ZERO) then
return t:mul(other)
end
if arrows:eq(R.ONE) then
return t:pow(other)
end
if arrows:eq(2) then
return t:tetrate(other)
end
other = Big:create(other)
if (other:lt(R.ZERO)) then
return Big:create(R.NaN)
end
if (other:eq(R.ZERO)) then
return Big:create(R.ONE)
end
if (other:eq(R.ONE)) then
return t:clone()
end
--[[if (arrows:gte(maxArrow)) then
return Big:create(R.POSITIVE_INFINITY)
end--]]
local arrowsNum = arrows:to_number()
if (other:eq(2)) then
return t:arrow(arrows:sub(R.ONE), t)
end
if (t:max(other):gt("10{"..tostring(arrowsNum+1).."}"..tostring(R.MAX_SAFE_INTEGER))) then
return t:max(other)
end
local r = nil
if (t:gt("10{"..tostring(arrowsNum).."}"..tostring(R.MAX_SAFE_INTEGER)) or other:gt(R.MAX_SAFE_INTEGER)) then
if (t:gt("10{"..tostring(arrowsNum).."}"..tostring(R.MAX_SAFE_INTEGER))) then
r = t:clone()
r.array[arrowsNum + 1] = r.array[arrowsNum + 1] - 1
r:normalize()
elseif (t:gt("10{"..tostring(arrowsNum - 1).."}"..tostring(R.MAX_SAFE_INTEGER))) then
r = Big:create(t.array[arrowsNum])
else
r = Big:create(R.ZERO)
end
local j = r:add(other)
j.array[arrowsNum+1] = (j.array[arrowsNum+1] or 0) + 1
j:normalize()
return j
end
local y = other:to_number()
local f = math.floor(y)
local arrows_m1 = arrows:sub(R.ONE)
local i = 0
local m = Big:create("10{"..tostring(arrowsNum - 1).."}"..tostring(R.MAX_SAFE_INTEGER))
r = t:arrow(arrows_m1, y-f)
while (f ~= 0) and r:lt(m) and (i<100) do
if (f > 0) then
r = t:arrow(arrows_m1, r)
f = f - 1
end
i = i + 1
end
if (i == 100) then
f = 0
end
r.array[arrowsNum] = (r.array[arrowsNum] or 0) + f
r:normalize()
return r
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:lambertw()
local x = self:clone()
if (x:isNaN()) then
return x;
end
if (x:lt(-0.3678794411710499)) then
print("lambertw is unimplemented for results less than -1, sorry!")
local a = nil
return a.b
end
if (x:gt(R.TETRATED_MAX_SAFE_INTEGER)) then
return x;
end
if (x:gt(R.EE_MAX_SAFE_INTEGER)) then
x.array[1] = x.array[1] - 1
return x;
end
if (x:gt(R.E_MAX_SAFE_INTEGER)) then
return Big:d_lambertw(x)
else
return Big:create(Big:f_lambertw(x.sign*x.array[1]))
end
end
function Big:f_lambertw(z)
local tol = 1e-10
local w = nil
local wn = nil
local OMEGA = 0.56714329040978387299997
if (not Big:create(z):isFinite()) then
return z;
end
if z == 0 then
return z;
end
if z == 1 then
return OMEGA
end
if (z < 10) then
w = 0
else
w = math.log(z) - math.log(math.log(z))
end
for i=0,99 do
wn = (z*math.exp(-w)+w*w)/(w+1)
if (math.abs(wn-w)<tol*math.abs(wn)) then
return wn
end
w=wn
end
print("Iteration failed to converge: "+z)
local a = nil
return a.b
end
function Big:d_lambertw(z)
local tol = 1e-10
z = Big:create(z)
local w = nil
local ew = nil
local wewz = nil
local wn = nil
local OMEGA = 0.56714329040978387299997
if (not z:isFinite()) then
return z;
end
if (z == 0) then
return z
end
if (z == 1) then
return OMEGA
end
w = z:ln()
for i=0, 99 do
ew = w:neg():exp()
wewz = w:sub(z:mul(ew))
wn = w:sub(wewz:div(w:add(R.ONE):sub((w:add(2)):mul(wewz):div((w:mul(2):add(2))))))
if (wn:sub(w):abs():lt(wn:abs():mul(tol))) then
return wn
end
w = wn
end
print("Iteration failed to converge: "+z)
local a = nil
return a.b
end
------------------------metastuff----------------------------
function OmegaMeta.__add(b1, b2)
if type(b1) == "number" then
return Big:create(b1):add(b2)
end
return b1:add(b2)
end
function OmegaMeta.__sub(b1, b2)
if type(b1) == "number" then
return Big:create(b1):sub(b2)
end
return b1:sub(b2)
end
function OmegaMeta.__mul(b1, b2)
if type(b1) == "number" then
return Big:create(b1):mul(b2)
end
return b1:mul(b2)
end
function OmegaMeta.__div(b1, b2)
if type(b1) == "number" then
return Big:create(b1):div(b2)
end
return b1:div(b2)
end
function OmegaMeta.__mod(b1, b2)
if type(b1) == "number" then
return Big:create(b1):mod(b2)
end
return b1:mod(b2)
end
function OmegaMeta.__unm(b)
return b:neg()
end
function OmegaMeta.__pow(b1, b2)
if type(b1) == "number" then
return Big:create(b1):pow(b2)
end
return b1:pow(b2)
end
function OmegaMeta.__le(b1, b2)
b1 = Big:create(b1)
return b1:lte(b2)
end
function OmegaMeta.__lt(b1, b2)
b1 = Big:create(b1)
return b1:lt(b2)
end
function OmegaMeta.__ge(b1, b2)
b1 = Big:create(b1)
return b1:gte(b2)
end
function OmegaMeta.__gt(b1, b2)
b1 = Big:create(b1)
return b1:gt(b2)
end
function OmegaMeta.__eq(b1, b2)
b1 = Big:create(b1)
return b1:eq(b2)
end
function OmegaMeta.__tostring(b)
return number_format(b)
end
---------------------------------------
return Big