diff options
Diffstat (limited to 'src/lgmp.lua')
-rw-r--r-- | src/lgmp.lua | 1639 |
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 + |