Category talk:Wren-gmp
Arbitrary precision arithmetic
Although this is already supported in an easy to use way by the Wren-big module, there are some RC tasks which that module (written entirely in Wren) struggles to complete in an acceptable time or to a satisfactory standard.
I have therefore written a Wren wrapper for the C library, GMP, to deal with such cases. This supports arithmetic not just on integers and rational numbers (as Wren-big does) but also on floating point numbers of arbitrary size. Most of GMP's functions (around 190) have been wrapped though some - notably those concerned with input/output and random numbers - have been excluded as I didn't think they would be very useful from Wren's perspective. I have also included some additional 'convenience' methods which can be coded in a few lines using the GMP functions as well as some prime factorization routines.
GMP is not an ideal fit for an object oriented language such as Wren because arithmetic operations mutate the object itself rather than producing a new object each time as 'normal' arithmetic (and Wren-big) do. However, this constant recycling of memory means that fewer variables and less garbage collection is required for a typical application and so there's an inevitable trade-off here between maximizing efficiency/performance and easy of use. In an attempt to retain as much of the latter as possible:
1. I have included versions of the main functions which operate on and always return a reference to the current object which reduces verbosity and enables method chaining. These methods also sense the type of the argument eliminating the need to have separate versions for GMP types and unsigned integers.
2. The three classes: Mpz, Mpq and Mpf all inherit from the Comparable trait which mean that the normal ordering operators (<, <=, ==, !=, >=, >) can be used for comparisons.
3. I have also included operator overloading for the basic arithmetic operations with the difference that these always produce a new object rather than mutating the current one. Consequently, these should be used sparingly in scripts which need to maximize performance but can be used more freely in other scripts to provide a more 'natural' programming experience.
4. Memory is managed automatically by Wren which calls an object's finalizer just before it is about to be garbage collected. The finalizer in turn calls the appropriate GMP 'clear' function to ensure that memory allocated to the object is fully released. So there is no need for the user to call this function directly and, to avoid 'double clear' scenarios, it is not exposed by Wren at all. If you want to reduce memory usage prior to garbage collection, then the object's 'reset' method can be called instead.
5. The wrapper also ensures that Mpf objects are always canonicalized so there is no need for the user to worry about this particular aspect.
MPF or MPFR?
I did wonder about using MPFR rather than MPF for floating-point support. MPFR is undoubtedly better not just from a technical perspective but also because it supports many more functions (notably the transcendental functions) than MPF does and even the GMP folks themselves recommend that it should be considered for new projects.
However, it's also far more complicated to wrap and doesn't integrate quite so well as MPF with the rest of GMP - as well as an additional rounding mode it uses a default value of NaN rather than zero for new objects which is not ideal from Wren's perspective.
I have therefore decided to stick with MPF for basic arithmetic, for which it is perfectly adequate, but use MPFR for the transcendental functions. There are 25 such functions which I thought it would be worthwhile supporting and, as the wrapper converts automatically between the MPF and MPFR types, this is transparent to the user.
How fast?
Early results suggest Wren-gmp will be significantly faster than Wren-big for scripts requiring a lot of 'big number' arithmetic. However, writers of Wren-cli scripts which require file handling or other stuff which embedded Wren doesn't support 'out of the box' may prefer to stick to the former rather than make one off changes to the C executable.
Of course, the speed improvement doesn't mean that Wren will be able to compete with the statically typed compiled languages which use GMP or a similar package - it won't. Even though Wren's embedding API is quite fast and GMP/MPFR are very fast, this won't compensate for the fact that Wren is interpreted and uses double precision floating point for all numeric work even when only integers are required.
Source code (Wren)
/* Module "gmp.wren" */
import "./trait" for Comparable
/*
Mpz represents an arbitrary length integer allowing arithmetic operations on signed integers of
unlimited size. An Mpz object is a pointer to the GMP type mpz_t and is mutable. Many methods
map directly to the corresponding GMP functions though others are provided for convenience.
If Num objects are passed which are not integers, they will be truncated towards zero by GMP.
*/
foreign class Mpz is Comparable {
// Creates small commonly used Mpz objects.
static minusOne { from(-1) }
static zero { new() }
static one { from(1) }
static two { from(2) }
static three { from(3) }
static four { from(4) }
static five { from(5) }
static six { from(6) }
static seven { from(7) }
static eight { from(8) }
static nine { from(9) }
static ten { from(10) }
// Swaps the values of two Mpz objects.
foreign static swap(op1, op2)
// Splits an Mpz into a double plus an exponent (returned as a list of two Nums).
foreign static frexp(op)
// Returns a list containing the quotient and remainder of (c)dividing two Mpz objects.
foreign static cdivRem(n, d)
// Returns a list containing the quotient and remainder of (c)dividing an Mpz object by a uint.
foreign static cdivRemUi(n, d)
// Returns a list containing the quotient and remainder of (f)dividing two Mpz objects.
foreign static fdivRem(n, d)
// Returns a list containing the quotient and remainder of (f)dividing an Mpz object by a uint.
foreign static fdivRemUi(n, d)
// Returns a list containing the quotient and remainder of (t)dividing two Mpz objects.
foreign static tdivRem(n, d)
// Returns a list containing the quotient and remainder of (t)dividing an Mpz object by a uint.
foreign static tdivRemUi(n, d)
// Aliases for tdivRem and tdivRemUi
static divRem(n, d) { tdivRem(n, d) }
static divRemUi(n, d) { tdivRemUi(n, d) }
// Returns a list containing the n'th (uint) root of op (Mpz) and the remainder.
foreign static rootRem(op, n)
// Returns a list containing the square root of op (Mpz) and the remainder.
foreign static sqrtRem(op, n)
// Returns the Jacobi symbol (a/b) of two Mpz objects.
foreign static jacobi(a, b)
// Returns the Legendre symbol (a/p) of two Mpz objects.
foreign static legendre(a, p)
// Returns the Kronecker symbol (a/b) of two Mpz objects.
foreign static kronecker(a, b)
// Returns the Hamming distance between two Mpz objects.
foreign static hamDist(op1, op2)
// Returns the smaller of two Mpz objects.
static min(op1, op2) {
if (!(op1 is Mpz)) op1 = from(op1)
if (!(op2 is Mpz)) op2 = from(op2)
if (op1 < op2) return op1
return op2
}
// Returns the greater of two Mpz objects.
static max(op1, op2) {
if (!(op1 is Mpz)) op1 = from(op1)
if (!(op2 is Mpz)) op2 = from(op2)
if (op1 > op2) return op1
return op2
}
// Returns the positive difference of two Mpz objects.
static dim(op1, op2) {
if (!(op1 is Mpz)) op1 = from(op1)
if (!(op2 is Mpz)) op2 = from(op2)
if (op1 >= op2) return op1 - op2
return Mpz.zero
}
// Private method which aborts the script if an argument is of an invalid type or value.
static abort_() { Fiber.abort("Argument type or value is invalid.") }
// Creates a new Mpz object with a value of zero.
construct new() {}
// Creates a new Mpz object from:
construct fromMpz(op) {} // another Mpz object
construct fromDbl(op) {} // a double
construct fromStr(op, b) {} // a base 'b' string (assigns zero if invalid)
static fromStr(op) { fromStr(op, 10) } // a base 10 string
// Convenience method which creates a new Mpz object from any other numeric type.
static from(op) {
if (op is Mpz) return fromMpz(op)
if (op is Num) {
if (op.isInteger) return (op >= 0) ? new().setUi(op) : new().setSi(op)
return fromDbl(op)
}
if (op is Mpq) return new().setMpq(op)
if (op is Mpf) return new().setMpf(op)
abort_()
}
// Assigns a new value to the current instance using :
foreign setMpz(op) // another Mpz object
foreign setMpq(op) // an Mpq object
foreign setMpf(op) // an Mpf object
foreign setDbl(op) // a double
foreign setUi(op) // an unsigned integer
foreign setSi(op) // a signed integer
foreign setStr(str, b) // a base 'b' string (unchanged if invalid)
setStr(str) { setStr(str, 10) } // a base 10 string
// Convenience method which assigns a new value to the current instance
// from any other numeric type.
set(op) {
if (op is Mpz) return setMpz(op)
if (op is Num) {
if (op.isInteger) return (op >= 0) ? setUi(op) : setSi(op)
return setDbl(op)
}
if (op is Mpq) return setMpq(op)
if (op is Mpf) return setMpf(op)
Mpz.abort_()
}
// Resets the value of the current instance to zero and the space allocated to 64 bits.
reset() { setUi(0).setBits(64) }
// Changes the space allocated for the current instance to n bits.
// The former is reset to zero if its value no longer fits.
foreign setBits(n)
// Converts the current instance to:
foreign toNum // a number
foreign toString(b) // a base 'b' string
toString { toString(10) } // a base 10 string
toMpq { Mpq.from(this) } // an Mpq object
toMpf { Mpf.from(this) } // an Mpf object
/* Methods which assign their result to the current instance ('this').
'uint' denotes a Num which is an unsigned integer.
'sint' denotes a Num which is a signed integer. */
foreign add(op1, op2) // adds two Mpz objects
foreign addUi(op1, op2) // adds an Mpz object and a uint
foreign sub(op1, op2) // subtracts one Mpz object from another
foreign subUi(op1, op2) // subtracts a uint from an Mpz object
foreign uiSub(op1, op2) // subtracts an Mpz object from a uint
foreign mul(op1, op2) // multiplies two Mpz objects
foreign mulUi(op1, op2) // multiplies an Mpz object by a uint
foreign mulSi(op1, op2) // multiplies an Mpz object by a sint
foreign addMul(op1, op2) // multiplies two Mpz objects and adds the result to this
foreign addMulUi(op1, op2) // multiplies an Mpz by op2 (uint) and adds the result to this
foreign subMul(op1, op2) // multiplies two Mpz objects and subtracts the result from this
foreign subMulUi(op1, op2) // multiplies an Mpz by a uint and subtracts the result from this
foreign cdiv(n, d) // divides one Mpz object by another (rounds towards +infinity)
foreign cdivUi(n, d) // divides an Mpz object by a uint (rounds towards +infinity)
foreign fdiv(n, d) // divides one Mpz object by another (rounds towards -infinity)
foreign fdivUi(n, d) // divides an Mpz object by a uint (rounds towards -infinity)
foreign tdiv(n, d) // divides one Mpz object by another (rounds towards zero)
foreign tdivUi(n, d) // divides an Mpz object by a uint (rounds towards zero)
addSi(op1, op2) { (op2 >= 0) ? addUi(op1, op2) : subUi(op1, -op2) } // op2 is a sint
subSi(op1, op2) { (op2 >= 0) ? subUi(op1, op2) : addUi(op1, -op2) } // op2 is a sint
div(n, d) { tdiv(n, d) } // alias for tdiv
divUi(n, d) { tdivUi(n, d) } // alias for tdivUi
divSi(n, d) { (d >= 0) ? tdivUi(n, d) : tdivUi(n, -d).neg } // d is a sint
foreign crem(n, d) // sets the remainder after 'cdiv' by another Mpz object
foreign cremUi(n, d) // sets the remainder after 'cdiv' by a uint
foreign frem(n, d) // sets the remainder after 'fdiv' by another Mpz object
foreign fremUi(n, d) // sets the remainder after 'fdiv' by a uint
foreign trem(n, d) // sets the remainder after 'tdiv' by another Mpz object
foreign tremUi(n, d) // sets the remainder after 'tdiv' by a uint
rem(n, d) { trem(n,d) } // alias for trem
remUi(n, d) { tremUi(n, d) } // alias for tremUi
remSi(n, d) { (d >= 0) ? tremUi(n, d) : tremUi(n, -d) } // d is a sint
foreign mod(n, d) // sets to n (Mpz) mod d (Mpz) ignoring the sign of d
foreign modUi(n, d) // sets to n (Mpz) mod d (uint) ignoring the sign of d
foreign divExact(n, d) // sets to n/d (both Mpz objects) when this is known to be exact
foreign divExactUi(n, d) // as divExact when the second argument is a uint
foreign neg(op) // sets to -op (Mpz)
foreign abs(op) // sets to the absolute value of op (Mpz)
inc(op) { addUi(op, 1) } // adds one to op
dec(op) { subUi(op, 1) } // subtracts one from op
foreign pow(base, exp) // raises base (Mpz) to the power exp (uint)
foreign uiPow(base, exp) // raises base (uint) to the power exp (uint)
square(op) { mul(op, op) } // sets to the square of op
cube(op) { pow(op, 3) } // sets to the cube of op
foreign modPow(base, exp, mod) // raises base (Mpz) to the power exp (Mpz) modulo mod (Mpz)
foreign modPowUi(base, exp, mod) // raises base (Mpz) to the power exp (uint) modulo mod (Mpz)
foreign root(op, n) // sets to the n'th root (uint) of op (Mpz)
foreign sqrt(op) // sets to the square root of op (Mpz)
cbrt(op) { root(op, 3) } // sets to the cube root of op (Mpz)
foreign lsh(n, b) // shifts n (Mpz) by b (uint) bits to the left
foreign rsh(n, b) // shifts n (Mpz) by b (uint) bits to the right
foreign com(op) // one's complement of an Mpz object
foreign and(op1, op2) // bitwise 'and' of two Mpz objects
foreign ior(op1, op2) // bitwise 'inclusive or' of two Mpz objects
foreign xor(op1, op2) // bitwise 'exclusive or' of two Mpz object
foreign gcd(op1, op2) // greatest common denominator of two Mpz objects
foreign gcdUi(op1, op2) // greatest common denominator of an Mpz object and a uint
foreign lcm(op1, op2) // lowest common multiple of two Mpz objects
foreign lcmUi(op1, op2) // lowest common multiple of an Mpz object and a uint
foreign modInv(op1, op2) // modular inverse of op1 mod op2
foreign remove(op, f) // removes all factors f from op and returns number removed
foreign nextPrime(op) // next prime > op (Mpz)
prevPrime(op) { // previous prime < op (Mpz) or aborts if no such prime
if (op < Mpz.three) {
Mpz.abort_()
}
if (op == Mpz.three) {
this.setMpz(Mpz.two)
return
}
var n = Mpz.new().setMpz(op.isEven ? op - Mpz.one : op - Mpz.two)
while (true) {
if (n.probPrime(15) > 0) {
this.setMpz(n)
return
}
n.sub(Mpz.two)
}
}
/* Convenience versions of the above methods where the first (or only) argument is 'this'.
Unless otherwise noted, any other argument must either be another Mpz object or a uint.
Other Nums are converted by GMP to uint. */
add(op) { (op is Mpz) ? add(this, op) : ((op is Num) ? addSi(this, op) : Mpz.abort_()) } // sint
sub(op) { (op is Mpz) ? sub(this, op) : ((op is Num) ? subSi(this, op) : Mpz.abort_()) } // sint
mul(op) { // sint
if (op is Mpz) return mul(this, op)
if (op is Num) {
return (op >= 0) ? mulUi(this, op) : mulSi(this, op)
}
Mpz.abort_()
}
addMul(op) { (op is Mpz) ? addMul(this, op) : ((op is Num) ? addMulUi(this, op) : Mpz.abort_()) }
subMul(op) { (op is Mpz) ? subMul(this, op) : ((op is Num) ? subMulUi(this, op) : Mpz.abort_()) }
cdiv(d) { (d is Mpz) ? cdiv(this, d) : ((d is Num) ? cdivUi(this, d) : Mpz.abort_()) }
fdiv(d) { (d is Mpz) ? fdiv(this, d) : ((d is Num) ? fdivUi(this, d) : Mpz.abort_()) }
tdiv(d) { (d is Mpz) ? tdiv(this, d) : ((d is Num) ? tdivUi(this, d) : Mpz.abort_()) }
div(d) { (d is Mpz) ? tdiv(this, d) : ((d is Num) ? divSi (this, d) : Mpz.abort_()) } // sint
crem(d) { (d is Mpz) ? crem(this, d) : ((d is Num) ? cremUi(this, d) : Mpz.abort_()) }
frem(d) { (d is Mpz) ? frem(this, d) : ((d is Num) ? fremUi(this, d) : Mpz.abort_()) }
trem(d) { (d is Mpz) ? trem(this, d) : ((d is Num) ? tremUi(this, d) : Mpz.abort_()) }
rem(d) { (d is Mpz) ? trem(this, d) : ((d is Num) ? remSi (this, d) : Mpz.abort_()) } // sint
mod(d) { (d is Mpz) ? mod (this, d) : ((d is Num) ? modUi (this, d) : Mpz.abort_()) }
divExact(d) { (d is Mpz) ? divExact(this, d) : ((d is Num) ? divExact(this, d) : Mpz.abort_()) }
neg { neg(this) }
abs { abs(this) }
inc { addUi(this, 1) }
dec { subUi(this, 1) }
pow(exp) { pow(this, exp) } // exp is a uint
square { mul(this, this) }
cube { pow(this, 3) }
// Exp can either be an Mpz object or a uint, mod must be an Mpz object.
modPow(exp, mod) {
if (exp is Mpz) return modPow(this, exp, mod)
if (exp is Num) return modPowUi(this, exp, mod)
Mpz.abort_()
}
root(n) { root(this, n) } // n is a uint
sqrt { sqrt(this) }
cbrt { root(this, 3) }
lsh(b) { lsh(this, b) } // b is a uint
rsh(b) { rsh(this, b) } // b is a uint
com { com(this) }
and(op) { and(this, op) }
ior(op) { ior(this, op) }
xor(op) { xor(this, op) }
gcd(op) { (op is Mpz) ? gcd(this, op) : ((op is Num) ? gcdUi(this, op) : Mpz.abort_()) }
lcm(op) { (op is Mpz) ? lcm(this, op) : ((op is Num) ? lcmUi(this, op) : Mpz.abort_()) }
modInv(op) { modInv(this, op) } // op is an Mpz object
remove(f) { remove(this, f) } // f is an Mpz object
nextPrime { nextPrime(this) }
prevPrime { prevPrime(this) }
/* As above methods where the first (or only) argument is 'this'
but return a new Mpz object rather than mutating 'this'. */
- { copy().neg }
~ { copy().com }
+(op) { copy().add(op) }
-(op) { copy().sub(op) }
*(op) { copy().mul(op) }
/(op) { copy().div(op) }
%(op) { copy().rem(op) }
<<(b) { copy().lsh(b) }
>>(b) { copy().rsh(b) }
&(op) { copy().and(op) }
|(op) { copy().ior(op) }
^(op) { copy().xor(op) }
/* Methods which may mutate the current instance or simply return it. */
min(op) { (op < this) ? set(op) : this } // minimum of this and op
max(op) { (op > this) ? set(op) : this } // maximum of this and op
clamp(min, max) { // clamps this to the interval [min, max]
if (min > max) Fiber.abort("Range cannot be decreasing.")
if (this < min) set(min) else if (this > max) set(max)
return this.copy()
}
/* Comparison methods which return -1, 0, 1
if this < op, this == op or this > op respectively. */
foreign cmpMpz(op) // compare this to another Mpz object
foreign cmpDbl(op) // compare this to a double
foreign cmpUi(op) // compare this to a uint
foreign cmpSi(op) // compare this to a sint
foreign cmpAbsMpz(op) // compare this to another Mpz object by absolute values
foreign cmpAbsDbl(op) // compare this to a double by absolute values
foreign cmpAbsUi(op) // compare this to a uint by absolute values
// Needed to satisfy Comparable trait and allow relational operators to be used.
compare(op) {
if (op is Mpz) return cmpMpz(op)
if (op is Num) return !op.isInteger ? cmpDbl(op) : (op < 0) ? cmpSi(op) : cmpUi(op)
Mpz.abort_()
}
// Convenience method for comparison by absolute values.
compareAbs(op) {
if (op is Mpz) return cmpAbsMpz(op)
if (op is Num) return !op.isInteger ? cmpAbsDbl(op) : cmpAbsUi(op)
Mpz.abort_()
}
/* Miscellaneous methods. */
copy() { Mpz.fromMpz(this) } // copies 'this' to a new Mpz object
foreign isOdd // true if 'this' is odd
foreign isEven // true if 'this' is even
isZero { cmpUi(0) == 0 } // true if 'this' is zero
foreign isDivisible(d) // true if 'this' is divisible by d (Mpz)
foreign isDivisibleUi(d) // true if 'this' is divisible by d (uint)
foreign isDivisible2(b) // true if 'this' is divisible by 2^b (uint)
foreign isCongruent(c, d) // true if 'this' is congruent to c (Mpz) mod d (Mpz)
foreign isCongruentUi(c, d) // true if 'this' is congruent to c (uint) mod d (uint)
foreign isCongruent2(c, b) // true if 'this' is congruent to c (uint) mod 2^b(uint)
foreign isPower // true if 'this' = a ^ b, for some integers a and b with b > 1
foreign isSquare // true if 'this' = a ^ 2, for some integer a
foreign probPrime(reps) // 0, 1 or 2 if 'this' is definitely non-prime, probably prime
// or definitely prime respectively after 'reps' repetitions
foreign sign(op) // the sign of an Mpz object
sign { sign(this) } // the sign of the current instance
foreign factorial(n) // the factorial of n (uint), n!
foreign factorial2(n) // the double factorial of n (uint), n!!
foreign mfactorial(n, m) // the m-multifactorial of n, n!^m, both arguments uints
foreign primorial(n) // the primorial of n (uint) i.e. product of all primes <= n
foreign binomial(n, k) // the binomial coefficent of n (Mpz) over k (uint)
foreign binomialUi(n, k) // the binomial coefficent of n (uint) over k (uint)
foreign fibonacci(n) // the n'th (uint) Fibonacci number
foreign lucas(n) // the n'th (uint) Lucas number
multinomial(n, f) { // the multinomial coefficient of n over a list f where sum(f) == n
if (!(n is Num && n >= 0)) {
Fiber.abort("First argument must be a non-negative integer.")
}
if (!(f is List)) Fiber.abort("Second argument must be a list.")
var sum = f.reduce { |acc, i| acc + i }
if (n != sum) {
Fiber.abort("The elements of the list must sum to 'n'.")
}
var prod = Mpz.one
var fact = Mpz.new()
for (e in f) {
if (e < 0) Fiber.abort("The elements of the list must be non-negative integers.")
if (e > 1) prod.mul(fact.factorial(e))
}
return factorial(n).div(prod)
}
foreign popCount // number of 1 bits in this
foreign scan0(start) // index of first 0 bit in this starting from index 'start'
foreign scan1(start) // index of first 1 bit in this starting from index 'start'
foreign setBit(index) // set bit at 'index' in this
foreign clrBit(index) // clear bit at 'index' in this
foreign comBit(index) // complement bit at 'index' in this
foreign tstBit(index) // test bit at 'index' in this and return its value
foreign sizeInBase(base) // number of digits in the given base 2..62 ignoring any sign
// if the base is not a power of 2 may be one too big
foreign digitsInBase(base) // as sizeInBase, always exact but slower
sizeInBits { sizeInBase(2) } // number of binary digits in this ignoring any sign
/* Prime factorization methods. */
// Private worker method for Pollard's Rho algorithm.
static pollardRho_(m, seed, c) {
var g = Fn.new { |x| (x * x).add(c).rem(m) }
var x = Mpz.from(seed)
var y = Mpz.from(seed)
var z = Mpz.one
var d = Mpz.one
var count = 0
while (true) {
x = g.call(x)
y = g.call(g.call(y))
d = (x - y).abs.rem(m)
z.mul(d)
count = count + 1
if (count == 100) {
d.gcd(z, m)
if (d != 1) break
z.set(1)
count = 0
}
}
if (d == m) return Mpz.zero
return d
}
// Returns a factor (Mpz) of 'm' (an Mpz object or an integral Num) using the
// Pollard's Rho algorithm. Both the 'seed' and 'c' can be set to integers.
// Returns Mpz.zero in the event of failure.
static pollardRho(m, seed, c) {
if (m < 2) return Mpz.zero
if (m is Num) m = Mpz.from(m)
if (m.probPrime(15) > 0) return m.copy()
if (m.isSquare) return m.copy().sqrt
for (p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]) {
if (m.isDivisibleUi(p)) return Mpz.from(p)
}
return pollardRho_(m, seed, c)
}
// Convenience version of the above method which uses a seed of 2 and a value for c of 1.
static pollardRho(m) { pollardRho(m, 2, 1) }
// Private method for factorizing smaller numbers (Mpz) using a wheel with basis [2, 3, 5].
static primeFactorsWheel_(m) {
var n = m.copy()
var inc = [4, 2, 4, 2, 4, 6, 2, 6]
var factors = []
var k = Mpz.from(37)
var i = 0
while (k * k <= n) {
if (n.isDivisible(k)) {
factors.add(k.copy())
n.div(k)
} else {
k.add(inc[i])
i = (i + 1) % 8
}
}
if (n > 1) factors.add(n)
return factors
}
// Private worker method (recursive) to obtain the prime factors of a number (Mpz).
static primeFactors_(m, trialDivs) {
if (m.probPrime(15) > 0) return [m.copy()]
var n = m.copy()
var factors = []
var seed = 2
var c = 1
var checkPrime = true
var threshold = 1e11 // from which using PR may be advantageous
if (trialDivs) {
for (p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]) {
while (n.isDivisibleUi(p)) {
factors.add(Mpz.from(p))
n.div(p)
}
}
}
while (n > 1) {
if (checkPrime && n.probPrime(15) > 0) {
factors.add(n.copy())
break
}
if (n >= threshold) {
var d = pollardRho_(n, seed, c)
if (d != 0) {
factors.addAll(primeFactors_(d, false))
n.div(d)
checkPrime = true
} else if (c == 1) {
if (n.isSquare) {
n.sqrt
var pf = primeFactors_(n, false)
factors.addAll(pf)
factors.addAll(pf)
break
} else {
c = 2
checkPrime = false
}
} else if (c < 101) {
c = c + 1
} else if (seed < 101) {
seed = seed + 1
} else {
factors.addAll(primeFactorsWheel_(n))
break
}
} else {
factors.addAll(primeFactorsWheel_(n))
break
}
}
factors.sort()
return factors
}
// Returns a list of the primes factors (Mpz) of 'm' (an Mpz object or an integral Num)
// using the wheel based factorization and/or Pollard's Rho algorithm as appropriate.
static primeFactors(m) {
if (m < 2) return []
if (m is Num) m = Mpz.from(m)
return primeFactors_(m, true)
}
// Returns all the divisors of 'n' including 1 and 'n' itself.
static divisors(n) {
if (n < 1) return []
if (n is Num) n = from(n)
var divs = []
var divs2 = []
var i = one
var k = n.isEven ? one : two
var sqrt = n.copy().sqrt
while (i <= sqrt) {
if (n.isDivisible(i)) {
divs.add(i.copy())
var j = n / i
if (j != i) divs2.add(j)
}
i.add(k)
}
if (!divs2.isEmpty) divs = divs + divs2[-1..0]
return divs
}
// Returns all the divisors of 'n' excluding 'n'.
static properDivisors(n) {
var d = divisors(n)
var c = d.count
return (c <= 1) ? [] : d[0..-2]
}
// As 'divisors' method but uses a different algorithm.
// Better for large numbers with a small number of prime factors.
static divisors2(n) {
if (n is Num) n = from(n)
var pf = primeFactors(n)
if (pf.count == 0) return (n == 1) ? [one] : pf
var arr = []
if (pf.count == 1) {
arr.add([pf[0].copy(), 1])
} else {
var prevPrime = pf[0]
var count = 1
for (i in 1...pf.count) {
if (pf[i] == prevPrime) {
count = count + 1
} else {
arr.add([prevPrime.copy(), count])
prevPrime = pf[i]
count = 1
}
}
arr.add([prevPrime.copy(), count])
}
var divisors = []
var generateDivs
generateDivs = Fn.new { |currIndex, currDivisor|
if (currIndex == arr.count) {
divisors.add(currDivisor.copy())
return
}
for (i in 0..arr[currIndex][1]) {
generateDivs.call(currIndex+1, currDivisor)
currDivisor = currDivisor * arr[currIndex][0]
}
}
generateDivs.call(0, one)
return divisors.sort()
}
// As 'properDivisors' but uses 'divisors2' method.
static properDivisors2(n) {
var d = divisors2(n)
var c = d.count
return (c <= 1) ? [] : d[0..-2]
}
// Returns the sum of all the divisors of 'n' including 1 and 'n' itself.
static divisorSum(n) {
if (n < 1) return zero
n = from(n)
var total = one
var power = two
while (n.isDivisible(two)) {
total.add(power)
power.mul(2)
n.div(2)
}
var i = three
while (i * i <= n) {
var sum = one
power.set(i)
while (n.isDivisible(i)) {
sum.add(power)
power.mul(i)
n.div(i)
}
total.mul(sum)
i.add(2)
}
if (n > 1) total.mul(n + 1)
return total
}
// Returns the number of divisors of 'n' including 1 and 'n' itself.
static divisorCount(n) {
if (n < 1) return 0
n = from(n)
var count = 0
var prod = 1
while (n.isDivisible(two)) {
count = count + 1
n.div(2)
}
prod = prod * (1 + count)
var i = three
while (i * i <= n) {
count = 0
while (n.isDivisible(i)) {
count = count + 1
n.div(i)
}
prod = prod * (1 + count)
i.add(2)
}
if (n > 2) prod = prod * 2
return prod
}
/* Methods which apply to a sequence of Mpz objects. */
static sum(sz) { sz.reduce(Mpz.zero) { |acc, x| acc.add(x) } }
static prod(sz) { sz.reduce(Mpz.one) { |acc, x| acc.mul(x) } }
static min(sz) { sz.reduce { |acc, x| (x > acc) ? x : acc } }
static max(sz) { sz.reduce { |acc, x| (x < acc) ? x : acc } }
}
/*
Mpq represents an arbitrary length rational number allowing arithmetic operations on such
numbers of unlimited size. An Mpq object is a pointer to the GMP type mpq_t and is mutable.
Many methods map directly to the corresponding GMP functions though others are provided for
convenience.
Mpq objects are always automatically canonicalized (n/d in lowest form, d > 0) by constructors
or setters. Zero is represented by 0/1. If integers are required, Nums which are not integers
will be truncated towards zero by GMP.
*/
foreign class Mpq is Comparable {
// Creates small commonly used Mpq objects.
static minusOne { from(-1, 1) }
static zero { new() }
static one { from(1, 1) }
static two { from(2, 1) }
static three { from(3, 1) }
static four { from(4, 1) }
static five { from(5, 1) }
static six { from(6, 1) }
static seven { from(7, 1) }
static eight { from(8, 1) }
static nine { from(9, 1) }
static ten { from(10, 1) }
static half { from(1, 2) }
static third { from(1, 3) }
static quarter { from(1, 4) }
static fifth { from(1, 5) }
static sixth { from(1, 6) }
static seventh { from(1, 7) }
static eighth { from(1, 8) }
static ninth { from(1, 9) }
static tenth { from(1, 10) }
// Swaps the values of two Mpq objects.
foreign static swap(op1, op2)
// Returns the smaller of two Mpq objects.
static min(op1, op2) {
if (!(op1 is Mpq)) op1 = from(op1)
if (!(op2 is Mpq)) op2 = from(op2)
if (op1 < op2) return op1
return op2
}
// Returns the greater of two Mpq objects.
static max(op1, op2) {
if (!(op1 is Mpq)) op1 = from(op1)
if (!(op2 is Mpq)) op2 = from(op2)
if (op1 > op2) return op1
return op2
}
// Returns the positive difference of two Mpq objects.
static dim(op1, op2) {
if (!(op1 is Mpq)) op1 = from(op1)
if (!(op2 is Mpq)) op2 = from(op2)
if (op1 >= op2) return op1 - op2
return Mpq.zero
}
// Creates a new Mpq object with a value of 0/1.
construct new() {}
// Convenience method which creates a new Mpq object from any other numeric type.
static from(op) { new().set(op) }
// Convenience method which creates a new Mpq object from two integers (second always unsigned).
static from(op1, op2) { new().set(op1, op2) }
// Convenience methods which create a new Mpq object from a string (zero if invalid).
static fromStr(str, b) { new().setStr(str, b) } // base 'b'
static fromStr(str) { new().setStr(str, 10) } // base 10
// Assigns new values to the current instance using :
foreign setMpq(op) // another Mpq object
foreign setMpz(op) // an Mpz object
foreign setMpf(op) // an Mpf object
foreign setDbl(op) // a double
foreign setUi(op1, op2) // two unsigned integers op1/op2
foreign setSi(op1, op2) // a signed and an unsigned integer op1/op2
foreign setStr(str, b) // a base 'b' string (unchanged if invalid)
setStr(str) { setStr(str, 10) } // a base 10 string
// Convenience method which assigns a new value to the current instance
// from any other numeric type.
set(op) {
if (op is Mpq) return setMpq(op)
if (op is Num) {
if (op.isInteger) return (op >= 0) ? setUi(op, 1) : setSi(op, 1)
return setDbl(op)
}
if (op is Mpz) return setMpz(op)
if (op is Mpf) return setMpf(op)
Mpz.abort_()
}
// Convenience method which assigns a new value to the current instance
// from two integers (second always unsigned).
set(op1, op2) {
if ((op1 is Num) && (op2 is Num)) {
if (op1.isInteger && op2.isInteger && op2 > 0) {
return (op1 >= 0) ? setUi(op1, op2) : setSi(op1, op2)
} else {
return setDbl(op1/op2)
}
}
Mpz.abort()
}
// Resets the value of the current instance to zero.
reset() { setUi(0, 1) }
// Properties
foreign num // gets the numerator of this instance as an Mpz object
foreign den // gets the denominator of this instance as an Mpz object
foreign num=(op) // sets the numerator of this instance to an Mpz object
foreign den=(op) // sets the denominator of this instance to an Mpz object
setNum(op) { num = op } // alias for 'num' setter
setDen(op) { den = op } // alias for 'den' setter
// Converts the current instance to:
foreign toNum // a number
foreign toString(b) // a base 'b' string
toString { toString(10) } // a base 10 string
toMpz { Mpz.from(this) } // an Mpz object
toMpf { Mpf.from(this) } // an Mpf object
/* Methods which assign their result to the current instance ('this').
'uint' denotes a Num which is an unsigned integer. */
foreign add(op1, op2) // adds two Mpq objects
foreign sub(op1, op2) // subtracts one Mpq object from another
foreign mul(op1, op2) // multiplies two Mpq objects
foreign mul2(op1, op2) // multiplies op1 (Mpq) by 2^op2 (uint)
foreign div(op1, op2) // divides one Mpq object by another
foreign div2(op1, op2) // divides op1 (Mpq) by 2^op2 (uint)
foreign neg(op) // sets to -op (Mpq)
foreign abs(op) // sets to the absolute value of op (Mpq)
foreign inv(op) // sets to 1/op (Mpq)
// rounding methods, similar to those in Mpf class
ceil(op) { // higher integer
if (op.den == Mpz.one) return setMpq(op)
var div = op.num / op.den
if (op.sign >= 0) div.inc
return setMpz(div)
}
floor(op) { // lower integer
if (op.den == Mpz.one) return setMpq(op)
var div = op.num / op.den
if (op.sign < 0) div.dec
return setMpz(div)
}
trunc(op) { op.sign < 0 ? ceil(op) : floor(op) } // lower integer, towards zero
round(op) { // nearer integer, 1/2 away from zero
if (op.den == Mpz.one) return setMpq(op)
var op2 = op.copy()
if (op2.sign < 0) op2.sub(Mpq.half) else op2.add(Mpq.half)
return trunc(op2)
}
roundUp (op) { op.sign >= 0 ? ceil(op) : floor(op) } // higher integer, away from zero
/* As above methods where the first (or only) argument is 'this'. */
add(op) { add(this, op) }
sub(op) { sub(this, op) }
mul(op) { mul(this, op) }
mul2(op) { mul2(this, op) }
div(op) { div(this, op) }
div2(op) { div2(this, op) }
neg { neg(this) }
abs { abs(this) }
inv { inv(this) }
ceil { ceil(this) }
floor { floor(this) }
trunc { trunc(this) }
round { round(this) }
roundUp { roundUp(this) }
/* As above methods where the first (or only) argument is 'this'
but return a new Mpq object rather than mutating 'this'. */
- { copy().neg }
+(op) { copy().add(op) }
-(op) { copy().sub(op) }
*(op) { copy().mul(op) }
/(op) { copy().div(op) }
<<(op) { copy().mul2(op) } // equivalent to mul2(op)
>>(op) { copy().div2(op) } // equivalent to div2(op)
/* Methods which may mutate the current instance or simply return it. */
min(op) { (op < this) ? set(op) : this } // minimum of this and op
max(op) { (op > this) ? set(op) : this } // maximum of this and op
clamp(min, max) { // clamps this to the interval [min, max]
if (min > max) Fiber.abort("Range cannot be decreasing.")
if (this < min) set(min) else if (this > max) set(max)
return this.copy()
}
/* Comparison methods which return -1, 0, 1
if this < op, this == op or this > op respectively. */
foreign cmpMpq(op) // compare this to another Mpq object
foreign cmpMpz(op) // compare this to an Mpz object
foreign cmpUi(num, den) // compare this to two uints num/den
foreign cmpSi(num, den) // compare this to a sint and a uint num/den
foreign ==(op) // true if this and op are equal (faster than cmpMpq(op))
!=(op) { !(this == op) } // true if this and op are unequal
// Needed to satisfy Comparable trait and allow relational operators to be used.
compare(op) {
if (op is Mpq) return cmpMpq(op)
if (op is Mpz) return cmpMpz(op)
if (op is Num) return (op < 0) ? cmpSi(op) : cmpUi(op)
Mpz.abort_()
}
/* Miscellaneous methods. */
copy() { Mpq.from(this) } // copies 'this' to a new Mpq object
foreign sign(op) // the sign of an Mpq object
sign { sign(this) } // the sign of the current instance
isZero { cmpUi(0) == 0 } // returns 'true' if the current instance is zero
fraction { // the fractional part of this with the same sign, as a new Mpq object
var t = copy().trunc
return t.sub(this, t)
}
/* Methods which apply to a sequence of Mpq objects. */
static sum(sq) { sq.reduce(Mpq.zero) { |acc, x| acc.add(x) } }
static prod(sq) { sq.reduce(Mpq.one) { |acc, x| acc.mul(x) } }
static mean(sq) { sum(sq).div(sq.count) }
static min(sq) { sq.reduce { |acc, x| (x > acc) ? x : acc } }
static max(sq) { sq.reduce { |acc, x| (x < acc) ? x : acc } }
}
/*
Mpf represents an arbitrary length floating-point number allowing arithmetic operations on such
numbers of unlimited size. An Mpf object is a pointer to the GMP type mpf_t and is mutable.
Many methods map directly to the corresponding GMP functions though others are provided for
convenience.
The mantissa of each Mpf object has a mimimum user-selectable precision, limited only by memory,
which can be increased or decreased at any time. In practice GMP may use a higher precision.
If integers are required, Nums which are not integers will be truncated towards zero by GMP.
*/
foreign class Mpf is Comparable {
// Creates small commonly used Mpf objects with default precision.
static minusOne { from(-1) }
static zero { new() }
static one { from(1) }
static two { from(2) }
static three { from(3) }
static four { from(4) }
static five { from(5) }
static six { from(6) }
static seven { from(7) }
static eight { from(8) }
static nine { from(9) }
static ten { from(10) }
static half { from(0.5) }
static third { new().inv(three) }
static quarter { from(0.25) }
static fifth { from(0.2) }
static sixth { new().inv(six) }
static seventh { new().inv(seven) }
static eighth { from(0.125) }
static ninth { new().inv(nine) }
static tenth { from(0.1) }
// Creates transcendental constants with a specified precision.
static e(prec) { from(1, prec).exp } // E
static ln2(prec) { from(2, prec).log } // natural log of 2
static ln10(prec) { from(10, prec).log } // natural log of 10
static pi(prec) { new(prec).acos(Mpf.zero).mul(2) } // Pi
static tau(prec) { new(prec).acos(Mpf.zero).mul(4) } // Tau (twice Pi)
static phi(prec) { from(5, prec).sqrt.add(1).div(2) } // Phi (golden ratio)
static sqrt2(prec) { from(2, prec).sqrt } // Square root of 2
static euler(prec) { from(1, prec).digamma.neg } // Euler's constant
// Convenience versions of the above constants which use the default precision.
static e { from(1).exp }
static ln2 { from(2).log }
static ln10 { from(10).log }
static pi { new().acos(Mpf.zero).mul(2) }
static tau { new().acos(Mpf.zero).mul(4) }
static phi { from(5).sqrt.add(1).div(2) }
static sqrt2 { from(2).sqrt }
static euler { from(1).digamma.neg }
// Swaps the values of two Mpf objects.
foreign static swap(op1, op2)
// Splits an Mpf into a double plus an exponent (returned as a list of two Nums).
foreign static frexp(op)
// Gets the string presentation of am Mpf object in base b with up to n digits.
// Returns it as a list containing a digit string and an exponent.
// The digit string has an implicit radix point immediately to the left of the first digit.
foreign static getStr(op, b, n)
// Returns the smaller of two Mpf objects.
static min(op1, op2) {
if (!(op1 is Mpf)) op1 = from(op1)
if (!(op2 is Mpf)) op2 = from(op2)
if (op1 < op2) return op1
return op2
}
// Returns the greater of two Mpf objects.
static max(op1, op2) {
if (!(op1 is Mpf)) op1 = from(op1)
if (!(op2 is Mpf)) op2 = from(op2)
if (op1 > op2) return op1
return op2
}
// Returns the positive difference of two Mpf objects.
static dim(op1, op2) {
if (!(op1 is Mpf)) op1 = from(op1)
if (!(op2 is Mpf)) op2 = from(op2)
if (op1 >= op2) return op1 - op2
return Mpf.zero
}
foreign static defaultPrec // returns the default precision in bits actually used
foreign static defaultPrec=(prec) // sets the default precision to at least 'prec' bits
// Creates a new Mpf object with a value of 0 and precision of:
construct new() {} // default
construct new(prec) {} // at least 'prec' bits
// Convenience methods which create a new Mpf object from any other applicable type
// with default precision.
static from(op) { new().set(op) } // any numeric type
static fromStr(str, b) { new().setStr(str, b) } // a base 'b' string (zero if invalid)
static fromStr(str) { new().setStr(str, 10) } // a base 10 string (zero if invalid)
// Convenience methods which create a new Mpq object from any other applicable type
// with a precision of at least 'prec' bits.
static from(op, prec) { new(prec).set(op) } // any numeric type
static fromStr(str, b, prec) { new(prec).setStr(str, b) } // a base 'b' string (zero if invalid)
// Assigns new values to the current instance using :
foreign setMpf(op) // another Mpf object
foreign setMpq(op) // an Mpq object
foreign setMpz(op) // an Mpz object
foreign setDbl(op) // a double
foreign setUi(op) // an unsigned integer
foreign setSi(op) // a signed integer
foreign setStr(str, b) // a base 'b' string (unchanged if invalid)
setStr(str) { setStr(str, 10) } // a base 10 string
// Convenience method which assigns a new value to the current instance
// from any other numeric type.
set(op) {
if (op is Mpf) return setMpf(op)
if (op is Num) {
if (op.isInteger) return (op >= 0) ? setUi(op) : setSi(op)
return setDbl(op)
}
if (op is Mpz) return setMpz(op)
if (op is Mpq) return setMpq(op)
Mpz.abort_()
}
// Resets the value of the current instance to zero with default precision.
reset() { setUi(0).setPrec(Mpf.defaultPrec) }
// Properties.
foreign prec // returns the current precision of this instance in bits
foreign prec=(prec) // sets the precision of this instance to at least 'prec' bits
setPrec(prec) { this.prec = prec } // alias for 'prec' setter
// Converts the current instance to:
foreign toNum // a number
foreign toSint // a signed integer (Num)
foreign toUint // an unsigned integer (Num)
toString(b, d) { // a base 'b' string with up to d radix places
var res = Mpf.getStr(this, b, d)
var digits = res[0].toString
if (digits == "") return "0"
var sgn = ""
if (digits[0] == "-") {
sgn = "-"
digits = digits[1..-1]
}
var exp = res[1]
if (exp == 0) return sgn + "0." + digits
if (exp < 0) return sgn + "0." + ("0" * (-exp)) + digits
var c = digits.count
if (c > exp) return sgn + digits[0...exp] + "." + digits[exp..-1]
if (c == exp) return sgn + digits
return sgn + digits + ("0" * (exp - c))
}
toString(d) { toString(10, d) } // a base 'b' string with up to 'd' radix places
toString { toString(10, 64) } // a base 10 string with up to 64 radix places
toDecStr(p, round) { // as toString but truncated to p decimal places
if (!(round is Bool)) Mpz.abort_() // and optionally rounded
if (!((p is Num) && p.isInteger && p >= 0)) Mpz.abort_()
var str = toString
var dp = str.indexOf(".")
if (dp == -1) return str
var str2 = str[dp+1..-1]
if (str2.count <= p) return str
if (!round) {
if (p == 0) return str[0...dp]
return str[0..dp] + str2[0...p]
}
var power = Mpf.ten.pow(p)
var temp = (this * power + Mpf.half).floor.div(power)
return temp.toDecStr(p, false)
}
toDecStr(p) { toDecStr(p, true) } // convenience version of toDecStr with 'round' equals true
toMpz { Mpz.from(this) } // an Mpz object
toMpq { Mpq.from(this) } // an Mpq object
/* Methods which assign their result to the current instance ('this').
'uint' denotes a Num which is an unsigned integer. */
foreign add(op1, op2) // adds two Mpf objects
foreign addUi(op1, op2) // adds an Mpf object and a uint
foreign sub(op1, op2) // subtracts one Mpf object from another
foreign subUi(op1, op2) // subtracts a uint from an Mpf object
foreign uiSub(op1, op2) // subtracts an Mpf object from a uint
foreign mul(op1, op2) // multiplies two Mpf objects
foreign mulUi(op1, op2) // multiplies an Mpf object by a uint
foreign mul2(op1, op2) // multiplies op1 (Mpf) by 2^op2 (uint)
foreign div(op1, op2) // divides one Mpf object by another
foreign divUi(op1, op2) // divides an Mpf object by a uint
foreign uiDiv(op1, op2) // divides a uint by an Mpf object
foreign div2(op1, op2) // divides op1 (Mpf) by 2^op2 (uint)
addSi(op1, op2) { (op2 >= 0) ? addUi(op1, op2) : subUi(op1, -op2) } // op2 is a sint
subSi(op1, op2) { (op2 >= 0) ? subUi(op1, op2) : addUi(op1, -op2) } // op2 is a sint
mulSi(op1, op2) { (op2 >= 0) ? mulUi(op1, op2) : mulUi(op1, -op2).neg } // op2 is a sint
divSi(op1, op2) { (op2 >= 0) ? divUi(op1, op2) : divUi(op1, -op2).neg } // op2 is a sint
foreign neg(op) // sets to -op (Mpf)
foreign abs(op) // sets to the absolute value of op (Mpf)
inc(op) { addUi(op, 1) } // adds one to op (Mpf)
dec(op) { subUi(op, 1) } // subtracts one from op (Mpf)
inv(op) { uiDiv(1, op) } // sets to 1/op (Mpf)
foreign relDiff(op1, op2) // sets to relative difference of two Mpf objects
foreign pow(base, exp) // raises base (Mpf) to the power exp (uint)
foreign powz(base, exp) // raises base (Mpf) to the power exp (Mpz)
foreign powf(base, exp) // raises base (Mpf) to the power exp (Mpf)
square(op) { mul(op, op) } // sets to the square of op (Mpf)
cube(op) { pow(op, 3) } // sets to the cube of op (Mpf)
foreign root(op, n) // sets to the n'th root (uint) of op (Mpf)
foreign sqrt(op) // sets to the square root of op (Mpf)
foreign sqrtUi(op) // sets to the square root of op (uint)
foreign cbrt(op) // sets to the cube root of op (Mpf)
foreign hypot(x, y) // sets to the Euclidean norm of x and y
foreign ceil(op) // rounds to the next higher integer
foreign floor(op) // rounds to the next lower integer
foreign trunc(op) // rounds to the next integer towards zero
round(op) { // rounds to the nearest integer, half away from zero
var sgn = Mpf.from(op.sign)
var op2 = op.copy()
return mul(op2.abs.add(Mpf.half).floor, sgn)
}
roundUp(op) { // rounds to the next integer away from zero
var op2 = op.copy()
return (op2 >= 0) ? set(op2.ceil) : set(op2.floor)
}
// Transcendental methods which set 'this' to the:
foreign log(op) // natural logarithm of op
foreign log2(op) // base two logarithm of op
foreign log10(op) // base ten logarithm of op
foreign exp(op) // exponential of op
foreign cos(op) // cosine of op
foreign sin(op) // sine of op
foreign tan(op) // tangent of op
foreign acos(op) // arc-cosine of op
foreign asin(op) // arc-sine of op
foreign atan(op) // arc-tangent of op
foreign atan2(y, x) // arc-tangent 2 of y and x
foreign cosh(op) // hyperbolic cosine of op
foreign sinh(op) // hyperbolic sine of op
foreign tanh(op) // hyperbolic tangent of op
foreign gamma(op) // gamma function of op
foreign gammaInc(op, op2) // incomplete gamma function of op and op2
foreign lgamma(op) // natural logarithm of the absolute value of gamma(op)
foreign digamma(op) // digamma (or psi) function of op
foreign zeta(op) // zeta function of op (Mpf)
foreign zetaUi(op) // zeta function of op (uint)
/* As above methods where the first (or only) argument is 'this'.
Unless otherwise noted, any other argument must either be another Mpf object or a sint.
Other Nums are converted by GMP to uint. */
add(op) { (op is Mpf) ? add(this, op) : ((op is Num) ? addSi(this, op) : Mpz.abort_()) }
sub(op) { (op is Mpf) ? sub(this, op) : ((op is Num) ? subSi(this, op) : Mpz.abort_()) }
mul(op) { (op is Mpf) ? mul(this, op) : ((op is Num) ? mulSi(this, op) : Mpz.abort_()) }
mul2(op) { mul2(this, op) }
div(op) { (op is Mpf) ? div(this, op) : ((op is Num) ? divSi(this, op) : Mpz.abort_()) }
div2(op) { div2(this, op) }
neg { neg(this) }
abs { abs(this) }
inc { addUi(this, 1) }
dec { subUi(this, 1) }
inv { uiDiv(1, this) }
relDiff(op) { relDiff(this, op) } // op must be another Mpf object
pow(exp) { pow(this, exp) } // exp must be a uint
powz(exp) { powz(this, exp) } // exp must be an Mpz object
powf(exp) { powf(this, exp) } // exp must be an Mpf object
square { mul(this, this) }
cube { pow(this, 3) }
root(n) { root(this, n) }
sqrt { sqrt(this) }
cbrt { cbrt(this) }
hypot(y) { hypot(this, y) }
ceil { ceil(this) }
floor { floor(this) }
trunc { trunc(this) }
round { round(this) }
roundUp { roundUp(this) }
log { log(this) }
log2 { log2(this) }
log10 { log10(this) }
exp { exp(this) }
cos { cos(this) }
sin { sin(this) }
tan { tan(this) }
acos { acos(this) }
asin { asin(this) }
atan { atan(this) }
atan2(x) { atan2(this, x) }
cosh { cosh(this) }
sinh { sinh(this) }
tanh { tanh(this) }
gamma { gamma(this) }
gammaInc(op) { gammaInc(this, op) }
lgamma { lgamma(this) }
digamma { digamma(this) }
zeta { zeta(this) }
/* As above methods where the first (or only) argument is 'this'
but return a new Mpf object rather than mutating 'this'.*/
- { copy().neg }
+(op) { copy().add(op) }
-(op) { copy().sub(op) }
*(op) { copy().mul(op) }
/(op) { copy().div(op) }
<<(op) { copy().mul2(op) } // equivalent to mul2(op)
>>(op) { copy().div2(op) } // equivalent to div2(op)
/* Methods which may mutate the current instance or simply return it. */
min(op) { (op < this) ? set(op) : this } // minimum of this and op
max(op) { (op > this) ? set(op) : this } // maximum of this and op
clamp(min, max) { // clamps this to the interval [min, max]
if (min > max) Fiber.abort("Range cannot be decreasing.")
if (this < min) set(min) else if (this > max) set(max)
return this.copy()
}
/* Comparison methods which return -1, 0, 1
if this < op, this == op or this > op respectively. */
foreign cmpMpf(op) // compare this to another Mpf object
foreign cmpMpz(op) // compare this to an Mpz object
foreign cmpDbl(op) // compare this to a double
foreign cmpUi(op) // compare this to an unsigned integer
foreign cmpSi(op) // compare this to a signed integer
// Needed to satisfy Comparable trait and allow relational operators to be used.
compare(op) {
if (op is Mpf) return cmpMpf(op)
if (op is Mpz) return cmpMpz(op)
if (op is Num) return !op.isInteger ? cmpDbl(op) : (op < 0) ? cmpSi(op) : cmpUi(op)
Mpz.abort_()
}
/* Miscellaneous methods. */
copy() { Mpf.from(this, prec) } // copies 'this' to a new Mpf object with the same precision
foreign isInteger // true if the current instance is an integer
foreign sign(op) // the sign of an Mpf object
sign { sign(this) } // the sign of the current instance
isZero { cmpUi(0) == 0 } // returns 'true' if the current instance is zero
fraction { // the fractional part of this with the same sign, as a new Mpf object
var t = copy().trunc
return t.sub(this, t)
}
/* Methods which apply to a sequence of Mpf objects. */
static sum(sf, prec) { sf.reduce(Mpf.from(0, prec)) { |acc, x| acc.add(x) } }
static prod(sf, prec) { sf.reduce(Mpf.from(1, prec)) { |acc, x| acc.mul(x) } }
static mean(sf, prec) { sum(sf, prec) / sf.count }
// Convenience versions of above methods where the return value has default precision.
static sum(sf) { sf.reduce(Mpf.zero) { |acc, x| acc.add(x) } }
static prod(sf) { sf.reduce(Mpf.one) { |acc, x| acc.mul(x) } }
static mean(sf) { sum(sf).div(sf.count) }
// Min/max of a sequence of Mpf objects.
static min(sf) { sf.reduce { |acc, x| (x > acc) ? x : acc } }
static max(sf) { sf.reduce { |acc, x| (x < acc) ? x : acc } }
}
Source code (C)
/* gcc -O3 wren-gmp.c -o wren-gmp -lmpfr -lgmp -lwren -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>
#include <mpfr.h>
#include "wren.h"
/* Mpz functions */
void Mpz_allocate(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(mpz_t));
int slots = wrenGetSlotCount(vm);
if (slots == 1) {
mpz_init(*pz);
} else if (slots == 2) {
if (wrenGetSlotType(vm, 1) == WREN_TYPE_NUM) {
double op = wrenGetSlotDouble(vm, 1);
mpz_init_set_d(*pz, op);
} else {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_init_set(*pz, *pop);
}
} else {
const char *str = wrenGetSlotString(vm, 1);
int base = (int)wrenGetSlotDouble(vm, 2);
mpz_init_set_str(*pz, str, base);
}
}
void Mpz_finalize(void* data) {
mpz_t *pz = (mpz_t*)data;
mpz_clear(*pz);
}
void Mpz_swap(WrenVM* vm) {
mpz_t *pop1 = (mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_t *pop2 = (mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_swap(*pop1, *pop2);
}
void Mpz_frexp(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
signed long int exp = 0;
double ret = mpz_get_d_2exp(&exp, *pop);
wrenEnsureSlots(vm, 3);
wrenSetSlotNewList(vm, 0);
wrenSetSlotDouble(vm, 1, ret);
wrenSetSlotDouble(vm, 2,(double)exp);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
}
void Mpz_cdivRem(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pd = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_cdiv_qr(q, r, *pn, *pd);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_cdivRemUi(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int d = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_cdiv_qr_ui(q, r, *pn, d);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_fdivRem(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pd = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_fdiv_qr(q, r, *pn, *pd);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_fdivRemUi(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int d = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_fdiv_qr_ui(q, r, *pn, d);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_tdivRem(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pd = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_tdiv_qr(q, r, *pn, *pd);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_tdivRemUi(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int d = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_t q, r;
mpz_init(q);
mpz_init(r);
mpz_tdiv_qr_ui(q, r, *pn, d);
wrenEnsureSlots(vm, 3);
mpz_t *pq = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *pr = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*pq, q);
mpz_set(*pr, r);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(q);
mpz_clear(r);
}
void Mpz_rootRem(WrenVM* vm) {
const mpz_t *pu = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_t root, rem;
mpz_init(root);
mpz_init(rem);
mpz_rootrem(root, rem, *pu, n);
wrenEnsureSlots(vm, 3);
mpz_t *proot = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *prem = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*proot, root);
mpz_set(*prem, rem);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(root);
mpz_clear(rem);
}
void Mpz_sqrtRem(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_t rop1, rop2;
mpz_init(rop1);
mpz_init(rop2);
mpz_sqrtrem(rop1, rop2, *pop);
wrenEnsureSlots(vm, 3);
mpz_t *prop1 = (mpz_t*)wrenSetSlotNewForeign(vm, 1, 0, sizeof(mpz_t));
mpz_t *prop2 = (mpz_t*)wrenSetSlotNewForeign(vm, 2, 0, sizeof(mpz_t));
mpz_set(*prop1, rop1);
mpz_set(*prop2, rop2);
wrenSetSlotNewList(vm, 0);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
mpz_clear(rop1);
mpz_clear(rop2);
}
void Mpz_jacobi(WrenVM* vm) {
const mpz_t *pa = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pb = (const mpz_t*)wrenGetSlotForeign(vm, 2);
int jac = mpz_jacobi(*pa, *pb);
wrenSetSlotDouble(vm, 0, (double)jac);
}
void Mpz_legendre(WrenVM* vm) {
const mpz_t *pa = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pp = (const mpz_t*)wrenGetSlotForeign(vm, 2);
int leg = mpz_legendre(*pa, *pp);
wrenSetSlotDouble(vm, 0, (double)leg);
}
void Mpz_kronecker(WrenVM* vm) {
const mpz_t *pa = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pb = (const mpz_t*)wrenGetSlotForeign(vm, 2);
int kron = mpz_kronecker(*pa, *pb);
wrenSetSlotDouble(vm, 0, (double)kron);
}
void Mpz_hamDist(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mp_bitcnt_t hd = mpz_hamdist(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)hd);
}
void Mpz_setMpz(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_set(*pz, *pop);
}
void Mpz_setMpq(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpz_set_q(*pz, *pop);
}
void Mpz_setMpf(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpz_set_f(*pz, *pop);
}
void Mpz_setDbl(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
double op = wrenGetSlotDouble(vm, 1);
mpz_set_d(*pz, op);
}
void Mpz_setUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_set_ui(*pz, op);
}
void Mpz_setSi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
signed long int op = (signed long int)wrenGetSlotDouble(vm, 1);
mpz_set_si(*pz, op);
}
void Mpz_setStr(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const char *str = wrenGetSlotString(vm, 1);
int base = (int)wrenGetSlotDouble(vm, 2);
mpz_set_str(*pz, str, base);
}
void Mpz_setBits(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t n = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpz_realloc2(*pz, n);
}
void Mpz_toNum(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, mpz_get_d(*pop));
}
void Mpz_toString(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int base = (int)wrenGetSlotDouble(vm, 1);
char *ret = mpz_get_str(NULL, base, *pop);
wrenSetSlotString(vm, 0, ret);
free(ret);
}
void Mpz_add(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_add(*pz, *pop1, *pop2);
}
void Mpz_addUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_add_ui(*pz, *pop1, op2);
}
void Mpz_sub(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_sub(*pz, *pop1, *pop2);
}
void Mpz_subUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_sub_ui(*pz, *pop1, op2);
}
void Mpz_uiSub(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op1 = (unsigned long int)wrenGetSlotDouble(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_ui_sub(*pz, op1, *pop2);
}
void Mpz_mul(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_mul(*pz, *pop1, *pop2);
}
void Mpz_mulUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_mul_ui(*pz, *pop1, op2);
}
void Mpz_mulSi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
long int op2 = (long int)wrenGetSlotDouble(vm, 2);
mpz_mul_si(*pz, *pop1, op2);
}
void Mpz_addMul(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_addmul(*pz, *pop1, *pop2);
}
void Mpz_addMulUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_addmul_ui(*pz, *pop1, op2);
}
void Mpz_subMul(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_submul(*pz, *pop1, *pop2);
}
void Mpz_subMulUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_submul_ui(*pz, *pop1, op2);
}
void Mpz_cdiv(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_cdiv_q(*pz, *pop1, *pop2);
}
void Mpz_cdivUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_cdiv_q_ui(*pz, *pop1, op2);
}
void Mpz_fdiv(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_fdiv_q(*pz, *pop1, *pop2);
}
void Mpz_fdivUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_fdiv_q_ui(*pz, *pop1, op2);
}
void Mpz_tdiv(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_tdiv_q(*pz, *pop1, *pop2);
}
void Mpz_tdivUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_tdiv_q_ui(*pz, *pop1, op2);
}
void Mpz_crem(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_cdiv_r(*pz, *pop1, *pop2);
}
void Mpz_cremUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_cdiv_r_ui(*pz, *pop1, op2);
}
void Mpz_frem(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_fdiv_r(*pz, *pop1, *pop2);
}
void Mpz_fremUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_fdiv_r_ui(*pz, *pop1, op2);
}
void Mpz_trem(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_tdiv_r(*pz, *pop1, *pop2);
}
void Mpz_tremUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_tdiv_r_ui(*pz, *pop1, op2);
}
void Mpz_mod(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_mod(*pz, *pop1, *pop2);
}
void Mpz_modUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_mod_ui(*pz, *pop1, op2);
}
void Mpz_divExact(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_divexact(*pz, *pop1, *pop2);
}
void Mpz_divExactUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_divexact_ui(*pz, *pop1, op2);
}
void Mpz_neg(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_neg(*pz, *pop);
}
void Mpz_abs(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_abs(*pz, *pop);
}
void Mpz_pow(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pbase = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int exp = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_pow_ui(*pz, *pbase, exp);
}
void Mpz_uiPow(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int base = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int exp = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_ui_pow_ui(*pz, base, exp);
}
void Mpz_modPow(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pbase = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pexp = (const mpz_t*)wrenGetSlotForeign(vm, 2);
const mpz_t *pmod = (const mpz_t*)wrenGetSlotForeign(vm, 3);
mpz_powm(*pz, *pbase, *pexp, *pmod);
}
void Mpz_modPowUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pbase = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int exp = (unsigned long int)wrenGetSlotDouble(vm, 2);
const mpz_t *pmod = (const mpz_t*)wrenGetSlotForeign(vm, 3);
mpz_powm_ui(*pz, *pbase, exp, *pmod);
}
void Mpz_root(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_root(*pz, *pop, n);
}
void Mpz_sqrt(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_sqrt(*pz, *pop);
}
void Mpz_lsh(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpz_mul_2exp(*pz, *pop1, op2);
}
void Mpz_rsh(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpz_fdiv_q_2exp(*pz, *pop1, op2);
}
void Mpz_com(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_com(*pz, *pop);
}
void Mpz_and(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_and(*pz, *pop1, *pop2);
}
void Mpz_ior(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_ior(*pz, *pop1, *pop2);
}
void Mpz_xor(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_xor(*pz, *pop1, *pop2);
}
void Mpz_gcd(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_gcd(*pz, *pop1, *pop2);
}
void Mpz_gcdUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_gcd_ui(*pz, *pop1, op2);
}
void Mpz_lcm(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_lcm(*pz, *pop1, *pop2);
}
void Mpz_lcmUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_lcm_ui(*pz, *pop1, op2);
}
void Mpz_modInv(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mpz_invert(*pz, *pop1, *pop2);
}
void Mpz_nextPrime(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_nextprime(*pz, *pop);
}
void Mpz_remove(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
const mpz_t *pf = (const mpz_t*)wrenGetSlotForeign(vm, 2);
mp_bitcnt_t n = mpz_remove(*pz, *pop, *pf);
wrenSetSlotDouble(vm, 0, (double)n);
}
void Mpz_cmpMpz(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
int ret = mpz_cmp(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpDbl(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
double op2 = wrenGetSlotDouble(vm, 1);
int ret = mpz_cmp_d(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpUi(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 1);
int ret = mpz_cmp_ui(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpSi(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
signed long int op2 = (signed long int)wrenGetSlotDouble(vm, 1);
int ret = mpz_cmp_si(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpAbsMpz(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
int ret = mpz_cmpabs(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpAbsDbl(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
double op2 = wrenGetSlotDouble(vm, 1);
int ret = mpz_cmpabs_d(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_cmpAbsUi(WrenVM* vm) {
const mpz_t *pop1 = (const mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 1);
int ret = mpz_cmpabs_ui(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_isOdd(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int ret = mpz_odd_p(*pop);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isEven(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int ret = mpz_even_p(*pop);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isDivisible(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
mpz_t *pd = (mpz_t*)wrenGetSlotForeign(vm, 1);
int ret = mpz_divisible_p(*pn, *pd);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isDivisibleUi(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int d = (unsigned long int)wrenGetSlotDouble(vm, 1);
int ret = mpz_divisible_ui_p(*pn, d);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isDivisible2(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t b = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
int ret = mpz_divisible_2exp_p(*pn, b);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isCongruent(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
mpz_t *pc = (mpz_t*)wrenGetSlotForeign(vm, 1);
mpz_t *pd = (mpz_t*)wrenGetSlotForeign(vm, 2);
int ret = mpz_congruent_p(*pn, *pc, *pd);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isCongruentUi(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int c = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int d = (unsigned long int)wrenGetSlotDouble(vm, 2);
int ret = mpz_congruent_ui_p(*pn, c, d);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isCongruent2(WrenVM* vm) {
mpz_t *pn = (mpz_t*)wrenGetSlotForeign(vm, 0);
mpz_t *pc = (mpz_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t b = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
int ret = mpz_congruent_2exp_p(*pn, *pc, b);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isPower(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int ret = mpz_perfect_power_p(*pop);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_isSquare(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int ret = mpz_perfect_square_p(*pop);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpz_probPrime(WrenVM* vm) {
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int reps = (int)wrenGetSlotDouble(vm, 1);
int ret = mpz_probab_prime_p(*pn, reps);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_sign(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int ret = mpz_sgn(*pop);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_factorial(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_fac_ui(*pz, n);
}
void Mpz_factorial2(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_2fac_ui(*pz, n);
}
void Mpz_mfactorial(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int m = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_mfac_uiui(*pz, n, m);
}
void Mpz_primorial(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_primorial_ui(*pz, n);
}
void Mpz_binomial(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pn = (const mpz_t*)wrenGetSlotForeign(vm, 1);
unsigned long int k = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_bin_ui(*pz, *pn, k);
}
void Mpz_binomialUi(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int k = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpz_bin_uiui(*pz, n, k);
}
void Mpz_fibonacci(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_fib_ui(*pz, n);
}
void Mpz_lucas(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpz_lucnum_ui(*pz, n);
}
void Mpz_popCount(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t ret = mpz_popcount(*pop);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_scan0(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t startingBit = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mp_bitcnt_t ret = mpz_scan0(*pop, startingBit);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_scan1(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t startingBit = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mp_bitcnt_t ret = mpz_scan1(*pop, startingBit);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_setBit(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t bitIndex = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpz_setbit(*pz, bitIndex);
}
void Mpz_clrBit(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t bitIndex = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpz_clrbit(*pz, bitIndex);
}
void Mpz_comBit(WrenVM* vm) {
mpz_t *pz = (mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t bitIndex = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpz_combit(*pz, bitIndex);
}
void Mpz_tstBit(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t bitIndex = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
int ret = mpz_tstbit(*pop, bitIndex);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_sizeInBase(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int base = (int)wrenGetSlotDouble(vm, 1);
size_t ret = mpz_sizeinbase(*pop, base);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpz_digitsInBase(WrenVM* vm) {
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 0);
int base = (int)wrenGetSlotDouble(vm, 1);
char *ret = mpz_get_str(NULL, base, *pop);
size_t digits = strlen(ret);
if (ret[0] == '-') --digits;
wrenSetSlotDouble(vm, 0, (double)digits);
free(ret);
}
/* Mpq functions */
void Mpq_allocate(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(mpq_t));
mpq_init(*pq);
}
void Mpq_finalize(void* data) {
mpq_t *pq = (mpq_t*)data;
mpq_clear(*pq);
}
void Mpq_swap(WrenVM* vm) {
mpq_t *pop1 = (mpq_t*)wrenGetSlotForeign(vm, 1);
mpq_t *pop2 = (mpq_t*)wrenGetSlotForeign(vm, 2);
mpq_swap(*pop1, *pop2);
}
void Mpq_setMpq(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpq_set(*pq, *pop);
}
void Mpq_setMpz(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpq_set_z(*pq, *pop);
}
void Mpq_setMpf(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpq_set_f(*pq, *pop);
}
void Mpq_setDbl(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
double op = wrenGetSlotDouble(vm, 1);
mpq_set_d(*pq, op);
}
void Mpq_setUi(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op1 = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpq_set_ui(*pq, op1, op2);
mpq_canonicalize(*pq);
}
void Mpq_setSi(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
signed long int op1 = (signed long int)wrenGetSlotDouble(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpq_set_si(*pq, op1, op2);
mpq_canonicalize(*pq);
}
void Mpq_setStr(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const char *str = wrenGetSlotString(vm, 1);
int base = (int)wrenGetSlotDouble(vm, 2);
mpq_set_str(*pq, str, base);
mpq_canonicalize(*pq);
}
void Mpq_num(WrenVM* vm) {
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 0);
wrenEnsureSlots(vm, 2);
wrenGetVariable(vm, "./gmp", "Mpz", 1);
mpz_t *pnum = (mpz_t*)wrenSetSlotNewForeign(vm, 0, 1, sizeof(mpz_t));
mpq_get_num(*pnum, *pop);
}
void Mpq_den(WrenVM* vm) {
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 0);
wrenEnsureSlots(vm, 2);
wrenGetVariable(vm, "./gmp", "Mpz", 1);
mpz_t *pden = (mpz_t*)wrenSetSlotNewForeign(vm, 0, 1, sizeof(mpz_t));
mpq_get_den(*pden, *pop);
}
void Mpq_setNum(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pnumerator = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpq_set_num(*pq, *pnumerator);
mpq_canonicalize(*pq);
}
void Mpq_setDen(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pdenominator = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpq_set_den(*pq, *pdenominator);
mpq_canonicalize(*pq);
}
void Mpq_toNum(WrenVM* vm) {
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, mpq_get_d(*pop));
}
void Mpq_toString(WrenVM* vm) {
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 0);
int base = (int)wrenGetSlotDouble(vm, 1);
char *ret = mpq_get_str(NULL, base, *pop);
wrenSetSlotString(vm, 0, ret);
free(ret);
}
void Mpq_add(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 2);
mpq_add(*pq, *pop1, *pop2);
}
void Mpq_sub(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 2);
mpq_sub(*pq, *pop1, *pop2);
}
void Mpq_mul(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 2);
mpq_mul(*pq, *pop1, *pop2);
}
void Mpq_mul2(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpq_mul_2exp(*pq, *pop1, op2);
}
void Mpq_div(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 2);
mpq_div(*pq, *pop1, *pop2);
}
void Mpq_div2(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpq_div_2exp(*pq, *pop1, op2);
}
void Mpq_neg(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpq_neg(*pq, *pop);
}
void Mpq_abs(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpq_abs(*pq, *pop);
}
void Mpq_inv(WrenVM* vm) {
mpq_t *pq = (mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpq_inv(*pq, *pop);
}
void Mpq_cmpMpq(WrenVM* vm) {
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
int ret = mpq_cmp(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpq_cmpMpz(WrenVM* vm) {
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
int ret = mpq_cmp_z(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpq_cmpUi(WrenVM* vm) {
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 0);
unsigned long int num2 = (unsigned long int)wrenGetSlotDouble(vm, 1);
unsigned long int den2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
int ret = mpq_cmp_ui(*pop1, num2, den2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpq_cmpSi(WrenVM* vm) {
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 0);
long int num2 = (long int)wrenGetSlotDouble(vm, 1);
unsigned long int den2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
int ret = mpq_cmp_si(*pop1, num2, den2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpq_equals(WrenVM* vm) {
const mpq_t *pop1 = (const mpq_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop2 = (const mpq_t*)wrenGetSlotForeign(vm, 1);
int ret = mpq_equal(*pop1, *pop2);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpq_sign(WrenVM* vm) {
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 0);
int ret = mpq_sgn(*pop);
wrenSetSlotDouble(vm, 0, (double)ret);
}
/* Mpf functions */
void Mpf_allocate(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(mpf_t));
int slots = wrenGetSlotCount(vm);
if (slots == 1) {
mpf_init(*pf);
} else {
mp_bitcnt_t prec = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpf_init2(*pf, prec);
}
}
void Mpf_finalize(void* data) {
mpf_t *pf = (mpf_t*)data;
mpf_clear(*pf);
}
void Mpf_swap(WrenVM* vm) {
mpf_t *pop1 = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_t *pop2 = (mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_swap(*pop1, *pop2);
}
void Mpf_frexp(WrenVM* vm) {
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
signed long int exp = 0;
double ret = mpf_get_d_2exp(&exp, *pop);
wrenEnsureSlots(vm, 3);
wrenSetSlotNewList(vm, 0);
wrenSetSlotDouble(vm, 1, ret);
wrenSetSlotDouble(vm, 2,(double)exp);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
}
void Mpf_getStr(WrenVM* vm) {
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
int base = (int)wrenGetSlotDouble(vm, 2);
size_t nDigits = (size_t)wrenGetSlotDouble(vm, 3);
mp_exp_t exp = 0;
char *ret = mpf_get_str(NULL, &exp, base, nDigits, *pop);
wrenEnsureSlots(vm, 3);
wrenSetSlotNewList(vm, 0);
wrenSetSlotString(vm, 1, ret);
wrenSetSlotDouble(vm, 2,(double)exp);
wrenInsertInList(vm, 0, 0, 1);
wrenInsertInList(vm, 0, 1, 2);
free(ret);
}
void Mpf_defaultPrec(WrenVM* vm) {
mp_bitcnt_t prec = mpf_get_default_prec();
wrenSetSlotDouble(vm, 0, (double)prec);
}
void Mpf_setDefaultPrec(WrenVM* vm) {
mp_bitcnt_t prec = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpf_set_default_prec(prec);
}
void Mpf_setMpf(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_set(*pf, *pop);
}
void Mpf_setMpq(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpq_t *pop = (const mpq_t*)wrenGetSlotForeign(vm, 1);
mpf_set_q(*pf, *pop);
}
void Mpf_setMpz(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop = (const mpz_t*)wrenGetSlotForeign(vm, 1);
mpf_set_z(*pf, *pop);
}
void Mpf_setDbl(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
double op = wrenGetSlotDouble(vm, 1);
mpf_set_d(*pf, op);
}
void Mpf_setUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpf_set_ui(*pf, op);
}
void Mpf_setSi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
signed long int op = (signed long int)wrenGetSlotDouble(vm, 1);
mpf_set_si(*pf, op);
}
void Mpf_setStr(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const char *str = wrenGetSlotString(vm, 1);
int base = (int)wrenGetSlotDouble(vm, 2);
mpf_set_str(*pf, str, base);
}
void Mpf_prec(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t ret = mpf_get_prec(*pop);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_setPrec(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mp_bitcnt_t prec = (mp_bitcnt_t)wrenGetSlotDouble(vm, 1);
mpf_set_prec(*pf, prec);
}
void Mpf_toNum(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, mpf_get_d(*pop));
}
void Mpf_toSint(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)mpf_get_si(*pop));
}
void Mpf_toUint(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)mpf_get_ui(*pop));
}
void Mpf_add(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_add(*pf, *pop1, *pop2);
}
void Mpf_addUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpf_add_ui(*pf, *pop1, op2);
}
void Mpf_sub(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_sub(*pf, *pop1, *pop2);
}
void Mpf_subUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpf_sub_ui(*pf, *pop1, op2);
}
void Mpf_uiSub(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op1 = (unsigned long int)wrenGetSlotDouble(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_ui_sub(*pf, op1, *pop2);
}
void Mpf_mul(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_mul(*pf, *pop1, *pop2);
}
void Mpf_mulUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpf_mul_ui(*pf, *pop1, op2);
}
void Mpf_mul2(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpf_mul_2exp(*pf, *pop1, op2);
}
void Mpf_div(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_div(*pf, *pop1, *pop2);
}
void Mpf_divUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpf_div_ui(*pf, *pop1, op2);
}
void Mpf_uiDiv(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op1 = (unsigned long int)wrenGetSlotDouble(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_ui_div(*pf, op1, *pop2);
}
void Mpf_div2(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mp_bitcnt_t op2 = (mp_bitcnt_t)wrenGetSlotDouble(vm, 2);
mpf_div_2exp(*pf, *pop1, op2);
}
void Mpf_neg(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_neg(*pf, *pop);
}
void Mpf_abs(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_abs(*pf, *pop);
}
void Mpf_relDiff(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 2);
mpf_reldiff(*pf, *pop1, *pop2);
}
void Mpf_pow(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pbase = (const mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int exp = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpf_pow_ui(*pf, *pbase, exp);
}
void Mpf_sqrt(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_sqrt(*pf, *pop);
}
void Mpf_sqrtUi(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op = (unsigned long int)wrenGetSlotDouble(vm, 1);
mpf_sqrt_ui(*pf, op);
}
void Mpf_ceil(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_ceil(*pf, *pop);
}
void Mpf_floor(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_floor(*pf, *pop);
}
void Mpf_trunc(WrenVM* vm) {
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_trunc(*pf, *pop);
}
void Mpf_cmpMpf(WrenVM* vm) {
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 0);
const mpf_t *pop2 = (const mpf_t*)wrenGetSlotForeign(vm, 1);
int ret = mpf_cmp(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_cmpMpz(WrenVM* vm) {
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 0);
const mpz_t *pop2 = (const mpz_t*)wrenGetSlotForeign(vm, 1);
int ret = mpf_cmp_z(*pop1, *pop2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_cmpDbl(WrenVM* vm) {
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 0);
double op2 = wrenGetSlotDouble(vm, 1);
int ret = mpf_cmp_d(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_cmpUi(WrenVM* vm) {
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long int op2 = (unsigned long int)wrenGetSlotDouble(vm, 1);
int ret = mpf_cmp_ui(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_cmpSi(WrenVM* vm) {
const mpf_t *pop1 = (const mpf_t*)wrenGetSlotForeign(vm, 0);
signed long int op2 = (signed long int)wrenGetSlotDouble(vm, 1);
int ret = mpf_cmp_si(*pop1, op2);
wrenSetSlotDouble(vm, 0, (double)ret);
}
void Mpf_isInteger(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
int ret = mpf_integer_p(*pop);
wrenSetSlotBool(vm, 0, (bool)ret);
}
void Mpf_sign(WrenVM* vm) {
const mpf_t *pop = (const mpf_t*)wrenGetSlotForeign(vm, 0);
int ret = mpf_sgn(*pop);
wrenSetSlotDouble(vm, 0, (double)ret);
}
/* Mpf functions which require MPFR. */
void Mpf_powz(WrenVM* vm) {
mpfr_t op1, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop1 = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpz_t *pop2 = (mpz_t*)wrenGetSlotForeign(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop1);
mpfr_init2(op1, prec2);
mpfr_set_f(op1, *pop1, MPFR_RNDN);
mpfr_pow_z(res, op1, *pop2, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op1);
mpfr_clear(res);
}
void Mpf_powf(WrenVM* vm) {
mpfr_t op1, op2, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop1 = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_t *pop2 = (mpf_t*)wrenGetSlotForeign(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop1);
mpfr_init2(op1, prec2);
mpfr_set_f(op1, *pop1, MPFR_RNDN);
mpfr_prec_t prec3 = (mpfr_prec_t)mpf_get_prec(*pop2);
mpfr_init2(op2, prec3);
mpfr_set_f(op2, *pop2, MPFR_RNDN);
mpfr_pow(res, op1, op2, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op1);
mpfr_clear(op2);
mpfr_clear(res);
}
void Mpf_root(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
unsigned long int n = (unsigned long int)wrenGetSlotDouble(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_rootn_ui(res, op, n, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_cbrt(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_cbrt(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_hypot(WrenVM* vm) {
mpfr_t rx, ry, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *px = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_t *py = (mpf_t*)wrenGetSlotForeign(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*px);
mpfr_init2(rx, prec2);
mpfr_set_f(rx, *px, MPFR_RNDN);
mpfr_prec_t prec3 = (mpfr_prec_t)mpf_get_prec(*py);
mpfr_init2(ry, prec3);
mpfr_set_f(ry, *py, MPFR_RNDN);
mpfr_hypot(res, rx, ry, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(rx);
mpfr_clear(ry);
mpfr_clear(res);
}
void Mpf_log(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_log(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_log2(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_log2(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_log10(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_log10(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_exp(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_exp(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_cos(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_cos(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_sin(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_sin(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_tan(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_tan(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_acos(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_acos(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_asin(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_asin(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_atan(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_atan(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_atan2(WrenVM* vm) {
mpfr_t ry, rx, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *py = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_t *px = (mpf_t*)wrenGetSlotForeign(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*py);
mpfr_init2(ry, prec2);
mpfr_set_f(ry, *py, MPFR_RNDN);
mpfr_prec_t prec3 = (mpfr_prec_t)mpf_get_prec(*px);
mpfr_init2(rx, prec3);
mpfr_set_f(rx, *px, MPFR_RNDN);
mpfr_atan2(res, ry, rx, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(ry);
mpfr_clear(rx);
mpfr_clear(res);
}
void Mpf_cosh(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_cosh(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_sinh(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_sinh(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_tanh(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_tanh(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_gamma(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_gamma(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_gammaInc(WrenVM* vm) {
mpfr_t op, op2, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpf_t *pop2 = (mpf_t*)wrenGetSlotForeign(vm, 2);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_prec_t prec3 = (mpfr_prec_t)mpf_get_prec(*pop2);
mpfr_init2(op2, prec3);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_set_f(op2, *pop2, MPFR_RNDN);
mpfr_gamma_inc(res, op, op2, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(op2);
mpfr_clear(res);
}
void Mpf_lgamma(WrenVM* vm) {
mpfr_t op, res;
int signnp = 0;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_lgamma(res, &signnp, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_digamma(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_digamma(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_zeta(WrenVM* vm) {
mpfr_t op, res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
mpf_t *pop = (mpf_t*)wrenGetSlotForeign(vm, 1);
mpfr_prec_t prec1 = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec1);
mpfr_prec_t prec2 = (mpfr_prec_t)mpf_get_prec(*pop);
mpfr_init2(op, prec2);
mpfr_set_f(op, *pop, MPFR_RNDN);
mpfr_zeta(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(op);
mpfr_clear(res);
}
void Mpf_zetaUi(WrenVM* vm) {
mpfr_t res;
mpf_t *pf = (mpf_t*)wrenGetSlotForeign(vm, 0);
unsigned long op = (unsigned long)wrenGetSlotDouble(vm, 1);
mpfr_prec_t prec = (mpfr_prec_t)mpf_get_prec(*pf);
mpfr_init2(res, prec);
mpfr_zeta_ui(res, op, MPFR_RNDN);
mpfr_get_f(*pf, res, MPFR_RNDN);
mpfr_clear(res);
}
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "./gmp") == 0) {
if (strcmp(className, "Mpz") == 0) {
methods.allocate = Mpz_allocate;
methods.finalize = Mpz_finalize;
} else if (strcmp(className, "Mpq") == 0) {
methods.allocate = Mpq_allocate;
methods.finalize = Mpq_finalize;
} else if (strcmp(className, "Mpf") == 0) {
methods.allocate = Mpf_allocate;
methods.finalize = Mpf_finalize;
}
}
return methods;
}
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "./gmp") == 0) {
if (strcmp(className, "Mpz") == 0) {
if(isStatic && strcmp(signature, "swap(_,_)") == 0) return Mpz_swap;
if(isStatic && strcmp(signature, "frexp(_)") == 0) return Mpz_frexp;
if(isStatic && strcmp(signature, "cdivRem(_,_)") == 0) return Mpz_cdivRem;
if(isStatic && strcmp(signature, "cdivRemUi(_,_)") == 0) return Mpz_cdivRemUi;
if(isStatic && strcmp(signature, "fdivRem(_,_)") == 0) return Mpz_fdivRem;
if(isStatic && strcmp(signature, "fdivRemUi(_,_)") == 0) return Mpz_fdivRemUi;
if(isStatic && strcmp(signature, "tdivRem(_,_)") == 0) return Mpz_tdivRem;
if(isStatic && strcmp(signature, "tdivRemUi(_,_)") == 0) return Mpz_tdivRemUi;
if(isStatic && strcmp(signature, "rootRem(_,_)") == 0) return Mpz_rootRem;
if(isStatic && strcmp(signature, "sqrtRem(_,_)") == 0) return Mpz_sqrtRem;
if(isStatic && strcmp(signature, "jacobi(_,_)") == 0) return Mpz_jacobi;
if(isStatic && strcmp(signature, "legendre(_,_)") == 0) return Mpz_legendre;
if(isStatic && strcmp(signature, "kronecker(_,_)") == 0) return Mpz_kronecker;
if(isStatic && strcmp(signature, "hamDist(_,_)") == 0) return Mpz_hamDist;
if(!isStatic && strcmp(signature, "setMpz(_)") == 0) return Mpz_setMpz;
if(!isStatic && strcmp(signature, "setMpq(_)") == 0) return Mpz_setMpq;
if(!isStatic && strcmp(signature, "setMpf(_)") == 0) return Mpz_setMpf;
if(!isStatic && strcmp(signature, "setDbl(_)") == 0) return Mpz_setDbl;
if(!isStatic && strcmp(signature, "setUi(_)") == 0) return Mpz_setUi;
if(!isStatic && strcmp(signature, "setSi(_)") == 0) return Mpz_setSi;
if(!isStatic && strcmp(signature, "setStr(_,_)") == 0) return Mpz_setStr;
if(!isStatic && strcmp(signature, "setBits(_)") == 0) return Mpz_setBits;
if(!isStatic && strcmp(signature, "toNum") == 0) return Mpz_toNum;
if(!isStatic && strcmp(signature, "toString(_)") == 0) return Mpz_toString;
if(!isStatic && strcmp(signature, "add(_,_)") == 0) return Mpz_add;
if(!isStatic && strcmp(signature, "addUi(_,_)") == 0) return Mpz_addUi;
if(!isStatic && strcmp(signature, "sub(_,_)") == 0) return Mpz_sub;
if(!isStatic && strcmp(signature, "subUi(_,_)") == 0) return Mpz_subUi;
if(!isStatic && strcmp(signature, "uiSub(_,_)") == 0) return Mpz_uiSub;
if(!isStatic && strcmp(signature, "mul(_,_)") == 0) return Mpz_mul;
if(!isStatic && strcmp(signature, "mulUi(_,_)") == 0) return Mpz_mulUi;
if(!isStatic && strcmp(signature, "mulSi(_,_)") == 0) return Mpz_mulSi;
if(!isStatic && strcmp(signature, "addMul(_,_)") == 0) return Mpz_addMul;
if(!isStatic && strcmp(signature, "addMulUi(_,_)") == 0) return Mpz_addMulUi;
if(!isStatic && strcmp(signature, "subMul(_,_)") == 0) return Mpz_subMul;
if(!isStatic && strcmp(signature, "subMulUi(_,_)") == 0) return Mpz_subMulUi;
if(!isStatic && strcmp(signature, "cdiv(_,_)") == 0) return Mpz_cdiv;
if(!isStatic && strcmp(signature, "cdivUi(_,_)") == 0) return Mpz_cdivUi;
if(!isStatic && strcmp(signature, "fdiv(_,_)") == 0) return Mpz_fdiv;
if(!isStatic && strcmp(signature, "fdivUi(_,_)") == 0) return Mpz_fdivUi;
if(!isStatic && strcmp(signature, "tdiv(_,_)") == 0) return Mpz_tdiv;
if(!isStatic && strcmp(signature, "tdivUi(_,_)") == 0) return Mpz_tdivUi;
if(!isStatic && strcmp(signature, "crem(_,_)") == 0) return Mpz_crem;
if(!isStatic && strcmp(signature, "cremUi(_,_)") == 0) return Mpz_cremUi;
if(!isStatic && strcmp(signature, "frem(_,_)") == 0) return Mpz_frem;
if(!isStatic && strcmp(signature, "fremUi(_,_)") == 0) return Mpz_fremUi;
if(!isStatic && strcmp(signature, "trem(_,_)") == 0) return Mpz_trem;
if(!isStatic && strcmp(signature, "tremUi(_,_)") == 0) return Mpz_tremUi;
if(!isStatic && strcmp(signature, "mod(_,_)") == 0) return Mpz_mod;
if(!isStatic && strcmp(signature, "modUi(_,_)") == 0) return Mpz_modUi;
if(!isStatic && strcmp(signature, "divExact(_,_)") == 0) return Mpz_divExact;
if(!isStatic && strcmp(signature, "divExactUi(_,_)") == 0) return Mpz_divExactUi;
if(!isStatic && strcmp(signature, "neg(_)") == 0) return Mpz_neg;
if(!isStatic && strcmp(signature, "abs(_)") == 0) return Mpz_abs;
if(!isStatic && strcmp(signature, "pow(_,_)") == 0) return Mpz_pow;
if(!isStatic && strcmp(signature, "uiPow(_,_)") == 0) return Mpz_uiPow;
if(!isStatic && strcmp(signature, "modPow(_,_,_)") == 0) return Mpz_modPow;
if(!isStatic && strcmp(signature, "modPowUi(_,_,_)") == 0) return Mpz_modPowUi;
if(!isStatic && strcmp(signature, "root(_,_)") == 0) return Mpz_root;
if(!isStatic && strcmp(signature, "sqrt(_)") == 0) return Mpz_sqrt;
if(!isStatic && strcmp(signature, "lsh(_,_)") == 0) return Mpz_lsh;
if(!isStatic && strcmp(signature, "rsh(_,_)") == 0) return Mpz_rsh;
if(!isStatic && strcmp(signature, "com(_)") == 0) return Mpz_com;
if(!isStatic && strcmp(signature, "and(_,_)") == 0) return Mpz_and;
if(!isStatic && strcmp(signature, "ior(_,_)") == 0) return Mpz_ior;
if(!isStatic && strcmp(signature, "xor(_,_)") == 0) return Mpz_xor;
if(!isStatic && strcmp(signature, "gcd(_,_)") == 0) return Mpz_gcd;
if(!isStatic && strcmp(signature, "gcdUi(_,_)") == 0) return Mpz_gcdUi;
if(!isStatic && strcmp(signature, "lcm(_,_)") == 0) return Mpz_lcm;
if(!isStatic && strcmp(signature, "lcmUi(_,_)") == 0) return Mpz_lcmUi;
if(!isStatic && strcmp(signature, "modInv(_,_)") == 0) return Mpz_modInv;
if(!isStatic && strcmp(signature, "nextPrime(_)") == 0) return Mpz_nextPrime;
if(!isStatic && strcmp(signature, "remove(_,_)") == 0) return Mpz_remove;
if(!isStatic && strcmp(signature, "cmpMpz(_)") == 0) return Mpz_cmpMpz;
if(!isStatic && strcmp(signature, "cmpDbl(_)") == 0) return Mpz_cmpDbl;
if(!isStatic && strcmp(signature, "cmpUi(_)") == 0) return Mpz_cmpUi;
if(!isStatic && strcmp(signature, "cmpSi(_)") == 0) return Mpz_cmpSi;
if(!isStatic && strcmp(signature, "cmpAbsMpz(_)") == 0) return Mpz_cmpAbsMpz;
if(!isStatic && strcmp(signature, "cmpAbsDbl(_)") == 0) return Mpz_cmpAbsDbl;
if(!isStatic && strcmp(signature, "cmpAbsUi(_)") == 0) return Mpz_cmpAbsUi;
if(!isStatic && strcmp(signature, "isOdd") == 0) return Mpz_isOdd;
if(!isStatic && strcmp(signature, "isEven") == 0) return Mpz_isEven;
if(!isStatic && strcmp(signature, "isDivisible(_)") == 0) return Mpz_isDivisible;
if(!isStatic && strcmp(signature, "isDivisibleUi(_)") == 0) return Mpz_isDivisibleUi;
if(!isStatic && strcmp(signature, "isDivisible2(_)") == 0) return Mpz_isDivisible2;
if(!isStatic && strcmp(signature, "isCongruent(_,_)") == 0) return Mpz_isCongruent;
if(!isStatic && strcmp(signature, "isCongruentUi(_,_)") == 0) return Mpz_isCongruentUi;
if(!isStatic && strcmp(signature, "isCongruent2(_,_)") == 0) return Mpz_isCongruent2;
if(!isStatic && strcmp(signature, "isPower") == 0) return Mpz_isPower;
if(!isStatic && strcmp(signature, "isSquare") == 0) return Mpz_isSquare;
if(!isStatic && strcmp(signature, "probPrime(_)") == 0) return Mpz_probPrime;
if(!isStatic && strcmp(signature, "sign(_)") == 0) return Mpz_sign;
if(!isStatic && strcmp(signature, "factorial(_)") == 0) return Mpz_factorial;
if(!isStatic && strcmp(signature, "factorial2(_)") == 0) return Mpz_factorial2;
if(!isStatic && strcmp(signature, "mfactorial(_,_)") == 0) return Mpz_mfactorial;
if(!isStatic && strcmp(signature, "primorial(_)") == 0) return Mpz_primorial;
if(!isStatic && strcmp(signature, "binomial(_,_)") == 0) return Mpz_binomial;
if(!isStatic && strcmp(signature, "binomialUi(_,_)") == 0) return Mpz_binomialUi;
if(!isStatic && strcmp(signature, "fibonacci(_)") == 0) return Mpz_fibonacci;
if(!isStatic && strcmp(signature, "lucas(_)") == 0) return Mpz_lucas;
if(!isStatic && strcmp(signature, "popCount") == 0) return Mpz_popCount;
if(!isStatic && strcmp(signature, "scan0(_)") == 0) return Mpz_scan0;
if(!isStatic && strcmp(signature, "scan1(_)") == 0) return Mpz_scan1;
if(!isStatic && strcmp(signature, "setBit(_)") == 0) return Mpz_setBit;
if(!isStatic && strcmp(signature, "clrBit(_)") == 0) return Mpz_clrBit;
if(!isStatic && strcmp(signature, "comBit(_)") == 0) return Mpz_comBit;
if(!isStatic && strcmp(signature, "tstBit(_)") == 0) return Mpz_tstBit;
if(!isStatic && strcmp(signature, "sizeInBase(_)") == 0) return Mpz_sizeInBase;
if(!isStatic && strcmp(signature, "digitsInBase(_)") == 0) return Mpz_digitsInBase;
} else if (strcmp(className, "Mpq") == 0) {
if(isStatic && strcmp(signature, "swap(_,_)") == 0) return Mpq_swap;
if(!isStatic && strcmp(signature, "setMpq(_)") == 0) return Mpq_setMpq;
if(!isStatic && strcmp(signature, "setMpz(_)") == 0) return Mpq_setMpz;
if(!isStatic && strcmp(signature, "setMpf(_)") == 0) return Mpq_setMpf;
if(!isStatic && strcmp(signature, "setDbl(_)") == 0) return Mpq_setDbl;
if(!isStatic && strcmp(signature, "setUi(_,_)") == 0) return Mpq_setUi;
if(!isStatic && strcmp(signature, "setSi(_,_)") == 0) return Mpq_setSi;
if(!isStatic && strcmp(signature, "setStr(_,_)") == 0) return Mpq_setStr;
if(!isStatic && strcmp(signature, "num") == 0) return Mpq_num;
if(!isStatic && strcmp(signature, "den") == 0) return Mpq_den;
if(!isStatic && strcmp(signature, "num=(_)") == 0) return Mpq_setNum;
if(!isStatic && strcmp(signature, "den=(_)") == 0) return Mpq_setDen;
if(!isStatic && strcmp(signature, "toNum") == 0) return Mpq_toNum;
if(!isStatic && strcmp(signature, "toString(_)") == 0) return Mpq_toString;
if(!isStatic && strcmp(signature, "add(_,_)") == 0) return Mpq_add;
if(!isStatic && strcmp(signature, "sub(_,_)") == 0) return Mpq_sub;
if(!isStatic && strcmp(signature, "mul(_,_)") == 0) return Mpq_mul;
if(!isStatic && strcmp(signature, "mul2(_,_)") == 0) return Mpq_mul2;
if(!isStatic && strcmp(signature, "div(_,_)") == 0) return Mpq_div;
if(!isStatic && strcmp(signature, "div2(_,_)") == 0) return Mpq_div2;
if(!isStatic && strcmp(signature, "neg(_)") == 0) return Mpq_neg;
if(!isStatic && strcmp(signature, "abs(_)") == 0) return Mpq_abs;
if(!isStatic && strcmp(signature, "inv(_)") == 0) return Mpq_inv;
if(!isStatic && strcmp(signature, "cmpMpq(_)") == 0) return Mpq_cmpMpq;
if(!isStatic && strcmp(signature, "cmpMpz(_)") == 0) return Mpq_cmpMpz;
if(!isStatic && strcmp(signature, "cmpUi(_,_)") == 0) return Mpq_cmpUi;
if(!isStatic && strcmp(signature, "cmpSi(_,_)") == 0) return Mpq_cmpSi;
if(!isStatic && strcmp(signature, "==(_)") == 0) return Mpq_equals;
if(!isStatic && strcmp(signature, "sign(_)") == 0) return Mpq_sign;
} else if (strcmp(className, "Mpf") == 0) {
if(isStatic && strcmp(signature, "swap(_,_)") == 0) return Mpf_swap;
if(isStatic && strcmp(signature, "frexp(_)") == 0) return Mpf_frexp;
if(isStatic && strcmp(signature, "getStr(_,_,_)") == 0) return Mpf_getStr;
if(isStatic && strcmp(signature, "defaultPrec")<