Code: Select all
local showtext = ""
local g = golly()
g.setbase(2)
g.setpos("0","0")
local bn = require "../gplus.bignum"
local false_literal = false
local true_literal = true
local bnParsec = BigNum.new("195435859872")
local bnParsecHalf = BigNum.mt.half(bnParsec) --BigNum.new("97717929936")
local bnParsecQuarter = BigNum.mt.half(bnParsecHalf) -- 48858964968
local bnAeon=bnParsec -- /c 195435859872
local bnAeonHalf = bnParsecHalf --/c (c=1) 97717929936
local bnTwoAeons=bnAeon+bnAeon -- maybe I have to implement multiplication and division:) 390871719744
local bnFourAeons=bnTwoAeons+bnTwoAeons -- maybe I have to implement multiplication and division:) 781743439488
local startGen = g.getgen()
local bnZero = BigNum.new(0)
local currentAeon = 0
local bnCurrentAeonBase = bnZero
local bnCurrentOffset
local nrGliderGPSECollisionsToShow = 10 -- 26 is maximum displayed, whatever bigger will be interrupted (there are 28 bits in total)
while startGen>bnCurrentAeonBase + bnAeonHalf do
bnCurrentAeonBase = bnCurrentAeonBase + bnAeon
currentAeon = currentAeon + 1
end
local startAeon = currentAeon
g.autoupdate(true_literal)
local function smoothmag(imag, fmag)
while imag ~= fmag do
if imag < fmag then
imag = imag + 1
else
imag = imag - 1
end
g.setmag(imag)
g.sleep(200)
end
return imag
end
local lastfstep
local function run_for_to(n, targetAeon, targetgen, istep, fstep, mags)
local bnTargetGen
local bnN
local magindex
local enterAeon = currentAeon
fstep = fstep or 11
if targetAeon~=nil then
if targetAeon+0>100 then
targetAeon = nil
end
end
if (targetgen ~= nil) and targetAeon ~= nil then
bnTargetGen = BigNum.new(targetgen)
if targetAeon<currentAeon then
-- g.note(showtext.." - target Aeon smaller than current one ")
return
end
while currentAeon < targetAeon do
bnCurrentAeonBase = bnCurrentAeonBase + bnAeon
currentAeon = currentAeon + 1
end
end
if (targetgen == nil or targetAeon==nil) and (n == nil) then
g.note(showtext.." - run_for_to with unknown duration")
return
end
bnCurrentOffset=BigNum.new(g.getgen()) - bnCurrentAeonBase
local bnStartGen=startGen - bnCurrentAeonBase
local bnEnterGen=bnCurrentOffset
if n ~= nil then
bnN = BigNum.new(n)
end
if (targetgen ~= nil) and (targetAeon~=nil) and (n ~= nil) then
if bnN+bnEnterGen ~= bnTargetGen then
if bnStartGen > bnTargetGen then return end -- skipping milestones to restart
if bnStartGen + bnN < bnTargetGen then -- must be script error
if bnN+bnEnterGen > bnTargetGen+BigNum.new(2^lastfstep) then
g.note(showtext.."("..currentAeon..") : - run_for_to for not matching to "..BigNum.mt.tostring(bnEnterGen).." + "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnTargetGen))
return
end
end
--g.note(showtext.."("..currentAeon..") : "..BigNum.mt.tostring(bnGen).." + "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnTargetGen).." running to first milestone after restart")
bnN = bnTargetGen - bnEnterGen
end
end
if (n==nil) then -- helper for editting at the end
bnN = bnTargetGen - bnEnterGen
--g.note(showtext.." : "..BigNum.mt.tostring(bnGen).." + "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnTargetGen))
end
if (targetgen == nil or targetAeon == nil) then -- helper for editting
bnTargetGen = bnN + bnEnterGen
while bnTargetGen>bnAeonHalf do
bnCurrentAeonBase = bnCurrentAeonBase + bnAeon
currentAeon = currentAeon + 1
bnTargetGen = bnTargetGen - bnAeon
bnEnterGen = bnEnterGen - bnAeon
end
g.setclipstr("run_for_to(\""..BigNum.mt.tostring(bnN).."\", "..currentAeon..", \""..BigNum.mt.tostring(bnTargetGen).."\"")
g.note(showtext.."("..currentAeon..") : "..BigNum.mt.tostring(bnEnterGen).." + "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnTargetGen))
end
local bnGen
local sTargetGen = BigNum.mt.tostring(bnTargetGen)
if bnN<=0 then return end
local nn=BigNum.mt.tostring(bnN)
istep = istep or math.min(30, math.floor(math.log(nn)/math.log(2))-6)
local cstep = g.getstep()
if cstep<fstep then cstep = fstep end
if cstep>istep then cstep = istep end
if mags then
magindex = 1
currmag = mags[magindex]
g.setmag(currmag)
magindex = magindex + 1
end
local bn3Eistep = BigNum.new(3*2^istep)
g.setstep(cstep)
while bnN > bnZero do
g.show(showtext.."("..currentAeon..") : "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnTargetGen).." i"..istep.." f"..fstep)
while (istep > fstep) and (bnN < bn3Eistep) do
istep = istep - 2
if istep < 0 then istep = 0 end
bn3Eistep = BigNum.new(3*2^istep)
cstep = istep
if mags and magindex <= #mags then
currmag = smoothmag(currmag, mags[magindex])
magindex = magindex + 1
end
g.setstep(cstep)
end
g.step()
bnGen=BigNum.new(g.getgen()) - bnCurrentAeonBase
bnN = bnTargetGen - bnGen
cstep = g.getstep()
if (cstep<istep) then -- owerwriting manual slowdown
cstep = cstep+1
g.setstep(cstep)
end
if (cstep>istep) then -- owerwriting manual speedup
cstep = cstep-1
g.setstep(cstep)
end
end
lastfstep = fstep
if (n==nil) and (enterAeon==currentAeon) then
-- no explicit duration when Aeon boundary is crossed
bnN=bnGen-bnEnterGen
g.setclipstr("run_for_to(\""..BigNum.mt.tostring(bnN).."\", "..currentAeon..", \""..BigNum.mt.tostring(bnGen).."\"")
g.note(showtext.."("..currentAeon..") : ".." final generation: "..BigNum.mt.tostring(bnEnterGen).." + "..BigNum.mt.tostring(bnN).."->"..BigNum.mt.tostring(bnGen))
end
end
local function run_from_to(bnN, targetAeon, bnTargetGen, istep, fstep, mags)
--bnTargetgen big number not nil (bnN==nil if to new Aeon)
if bnN==nil then
--g.note("T:"..BigNum.mt.tostring(bnTargetGen).." D:nil")
run_for_to(nil, targetAeon, BigNum.mt.tostring(bnTargetGen), istep, fstep, mags)
else
local bnDuration = bnTargetGen - bnN
--g.note("T:"..BigNum.mt.tostring(bnTargetGen).." D:"..BigNum.mt.tostring(bnDuration))
run_for_to(BigNum.mt.tostring(bnDuration), targetAeon, BigNum.mt.tostring(bnTargetGen), istep, fstep, mags)
end
end
local function distance_bits(prevTime)
-- somehow when interrupted, restart skips to "remaining bits read" ... I should check why it happens, but it is method how to speed the show up,
-- so it looks like desired feature.
local bngcCollisionPos = bnParsecQuarter+0
local bngcCollisionTime = -bnAeon-bnTwoAeons
local collisionAeon=10 -- 3rd collision only
local bnReadTime = -bnTwoAeons
local gnPrevTime = BigNum.new(prevTime)
local bngcCollisionTimeOffs
local bnReadTimeOffs
local i
-- 12-8 12-4 12-2 12-1 12-0.5
-- 12-6 12-3 12-1.5 12-0.75
for i=3,nrGliderGPSECollisionsToShow,1 do
bngcCollisionPos=BigNum.mt.half(bngcCollisionPos)
bngcCollisionTime=BigNum.mt.half(bngcCollisionTime)
bnReadTime=BigNum.mt.half(bnReadTime)
if bnReadTime>-22000 then
-- remaining bits should be processed extra
break
end
bngcCollisionTimeOffs=bngcCollisionTime+bnAeon
bnReadTimeOffs=bnReadTime+bnAeon
if i==3 then -- Aeon exception
bngcCollisionTimeOffs=bngcCollisionTimeOffs+bnAeon
end
g.setpos(BigNum.mt.tostring(bngcCollisionPos), BigNum.mt.tostring(bngcCollisionPos))
showtext="Fast-forwarding to FSE glider with GPSE collision nr. "..i
run_from_to(gnPrevTime, collisionAeon, bngcCollisionTimeOffs+2048, 30, 0, {-30,-27,-24,-21,-18,-16, -14, -12, -10, -8, -6, -4, -2, 0})
gnPrevTime=bngcCollisionTimeOffs+4096
run_for_to("2048", collisionAeon, gnPrevTime, nil, 0, {0})
g.setpos(0, 0)
showtext="Fast-forwarding to distance bit read nr. "..i
if i==3 then
gnPrevTime=nil
collisionAeon=11
end
run_from_to(gnPrevTime, collisionAeon, bnReadTimeOffs+2048, 30, 0, {-30, -2})
showtext="Note the gliders going from the center ..."
gnPrevTime=bnReadTimeOffs+4128
run_for_to(2080, collisionAeon, gnPrevTime, nil, 0, {0})
end
end
showtext="Startng crash FSE"
g.setpos(BigNum.mt.tostring(bnParsec), BigNum.mt.tostring(bnParsec))
run_for_to(1024,0,1024,4,4,{-1})
showtext="Startng crash FNW"
g.setpos(BigNum.mt.tostring(-bnParsec), BigNum.mt.tostring(-bnParsec))
run_for_to(1024,0,2048,4,4,{-1})
showtext="Fast-forwarding to first collision of gliders from GPSEs..."
g.setpos(0,0)
run_for_to(nil, 4, 1344, 30, 6, {-30, -27, -24, -21, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0})
showtext="Note the gliders going from the center..."
run_for_to("992", 4, "2336", 4, 4, {0})
g.setpos(BigNum.mt.tostring(bnParsecHalf), BigNum.mt.tostring(bnParsecHalf))
showtext="Fast-forwarding to first FSW glider with GPSE collision..."
run_for_to(nil, 6, 1024, 30,2,{-30,-27,-24,-21,-18,-16, -14, -12, -10, -8, -6, -4, -2, 0})
run_for_to("2048", 6, "3072")
--local xs=BigNum.mt.tostring(-bnParsecHalf)
--g.setpos(xs, xs)
--local x,y=g.getpos()
--g.setpos("-97717929936","-97717929936")
--showtext="Fast-forwarding to first FNW glider with GPSE collision... "..
--xs.."x"..xs.." "..x.."x"..y
--local x,y=g.getpos()
--g.note("cancel.."..xs.."x"..xs.." "..x.."x"..y)
--golly bug? Does not work, but there is actally nothing important here
g.setpos(0, 0)
showtext="Fast-forwarding to first distance bit read ..."
run_for_to(nil,8,2048,30, 6, {-2})
showtext="Note the gliders going from the center ..."
run_for_to("1024", 8, "3072", 4, 4, {0})
g.setpos(BigNum.mt.tostring(bnParsecQuarter), BigNum.mt.tostring(bnParsecQuarter))
showtext="Fast-forwarding to second FSE glider with GPSE collision..."
run_for_to(nil, 9, 2048, 30,2,{-30,-27,-24,-21,-18,-16, -14, -12, -10, -8, -6, -4, -2, 0})
run_for_to("2048", 9, "4096")
g.setpos(0, 0)
showtext="Fast-forwarding to second distance bit read ..."
run_for_to(nil,10, 2048, 30, 6, {-2})
showtext="Note the gliders going from the center ..."
run_for_to("2048", 10, "4128", 4, 4, {0})
showtext="Fast-forwarding to first inserted MWSS bits ... here only 28 bits are encoded in pattern size"
run_for_to("194952", 10, "199080", nil, 4, {-30, -16, -8, -4, -2, 0})
showtext="Each inserted bit reduces pattern dimensions to half, there will be no chance to wait for result without the reduction"
run_for_to("1600", 10, "200680", nil, nil, {0})
showtext="Transform the initial crash site into a usable blinker elbow 253 bits"
run_for_to("16424488", 10, "16625168")
g.setpos("768", "-768")
showtext="Move the blinker elbow a bit to the northeast to make room for construction arms"
run_for_to("1038089520", 10, "1054715160", nil, nil, {-2})
g.setpos("768", "-1536")
showtext="Position some blocks in useful locations 10038 bits"
run_for_to("653883392", 10, "1708599272",nil,nil,{-2})
run_for_to("4480", 10, "1708603752", 6, 6)
run_for_to("3962880", 10, "1712566632",nil,nil,{-2})
showtext="Construct the decoder and better construction arm (DBCA) 1246983 bits"
run_for_to("81722276800", 10, "83434843432", 30, 6)
showtext="Launch a Corderrake to activate the meteor shower seed and pass control to the DBCA 1615 bits"
run_for_to("105840640", 10, "83540684072", nil, 6)
showtext="Initialise DBCA and position construction elbow 203 bits"
run_for_to("13303808", 10, "83553987880")
g.setpos("0", "0")
showtext="The DBCA removes the pi explosion"
run_for_to("7667712", 10, "83561655592", nil, 6, {0})
g.setpos("768", "-1336")
showtext="The DBCA constructs some switching circuitry and lounches first glider far SE"
run_for_to("12374000", 10, "83574029592", 14, 4, {-2})
g.setpos("0", "0")
showtext="The DBCA lounches third glider far SE to finish construction of one time reflector"
run_for_to("5302784", 10, "83579332376", nil, 6, {0})
run_for_to("992", 10, "83579333368", 3, 3)
g.setpos("1024", "0")
showtext="The DBCA constructs some switching circuitry 7056 bits"
run_for_to("386351648", 10, "83965685016", nil, 5, {-2})
showtext="The DBCA constructs the extreme compression construction arm (ECCA) 160650 bits"
run_for_to("10528358400", 10, "94494043416")
g.setpos("1024", "-1024")
showtext="The DBCA constructs some additional switching circuitry and jumps southeast 2628 bits"
run_for_to("172052480", 10, "94666095896", nil, 6, {-2})
showtext="Notice one glider phase and color will emit gliders, which are counted by the circuitry trash (N gliders absorber)"
run_for_to("36864", 10, "94666132760", 6, 6)
showtext="The DBCA constructs a BSRD and some Corderabsorbers in the far south-east 20691 bits"
run_for_to("1389174784", 10, "96055307544", 30, 6)
g.setpos("768", "-1536")
showtext="The trash is gone and the last glider-emission activates switching circuitry to redirect future bits to the BSRD and closes DBCA"
run_for_to("557056", 10, "96055864600", nil, 6)
run_for_to("22000", 10, "96055886600", 6, 6)
showtext="The p8 reflectors are activated and the 'few' remaining gliders are rerouted to the BSRD 2 bits"
run_for_to("765952", 10, "96056652568")
if startAeon<10 then
--g.note("save me!"..startAeon)
end
do distance_bits("96056652568") end
showtext="Remaining distance bits generated (28 in total)"
g.setpos("0", "0")
-- let us ignore length in next run_for_to (as the number of watched distance reads could vary)
bnCurrentAeonBase = bnCurrentAeonBase - bnAeon
currentAeon = currentAeon - 1
run_for_to(nil, 12, "-16000",nil,0,{-4, -4, -4, -4, -4, -4, -3})
run_for_to("21016", 12, "5016", 5, 2, {-2})
showtext="Now we wait for recepies to reach far SE (creating reflectors and corder absorbers)"
run_for_to("89524727808", 12, "89524732824")
g.setpos(BigNum.mt.tostring(bnParsec+200),BigNum.mt.tostring(bnParsec-200))
showtext="SE one time reflector is almost created"
run_for_to(nil, 14, "83573730968",nil,nil,{0})
showtext="SE one time reflector is created"
run_for_to("11534336", 14, "83585265752", nil, 6)
showtext="The DBCA jump to far SE arrives"
run_for_to("11080855040", 14, "94666120792", 30, 6)
g.setpos(BigNum.mt.tostring(bnParsec+700), BigNum.mt.tostring(bnParsec-700))
showtext="The BSRD and Corderabsorbers commence construction in the far south-east"
run_for_to("8092", 14, "94666128884", 8, 8, {-3})
run_for_to("1456288256", 14, "96122417240")
g.setpos(BigNum.mt.tostring(bnParsec), BigNum.mt.tostring(bnParsec))
showtext="The BSRD in the far south-east begins reflecting gliders"
run_for_to("196096", 14, "96122613848",nil,6,{-3})
g.setpos(BigNum.mt.tostring(bnParsec), BigNum.mt.tostring(bnParsec))
showtext="The BSRD continues reflecting gliders (grab a coffee and come back later; we will wait for you)"
run_for_to(nil, 15, "-86200016712",nil,nil,{-5})
showtext="The recipe returns from the BSRD to the ECCA"
run_for_to("768630145024", 18, "96122548696",nil, nil, {-30})
if startAeon<18 then
g.note("Gliders reaching ECCA!")
end
g.setpos("1024", "0")
showtext="The ECCA reflects the first glider back to destroy the BSRD 1 bit"
run_for_to("65536", 18, "96122614232", nil, nil, {-2})
g.setpos("512", "-1024")
showtext="The ECCA destroys the remnants of the DBCA 3820 bits"
run_for_to("250347520", 18, "96372961752", nil, nil, {-3})
showtext="The ECCA fires a glider to switch the direction of subsequent gliders 179 bits"
run_for_to("11730944", 18, "96384692696")
g.setpos("0", "0")
showtext="The ECCA eliminates ash from the GPSE collision 643 bits"
run_for_to("25467800", 18, "96410160496", nil, nil, {0})
showtext="The ECCA builds an elbow in the far northwest (notice the use of integrated one time reflector of GPSE) 1274 bits"
run_for_to("7800", 18, "96410168400", 6, 6, {-2})
showtext="The ECCA launches a salvo of Corderships to clean the south-east trail 52265 bits"
run_for_to(nil, 19, "-95533915592", nil, nil, {0})
showtext="The ECCA builds some Corderabsorbers in the far south-west 25078 bits"
run_for_to("1643511808", 19, "-93890403784")
showtext="The ECCA launches a salvo of Corderships to clean the south-west trail 20806 bits"
run_for_to("1363542016", 19, "-92526861768", nil, nil, {-2})
showtext="The ECCA launches a salvo of Corderships to clean the north-west trail 30031 bits"
run_for_to("1968111616", 19, "-90558750152")
showtext="The ECCA prepares circuitry to destroy its own elbow 316 bits"
run_for_to("20709376", 19, "-90538040776")
showtext="The ECCA builds a seed for the ATBC pattern dependent 58173 bits"
run_for_to("3745875000", 19, "-86792165775", nil, 6, {-2})
showtext="The ECCA constructs Corderabsorbers in the far north-west 7793 bits"
run_for_to("591757312", 19, "-86200408456",nil,0)
showtext="The ECCA returns to a known state for self-destruction remaining 6 bits"
run_for_to("393216", 19, "-86200015240")
g.setpos(BigNum.mt.tostring(bnParsec+300),BigNum.mt.tostring(bnParsec))
showtext="Glider destroying DBCA arrives"
run_for_to(nil, 22, "96056054232", 30, 6, {-30, -25, -20, -16, -12, -8, -6, -4, -2})
run_for_to("5500", 22, "96056059732", 3, 0)
showtext="The Corderships embark on their journey to clean up the ash trails"
g.setpos(BigNum.mt.tostring(-bnParsec), BigNum.mt.tostring(-bnParsec))
run_for_to("354100000", 22, "96410159732", nil, 0, {-2})
showtext="ECCA arm switches to FNW"
run_for_to("6000", 22, "96410165732",6,6)
g.setpos(BigNum.mt.tostring(-bnParsec+500), BigNum.mt.tostring(bnParsec-400))
showtext="The Corderabsorbers commence construction using slow^2 gliders"
run_for_to("1643511808", 23, "-93890403400", nil, nil, {0})
showtext="The Corderabsorbers at FSW are fully complete"
run_for_to("7004788736", 23, "-86885614664")
g.setpos(BigNum.mt.tostring(-bnParsec), BigNum.mt.tostring(-bnParsec))
showtext="The Corderabsorbers commence construction in the far north-west"
run_for_to("525205504", 23, "-86360409160", nil, nil, {-2})
g.setpos("0", "0")
showtext="The Corderships continue cleaning the ash trails"
run_for_to("1550728134656", 30, "96316706392", nil, nil, {-30})
if startAeon<30 then
--g.note("save me!"..startAeon)
end
g.setpos(BigNum.mt.tostring(bnParsec+990), BigNum.mt.tostring(bnParsec+990))
showtext="The Corderships begin colliding with the SE Corderabsorbers"
run_for_to("3425239040", 31, "-95693914440", nil, nil, {-2})
showtext="The Corderships have finished colliding with the SE Corderabsorbers"
run_for_to("93464028", 31, "-95600450412", nil, nil)
run_for_to("2000", 31, "-95600447864", nil, 0, {0})
g.setpos(BigNum.mt.tostring(-bnParsec+500), BigNum.mt.tostring(bnParsec-400))
showtext="The Corderships begin colliding with the SW Corderabsorbers"
run_for_to("1763542016", 31, "-93836905848", nil, nil, {-1})
showtext="The Corderships have finished colliding with the SW Corderabsorbers"
run_for_to("1243492016", 31, "-92593413832", nil, nil, {-1, 0})
run_for_to("6010", 31, "-92593407486", nil, 0)
g.setpos(BigNum.mt.tostring(-bnParsec-500), BigNum.mt.tostring(-bnParsec-500))
showtext="The Corderships colliding with the NW Corderabsorbers"
run_for_to("1968117000", 31, "-90625290486", nil, 6, {-13, -13, -13, -10, -8, -6, -4, -2, -1})
run_for_to("1500", 31, "-90625288930", nil, 0)
g.setpos(BigNum.mt.tostring(-bnParsec), BigNum.mt.tostring(-bnParsec))
showtext="The last NW Cordership sends a return signal back to destroy the ECCA"
run_for_to("2000", 31, "-90625286930", nil, nil, {-2})
run_for_to("1363542016", 31, "-89261744914", nil, 2,{-2})
showtext="The ECCA awaits the return glider before self-destructing and emitting an MWSS"
g.setpos("768", "0")
run_for_to("780379899000", 35, "-90625285402", 30, 6, {-30, -27, -24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -4, -1})
showtext="The MWSS triggers the ATBC seed"
run_for_to("15296", 35, "-90625270098", 0, 0, {-1})
g.setpos("-500", "0")
run_for_to("10000", 35, "-90625260098", 0, 0, {-1})
Code: Select all
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{1
--
-- File Name: bignum.lua
-- Package Name: BigNum
--
-- Project: Big Numbers library for Lua
-- Mantainers: fmp - Frederico Macedo Pessoa
-- msm - Marco Serpa Molinaro
-- vm - Vladan Majerech
--
-- History:
-- Version Autor Date Notes
-- 2.0 vm 12/11/2022 Edited for personal needs (just +,-,<,=,>,tostring) bug fixing tostring
-- 1.1 fmp/msm 12/11/2004 Some bug fixes (thanks Isaac Gouy)
-- alfa fmp/msm 03/22/2003 Start of Development
-- beta fmp/msm 07/11/2003 Release
--
-- Description:
-- Big numbers manipulation library for Lua.
-- A Big Number is a table with as many numbers as necessary to represent
-- its value in base 'RADIX'. It has a field 'len' containing the num-
-- ber of such numbers and a field 'signal' that may assume the values
-- '+' and '-'.
--
--$.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--%%%%%%%% Constants used in the file %%%%%%%%--{{{1
RADIX_LEN = 6 ;
RADIX_FIL = "000000" ; -- length >= RADIX_LEN
RADIX = 10^RADIX_LEN ;
--%%%%%%%% Start of Code %%%%%%%%--
BigNum = {} ;
BigNum.mt = {} ;
--BigNum.new{{{1
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--
-- Function: New
--
--
-- Description:
-- Creates a new Big Number based on the parameter num.
--
-- Parameters:
-- num - a string, number or BigNumber.
--
-- Returns:
-- A Big Number, or a nil value if an error occured.
--
--
-- %%%%%%%% --
function BigNum.new( num ) --{{{2
local bignum = {} ;
setmetatable( bignum , BigNum.mt ) ;
BigNum.change( bignum , num ) ;
return bignum ;
end
--%%%%%%%%%%%%%%%%%%%% Functions for metatable %%%%%%%%%%%%%%%%%%%%--{{{1
--BigNum.mt.sub{{{2
function BigNum.mt.sub( num1 , num2 )
local temp = BigNum.new() ;
local bnum1 = BigNum.new( num1 ) ;
local bnum2 = BigNum.new( num2 ) ;
BigNum.sub( bnum1 , bnum2 , temp ) ;
return temp ;
end
--BigNum.mt.add{{{2
function BigNum.mt.add( num1 , num2 )
local temp = BigNum.new() ;
local bnum1 = BigNum.new( num1 ) ;
local bnum2 = BigNum.new( num2 ) ;
BigNum.add( bnum1 , bnum2 , temp ) ;
return temp ;
end
--BigNum.mt.tostring{{{2
function BigNum.mt.tostring( bnum )
local i = 0
local j
local temp = ""
local str
local dotpos
if bnum == nil then
return "nil"
elseif bnum.len > 0 then
for i = bnum.len - 2 , 0 , -1 do
str = tostring(bnum[i])
dotpos = string.find(str..".","%.")
temp = temp .. string.sub(RADIX_FIL..string.sub(str,1,dotpos-1),-RADIX_LEN)
end
str = tostring(bnum[bnum.len - 1])
dotpos = string.find(str..".","%.")
temp = string.sub(str,1,dotpos-1) .. temp
if bnum.signal == '-' then
temp = bnum.signal .. temp
end
return temp
else
return ""
end
end
--BigNum.mt.eq{{{2
function BigNum.mt.eq( num1 , num2 )
local bnum1 = BigNum.new( num1 ) ;
local bnum2 = BigNum.new( num2 ) ;
return BigNum.eq( bnum1 , bnum2 ) ;
end
--BigNum.mt.lt{{{2
function BigNum.mt.lt( num1 , num2 )
local bnum1 = BigNum.new( num1 ) ;
local bnum2 = BigNum.new( num2 ) ;
return BigNum.lt( bnum1 , bnum2 ) ;
end
--BigNum.mt.le{{{2
function BigNum.mt.le( num1 , num2 )
local bnum1 = BigNum.new( num1 ) ;
local bnum2 = BigNum.new( num2 ) ;
return BigNum.le( bnum1 , bnum2 ) ;
end
--BigNum.mt.unm{{{2
function BigNum.mt.unm( num )
local ret = BigNum.new( num )
if ret.signal == '+' then
ret.signal = '-'
else
ret.signal = '+'
end
return ret
end
--BigNum.mt.half{{{2
function BigNum.mt.half( num )
local ret = BigNum.new()
local bnum = BigNum.new( num ) ;
BigNum.half( bnum , ret ) ;
return ret ;
end
--%%%%%%%%%%%%%%%%%%%% Metatable Definitions %%%%%%%%%%%%%%%%%%%%--{{{1
BigNum.mt.__metatable = "hidden" ; -- answer to getmetatable(aBignum)
-- BigNum.mt.__index = "inexistent field" ; -- attempt to acess nil valued field
-- BigNum.mt.__newindex = "not available" ; -- attempt to create new field
BigNum.mt.__tostring = BigNum.mt.tostring ;
-- arithmetics
BigNum.mt.__add = BigNum.mt.add ;
BigNum.mt.__sub = BigNum.mt.sub ;
BigNum.mt.__unm = BigNum.mt.unm ;
-- Comparisons
BigNum.mt.__eq = BigNum.mt.eq ;
BigNum.mt.__le = BigNum.mt.le ;
BigNum.mt.__lt = BigNum.mt.lt ;
--concatenation
-- BigNum.me.__concat = ???
setmetatable( BigNum.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ;
--%%%%%%%%%%%%%%%%%%%% Basic Functions %%%%%%%%%%%%%%%%%%%%--{{{1
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: ADD
--
--
-- Description:
-- Adds two Big Numbers.
--
-- Parameters:
-- bnum1, bnum2 - Numbers to be added.
-- bnum3 - result
--
-- Returns:
-- 0
--
-- Exit assertions:
-- bnum3 is the result of the sum.
--
-- %%%%%%%% --
--Funcao BigNum.add{{{2
function BigNum.add( bnum1 , bnum2 , bnum3 )
local maxlen = 0 ;
local i = 0 ;
local carry = 0 ;
local signal = '+' ;
local old_len = 0 ;
--Handle the signals
if bnum1 == nil or bnum2 == nil or bnum3 == nil then
error("Function BigNum.add: parameter nil") ;
elseif bnum1.signal == '-' and bnum2.signal == '+' then
bnum1.signal = '+' ;
BigNum.sub( bnum2 , bnum1 , bnum3 ) ;
if not rawequal(bnum1, bnum3) then
bnum1.signal = '-' ;
end
return 0 ;
elseif bnum1.signal == '+' and bnum2.signal == '-' then
bnum2.signal = '+' ;
BigNum.sub( bnum1 , bnum2 , bnum3 ) ;
if not rawequal(bnum2, bnum3) then
bnum2.signal = '-' ;
end
return 0 ;
elseif bnum1.signal == '-' and bnum2.signal == '-' then
signal = '-' ;
end
--
old_len = bnum3.len ;
if bnum1.len > bnum2.len then
maxlen = bnum1.len ;
else
maxlen = bnum2.len ;
bnum1 , bnum2 = bnum2 , bnum1 ;
end
--School grade sum
for i = 0 , maxlen - 1 do
if bnum2[i] ~= nil then
bnum3[i] = bnum1[i] + bnum2[i] + carry ;
else
bnum3[i] = bnum1[i] + carry ;
end
if bnum3[i] >= RADIX then
bnum3[i] = bnum3[i] - RADIX ;
carry = 1 ;
else
carry = 0 ;
end
end
--Update the answer's size
if carry == 1 then
bnum3[maxlen] = 1 ;
end
bnum3.len = maxlen + carry ;
bnum3.signal = signal ;
for i = bnum3.len, old_len do
bnum3[i] = nil ;
end
return 0 ;
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: SUB
--
--
-- Description:
-- Subtracts two Big Numbers.
--
-- Parameters:
-- bnum1, bnum2 - Numbers to be subtracted.
-- bnum3 - result
--
-- Returns:
-- 0
--
-- Exit assertions:
-- bnum3 is the result of the subtraction.
--
-- %%%%%%%% --
--Funcao BigNum.sub{{{2
function BigNum.sub( bnum1 , bnum2 , bnum3 )
local maxlen = 0 ;
local i = 0 ;
local carry = 0 ;
local old_len = 0 ;
--Handle the signals
if bnum1 == nil or bnum2 == nil or bnum3 == nil then
error("Function BigNum.sub: parameter nil") ;
elseif bnum1.signal == '-' and bnum2.signal == '+' then
bnum1.signal = '+' ;
BigNum.add( bnum1 , bnum2 , bnum3 ) ;
bnum3.signal = '-' ;
if not rawequal(bnum1, bnum3) then
bnum1.signal = '-' ;
end
return 0 ;
elseif bnum1.signal == '-' and bnum2.signal == '-' then
bnum1.signal = '+' ;
bnum2.signal = '+' ;
BigNum.sub( bnum2, bnum1 , bnum3 ) ;
if not rawequal(bnum1, bnum3) then
bnum1.signal = '-' ;
end
if not rawequal(bnum2, bnum3) then
bnum2.signal = '-' ;
end
return 0 ;
elseif bnum1.signal == '+' and bnum2.signal == '-' then
bnum2.signal = '+' ;
BigNum.add( bnum1 , bnum2 , bnum3 ) ;
if not rawequal(bnum2, bnum3) then
bnum2.signal = '-' ;
end
return 0 ;
end
--Tests if bnum2 > bnum1
if BigNum.compareAbs( bnum1 , bnum2 ) == 2 then
BigNum.sub( bnum2 , bnum1 , bnum3 ) ;
bnum3.signal = '-' ;
return 0 ;
else
maxlen = bnum1.len ;
end
old_len = bnum3.len ;
bnum3.len = 0 ;
--School grade subtraction
for i = 0 , maxlen - 1 do
if bnum2[i] ~= nil then
bnum3[i] = bnum1[i] - bnum2[i] - carry ;
else
bnum3[i] = bnum1[i] - carry ;
end
if bnum3[i] < 0 then
bnum3[i] = RADIX + bnum3[i] ;
carry = 1 ;
else
carry = 0 ;
end
if bnum3[i] ~= 0 then
bnum3.len = i + 1 ;
end
end
bnum3.signal = '+' ;
--Check if answer's size if zero
if bnum3.len == 0 then
bnum3.len = 1 ;
bnum3[0] = 0 ;
end
if carry == 1 then
error( "Error in function sub" ) ;
end
for i = bnum3.len , max( old_len , maxlen - 1 ) do
bnum3[i] = nil ;
end
return 0 ;
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: HALF
--
--
-- Description:
-- Divides absolute value by 2.
--
-- Parameters:
-- bnum1 - Number to be halved.
-- bnum2 - result
--
-- Returns:
-- boolean ... was the bnum1 odd?
--
-- Exit assertions:
-- bnum2 is the result of the halving.
--
-- %%%%%%%% --
--Funcao BigNum.half{{{2
function BigNum.half( bnum1 , bnum2 )
local maxlen = bnum1.len ;
local i = 0 ;
if bnum1 == nil or bnum2 == nil then
error("Function BigNum.half: parameter nil") ;
end
for i = maxlen, bnum2.len-1, 1 do
bnum2[i] = nil ;
end
bnum2.len = maxlen
local carry = 0
if bnum1[maxlen-1]<2 then
bnum2[maxlen-1]=nil
bnum2.len=maxlen-1
carry = bnum1[maxlen-1] % 2
end
for i = bnum2.len - 1,0,-1 do
bnum2[i] = (bnum1[i] + carry * RADIX)//2
carry = bnum1[i] % 2
end
bnum2.signal = bnum1.signal ;
--Check if answer's size if zero
if bnum2.len == 0 then
bnum2.len = 1 ;
bnum2[0] = 0 ;
end
return carry == 1 ;
end
--%%%%%%%%%%%%%%%%%%%% Comparison Functions %%%%%%%%%%%%%%%%%%%%--{{{1
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: EQ
--
--
-- Description:
-- Compares two Big Numbers.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- Returns true if they are equal or false otherwise.
--
-- %%%%%%%% --
--BigNum.eq{{{2
function BigNum.eq( bnum1 , bnum2 )
if BigNum.compare( bnum1 , bnum2 ) == 0 then
return true ;
else
return false ;
end
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: LT
--
--
-- Description:
-- Verifies if bnum1 is lesser than bnum2.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- Returns true if bnum1 is lesser than bnum2 or false otherwise.
--
-- %%%%%%%% --
--BigNum.lt{{{2
function BigNum.lt( bnum1 , bnum2 )
if BigNum.compare( bnum1 , bnum2 ) == 2 then
return true ;
else
return false ;
end
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: LE
--
--
-- Description:
-- Verifies if bnum1 is lesser or equal than bnum2.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- Returns true if bnum1 is lesser or equal than bnum2 or false otherwise.
--
-- %%%%%%%% --
--BigNum.le{{{2
function BigNum.le( bnum1 , bnum2 )
local temp = -1 ;
temp = BigNum.compare( bnum1 , bnum2 )
if temp == 0 or temp == 2 then
return true ;
else
return false ;
end
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: Compare Absolute Values
--
--
-- Description:
-- Compares absolute values of bnum1 and bnum2.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- 1 - |bnum1| > |bnum2|
-- 2 - |bnum1| < |bnum2|
-- 0 - |bnum1| = |bnum2|
--
-- %%%%%%%% --
--BigNum.compareAbs{{{2
function BigNum.compareAbs( bnum1 , bnum2 )
if bnum1 == nil or bnum2 == nil then
error("Function compare: parameter nil") ;
elseif bnum1.len > bnum2.len then
return 1 ;
elseif bnum1.len < bnum2.len then
return 2 ;
else
local i ;
for i = bnum1.len - 1 , 0 , -1 do
if bnum1[i] > bnum2[i] then
return 1 ;
elseif bnum1[i] < bnum2[i] then
return 2 ;
end
end
end
return 0 ;
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: Compare
--
--
-- Description:
-- Compares values of bnum1 and bnum2.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- 1 - |bnum1| > |bnum2|
-- 2 - |bnum1| < |bnum2|
-- 0 - |bnum1| = |bnum2|
--
-- %%%%%%%% --
--BigNum.compare{{{2
function BigNum.compare( bnum1 , bnum2 )
local signal = 0 ;
if bnum1 == nil or bnum2 == nil then
error("Funtion BigNum.compare: parameter nil") ;
elseif bnum1.signal == '+' and bnum2.signal == '-' then
return 1 ;
elseif bnum1.signal == '-' and bnum2.signal == '+' then
return 2 ;
elseif bnum1.signal == '-' and bnum2.signal == '-' then
signal = 1 ;
end
if bnum1.len > bnum2.len then
return 1 + signal ;
elseif bnum1.len < bnum2.len then
return 2 - signal ;
else
local i ;
for i = bnum1.len - 1 , 0 , -1 do
if bnum1[i] > bnum2[i] then
return 1 + signal ;
elseif bnum1[i] < bnum2[i] then
return 2 - signal ;
end
end
end
return 0 ;
end
--%%%%%%%%%%%%%%%%%%%% Low level Functions %%%%%%%%%%%%%%%%%%%%--{{{1
--BigNum.copy{{{2
function BigNum.copy( bnum1 , bnum2 )
if bnum1 ~= nil and bnum2 ~= nil then
local i ;
for i = 0 , bnum1.len - 1 do
bnum2[i] = bnum1[i] ;
end
bnum2.len = bnum1.len ;
else
error("Function BigNum.copy: parameter nil") ;
end
end
--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%{{{2
--
-- Function: Change
--
-- Description:
-- Changes the value of a BigNum.
-- This function is called by BigNum.new.
--
-- Parameters:
-- bnum1, bnum2 - numbers
--
-- Returns:
-- 1 - |bnum1| > |bnum2|
-- 2 - |bnum1| < |bnum2|
-- 0 - |bnum1| = |bnum2|
--
-- %%%%%%%% --
--BigNum.change{{{2
function BigNum.change( bnum1 , num )
local j = 0 ;
local len = 0 ;
local num = num ;
local l ;
local oldLen = 0 ;
if bnum1 == nil then
error( "BigNum.change: parameter nil" ) ;
elseif type( bnum1 ) ~= "table" then
error( "BigNum.change: parameter error, type unexpected" ) ;
elseif num == nil then
bnum1.len = 1 ;
bnum1[0] = 0 ;
bnum1.signal = "+";
elseif type( num ) == "table" and num.len ~= nil then --check if num is a big number
--copy given table to the new one
for i = 0 , num.len do
bnum1[i] = num[i] ;
end
if num.signal ~= '-' and num.signal ~= '+' then
bnum1.signal = '+' ;
else
bnum1.signal = num.signal ;
end
oldLen = bnum1.len ;
bnum1.len = num.len ;
elseif type( num ) == "string" or type( num ) == "number" then
if string.sub( num , 1 , 1 ) == '+' or string.sub( num , 1 , 1 ) == '-' then
bnum1.signal = string.sub( num , 1 , 1 ) ;
num = string.sub(num, 2) ;
else
bnum1.signal = '+' ;
end
num = string.gsub( num , " " , "" )
local sf = string.find( num , "e" )
--Handles if the number is in exp notation
if sf ~= nil then
local e = string.sub( num , sf + 1 )
num = string.sub( num , 1 , sf - 1 )
e = tonumber(e) ;
if e ~= nil and e > 0 then
e = tonumber(e) ;
else
error( "Function BigNum.change: string is not a valid number" ) ;
end
local dotpos=string.find(num..".","%.")
num = string.gsub( num , "%." , "" )
local dotshift = string.len(num)+1-dotpos
for i = 1 , e do
num = num .. "0"
end
if dotshift>0 then num = string.sub(num,1,-dotshift-1) end
else
sf = string.find( num , "%." ) ;
if sf ~= nil then
num = string.sub( num , 1 , sf - 1 ) ;
end
end
l = string.len( num ) ;
oldLen = bnum1.len ;
if (l > RADIX_LEN) then
local mod = l-( math.floor( l / RADIX_LEN ) * RADIX_LEN ) ;
for i = 1 , l-mod, RADIX_LEN do
bnum1[j] = tonumber( string.sub( num, -( i + RADIX_LEN - 1 ) , -i ) );
--Check if string dosn't represents a number
if bnum1[j] == nil then
error( "Function BigNum.change: string is not a valid number" ) ;
bnum1.len = 0 ;
return 1 ;
end
j = j + 1 ;
len = len + 1 ;
end
if (mod ~= 0) then
bnum1[j] = tonumber( string.sub( num , 1 , mod ) ) ;
bnum1.len = len + 1 ;
else
bnum1.len = len ;
end
--Eliminate trailing zeros
for i = bnum1.len - 1 , 1 , -1 do
if bnum1[i] == 0 then
bnum1[i] = nil ;
bnum1.len = bnum1.len - 1 ;
else
break ;
end
end
else
-- string.len(num) <= RADIX_LEN
bnum1[j] = tonumber( num ) ;
bnum1.len = 1 ;
end
else
error( "Function BigNum.change: parameter error, type unexpected" ) ;
end
--eliminates the deprecated higher order 'algarisms'
if oldLen ~= nil then
for i = bnum1.len , oldLen do
bnum1[i] = nil ;
end
end
return 0 ;
end
--BigNum.put{{{2
--Places int in the position pos of bignum, fills before with zeroes and
--after with nil.
function BigNum.put( bnum , int , pos )
if bnum == nil then
error("Function BigNum.put: parameter nil") ;
end
local i = 0 ;
for i = 0 , pos - 1 do
bnum[i] = 0 ;
end
bnum[pos] = int ;
for i = pos + 1 , bnum.len do
bnum[i] = nil ;
end
bnum.len = pos ;
return 0 ;
end
--printraw{{{2
function printraw( bnum )
local i = 0 ;
if bnum == nil then
error( "Function printraw: parameter nil" ) ;
end
while 1 == 1 do
if bnum[i] == nil then
io.write( ' len '..bnum.len ) ;
if i ~= bnum.len then
io.write( ' ERRO!!!!!!!!' ) ;
end
io.write( "\n" ) ;
return 0 ;
end
io.write( 'r'..bnum[i] ) ;
i = i + 1 ;
end
end
--max{{{2
function max( int1 , int2 )
if int1 > int2 then
return int1 ;
else
return int2 ;
end
end
--decr{{{2
function decr( bnum1 )
local temp = {} ;
temp = BigNum.new( "1" ) ;
BigNum.sub( bnum1 , temp , bnum1 ) ;
return 0 ;
end