#
# Patch name: GNU MP math support
# Patch version: Beta 1
# Author's email: kmoon@geocities.com
# Version of PennMUSH: 1.7.4p10
# Date patch made: Wed Oct 24 18:45:54 GMT 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 arithmetic 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 arithmetic? 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 arithmetic scheme, all in
soft code. Anyway, on to installation issues.
INSTALLATION
To apply the patch, type (from your pennmush directory):
patch -p0 < gmpmath.174p10
From here, you can either:
I) Run Configure, using -DUSE_GMP_MATH as an additional compiler option, and
-lgmp as an additional library option.
II) 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.
CHANGES
mpiadd() was calling math_add() instead of math_mpz_add(). This has been
fixed. Updates were also made to work around changes in later versions of
PennMUSH, which checked for the ERANGE error. The *_mpz_* functions now use
is_mp_integer() instead of is_integer(). The difference is that the ERANGE
check has been removed. Also, the code was reorganized to result in a patch
with few hunks.
*** src/funmath.c.dist Wed Jul 11 19:46:04 2001
--- src/funmath.c Wed Oct 24 11:37:50 2001
***************
*** 42,47 ****
--- 42,683 ----
static MATH *math_hash_lookup _((char *));
+ #ifdef USE_GMP_MATH
+
+ /* when compiling in GMP support */
+
+ #include
+ #define BASE_GMP 10
+
+
+ /* prototypes */
+
+ int is_mp_integer _((char const *));
+ 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);
+
+
+ /* degenerate lmath wrapper functions */
+
+ FUNCTION(fun_mpz_add)
+ {
+ math_mpz_add(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_sub)
+ {
+ math_mpz_sub(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_mul)
+ {
+ math_mpz_mul(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_div)
+ {
+ math_mpz_div(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_floordiv)
+ {
+ math_mpz_floordiv(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_modulo)
+ {
+ math_mpz_modulo(args, nargs, buff, bp);
+ }
+
+ FUNCTION(fun_mpz_remainder)
+ {
+ math_mpz_remainder(args, nargs, buff, bp);
+ }
+
+
+ /* various functions */
+
+ FUNCTION(fun_mpz_cmp)
+ {
+ mpz_t N1, N2;
+
+ if (!is_mp_integer(args[0]) || !is_mp_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);
+ }
+
+ FUNCTION(fun_mpz_abs)
+ {
+ mpz_t result;
+
+ if (!is_mp_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);
+ }
+
+ FUNCTION(fun_mpz_modexp)
+ {
+ mpz_t result;
+ mpz_t zero;
+ mpz_t base, exponent, modulus;
+
+ if (!is_mp_integer(args[0]) || !is_mp_integer(args[1]) || !is_mp_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);
+ }
+
+ FUNCTION(fun_mpz_modinv)
+ {
+ mpz_t result;
+ mpz_t modulus;
+
+ if (!is_mp_integer(args[0]) || !is_mp_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);
+ }
+
+ FUNCTION(fun_mpz_gcd)
+ {
+ mpz_t result;
+ mpz_t N1, N2;
+
+ if (!is_mp_integer(args[0]) || !is_mp_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_mp_integer(args[0]) || !is_mp_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_mp_integer(args[0]) || !is_mp_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);
+ }
+
+
+ /* lmath functions */
+
+ 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_mp_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);
+ }
+
+ 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_mp_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_mp_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);
+ }
+
+ MATH_FUNC(math_mpz_mul)
+ {
+ /* Arbitrary precision integer multiplication */
+ mpz_t operand;
+ mpz_t result;
+ char *rbuff;
+ int n;
+
+ if (nptr < 1) {
+ safe_chr('0', buff, bp);
+ return;
+ }
+
+ if (!is_mp_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_mp_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);
+ }
+
+ 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_mp_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_mp_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_mp_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_mp_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_mp_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_mp_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_mp_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_mp_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);
+ }
+
+ /* utility functions */
+
+ int
+ is_mp_integer(str)
+ char const *str;
+ {
+ /* code stolen from the is_integer function, with no ERANGE checking */
+ char *end;
+
+ /* If we're emulating Tiny, anything is an integer */
+ if (TINY_MATH)
+ return 1;
+ if (!str)
+ return 0;
+ while (isspace(*str))
+ str++;
+ if (*str == '\0')
+ return NULL_EQ_ZERO;
+ /* we really should throw in a check to replace strtol(), but I'm lazy */
+ return 1;
+ }
+
+ 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 /* USE_GMP_MATH */
+
MATH_PROTO(math_add);
MATH_PROTO(math_sub);
MATH_PROTO(math_mul);
***************
*** 1998,2003 ****
--- 2634,2650 ----
,
{"REMAINDER", math_remainder}
,
+ #ifdef USE_GMP_MATH
+ {"MPIADD", math_mpz_add},
+ {"MPISUB", math_mpz_sub},
+ {"MPIMUL", math_mpz_mul},
+ {"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 /* USE_GMP_MATH */
{"MIN", math_min}
,
{"MAX", math_max}
*** src/function.c.dist Sat Sep 15 10:43:50 2001
--- src/function.c Wed Oct 24 08:44:44 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