Advertisement
ZNZNCOOP

Metaint

May 17th, 2018
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.56 KB | None | 0 0
  1. -- Метачисла позволяют оперировать огромными значениями. Например, посчитать факториал 300 или вычислить 2^2048 --
  2. --        Выражаю признательность HeroBrine1st (http://computercraft.ru/profile/19680-herobrine1st/),           --
  3. --              стараниями которого данная библиотека была доведена до логического завершения                   --
  4.  
  5. local metaint,m_table
  6. local b=7
  7. local base=10^b
  8.  
  9. local function div2(num) --целочисленное деление метачисла на 2
  10.   local c=0
  11.   for i=#num,1,-1 do
  12.     num[i],c = math.floor((c*base+num[i])/2), num[i]%2
  13.   end
  14.   while num[#num]==0 and #num>1 do num[#num]=nil end
  15.   return num
  16. end
  17.  
  18. local function div( op1, op2 )
  19.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  20.     if op2[1]==0 and op2[2]==nil then error("Division by zero",2) end -- проверяем деление на ноль
  21.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  22.     local quotient=metaint(0)      -- частное
  23.     local reminder=metaint(op1)    -- остаток
  24.     local c = {} -- промежуточный множитель
  25.       for i=1,#op1-#op2+1 do
  26.         c[i]=op1[#op2-1+i]
  27.       end
  28.     setmetatable(c,m_table)
  29.     local d
  30.     while reminder >= op2 do
  31.       d = c * op2 -- просто чтобы уйти от лишнего умножения
  32.       if reminder >= d then
  33.         quotient = quotient + c -- увеличиваем частное
  34.         reminder = reminder - d -- уменьшаем остаток
  35.       else
  36.         div2(c)                 -- или промежуточный множитель
  37.       end
  38.     end
  39.     return quotient, reminder
  40. end
  41.  
  42. m_table={ --Метатаблица для работы с метачислами
  43.   __index={
  44.     tonumber=function(self)  --Преобразует метачисло в обычное число (возможна потеря точности)
  45.       return tonumber(tostring(self))
  46.     end,
  47.  
  48.   pow=function(self,e,n)  --Возведение в степень e по модулю n
  49.     local a = metaint(self)
  50.     local p = metaint(e)
  51.     local res=metaint(1)
  52.     while (p[2] or p[1]~=0) do  -- p!=0
  53.       if p[1]%2==1 then
  54.         res=(res*a)%n
  55.         p[1]=p[1]-1  -- быстрое вычитание единицы
  56.       else
  57.         a=(a*a)%n
  58.         div2(p)
  59.       end
  60.     end
  61.     return res
  62.   end,
  63.  
  64.   sqrt=function(self)  -- извлечение квадратного корня (целочисленное)
  65.     local n0
  66.     local n1 = div2(self+1)
  67.     repeat
  68.       n0=n1
  69.       n1=div2(n0+self/n0)
  70.     until n1>=n0
  71.     return n0
  72.   end
  73.   },
  74.  
  75.   __tostring=function(self)  --Преобразует метачисло в строку
  76.     local res=""
  77.     local r
  78.     for i=1,#self do
  79.       r=tostring(math.floor(self[i]))
  80.       if i<#self then r=string.rep("0",b-#r)..r end
  81.       res=r..res
  82.     end
  83.     return res
  84.   end,
  85.  
  86.   __add=function(op1,op2)  --Сложение
  87.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  88.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  89.     local res={}
  90.     local c=0
  91.     for i=1,math.max(#op1,#op2) do
  92.       res[i]=(op1[i] or 0)+(op2[i] or 0)+c
  93.       if res[i]>=base then res[i]=res[i]-base c=1 else c=0 end
  94.     end
  95.     if c>0 then res[#res+1]=c end
  96.     setmetatable(res,m_table)
  97.     return res
  98.   end,
  99.  
  100.   __sub=function(op1,op2)  --Вычитание
  101.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  102.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  103.     local res={}
  104.     local c=0
  105.     for i=1,#op1 do
  106.       res[i]=op1[i]-(op2[i] or 0)-c
  107.       if res[i]<0 then res[i]=res[i]+base c=1 else c=0 end
  108.     end
  109.     while res[#res]==0 and #res>1 do res[#res]=nil end
  110.     setmetatable(res,m_table)
  111.     return res
  112.   end,
  113.  
  114.   __mul=function(op1,op2)  --Умножение
  115.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  116.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  117.     local res={}
  118.     local c,k
  119.     for i=1,#op1 do
  120.       c=0
  121.       for j=1,#op2 do
  122.         k=i+j-1
  123.         res[k]=(res[k] or 0)+op1[i]*op2[j]+c
  124.         if res[k]>=base then
  125.           c=math.floor(res[k]/base)
  126.           res[k]=res[k]-c*base
  127.         else c=0
  128.         end
  129.       end
  130.       if c>0 then res[k+1]=(res[k+1] or 0) + c end
  131.     end
  132.   while res[#res]==0 and #res>1 do res[#res]=nil end
  133.     setmetatable(res,m_table);
  134.     return res
  135.   end,
  136.  
  137.   __div=function(op1, op2)  --Целочисленное деление
  138.     local res = div(op1, op2)
  139.     return res
  140.   end,
  141.  
  142.   __mod=function(op1, op2)  --Деление по модулю
  143.     local _, res = div(op1, op2)
  144.     return res
  145.   end,
  146.  
  147.   __pow=function(op1,op2)  --Возведение в степень
  148.     if op2<0 then return metaint(0) end
  149.     if op2==0 then return metaint(1) end
  150.     if op2==1 then return metaint(op1) end
  151.     local res
  152.     if op2%2==0 then res=op1^(op2/2) return res*res end
  153.     res=op1^((op2-1)/2)
  154.     return res*res*op1
  155.   end,
  156.  
  157.   __eq=function(op1,op2)  --  ==
  158.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  159.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  160.     for i=1,math.max(#op1,#op2) do
  161.       if (op1[i] or 0)~=(op2[i] or 0) then return false end
  162.     end
  163.     return true
  164.   end,
  165.  
  166.   __lt=function(op1,op2)  --  <
  167.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  168.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  169.     for i=math.max(#op1,#op2),1,-1 do
  170.       if (op1[i] or 0)<(op2[i] or 0) then return true end
  171.       if (op1[i] or 0)>(op2[i] or 0) then return false end
  172.     end
  173.     return false
  174.   end,
  175.  
  176.   __le=function(op1,op2)  --  <=
  177.     if getmetatable(op1)~=m_table then op1=metaint(op1) end
  178.     if getmetatable(op2)~=m_table then op2=metaint(op2) end
  179.     for i=math.max(#op1,#op2),1,-1 do
  180.       if (op1[i] or 0)<(op2[i] or 0) then return true end
  181.       if (op1[i] or 0)>(op2[i] or 0) then return false end
  182.     end
  183.     return true
  184.   end,
  185.  
  186.   __concat=function(op1, op2)
  187.     return tostring(op1)..tostring(op2)
  188.   end
  189. }
  190.  
  191. --Функция создает новое метачисло из числа, строки или другого метачисла
  192. function metaint(num)
  193.   if not num or num=="" then num="0" end
  194.   local obj={}
  195.   if type(num)=="number" then
  196.     repeat
  197.       obj[#obj+1]=num % base
  198.       num=math.floor(num/base)
  199.     until num==0
  200.   elseif type(num)=="table" then
  201.     for i=1,#num do obj[i]=num[i] end
  202.   elseif type(num)=="string" then
  203.     while num~="" do
  204.       obj[#obj+1]=tonumber(num:sub(-b))
  205.       num=num:sub(1,-b-1)
  206.     end
  207.   end
  208.   setmetatable(obj,m_table)
  209.   return obj
  210. end
  211.  
  212. return metaint
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement