summaryrefslogtreecommitdiff
path: root/src/lgmp.lua
diff options
context:
space:
mode:
authorNicolas "Pixel" Noble <pixel@nobis-crew.org>2010-06-07 03:57:48 +0200
committerNicolas "Pixel" Noble <pixel@nobis-crew.org>2010-06-07 03:57:48 +0200
commit22356e5e0cf21fdad0029c3afb99a648a3b94f83 (patch)
treef83965e09b3ea9aa3efa0f734e483c92ef5f85eb /src/lgmp.lua
Initial commit of the gmp lua plugin.
Diffstat (limited to 'src/lgmp.lua')
-rw-r--r--src/lgmp.lua1639
1 files changed, 1639 insertions, 0 deletions
diff --git a/src/lgmp.lua b/src/lgmp.lua
new file mode 100644
index 0000000..2a09639
--- /dev/null
+++ b/src/lgmp.lua
@@ -0,0 +1,1639 @@
+
+--
+-- This file is part of the lgmp package for Lua 5.1.
+--
+-- Author: Wim Couwenberg
+-- Date : 2007/7/28
+--
+-- The lgmp package is distributed under the MIT license. See the "COPYRIGHT"
+-- file that came with the distribution of lgmp for license details.
+--
+
+--
+-- Adapted for lua-interface by Nicolas "Pixel" Noble
+--
+
+local type = type
+local getmetatable = getmetatable
+local assert = assert
+local error = error
+local match = string.match
+
+local prv
+local aux
+local randmeta = {}
+local zmeta = {}
+local fmeta = {}
+
+randmeta.__index = randmeta
+zmeta.__index = zmeta
+fmeta.__index = fmeta
+
+local function isrand(obj)
+ return type(obj) == "userdata" and getmetatable(obj) == randmeta
+end
+
+local function isz(obj)
+ return type(obj) == "userdata" and getmetatable(obj) == zmeta
+end
+
+local function isf(obj)
+ return type(obj) == "userdata" and getmetatable(obj) == fmeta
+end
+
+local function ntype(obj)
+ local t = type(obj)
+ if t == "number" then
+ if obj%1 == 0 then
+ if obj >= 0 and obj <= prv.ULONG_MAX then
+ return "u"
+ elseif obj >= prv.LONG_MIN and obj < 0 then
+ return "s"
+ elseif obj >= -prv.ULONG_MAX and obj < prv.LONG_MIN then
+ return "n"
+ end
+ end
+ return "d"
+ elseif t == "userdata" then
+ local m = getmetatable(obj)
+ if m == zmeta then
+ return "z"
+ elseif m == fmeta then
+ return "f"
+ end
+ end
+ return "?"
+end
+
+local function checkrand(obj)
+ assert(isrand(obj), "gmp random state expected")
+end
+
+local function checku(obj)
+ assert(type(obj) == "number" and obj >= 0 and obj <= prv.ULONG_MAX and obj%1 == 0, "unsigned integer expected")
+end
+
+local function checkn(obj)
+ assert(type(obj) == "number" and obj >= 0 and obj <= prv.LONG_MAX and obj%1 == 0, "non-negative intger expected")
+end
+
+local function checkbase(obj)
+ assert(type(obj) == "number" and obj >= 2 and obj <= 62 and obj%1 == 0, "gmp number base must be an integer between 2 and 62")
+end
+
+local function checkz(obj)
+ assert(isz(obj), "gmp integer expected")
+end
+
+local function checkzopt(obj)
+ assert(obj == nil or isz(obj), "gmp integer expected")
+end
+
+local function checkf(obj)
+ assert(isf(obj), "gmp floating point expected")
+end
+
+local function checkfopt(obj)
+ assert(obj == nil or isf(obj), "gmp floating point expected")
+end
+
+local dtoz = prv.mpz_init_set_d
+local dtof = prv.mpf_init_set_d
+
+function z(value, base)
+ if value == nil then
+ return prv.mpz_init()
+ elseif type(value) == "number" then
+ return dtoz(value)
+ elseif type(value) == "string" then
+ if base == nil then
+ base = 0
+ elseif base ~= 0 then
+ checkbase(base)
+ end
+ local res = prv.mpz_init_set_str(value, base)
+ if res then return res end
+ error("not a valid integer constant in base " .. base .. ": " .. value)
+ elseif isz(value) then
+ return prv.mpz_init_set(value)
+ elseif isf(value) then
+ local res = prv.mpz_init()
+ prv.mpz_set_f(res, value)
+ return res
+ else
+ error("cannot initialize gmp integer from " .. type(value))
+ end
+end
+
+function f(value, base)
+ if value == nil then
+ return prv.mpf_init()
+ elseif type(value) == "number" then
+ return dtof(value)
+ elseif type(value) == "string" then
+ if base == nil then
+ base = 10
+ elseif type(base) == "number" and base < 0 then
+ checkbase(-base)
+ else
+ checkbase(base)
+ end
+ local res = prv.mpf_init_set_str(value, base)
+ if res then return res end
+ error("not a valid floating point constant in base " .. base .. ": " .. value)
+ elseif isf(value) then
+ return prv.mpf_init_set(value)
+ elseif isz(value) then
+ local res = prv.mpf_init()
+ prv.mpf_set_z(res, value)
+ return res
+ else
+ error("cannot initialize gmp floating point from " .. type(value))
+ end
+end
+
+function zmeta:__tostring()
+ checkz(self)
+ return prv.mpz_get_str(10, self)
+end
+
+function zmeta:__concat(other)
+ if isz(self) then
+ return zmeta.get_str(self) .. other
+ else
+ return self .. zmeta.get_str(other)
+ end
+end
+
+function zmeta:__add(other)
+ if isz(self) then
+ return zmeta.add(self, other)
+ else
+ return zmeta.add(other, self)
+ end
+end
+
+function zmeta:__sub(other)
+ if isz(self) then
+ return zmeta.sub(self, other)
+ else
+ return zmeta.rsub(other, self)
+ end
+end
+
+function zmeta:__mul(other)
+ if isz(self) then
+ return zmeta.mul(self, other)
+ else
+ return zmeta.mul(other, self)
+ end
+end
+
+function zmeta:__div(other)
+ if isz(self) then
+ return zmeta.fdiv_q(self, other)
+ elseif type(other) == "number" then
+ return zmeta.fdiv_q(dtoz(self), other)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:__mod(other)
+ if isz(self) then
+ return zmeta.fdiv_r(self, other)
+ elseif type(self) == "number" then
+ return zmeta.fdiv_r(dtoz(self), other)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:__pow(exp)
+ checkz(self)
+ checku(exp)
+ return prv.mpz_pow_ui(self, exp)
+end
+
+function zmeta:__unm()
+ checkz(self)
+ return prv.mpz_neg(self)
+end
+
+function zmeta:__lt(other)
+ checkz(self)
+ checkz(other)
+ return prv.mpz_cmp(self, other) < 0
+end
+
+function zmeta:__le(other)
+ checkz(self)
+ checkz(other)
+ return prv.mpz_cmp(self, other) <= 0
+end
+
+function zmeta:__eq(other)
+ checkz(self)
+ checkz(other)
+ return prv.mpz_cmp(self, other) == 0
+end
+
+function zmeta:__gc()
+ checkz(self)
+ return prv.mpz_clear(self)
+end
+
+function zmeta:abs(res)
+ checkz(self)
+ checkzopt(res)
+ return prv.mpz_abs(self, res)
+end
+
+function zmeta:add(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_add(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_add_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_sub_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_add(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:addmul(a1, a2)
+ checkz(self)
+ checkz(a1)
+ local t = ntype(a2)
+ if t == "d" then
+ prv.mpz_addmul(self, a1, dtoz(a2))
+ elseif t == "u" then
+ prv.mpz_addmul_ui(self, a1, a2)
+ elseif t == "s" or t == "n" then
+ prv.mpz_submul_ui(self, a1, -a2)
+ elseif t == "z" then
+ prv.mpz_addmul(self, a1, a2)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:And(a, res)
+ checkz(self)
+ checkzopt(res)
+ if type(a) == "number" then
+ return prv.mpz_and(self, dtoz(a), res)
+ elseif isz(a) then
+ return prv.mpz_and(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:bin(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+
+ return prv.mpz_bin_ui(self, a, res)
+end
+
+function bin(a1, a2, res)
+ checku(a2)
+ checkzopt(res)
+ local t = ntype(a1)
+ if t == "d" then
+ return prv.mpz_bin_ui(dtoz(a1), a2, res)
+ elseif t == "u" then
+ return prv.mpz_bin_uiui(a1, a2, res)
+ elseif t == "s" or t == "n" then
+ if a2 <= prv.ULONG_MAX + a1 then
+ res = prv.mpz_bin_uiui(a2 - a1 - 1, a2, res)
+ if a2%2 ~= 0 then
+ prv.mpz_neg(res, res)
+ end
+ return res
+ else
+ return prv.mpz_bin_ui(dtoz(a1), a2, res)
+ end
+ elseif t == "z" then
+ return prv.mpz_bin_ui(a1, a2, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:cdiv_q(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_cdiv_q(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_cdiv_q_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ local r2
+ res, r2 = prv.mpz_fdiv_q_ui(self, -a, res)
+ return prv.mpz_neg(res, res), r2
+ elseif t == "z" then
+ return prv.mpz_cdiv_q(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:cdiv_q_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_cdiv_q_2exp(self, a, res)
+end
+
+function zmeta:cdiv_qr(a, r1, r2)
+ checkz(self)
+ checkzopt(r1)
+ checkzopt(r2)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_cdiv_qr(self, dtoz(a), r1, r2)
+ elseif t == "u" then
+ return prv.mpz_cdiv_qr_ui(self, a, r1, r2)
+ elseif t == "s" or t == "n" then
+ local r3
+ r1, r2, r3 = prv.mpz_fdiv_qr_ui(self, -a, r1, r2)
+ return prv.mpz_neg(r1, r1), r2, r3
+ elseif t == "z" then
+ return prv.mpz_cdiv_qr(self, a, r1, r2)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:cdiv_r(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_cdiv_r(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_cdiv_r_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_fdiv_r_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_cdiv_r(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:cdiv_r_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_cdiv_r_2exp(self, a, res)
+end
+
+function zmeta:cdiv(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "u" then
+ return prv.mpz_cdiv_ui(self, a)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_cdiv_ui(self, -a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:clrbit(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_clrbit(self, a, res)
+end
+
+function zmeta:cmp(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "d" or t == "n" then
+ return prv.mpz_cmp_d(self, a)
+ elseif t == "u" then
+ return prv.mpz_cmp_ui(self, a)
+ elseif t == "s" then
+ return prv.mpz_cmp_si(self, a)
+ elseif t == "z" then
+ return prv.mpz_cmp(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:cmpabs(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_cmpabs_d(self, a)
+ elseif t == "u" then
+ return prv.mpz_cmpabs_ui(self, a)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_cmpabs_ui(self, -a)
+ elseif t == "z" then
+ return prv.mpz_cmpabs(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:com(res)
+ checkz(self)
+ checkzopt(res)
+ return prv.mpz_com(self, res)
+end
+
+function zmeta:combit(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_combit(self, a, res)
+end
+
+function zmeta:congruent(a1, a2)
+ checkz(self)
+ local t1, t2 = ntype(a1), ntype(a2)
+ if t1 == "z" and t2 == "z" then
+ return prv.mpz_congruent_p(self, a1, a2) ~= 0
+ elseif t1 == "u" and t2 == "u" then
+ return prv.mpz_congruent_ui_p(self, a1, a2) ~= 0
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:congruent_2exp(a1, a2)
+ checkz(self)
+ checkz(a1)
+ checku(a2)
+ return prv.mpz_congruent_2exp_p(self, a1, a2) ~= 0
+end
+
+function zmeta:divexact(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_divexact(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_divexact_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpz_divexact_ui(self, -a, res)
+ return prv.mpz_neg(res, res)
+ elseif t == "z" then
+ return prv.mpz_divexact(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:divisible(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_divisible_p(self, dtoz(a)) ~= 0
+ elseif t == "u" then
+ return prv.mpz_divisible_ui_p(self, a) ~= 0
+ elseif t == "s" or t == "n" then
+ return prv.mpz_divisible_ui_p(self, -a) ~= 0
+ elseif t == "z" then
+ return prv.mpz_divisible_p(self, a) ~= 0
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:divisible_2exp(a)
+ checkz(self)
+ checku(a)
+ return prv.mpz_divisible_2exp_p(self, a) ~= 0
+end
+
+function fac(a, res)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_fac_ui(a, res)
+end
+
+function zmeta:fdiv_q(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_fdiv_q(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_fdiv_q_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ local r2
+ res, r2 = prv.mpz_cdiv_q_ui(self, -a, res)
+ return prv.mpz_neg(res, res), r2
+ elseif t == "z" then
+ return prv.mpz_fdiv_q(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:fdiv_q_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_fdiv_q_2exp(self, a, res)
+end
+
+function zmeta:fdiv_qr(a, r1, r2)
+ checkz(self)
+ checkzopt(r1)
+ checkzopt(r2)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_fdiv_qr(self, dtoz(a), r1, r2)
+ elseif t == "u" then
+ return prv.mpz_fdiv_qr_ui(self, a, r1, r2)
+ elseif t == "s" or t == "n" then
+ local r3
+ r1, r2, r3 = prv.mpz_cdiv_qr_ui(self, -a, r1, r2)
+ return prv.mpz_neg(r1, r1), r2, r3
+ elseif t == "z" then
+ return prv.mpz_fdiv_qr(self, a, r1, r2)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:fdiv_r(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_fdiv_r(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_fdiv_r_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_cdiv_r_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_fdiv_r(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:fdiv_r_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_fdiv_r_2exp(self, a, res)
+end
+
+function zmeta:fdiv(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "u" then
+ return prv.mpz_fdiv_ui(self, a)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_fdiv_ui(self, -a)
+ else
+ error("unsupported type")
+ end
+end
+
+function fib(a, res)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_fib_ui(a, res)
+end
+
+function fib2(a, r1, r2)
+ checku(a)
+ checkzopt(r1)
+ checkzopt(r2)
+ return prv.mpz_fib2_ui(a, r1, r2)
+end
+
+function zmeta:fits_sint()
+ checkz(self)
+ return prv.mpz_fits_sint_p(self) ~= 0
+end
+
+function zmeta:fits_slong()
+ checkz(self)
+ return prv.mpz_fits_slong_p(self) ~= 0
+end
+
+function zmeta:fits_sshort()
+ checkz(self)
+ return prv.mpz_fits_sshort_p(self) ~= 0
+end
+
+function zmeta:fits_uint()
+ checkz(self)
+ return prv.mpz_fits_uint_p(self) ~= 0
+end
+
+function zmeta:fits_ulong()
+ checkz(self)
+ return prv.mpz_fits_ulong_p(self) ~= 0
+end
+
+function zmeta:fits_ushort()
+ checkz(self)
+ return prv.mpz_fits_ushort_p(self) ~= 0
+end
+
+function zmeta:gcd(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_gcd(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_gcd_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_gcd_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_gcd(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:gcdext(a, r1, r2, r3)
+ checkz(self)
+ checkz(a)
+ checkzopt(r1)
+ checkzopt(r2)
+ checkzopt(r3)
+ return prv.mpz_gcdext(self, a, r1, r2, r3)
+end
+
+function zmeta:get_d()
+ checkz(self)
+ return prv.mpz_get_d(self)
+end
+
+function zmeta:get_d_2exp()
+ checkz(self)
+ return prv.mpz_get_d_2exp(self)
+end
+
+function zmeta:get_str(base)
+ checkz(self)
+ if base == nil then base = 10 else checkbase(base) end
+ return prv.mpz_get_str(base, self)
+end
+
+function zmeta:hamdist(a)
+ checkz(self)
+ checkz(a)
+ return prv.mpz_hamdist(self, a)
+end
+
+function zmeta:invert(a, res)
+ checkz(self)
+ checkz(a)
+ checkzopt(res)
+ local r2
+ res, r2 = prv.mpz_invert(self, a, res)
+ if r2 ~= 0 then
+ return res
+ end
+end
+
+function zmeta:ior(a, res)
+ checkz(self)
+ checkzopt(res)
+ if type(a) == "number" then
+ return prv.mpz_ior(self, dtoz(a), res)
+ elseif isz(a) then
+ return prv.mpz_ior(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:kronecker(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_kronecker(self, dtoz(a))
+ elseif t == "u" then
+ return prv.mpz_kronecker_ui(self, a)
+ elseif t == "s" then
+ return prv.mpz_kronecker_si(self, a)
+ elseif t == "n" then
+ return prv.mpz_kronecker(self, dtoz(a))
+ elseif t == "z" then
+ return prv.mpz_kronecker(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:rkronecker(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_kronecker(dtoz(a), self)
+ elseif t == "u" then
+ return prv.mpz_ui_kronecker(a, self)
+ elseif t == "s" then
+ return prv.mpz_si_kronecker(a, self)
+ elseif t == "n" then
+ return prv.mpz_kronecker(dtoz(a), self)
+ elseif t == "z" then
+ return prv.mpz_kronecker(a, self)
+ else
+ error("unsupported type")
+ end
+end
+
+zmeta.jacobi = zmeta.kronecker
+zmeta.rjacobi = zmeta.rkronecker
+
+zmeta.legendre = zmeta.kronecker
+zmeta.rlegendre = zmeta.rkronecker
+
+function zmeta:lcm(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_lcm(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_lcm_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_lcm_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_lcm(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function lucnum(a, res)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_lucnum_ui(a, res)
+end
+
+function lucnum2(a, r1, r2)
+ checku(a)
+ checkzopt(r1)
+ checkzopt(r2)
+ return prv.mpz_lucnum2_ui(a, r1, r2)
+end
+
+function zmeta:mod(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_mod(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_fdiv_r_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_cdiv_r_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_mod(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:mul(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_mul(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_mul_ui(self, a, res)
+ elseif t == "s" then
+ return prv.mpz_mul_si(self, a, res)
+ elseif t == "n" then
+ res = prv.mpz_mul_ui(self, -a, res)
+ return prv.mpz_neg(res, res)
+ elseif t == "z" then
+ return prv.mpz_mul(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:mul_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(self)
+ return prv.mpz_mul_2exp(self, a, res)
+end
+
+function zmeta:neg(res)
+ checkz(self)
+ checkzopt(res)
+ return prv.mpz_neg(self, res)
+end
+
+function zmeta:nextprime(res)
+ checkz(self)
+ checkzopt(res)
+ return prv.mpz_nextprime(self, res)
+end
+
+function zmeta:perfect_power()
+ checkz(self)
+ return prv.mpz_perfect_power_p(self) ~= 0
+end
+
+function zmeta:perfect_square()
+ checkz(self)
+ return prv.mpz_perfect_square_p(self) ~= 0
+end
+
+function zmeta:popcount()
+ checkz(self)
+ return prv.mpz_popcount(self)
+end
+
+function zmeta:pow(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_pow_ui(self, a, res)
+end
+
+function zmeta:powm(a1, a2, res)
+ checkz(self)
+ checkz(a2)
+ checkzopt(res)
+ local t = ntype(a1)
+ if t == "d" then
+ return prv.mpz_powm(self, dtoz(a1), a2, res)
+ elseif t == "u" then
+ return prv.mpz_powm_ui(self, a1, a2, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_powm(self, dtoz(a1), a2, res)
+ elseif t == "z" then
+ return prv.mpz_powm(self, a1, a2, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:probab_prime(a)
+ checkz(self)
+ if a == nil then a = 10 else ckechn(a) end
+ local res = prv.mpz_probab_prime_p(self, a)
+ return res ~= 0 and res
+end
+
+function zmeta:remove(a, res)
+ checkz(self)
+ checkzopt(res)
+ if type(a) == "number" then
+ return prv.mpz_remove(self, dtoz(a), res)
+ elseif isz(a) then
+ return prv.mpz_rempve(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:root(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ local r2
+ res, r2 = prv.mpz_root(self, a, res)
+ return res, r2 ~= 0
+end
+
+function zmeta:rootrem(a, r1, r2)
+ checkz(self)
+ checku(a)
+ checkzopt(r1)
+ checkzopt(r2)
+ return prv.mpz_rootrem(self, a, r1, r2)
+end
+
+function zmeta:scan0(a)
+ checkz(self)
+ if a == nil then a = 0 else checku(a) end
+ return prv.mpz_scan0(self, a)
+end
+
+function zmeta:scan1(a)
+ checkz(self)
+ if a == nil then a = 0 else checku(a) end
+ return prv.mpz_scan1(self, a)
+end
+
+function zmeta:set(a, base)
+ checkz(self)
+ if type(a) == "number" then
+ prv.mpz_set_d(self, a)
+ elseif type(a) == "string" then
+ if base == nil then
+ base = 0
+ elseif base ~= 0 then
+ checkbase(base)
+ end
+ if prv.mpz_set_str(self, a, base) ~= 0 then
+ error("not a valid integer constant in base " .. base .. ": " .. a)
+ end
+ elseif isz(a) then
+ prv.mpz_set(self, a)
+ elseif isf(a) then
+ prv.mpz_set_f(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:setbit(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_setbit(self, a, res)
+end
+
+function zmeta:sgn()
+ checkz(self)
+ return prv.mpz_sgn(self)
+end
+
+function zmeta:sizeinbase(a)
+ checkz(self)
+ if a == nil then a = 10 else checkbase(a) end
+ return prv.mpz_sizeinbase(self, a)
+end
+
+function zmeta:sqrt(res)
+ checkz(self)
+ assert(prv.mpz_sgn(self) >= 0, "taking square of negative number")
+ checkzopt(res)
+ return prv.mpz_sqrt(self, res)
+end
+
+function zmeta:sqrtrem(r1, r2)
+ checkz(self)
+ assert(prv.mpz_sgn(self) >= 0, "taking square of negative number")
+ checkzopt(r1)
+ checkzopt(r2)
+ return prv.mpz_sqrtrem(self, r1, r2)
+end
+
+function zmeta:sub(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_sub(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_sub_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_add_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_sub(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:rsub(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a1)
+ if t == "d" then
+ return prv.mpz_sub(dtoz(a), self, res)
+ elseif t == "u" then
+ return prv.mpz_ui_sub(a, self, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpz_add_ui(self, -a, res)
+ return prv.mpz_neg(res, res)
+ elseif t == "z" then
+ return prv.mpz_sub(a, self, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:submul(a1, a2)
+ checkz(self)
+ checkz(a1)
+ local t = ntype(a2)
+ if t == "d" then
+ prv.mpz_submul(self, a1, dtoz(a2))
+ elseif t == "u" then
+ prv.mpz_submul_ui(self, a1, a2)
+ elseif t == "s" or t == "n" then
+ prv.mpz_addmul_ui(self, a1, -a2)
+ elseif t == "z" then
+ prv.mpz_submul(self, a1, a2)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:tdiv_q(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_tdiv_q(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_tdiv_q_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ local r2
+ res, r2 = prv.mpz_tdiv_q_ui(self, -a, res)
+ return prv.mpz_neg(res, res), r2
+ elseif t == "z" then
+ return prv.mpz_tdiv_q(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:tdiv_q_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_tdiv_q_2exp(self, a, res)
+end
+
+function zmeta:tdiv_qr(a, r1, r2)
+ checkz(self)
+ checkzopt(r1)
+ checkzopt(r2)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_tdiv_qr(self, dtoz(a), r1, r2)
+ elseif t == "u" then
+ return prv.mpz_tdiv_qr_ui(self, a, r1, r2)
+ elseif t == "s" or t == "n" then
+ local r3
+ r1, r2, r3 = prv.mpz_tdiv_qr_ui(self, -a, r1, r2)
+ return prv.mpz_neg(r1, r1), r2, r3
+ elseif t == "z" then
+ return prv.mpz_tdiv_qr(self, a, r1, r2)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:tdiv_r(a, res)
+ checkz(self)
+ checkzopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpz_tdiv_r(self, dtoz(a), res)
+ elseif t == "u" then
+ return prv.mpz_tdiv_r_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_tdiv_r_ui(self, -a, res)
+ elseif t == "z" then
+ return prv.mpz_tdiv_r(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:tdiv_r_2exp(a, res)
+ checkz(self)
+ checku(a)
+ checkzopt(res)
+ return prv.tdiv_r_2exp(self, a, res)
+end
+
+function zmeta:tdiv(a)
+ checkz(self)
+ local t = ntype(a)
+ if t == "u" then
+ return prv.mpz_tdiv_ui(self, a)
+ elseif t == "s" or t == "n" then
+ return prv.mpz_tdiv_ui(self, -a)
+ else
+ error("unsupported type")
+ end
+end
+
+function zmeta:tstbit(a)
+ checkz(self)
+ checku(a)
+ return prv.mpz_tstbit(self, a)
+end
+
+function pow(a1, a2, res)
+ checku(a2)
+ checkzopt(res)
+ local t = ntype(a1)
+ if t == "d" then
+ return prv.mpz_pow_ui(dtoz(a1), a2, res)
+ elseif t == "u" then
+ return prv.mpz_ui_pow_ui(a1, a2, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpz_ui_pow_ui(-a1, a2, res)
+ if a2%2 ~= 0 then
+ prv.mpz_neg(res, res)
+ end
+ return res
+ elseif t == "z" then
+ return prv.mpz_pow_ui(a1, a2, res)
+ else
+ error("unsupported type")
+ end
+ return prv.mpz_ui_pow_ui(a1, a2, res)
+end
+
+function zmeta:xor(a, res)
+ checkz(self)
+ checkzopt(res)
+ if type(a) == "number" then
+ return prv.mpz_xor(self, dtoz(a), res)
+ elseif isz(a) then
+ return prv.mpz_xor(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:abs(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_abs(self, res)
+end
+
+function fmeta:add(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_add(self, dtof(a), res)
+ elseif t == "u" then
+ return prv.mpf_add_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpf_sub_ui(self, -a, res)
+ elseif t == "f" then
+ return prv.mpf_add(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:ceil(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_ceil(self, res)
+end
+
+function fmeta:cmp(a)
+ checkf(self)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_cmp_d(self, a)
+ elseif t == "u" then
+ return prv.mpf_cmp_ui(self, a)
+ elseif t == "s" then
+ return prv.mpf_cmp_si(self, a)
+ elseif t == "n" then
+ return prv.mpf_cmp(self, dtof(a))
+ elseif t == "f" then
+ return prv.mpf_cmp(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:div(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_div(self, dtof(a), res)
+ elseif t == "u" then
+ return prv.mpf_div_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpf_div_ui(self, -a, res)
+ return prv.mpf_neg(res, res);
+ elseif t == "f" then
+ return prv.mpf_div(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:eq(a1, a2)
+ checkf(self)
+ checkf(a1)
+ checku(a2)
+ return prv.mpf_eq(self, a1, a2) ~= 0
+end
+
+function fmeta:fits_sint()
+ checkf(self)
+ return prv.mpf_fits_sint_p(self) ~= 0
+end
+
+function fmeta:fits_sshort()
+ checkf(self)
+ return prv.mpf_fits_sshort_p(self) ~= 0
+end
+
+function fmeta:fits_uint()
+ checkf(self)
+ return prv.mpf_fits_uint_p(self) ~= 0
+end
+
+function fmeta:fits_ulong()
+ checkf(self)
+ return prv.mpf_fits_ulong_p(self) ~= 0
+end
+
+function fmeta:fits_ushort()
+ checkf(self)
+ return prv.mpf_fits_ushort_p(self) ~= 0
+end
+
+function fmeta:floor(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_floor(self, res)
+end
+
+function fmeta:get_d()
+ checkf(self)
+ return prv.mpf_get_d(self)
+end
+
+function fmeta:get_d_2exp()
+ checkf(self)
+ return prv.mpf_get_d_2exp(self)
+end
+
+get_default_prec = prv.mpf_get_default_prec
+
+function fmeta:get_prec()
+ checkf(self)
+ return prv.mpf_get_prec(self)
+end
+
+function fmeta:get_str(base, size)
+ checkf(self)
+ if base == nil then base = 10 else checkbase(base) end
+ if size == nil then size = 0 else checkn(size) end
+ return prv.mpf_get_str(base, size, self)
+end
+
+function fmeta:integer()
+ checkf(self)
+ return prv.mpf_integer_p(self) ~= 0
+end
+
+function fmeta:mul(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_mul(self, dtof(a), res)
+ elseif t == "u" then
+ return prv.mpf_mul_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpf_mul_ui(self, -a, res)
+ return prv.mpf_neg(res, res)
+ elseif t == "f" then
+ return prv.mpf_mul(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:mul_2exp(a, res)
+ checkf(self)
+ checku(a)
+ checkfopt(res)
+ return prv.mpf_mul_2exp(self, a, res)
+end
+
+function fmeta:neg(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_neg(self, res)
+end
+
+function fmeta:pow(a, res)
+ checkf(self)
+ checku(a)
+ checkfopt(res)
+ return prv.mpf_pow_ui(self, a, res)
+end
+
+function fmeta:reldiff(a, res)
+ checkf(self)
+ checkf(a)
+ checkfopt(res)
+ return prv.mpf_reldiff(self, a, res)
+end
+
+function set_default_prec(a)
+ checku(a)
+ prv.mpf_set_default_prec(a)
+end
+
+function fmeta:set_prec(a)
+ checkf(self)
+ checku(a)
+ prv.mpf_set_prec(self, a)
+end
+
+function fmeta:set(a, base)
+ checkf(self)
+ if type(a) == "number" then
+ prv.mpf_set_d(self, a)
+ elseif type(a) == "string" then
+ if base == nil then
+ base = 10
+ elseif type(base) == "number" and base < 0 then
+ checkbase(-base)
+ else
+ checkbase(base)
+ end
+ if prv.mpf_set_str(self, a, base) ~= 0 then
+ error("not a valid floating point constant in base " .. base .. ": " .. a)
+ end
+ elseif isf(a) then
+ prv.mpf_set(self, a)
+ elseif isz(a) then
+ prv.mpf_set_z(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:sgn()
+ checkf(self)
+ return prv.mpf_sgn(self)
+end
+
+function fmeta:sqrt(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_sqrt(self, res)
+end
+
+function sqrt(a, res)
+ checku(a)
+ checkfopt(res)
+ return prv.mpf_sqrt_ui(a, res)
+end
+
+function fmeta:sub(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_sub(self, dtof(a), res)
+ elseif t == "u" then
+ return prv.mpf_sub_ui(self, a, res)
+ elseif t == "s" or t == "n" then
+ return prv.mpf_add_ui(self, -a, res)
+ elseif t == "f" then
+ return prv.mpf_sub(self, a, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:trunc(res)
+ checkf(self)
+ checkfopt(res)
+ return prv.mpf_trunc(self, res)
+end
+
+function fmeta:rdiv(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_div(dtof(a), self, res)
+ elseif t == "u" then
+ return prv.mpf_ui_div(a, self, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpf_ui_div(-a, self, res)
+ return prv.mpf_neg(res, res)
+ elseif t == "f" then
+ return prv.mpf_div(a, self, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:rsub(a, res)
+ checkf(self)
+ checkfopt(res)
+ local t = ntype(a)
+ if t == "d" then
+ return prv.mpf_sub(dtof(a), self, res)
+ elseif t == "u" then
+ return prv.mpf_ui_sub(a, self, res)
+ elseif t == "s" or t == "n" then
+ res = prv.mpf_add_ui(self, -a, res)
+ return prv.mpf_neg(res, res)
+ elseif t == "f" then
+ return prv.mpf_sub(a, self, res)
+ else
+ error("unsupported type")
+ end
+end
+
+function fmeta:__add(a)
+ if isf(self) then
+ return fmeta.add(self, a)
+ else
+ return fmeta.add(a, self)
+ end
+end
+
+function fmeta:__sub(a)
+ if isf(self) then
+ return fmeta.sub(self, a)
+ else
+ return fmeta.rsub(a, self)
+ end
+end
+
+function fmeta:__mul(a)
+ if isf(self) then
+ return fmeta.mul(self, a)
+ else
+ return fmeta.mul(a, self)
+ end
+end
+
+function fmeta:__div(a)
+ if isf(self) then
+ return fmeta.div(self, a)
+ else
+ return fmeta.rdiv(a, self)
+ end
+end
+
+function fmeta:__unm()
+ checkf(self)
+ return prv.mpf_neg(self)
+end
+
+function fmeta:__pow(a)
+ checkf(self)
+ checku(a)
+ return prv.mpf_pow_ui(self, a)
+end
+
+function fmeta:__lt(a)
+ checkf(self)
+ checkf(a)
+ return prv.mpf_cmp(self, a) < 0
+end
+
+function fmeta:__le(a)
+ checkf(self)
+ checkf(a)
+ return prv.mpf_cmp(self, a) <= 0
+end
+
+function fmeta:__eq(a)
+ checkf(self)
+ checkf(a)
+ return prv.mpf_cmp(self, a) == 0
+end
+
+function fmeta:__tostring()
+ return fmeta.format(self, ".g")
+end
+
+function fmeta:__concat(other)
+ if isf(self) then
+ return fmeta.__tostring(self) .. other
+ else
+ return self .. fmeta.__tostring(other)
+ end
+end
+
+function fmeta:__gc()
+ checkf(self)
+ return prv.mpf_clear(self)
+end
+
+function rand(a)
+ if a == nil then
+ return prv.gmp_randinit_default()
+ else
+ checkrand(a)
+ return prv.gmp_randinit_set(a)
+ end
+end
+
+function randmeta:seed(a)
+ checkrand(self)
+ local t = ntype(a)
+ if a == "u" then
+ prv.gmp_randseed_ui(self, a)
+ elseif a == "z" then
+ prv.gmp_randseed(self, a)
+ else
+ error("unsupported type")
+ end
+end
+
+function randmeta:zbits(a, res)
+ checkrand(self)
+ checku(a)
+ checkzopt(res)
+ return prv.mpz_urandomb(self, a, res)
+end
+
+function randmeta:z(a, res)
+ checkrand(self)
+ checkz(a)
+ checkzopt(res)
+ return prv.mpz_urandomm(self, a, res)
+end
+
+function randmeta:fbits(a, res)
+ checkrand(self)
+ checku(a)
+ checkfopt(res)
+ return prv.mpf_urandomb(self, a, res)
+end
+
+function randmeta:__gc()
+ checkrand(self)
+ prv.gmp_randclear(self)
+end
+
+function randmeta:__tostring()
+ checkrand(self)
+ return "gmp random state"
+end
+
+function zmeta:format(fmt, p)
+ checkz(self)
+ assert(type(fmt) == "string", "gmp integer format string expected")
+ local fw, prec, conv =
+ match(fmt, "^%%?([0#+ ]?%d*)(%.?%*?%d*)Z?([dioxX])$")
+
+ if not conv or prec ~= "" and prec ~= ".*" and not match(prec, "^%.%d*$") then
+ error("invalid format string for gmp integer: " .. fmt)
+ end
+
+ if prec == ".*" then
+ checkn(p)
+ else
+ assert(p == nil, "precision incorrectly specified")
+ end
+
+ return prv.mpz_asprintf("%" .. fw .. prec .. "Z" .. conv, self, p)
+end
+
+function fmeta:format(fmt, p)
+ checkf(self)
+ assert(type(fmt) == "string", "gmp floating point format string expected")
+ local fw, prec, conv =
+ match(fmt, "^%%?([0#+ ]?%d*)(%.?%*?%d*)F?([aAeEfgG])$")
+
+ if not conv or prec ~= "" and prec ~= ".*" and not match(prec, "^%.%d*$") then
+ error("invalid format string for gmp floating point: " .. fmt)
+ end
+
+ if prec == ".*" then
+ checkn(p)
+ else
+ assert(p == nil, "precision incorrectly specified")
+ end
+
+ return prv.mpf_asprintf("%" .. fw .. prec .. "F" .. conv, self, p)
+end
+
+function lgmp_lua_init(l_prv, l_aux)
+ aux.randmeta = randmeta
+ aux.zmeta = zmeta
+ aux.fmeta = fmeta
+
+ prv = l_prv
+ aux = l_aux
+
+ lgmpversion = prv.version
+
+ lgmp_init = nil
+end
+