--[[
This file is part of luax.

luax is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

luax is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with luax.  If not, see <https://www.gnu.org/licenses/>.

For further information about luax you can visit
https://codeberg.org/cdsoft/luax
--]]

---------------------------------------------------------------------
-- imath
---------------------------------------------------------------------

local test = require "test"
local eq = test.eq

return function()

    local imath = require "imath"
    local Z = imath.new

    local x = Z"123456789123456789123456789123456789"
    local y = Z"123456789"
    local z = Z(123456789)

    eq(tostring(Z"0"), "0")
    eq(tostring(x), "123456789123456789123456789123456789")
    eq(tostring(-x), "-123456789123456789123456789123456789")
    eq(y, z)

    eq(x+x, Z"246913578246913578246913578246913578") eq(imath.add(x, x), x+x)
    eq(x+y, Z"123456789123456789123456789246913578") eq(imath.add(x, y), x+y)

    eq(tostring(x/y), "1000000001000000001000000001") eq(imath.div(x, y), x/y)
    eq(tostring(y/x), "0")                            eq(imath.div(y, x), y/x)
    eq(tostring(x//y), "1000000001000000001000000001")
    eq(tostring(y//x), "0")
    eq(tostring(x/x), "1")
    eq(tostring(x//x), "1")
    eq(tostring(x), "123456789123456789123456789123456789")
    eq(x:tostring(), "123456789123456789123456789123456789")
    eq(x:tostring(16), "17C6E3C032F89045AD746684045F15")

    eq(x == x, true)
    eq(x == y, false)
    eq(x <= x, true)
    eq(x <= y, false)
    eq(y <= x, true)
    eq(x < x, false)
    eq(x < y, false)
    eq(y < x, true)

    eq(imath.compare(x, x), 0)
    eq(imath.compare(x, y), 1)
    eq(imath.compare(y, x), -1)

    eq(x % y, Z"0")         eq(imath.mod(x, y), x % y)
    eq((x+42) % y, Z"42")   eq(imath.mod(x+42, y), (x+42) % y)
    eq({imath.quotrem(x, y)}, {x/y, x%y})
    eq({imath.quotrem(x+42, y)}, {(x+42)/y, (x+42)%y})

    eq(x * y, Z"15241578765432099765432099765432099750190521")  eq(imath.mul(x, y), x * y)
    eq(x ^ 66, Z"1096449217209414147119131646110531982240767944818966457216785250299174265220139163456740923758861710052869810719648890828342130323100740451036394063281282059780228574325236813630018571624515160046689153621838419929801133969173271701005233712599425354595970279419760387781124125528714606206528941036798429476769074253011974969994751639180578350170069826899362331058172653063459752163036724172659815557272307027604176852523818169805214252911016535469182474800856470972996134923591118551947450838144219722290127633015980904337487692021209387044014919632079049741419453749516944479064672634012033021101976221196817935642413184076282718965343243409753076127047155839851081797067789932925780611472925583506958393070385513106761382537372570137658963377242032299556693592498419585017996907636986600076654362631234028028069624396133755494805012035841008544858597598247730605698133161494835382145467495434120247543270849151086944343120348997302938484869497906565827809783728405368425746945270770762517300869123012377493784288823895238250529624081422482571501612151321681600727162505511399367323441910732778891034112797591852750276060204732909604979145123859754901305666177543584751536116677200158427741664787438433910516461642268526603015264596837088223146372771980937770766863053936996923047722222954180431361649714783276052387682420552058270463144242521850446329064974747542829770181349089554700244434213700193642242970863075766286070053993928905986435786126449234076513547859683719641170708230148764635543927053513875570586078609980776414474911471758549674114135249031099799577300641320998484389119193880305158080206743111941636857038984323945963777892111576232962184209332377930057852463416226307159804670489662465669354755873229928454394541856444066069390728935854911358989772826066778652357052026902921628362374170076729801911372498658801961923074583541022638334454341930678859903485753391124766826681290141084454419823887636025457948054769337136777932703242052852676100804551105141446592898047510441625493560671599172555980015699551577327664802903605750117830011818237385051841122709355322093110689040012960681941602808850459332056327487301314236579937564959499929132029742561059148572471472188733725192682829103593395762540045056214479082280328170372928415833847678876164722597553665272274796029992071995548836491506361")    eq(imath.pow(x, 66), x ^ 66)
    eq(x ^ 1, x)
    eq(x ^ 0, Z"1")
    eq(Z(0) ^ x, Z(0))
    eq(Z(0) ^ 0, Z(1))
    eq(x ^ 0, Z(1))

    eq(x << 16, Z"8090864131994864131994864131994864123904")        eq(imath.shift(x, 16), x << 16)
    eq(x >> 16, Z"1883801103568371416068371416068")
    eq(x << -16, Z"1883801103568371416068371416068")                eq(imath.shift(x, -16), x << -16)
    eq(x >> -16, Z"8090864131994864131994864131994864123904")

    eq(x - x, Z"0")                                         eq(imath.sub(x, x), x - x)
    eq(x - y, Z"123456789123456789123456789000000000")      eq(imath.sub(x, y), x - y)
    eq(y - x, Z"-123456789123456789123456789000000000")     eq(imath.sub(y, x), y - x)

    eq(-x, Z"-123456789123456789123456789123456789")    eq(imath.neg(x), -x) eq(imath.neg(-x), x)

    eq(x:abs(), Z"123456789123456789123456789123456789")
    eq((-x):abs(), Z"123456789123456789123456789123456789")

    eq(x:gcd(y), Z"123456789")      eq(imath.gcd(x, y), x:gcd(y))
    eq((1337*x):gcd(1337*y), Z"123456789"*Z"1337")

    eq(x:iseven(), false)       eq(imath.iseven(x), x:iseven())
    eq((x+1):iseven(), true)    eq(imath.iseven(x+1), (x+1):iseven())
    eq(x:isodd(), true)         eq(imath.isodd(x), x:isodd())
    eq((x+1):isodd(), false)    eq(imath.isodd(x+1), (x+1):isodd())

    eq(x:iszero(), false)       eq(imath.iszero(x), x:iszero())
    eq((x-x):iszero(), true)    eq(imath.iszero(x-x), (x-x):iszero())

    eq(x:lcm(y), Z"123456789123456789123456789123456789")   eq(imath.lcm(x, y), x:lcm(y))
    eq((1337*x):lcm(1337^2*y), Z"123456789123456789123456789123456789"/7*1337*1337)

    eq(x:sqr(), x*x)    eq(imath.sqr(x), x:sqr())

    local sqrx = x:sqrt()
    eq(sqrx, Z"351364183040128307")
    eq(sqrx*sqrx <= x and (sqrx+1)*(sqrx+1) > x, true)
    eq(imath.sqrt(x), x:sqrt())

    eq(y:tonumber(), 123456789)     eq(imath.tonumber(y), y:tonumber())
    eq(y:tostring(), "123456789")   eq(imath.tostring(y), y:tostring())

    eq((Z("6c62272e07bb0142", 16) << 64) + Z("62b821756295c58d", 16), Z"144066263297769815596495629667062367629")
    eq((Z("6c62272e07bb0142", 16) << 64) + Z("62b821756295c58d", 16), Z("6c62272e07bb0142".."62b821756295c58d", 16))
    eq((Z("6c62272e07bb0142", 16) << 64) + 0x62b821756295c58d,        Z"144066263297769815596495629667062367629")
    eq((Z(0x6c62272e07bb0142)     << 64) + 0x62b821756295c58d,        Z"144066263297769815596495629667062367629")

end
