#
# Patch name: GNU MP math support
# Patch version: Alpha 1
# Author's name: N M Oko
# Author's email: kmoon@geocities.com
# Version of PennMUSH: 1.7.3p14
# Date patch made: Sat Feb 10 14:10:40 PST 2001
# Author is willing to support (yes/no): yes
# Patch format: concatenated context diff
#
#
# This is a contributed PennMUSH patch. Its use is subject to the
# same restrictions found in PennMUSH's hdrs/copyrite.h file.
#
# No warranty is given for this patch. It is not necessarily going
# to work on your system, with any version of PennMUSH other than
# the one above, etc.
#
# If the author given above was willing to support the patch, you
# should write to the author if you have any questions or problems. Do
# *NOT* send email messages to Javelin or any PennMUSH mailing list about
# this patch!
#
# Below this line is the author's description of the patch,
# followed by the patch itself. If the patch is in context diff
# format, you'll probably apply it by typing: patch < patchfile
# in your top-level MUSH directory, unless instructed otherwise
# below.
#
SUMMARY
Briefly, GNU MP is a library that enables multiple precision arithematic in
applications. What this patch does is add limited GMP support to PennMUSH.
The .hlp files are not modified, so you'll need to write your own if you
intend to document this. I also chose not to modify any .cnf files, so you may
need to go through these and change these where appropriate.
WHY YOU WANT IT
Now, why would you want multiple precision arithematic? In short, it allows
you to do math with really big numbers to insane levels of accuracy, by
performing operations on multiple words at a time. For integers, the precision
is absolute. I haven't implemented rational number support yet, and I really
don't intend to ever implement floating point support.
My reasoning is this. First, rational number support can be implemented by the
user using basic algebraic relations and the integer support already provided.
Second, the floating point support, while more precise than using doubles or
floats, is still limited to an (arbitrary) precision. This would require more
modifications to PennMUSH than I care to make. The normal Penn funs using
normal double precision floating point math should provide more than enough
precision for most applications. If you really must, you could try using
rational numbers, or implementing a fixed point arithematic scheme, all in
soft code. Anyway, on to installation issues.
INSTALLATION
To apply the patch, type (from your pennmush directory):
patch -p0 < gmpmath.173p14
From here, you can either:
1) Run Configure, using -DUSE_GMP_MATH as an additional compiler option, and
-lgmp as an additional library option.
2) Modify (by hand) your Makefile so that the final binary uses -DUSE_GMP_MATH
as a compile time option, and -lgmp is passed to the linker.
Alternatively, you can put #define USE_GMP_MATH in your options.h (as shown
below) instead of using -DUSE_GMP_MATH.
/* This option is used to control GNU Multiple Precision math support.
* To use this option, you must have libgmp on your system (available
* in source code form from the Free Software Foundation--www.gnu.org),
* and then compile PennMUSH with -lgmp (which you can enable while
* running the Configure script).
*
* The functions mpiadd(), mpisub(), mpimul(), mpidiv(), mpifloordiv(),
* mpiremainder(), and mpimodulo() are enabled. These are equivalent to
* their non-mpi counterparts, except they only accept integers, and
* return an integer answer of arbitrary precision.
*
* lmath() support for these functions is included.
*
* Some other functions:
* mpimodexp(b,e,m) - (b ^ e) % m
* mpimodinv(a,m) - solves (a * x) % m == 1 for x
* mpiabs(a) - abs(a)
* mpigcd(a,b) - returns greatest common denominator of a and b
* mpilcm(a,b) - returns least common multiple of a and b
* mpiprimetest(a,n) - guess if a is prime using n trials (>0 --> yes)
* mpicompare(a,b) - if a > b --> >0, a == b --> 0, a < b --> <0
*
* Note that prime test uses a Miller-Rabin probabilistic primality test.
* While primality using this test is all but guaranteed, some composite
* numbers are capable of passing the test anyway. The degree of confidence
* is measured by the magnitude of the return value. 0 means the value is
* definitely composite.
*
* Warning! No attempt has been made to restrict memory usage while running
* the MP routines. While it would certainly require a very large number to
* do so, there is some possibility that an unscrupulous person could suck
* up a lot of memory or processing power while using these functions.
* However, it is hoped that the buffer limit imposed by PennMUSH should mean
* that these functions are no more dangerous than some others.
*/
/* #define USE_GMP_MATH /* */
EXAMPLE
To demonstrate the GMP math features, you can try adding some really big (like
20 decimal digits) numbers together, and compare them with the results from
add(). If you have bc or dc installed on your system, you can check answers
from the mpi functions with those programs. As a little bit of fun, I've
included MUSH code for a set of ufuns that do RSA encryption and decryption.
There should be no legal issues, as most of the restrictions in the U.S.
on exporting encryption were lifted some time ago, the RSA patents expired
in 2000, and it's all in source code form anyway.
@create RSA Demo
@DESCRIBE RSA Demo=%rHere's how it all works. But first, a note on the example.%r%rThe syntax I'm using lists the attribute name of the ufun, along with the parameter list. So if you have FN.BOB,,, and FN.BOB is on #483, you'd do something like u(#483/FN.BOB,param 1,param 2,param 3).%r%rFirst, use FN.KEYGEN,, to generate a public/private modulus triple. You can find lists of prime numbers at various places online. Or you can just guess randomly, and check the guess using MPIPRIMETEST(number,tests) to make a probabilistic check for primeness.%r%rNext, use FN.ENCRYPT,,, to encrypt, and FN.DECRYPT,,, to decrypt.%r%rIt's that simple. If you want more information on how this actually all works, there are several good references available online on the RSA algorithm.%r
&FN.CARMICHAEL RSA Demo=mpidiv(mpimul(%0,%1),mpigcd(%0,%1))
&FN.DECRYPT RSA Demo=decrypt(rest(%0),mpimodexp(first(%0),%1,%2))
&FN.ENCRYPT RSA Demo=[mpimodexp(setr(0,rand(%2)),%1,%2)] [encrypt(%0,%q0)]
&FN.EXP.E RSA Demo=switch(mpigcd(%0,%1),1,%1,u(fn.exp.e,%0,add(%1,2)))
&FN.KEYGEN RSA Demo=[setr(0,first(u(fn.keygen.public,%0,%1)))]/[u(fn.keygen.private,%0,%1,%q0)]
&FN.KEYGEN.PRIVATE RSA Demo=[mpimodinv(%2,mpimul(mpisub(%0,1),mpisub(%1,1)))] [mul(%0,%1)]
&FN.KEYGEN.PUBLIC RSA Demo=[u(fn.exp.e,u(fn.carmichael,mpisub(%0,1),mpisub(%1,1)),19)] [mpimul(%0,%1)]
This ends the MUSH code sample. Patch begins below.
*** src/function.c.orig Sat Feb 10 09:51:24 2001
--- src/function.c Sat Feb 10 13:08:37 2001
***************
*** 332,337 ****
--- 332,353 ----
{"MIX", fun_mix, 3, 4, FN_REG},
{"MODULO", fun_modulo, 2, 2, FN_REG},
{"MONEY", fun_money, 1, 1, FN_REG},
+ #ifdef USE_GMP_MATH
+ {"MPIABS", fun_mpz_abs, 1, 1, FN_REG},
+ {"MPIADD", fun_mpz_add, 2, INT_MAX, FN_REG},
+ {"MPICOMPARE", fun_mpz_cmp, 2, 2, FN_REG},
+ {"MPIDIV", fun_mpz_div, 2, 2, FN_REG},
+ {"MPIFLOORDIV", fun_mpz_floordiv, 2, 2, FN_REG},
+ {"MPIGCD", fun_mpz_gcd, 2, 2, FN_REG},
+ {"MPILCM", fun_mpz_lcm, 2, 2, FN_REG},
+ {"MPIMODEXP", fun_mpz_modexp, 3, 3, FN_REG},
+ {"MPIMODINV", fun_mpz_modinv, 2, 2, FN_REG},
+ {"MPIMODULO", fun_mpz_modulo, 2, 2, FN_REG},
+ {"MPIMUL", fun_mpz_mul, 2, INT_MAX, FN_REG},
+ {"MPIPRIMETEST", fun_mpz_primetest, 2, 2, FN_REG},
+ {"MPIREMAINDER", fun_mpz_remainder, 2, 2, FN_REG},
+ {"MPISUB", fun_mpz_sub, 2, 2, FN_REG},
+ #endif
#ifdef CREATION_TIMES
{"MTIME", fun_mtime, 1, 1, FN_REG},
#endif
*** src/funmath.c.orig Sat Feb 10 09:08:18 2001
--- src/funmath.c Sat Feb 10 15:59:50 2001
***************
*** 16,21 ****
--- 16,27 ----
#include "htab.h"
#include "confmagic.h"
+ #ifdef USE_GMP_MATH
+ /* when compiling in GMP support */
+ #include
+ #define BASE_GMP 10
+ #endif
+
#ifdef WIN32
#pragma warning( disable : 4761) /* NJG: disable warning re conversion */
#endif
***************
*** 42,47 ****
--- 48,65 ----
static MATH *math_hash_lookup _((char *));
+ #ifdef USE_GMP_MATH
+ void safe_mpz _((mpz_t, char *, char **));
+
+ MATH_PROTO(math_mpz_add);
+ MATH_PROTO(math_mpz_sub);
+ MATH_PROTO(math_mpz_mul);
+ MATH_PROTO(math_mpz_div);
+ MATH_PROTO(math_mpz_floordiv);
+ MATH_PROTO(math_mpz_remainder);
+ MATH_PROTO(math_mpz_modulo);
+ #endif
+
MATH_PROTO(math_add);
MATH_PROTO(math_sub);
MATH_PROTO(math_mul);
***************
*** 70,87 ****
--- 88,129 ----
math_add(args, nargs, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_add)
+ {
+ math_add(args, nargs, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_sub)
{
math_sub(args, nargs, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_sub)
+ {
+ math_mpz_sub(args, nargs, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_mul)
{
math_mul(args, nargs, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_mul)
+ {
+ math_mpz_mul(args, nargs, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_gt)
{
***************
*** 142,147 ****
--- 184,216 ----
safe_boolean(parse_number(args[0]) != parse_number(args[1]), buff, bp);
}
+ #ifdef USE_GMP_MATH
+ FUNCTION(fun_mpz_cmp)
+ {
+ mpz_t N1, N2;
+
+ if (!is_integer(args[0]) || !is_integer(args[1])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(N1, args[0], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ return;
+ }
+
+ if (mpz_init_set_str(N2, args[1], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ mpz_clear(N2);
+ return;
+ }
+
+ safe_integer(mpz_cmp(N1, N2), buff, bp);
+ mpz_clear(N1);
+ mpz_clear(N2);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_max)
{
***************
*** 292,297 ****
--- 361,392 ----
math_remainder(args, nargs, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_div)
+ {
+ math_mpz_div(args, nargs, buff, bp);
+ }
+
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_floordiv)
+ {
+ math_mpz_floordiv(args, nargs, buff, bp);
+ }
+
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_modulo)
+ {
+ math_mpz_modulo(args, nargs, buff, bp);
+ }
+
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_remainder)
+ {
+ math_mpz_remainder(args, nargs, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_abs)
***************
*** 303,308 ****
--- 398,423 ----
safe_number(fabs(parse_number(args[0])), buff, bp);
}
+ #ifdef USE_GMP_MATH
+ FUNCTION(fun_mpz_abs)
+ {
+ mpz_t result;
+
+ if (!is_integer(args[0])) {
+ safe_str(T(e_int), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, args[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_abs(result, result);
+ safe_mpz(result, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_dist2d)
{
***************
*** 896,901 ****
--- 1011,1099 ----
safe_number(pow(num, m), buff, bp);
}
+ #ifdef USE_GMP_MATH
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_modexp)
+ {
+ mpz_t result;
+ mpz_t zero;
+ mpz_t base, exponent, modulus;
+
+ if (!is_integer(args[0]) || !is_integer(args[1]) || !is_integer(args[2])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(exponent, args[1], BASE_GMP) == -1) {
+ mpz_clear(exponent);
+ return;
+ }
+
+ mpz_init_set_si(zero, 1);
+ if (mpz_cmp(exponent, zero) < 0) {
+ mpz_clear(zero);
+ mpz_clear(exponent);
+ safe_str("#-1 NEGATIVE EXPONENT UNDEFINED", buff, bp);
+ return;
+ }
+ mpz_clear(zero);
+
+ if (mpz_init_set_str(base, args[0], BASE_GMP) == -1) {
+ mpz_clear(exponent);
+ mpz_clear(base);
+ return;
+ }
+
+ if (mpz_init_set_str(modulus, args[2], BASE_GMP) == -1) {
+ mpz_clear(base);
+ mpz_clear(exponent);
+ mpz_clear(modulus);
+ return;
+ }
+
+ mpz_init(result);
+ mpz_powm(result, base, exponent, modulus);
+ mpz_clear(base);
+ mpz_clear(exponent);
+ mpz_clear(modulus);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ /* ARGSUSED */
+ FUNCTION(fun_mpz_modinv)
+ {
+ mpz_t result;
+ mpz_t modulus;
+
+ if (!is_integer(args[0]) || !is_integer(args[1])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, args[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ if (mpz_init_set_str(modulus, args[1], BASE_GMP) == -1) {
+ mpz_clear(result);
+ mpz_clear(modulus);
+ return;
+ }
+
+ if (!mpz_invert(result, result, modulus)) {
+ mpz_clear(modulus);
+ mpz_clear(result);
+ safe_str("#-1 MODULAR INVERSE UNDEFINED", buff, bp);
+ return;
+ }
+ mpz_clear(modulus);
+
+ safe_mpz(result, buff, bp);
+ }
+ #endif
+
/* ARGSUSED */
FUNCTION(fun_ln)
{
***************
*** 1248,1253 ****
--- 1446,1537 ----
#undef add_zeros
+ #ifdef USE_GMP_MATH
+ FUNCTION(fun_mpz_gcd)
+ {
+ mpz_t result;
+ mpz_t N1, N2;
+
+ if (!is_integer(args[0]) || !is_integer(args[1])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(N1, args[0], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ return;
+ }
+
+ if (mpz_init_set_str(N2, args[1], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ mpz_clear(N2);
+ return;
+ }
+
+ mpz_init(result);
+ mpz_gcd(result, N1, N2);
+ mpz_clear(N1);
+ mpz_clear(N2);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_lcm)
+ {
+ mpz_t result;
+ mpz_t N1, N2;
+
+ if (!is_integer(args[0]) || !is_integer(args[1])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(N1, args[0], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ return;
+ }
+
+ if (mpz_init_set_str(N2, args[1], BASE_GMP) == -1) {
+ mpz_clear(N1);
+ mpz_clear(N2);
+ return;
+ }
+
+ mpz_init(result);
+ mpz_lcm(result, N1, N2);
+ mpz_clear(N1);
+ mpz_clear(N2);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_primetest)
+ {
+ mpz_t result;
+ int reps;
+
+ if (!is_integer(args[0]) || !is_integer(args[1])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+ reps = parse_integer(args[1]);
+
+ /* This is really slow for big reps, so let's limit the number of tests
+ to a reasonable value. 100 should be more than anyone needs. */
+ if (reps > 100) {
+ safe_str("#-1 100 MAXIMUM REPETITIONS", buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, args[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ safe_integer(mpz_probab_prime_p(result, reps), buff, bp);
+ }
+ #endif
+
FUNCTION(fun_bound)
{
if (!is_number(args[0]) ||
***************
*** 1367,1372 ****
--- 1651,1689 ----
safe_number(result, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ MATH_FUNC(math_mpz_add)
+ {
+ /* Arbitrary precision integer addition */
+ mpz_t operand;
+ mpz_t result;
+ char *rbuff;
+ int n;
+
+ mpz_init_set_si(result, 0);
+
+ mpz_init(operand);
+ for (n = 0; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(operand, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ return;
+ }
+ mpz_add(result, result, operand);
+ }
+ mpz_clear(operand);
+
+ safe_mpz(result, buff, bp);
+ }
+ #endif
+
MATH_FUNC(math_and)
{
int n;
***************
*** 1410,1415 ****
--- 1727,1778 ----
safe_number(result, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ MATH_FUNC(math_mpz_sub)
+ {
+ /* Arbitrary precision integer subtraction */
+ mpz_t operand;
+ mpz_t result;
+ char *rbuff;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(operand);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(operand, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ return;
+ }
+ mpz_sub(result, result, operand);
+ }
+ mpz_clear(operand);
+
+ safe_mpz(result, buff, bp);
+ }
+ #endif
+
MATH_FUNC(math_mul)
{
NVAL result;
***************
*** 1437,1442 ****
--- 1800,1850 ----
safe_number(result, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ MATH_FUNC(math_mpz_mul)
+ {
+ /* Arbitrary precision integer subtraction */
+ mpz_t operand;
+ mpz_t result;
+ char *rbuff;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(operand);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(operand, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(operand);
+ mpz_clear(result);
+ return;
+ }
+ mpz_mul(result, result, operand);
+ }
+ mpz_clear(operand);
+
+ safe_mpz(result, buff, bp);
+ }
+ #endif
MATH_FUNC(math_min)
{
***************
*** 1727,1732 ****
--- 2135,2346 ----
safe_integer(divresult, buff, bp);
}
+ #ifdef USE_GMP_MATH
+ MATH_FUNC(math_mpz_div)
+ {
+ /* Arbitrary precision integer division using truncation */
+ mpz_t result;
+ mpz_t divisor;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(divisor);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(divisor, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ return;
+ }
+
+ if (parse_integer(ptr[n]) == 0) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T("#-1 DIVISION BY ZERO"), buff, bp);
+ return;
+ }
+
+ mpz_tdiv_q(result, result, divisor);
+ }
+ mpz_clear(divisor);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ MATH_FUNC(math_mpz_floordiv)
+ {
+ /* Arbitrary precision integer division rounding to -inf */
+ mpz_t result;
+ mpz_t divisor;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(divisor);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(divisor, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ return;
+ }
+
+ if (parse_integer(ptr[n]) == 0) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T("#-1 DIVISION BY ZERO"), buff, bp);
+ return;
+ }
+
+ mpz_fdiv_q(result, result, divisor);
+ }
+ mpz_clear(divisor);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ MATH_FUNC(math_mpz_remainder)
+ {
+ /* Arbitrary precision integer remainder */
+ mpz_t result;
+ mpz_t divisor;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(divisor);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(divisor, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ return;
+ }
+
+ if (parse_integer(ptr[n]) == 0) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T("#-1 DIVISION BY ZERO"), buff, bp);
+ return;
+ }
+
+ mpz_tdiv_r(result, result, divisor);
+ }
+ mpz_clear(divisor);
+
+ safe_mpz(result, buff, bp);
+ }
+
+ MATH_FUNC(math_mpz_modulo)
+ {
+ /* Arbitrary precision integer modulus */
+ mpz_t result;
+ mpz_t divisor;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_integer(ptr[0])) {
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_init_set_str(result, ptr[0], BASE_GMP) == -1) {
+ mpz_clear(result);
+ return;
+ }
+
+ mpz_init(divisor);
+ for (n = 1; n < nptr; n++) {
+ if (!is_integer(ptr[n])) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T(e_ints), buff, bp);
+ return;
+ }
+
+ if (mpz_set_str(divisor, ptr[n], BASE_GMP) == -1) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ return;
+ }
+
+ if (parse_integer(ptr[n]) == 0) {
+ mpz_clear(result);
+ mpz_clear(divisor);
+ safe_str(T("#-1 DIVISION BY ZERO"), buff, bp);
+ return;
+ }
+
+ mpz_mod(result, result, divisor);
+ }
+ mpz_clear(divisor);
+
+ safe_mpz(result, buff, bp);
+ }
+ #endif
+
MATH_FUNC(math_band)
{
unsigned int bretval;
***************
*** 1976,1982 ****
--- 2590,2622 ----
safe_number(sqrt(s / (nptr - 1)), buff, bp);
}
+ #ifdef USE_GMP_MATH
+ void
+ safe_mpz(result, buff, bp)
+ mpz_t result;
+ char *buff;
+ char **bp;
+ {
+ char *rbuff;
+
+ rbuff = (char *)mush_malloc(mpz_sizeinbase(result, BASE_GMP) + 2, "string");
+ if (!rbuff) {
+ mpz_clear(result);
+ return;
+ }
+
+ safe_str(mpz_get_str(rbuff, BASE_GMP, result), buff, bp);
+ mush_free((Malloc_t) rbuff, "string");
+ mpz_clear(result);
+ }
+ #endif
+
MATH mlist[] = {
+ #ifdef USE_GMP_MATH
+ {"MPIADD", math_mpz_add},
+ {"MPISUB", math_mpz_sub},
+ {"MPIMUL", math_mpz_mul},
+ #endif
{"ADD", math_add}
,
{"SUB", math_sub}
***************
*** 1995,2000 ****
--- 2635,2654 ----
,
{"REMAINDER", math_remainder}
,
+ #ifdef USE_GMP_MATH
+ {"MPIDIV", math_mpz_div}
+ ,
+ {"MPIFLOORDIV", math_mpz_floordiv}
+ ,
+ {"MPIMOD", math_mpz_modulo}
+ ,
+ {"MPIMODULO", math_mpz_modulo}
+ ,
+ {"MPIMODULUS", math_mpz_modulo}
+ ,
+ {"MPIREMAINDER", math_mpz_remainder}
+ ,
+ #endif
{"MIN", math_min}
,
{"MAX", math_max}