SHARE
TWEET

Metaint

ZNZNCOOP May 17th, 2018 (edited) 146 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top