summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2008-02-28 22:44:19 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2008-02-28 22:44:19 +0000
commitc0daa0df39fcb3be58fba09bb936f515368b085e (patch)
tree2e34f6ff45835a1575bb81690a45f1c4f7e4207a
parent16ccc49aedb2f5edc29d4d0c70a84d8fc06f78c2 (diff)
downloadclasspath-c0daa0df39fcb3be58fba09bb936f515368b085e.tar.gz
2008-02-28 Andrew John Hughes <gnu_andrew@member.fsf.org>
PR classpath/28664 * include/Makefile.am: Add generation of header file java_math_VMBigInteger.h * java/math/BigInteger.java: Separate NativeMPI into VMBigInteger. * native/jni/Makefile.am: Add java-math. * native/jni/java-math/java_math_VMBigInteger.c: Renamed from java_math_BigInteger.c. * vm/reference/java/math/VMBigInteger.java: Former NativeMPI class from java.math.BigInteger. 2006-11-28 Raif S. Naffah <classpath@naffah-raif.name> Jeroen Frijters <jeroen@sumatra.nl> PR classpath/28664 * configure.ac: Add support for configuring GNU MP. * native/jni/Makefile.am: Include java-math directory if required. * native/jni/java-math/.cvsignore: New file. * native/jni/java-math/Makefile.am: Likewise. * native/jni/java-math/java_math_BigInteger.c: Likewise. * java/math/BigInteger.java: Added support for native methods. * gnu/classpath/Configuration.java.in (WANT_NATIVE_BIG_INTEGER): New field.
-rw-r--r--ChangeLog25
-rw-r--r--configure.ac53
-rw-r--r--gnu/classpath/Configuration.java.in10
-rw-r--r--include/Makefile.am3
-rw-r--r--java/math/BigInteger.java559
-rw-r--r--native/jni/Makefile.am2
-rw-r--r--native/jni/java-math/.cvsignore7
-rw-r--r--native/jni/java-math/Makefile.am11
-rw-r--r--native/jni/java-math/java_math_VMBigInteger.c1396
-rw-r--r--vm/reference/java/math/VMBigInteger.java474
10 files changed, 2462 insertions, 78 deletions
diff --git a/ChangeLog b/ChangeLog
index a07f90330..400c1df4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-02-28 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ PR classpath/28664
+ * include/Makefile.am:
+ Add generation of header file java_math_VMBigInteger.h
+ * java/math/BigInteger.java: Separate NativeMPI into
+ VMBigInteger.
+ * native/jni/Makefile.am: Add java-math.
+ * native/jni/java-math/java_math_VMBigInteger.c:
+ Renamed from java_math_BigInteger.c.
+ * vm/reference/java/math/VMBigInteger.java:
+ Former NativeMPI class from java.math.BigInteger.
+
+2006-11-28 Raif S. Naffah <classpath@naffah-raif.name>
+ Jeroen Frijters <jeroen@sumatra.nl>
+
+ PR classpath/28664
+ * configure.ac: Add support for configuring GNU MP.
+ * native/jni/Makefile.am: Include java-math directory if required.
+ * native/jni/java-math/.cvsignore: New file.
+ * native/jni/java-math/Makefile.am: Likewise.
+ * native/jni/java-math/java_math_BigInteger.c: Likewise.
+ * java/math/BigInteger.java: Added support for native methods.
+ * gnu/classpath/Configuration.java.in (WANT_NATIVE_BIG_INTEGER): New field.
+
2008-02-27 Andrew John Hughes <gnu_andrew@member.fsf.org>
* configure.ac:
diff --git a/configure.ac b/configure.ac
index 50d4f497d..dbca5d80f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -246,6 +246,19 @@ AC_ARG_ENABLE([plugin],
AM_CONDITIONAL(CREATE_PLUGIN, test "x${COMPILE_PLUGIN}" = xyes)
dnl -----------------------------------------------------------
+dnl Native java.math.BigInteger (enabled by default)
+dnl -----------------------------------------------------------
+AC_ARG_ENABLE([gmp],
+ [AS_HELP_STRING(--enable-gmp,
+ compile native java.math.BigInteger library (disabled by --disable-gmp) [default=yes])],
+ [case "${enableval}" in
+ yes|true) COMPILE_GMP=yes ;;
+ no|false) COMPILE_GMP=no ;;
+ *) COMPILE_GMP=yes ;;
+ esac],
+ [COMPILE_GMP=yes])
+
+dnl -----------------------------------------------------------
dnl Sets the native libraries installation dir
dnl -----------------------------------------------------------
AC_ARG_WITH([native-libdir],
@@ -697,6 +710,26 @@ if test "x${COMPILE_JNI}" = xyes; then
AC_SUBST(PLUGIN_DIR, $HOME/.mozilla/plugins/)
fi
+
+ dnl Check for GNU MP library and header file
+ dnl for GNU MP versions >= 4.2 use __gmpz_combit; otherwise look for
+ dnl __gmpz_mul_si for earlier versions (>= 3.1).
+ dnl IMPORTANT: if you decide to look for __gmpz_combit, don't forget to
+ dnl change the name of the corresponding ac_ variable on lines 860...
+ if test "x${COMPILE_GMP}" = xyes; then
+ AC_CHECK_LIB(gmp, __gmpz_mul_si,
+ [GMP_CFLAGS=-I/usr/include
+ GMP_LIBS=-lgmp ],
+ [GMP_CFLAGS=
+ GMP_LIBS= ])
+ AC_SUBST(GMP_CFLAGS)
+ AC_SUBST(GMP_LIBS)
+
+ AC_CHECK_HEADERS([gmp.h])
+ fi
+
+else
+ COMPILE_GMP=no
fi
if test "x${REGENERATE_JNI_HEADERS}" = xyes; then
@@ -938,6 +971,25 @@ dnl -----------------------------------------------------------
AC_SUBST(DEFAULT_PREFS_PEER)
dnl -----------------------------------------------------------
+dnl Set GNU MP related params
+dnl -----------------------------------------------------------
+WANT_NATIVE_BIG_INTEGER=false
+if test "x${COMPILE_GMP}" = xyes; then
+ if test "x${ac_cv_lib_gmp___gmpz_mul_si}" = xyes; then
+ if test "x${ac_cv_header_gmp_h}" = xyes; then
+ WANT_NATIVE_BIG_INTEGER=true
+ AC_DEFINE(WITH_GNU_MP, 1, [Define to 1 if gmp is usable])
+ else
+ COMPILE_GMP=no
+ fi
+ else
+ COMPILE_GMP=no
+ fi
+fi
+AC_SUBST(WANT_NATIVE_BIG_INTEGER)
+AM_CONDITIONAL(CREATE_GMPBI_LIBRARY, test "x${COMPILE_GMP}" = xyes)
+
+dnl -----------------------------------------------------------
dnl output files
dnl -----------------------------------------------------------
AC_CONFIG_FILES([Makefile
@@ -958,6 +1010,7 @@ native/jni/Makefile
native/jni/classpath/Makefile
native/jni/java-io/Makefile
native/jni/java-lang/Makefile
+native/jni/java-math/Makefile
native/jni/java-net/Makefile
native/jni/java-nio/Makefile
native/jni/java-util/Makefile
diff --git a/gnu/classpath/Configuration.java.in b/gnu/classpath/Configuration.java.in
index 7fb864093..4a9b65f56 100644
--- a/gnu/classpath/Configuration.java.in
+++ b/gnu/classpath/Configuration.java.in
@@ -101,4 +101,14 @@ public interface Configuration
* com.sun.tools.javac implementation in tools.zip.
*/
String ECJ_JAR = "@ECJ_JAR@";
+
+ /**
+ * Set to <code>true</code> if the config script found that (a) an
+ * implementation of java.math.BigInteger, based on the GNU MP library, is
+ * desired in preference to a pure Java one, and (b) the GNU MP library was
+ * found on the platform where the JVM is to run. Otherwise, this field is
+ * set to <code>false</code>.
+ */
+ boolean WANT_NATIVE_BIG_INTEGER = @WANT_NATIVE_BIG_INTEGER@;
+
}
diff --git a/include/Makefile.am b/include/Makefile.am
index 07b59d517..6ae67827a 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -148,6 +148,7 @@ java_lang_VMMath.h \
java_lang_VMProcess.h \
java_lang_VMSystem.h \
java_lang_reflect_VMArray.h \
+java_math_VMBigInteger.h \
java_net_VMInetAddress.h \
java_net_VMNetworkInterface.h \
java_net_VMURLConnection.h \
@@ -393,6 +394,8 @@ java_lang_VMSystem.h: $(top_srcdir)/vm/reference/java/lang/VMSystem.java
$(JAVAH) -o $@ java.lang.VMSystem
java_lang_reflect_VMArray.h: $(top_srcdir)/vm/reference/java/lang/reflect/VMArray.java
$(JAVAH) -o $@ java.lang.reflect.VMArray
+java_math_VMBigInteger.h: $(top_srcdir)/vm/reference/java/math/VMBigInteger.java
+ $(JAVAH) -o $@ java.math.VMBigInteger
java_net_VMInetAddress.h: $(top_srcdir)/vm/reference/java/net/VMInetAddress.java
$(JAVAH) -o $@ java.net.VMInetAddress
java_net_VMNetworkInterface.h: $(top_srcdir)/vm/reference/java/net/VMNetworkInterface.java
diff --git a/java/math/BigInteger.java b/java/math/BigInteger.java
index 3fb75ffa3..b57fbde68 100644
--- a/java/math/BigInteger.java
+++ b/java/math/BigInteger.java
@@ -38,12 +38,14 @@ exception statement from your version. */
package java.math;
+import gnu.classpath.Configuration;
import gnu.java.math.MPN;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Random;
+import java.util.logging.Logger;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -59,6 +61,8 @@ import java.util.Random;
*/
public class BigInteger extends Number implements Comparable<BigInteger>
{
+ private static final Logger log = Logger.getLogger(BigInteger.class.getName());
+
/** All integers are stored in 2's-complement form.
* If words == null, the ival is the value of this BigInteger.
* Otherwise, the first ival elements of words make the value
@@ -67,9 +71,10 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private transient int[] words;
// Serialization fields.
+ // the first three, although not used in the code, are present for
+ // compatibility with older RI versions of this class. DO NOT REMOVE.
private int bitCount = -1;
private int bitLength = -1;
- private int firstNonzeroByteNum = -2;
private int lowestSetBit = -2;
private byte[] magnitude;
private int signum;
@@ -81,31 +86,52 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private static final int minFixNum = -100;
private static final int maxFixNum = 1024;
private static final int numFixNum = maxFixNum-minFixNum+1;
- private static final BigInteger[] smallFixNums = new BigInteger[numFixNum];
+ private static final BigInteger[] smallFixNums;
+
+ /** The alter-ego VMBigInteger instance for this. */
+ transient VMBigInteger mpz;
+
+ private static final boolean USING_NATIVE = Configuration.WANT_NATIVE_BIG_INTEGER
+ && initializeLibrary();
static
{
- for (int i = numFixNum; --i >= 0; )
- smallFixNums[i] = new BigInteger(i + minFixNum);
+ if (USING_NATIVE)
+ {
+ smallFixNums = null;
+ ZERO = valueOf(0L);
+ ONE = valueOf(1L);
+ TEN = valueOf(10L);
+ }
+ else
+ {
+ smallFixNums = new BigInteger[numFixNum];
+ for (int i = numFixNum; --i >= 0; )
+ smallFixNums[i] = new BigInteger(i + minFixNum);
+
+ ZERO = smallFixNums[-minFixNum];
+ ONE = smallFixNums[1 - minFixNum];
+ TEN = smallFixNums[10 - minFixNum];
+ }
}
/**
* The constant zero as a BigInteger.
* @since 1.2
*/
- public static final BigInteger ZERO = smallFixNums[0 - minFixNum];
+ public static final BigInteger ZERO;
/**
* The constant one as a BigInteger.
* @since 1.2
*/
- public static final BigInteger ONE = smallFixNums[1 - minFixNum];
+ public static final BigInteger ONE;
/**
* The constant ten as a BigInteger.
* @since 1.5
*/
- public static final BigInteger TEN = smallFixNums[10 - minFixNum];
+ public static final BigInteger TEN;
/* Rounding modes: */
private static final int FLOOR = 1;
@@ -130,19 +156,72 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private BigInteger()
{
+ super();
+
+ if (USING_NATIVE)
+ this.mpz = new VMBigInteger();
}
/* Create a new (non-shared) BigInteger, and initialize to an int. */
private BigInteger(int value)
{
+ super();
+
ival = value;
}
- public BigInteger(String val, int radix)
+ public BigInteger(String s, int radix)
{
- BigInteger result = valueOf(val, radix);
- this.ival = result.ival;
- this.words = result.words;
+ this();
+
+ int len = s.length();
+ int i, digit;
+ boolean negative;
+ byte[] bytes;
+ char ch = s.charAt(0);
+ if (ch == '-')
+ {
+ negative = true;
+ i = 1;
+ bytes = new byte[len - 1];
+ }
+ else
+ {
+ negative = false;
+ i = 0;
+ bytes = new byte[len];
+ }
+ int byte_len = 0;
+ for ( ; i < len; i++)
+ {
+ ch = s.charAt(i);
+ digit = Character.digit(ch, radix);
+ if (digit < 0)
+ throw new NumberFormatException("Invalid character at position #" + i);
+ bytes[byte_len++] = (byte) digit;
+ }
+
+ if (USING_NATIVE)
+ {
+ bytes = null;
+ if (this.mpz.fromString(s, radix) != 0)
+ throw new NumberFormatException("String \"" + s
+ + "\" is NOT a valid number in base "
+ + radix);
+ }
+ else
+ {
+ BigInteger result;
+ // Testing (len < MPN.chars_per_word(radix)) would be more accurate,
+ // but slightly more expensive, for little practical gain.
+ if (len <= 15 && radix <= 16)
+ result = valueOf(Long.parseLong(s, radix));
+ else
+ result = valueOf(bytes, byte_len, negative, radix);
+
+ this.ival = result.ival;
+ this.words = result.words;
+ }
}
public BigInteger(String val)
@@ -153,17 +232,26 @@ public class BigInteger extends Number implements Comparable<BigInteger>
/* Create a new (non-shared) BigInteger, and initialize from a byte array. */
public BigInteger(byte[] val)
{
+ this();
+
if (val == null || val.length < 1)
throw new NumberFormatException();
- words = byteArrayToIntArray(val, val[0] < 0 ? -1 : 0);
- BigInteger result = make(words, words.length);
- this.ival = result.ival;
- this.words = result.words;
+ if (USING_NATIVE)
+ this.mpz.fromByteArray(val);
+ else
+ {
+ words = byteArrayToIntArray(val, val[0] < 0 ? -1 : 0);
+ BigInteger result = make(words, words.length);
+ this.ival = result.ival;
+ this.words = result.words;
+ }
}
public BigInteger(int signum, byte[] magnitude)
{
+ this();
+
if (magnitude == null || signum > 1 || signum < -1)
throw new NumberFormatException();
@@ -177,18 +265,25 @@ public class BigInteger extends Number implements Comparable<BigInteger>
return;
}
- // Magnitude is always positive, so don't ever pass a sign of -1.
- words = byteArrayToIntArray(magnitude, 0);
- BigInteger result = make(words, words.length);
- this.ival = result.ival;
- this.words = result.words;
+ if (USING_NATIVE)
+ this.mpz.fromSignedMagnitude(magnitude, signum == -1);
+ else
+ {
+ // Magnitude is always positive, so don't ever pass a sign of -1.
+ words = byteArrayToIntArray(magnitude, 0);
+ BigInteger result = make(words, words.length);
+ this.ival = result.ival;
+ this.words = result.words;
- if (signum < 0)
- setNegative();
+ if (signum < 0)
+ setNegative();
+ }
}
public BigInteger(int numBits, Random rnd)
{
+ this();
+
if (numBits < 0)
throw new IllegalArgumentException();
@@ -197,6 +292,22 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private void init(int numBits, Random rnd)
{
+ if (USING_NATIVE)
+ {
+ int length = (numBits + 7) / 8;
+ byte[] magnitude = new byte[length];
+ rnd.nextBytes(magnitude);
+ int discardedBitCount = numBits % 8;
+ if (discardedBitCount != 0)
+ {
+ discardedBitCount = 8 - discardedBitCount;
+ magnitude[0] = (byte)((magnitude[0] & 0xFF) >>> discardedBitCount);
+ }
+ this.mpz.fromSignedMagnitude(magnitude, false);
+ magnitude = null;
+ return;
+ }
+
int highbits = numBits & 31;
// minimum number of bytes to store the above number of bits
int highBitByteCount = (highbits + 7) / 8;
@@ -235,20 +346,23 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger(int bitLength, int certainty, Random rnd)
{
- this(bitLength, rnd);
+ this();
- // Keep going until we find a probable prime.
- BigInteger result;
+ BigInteger result = new BigInteger();
while (true)
{
- // ...but first ensure that BI has bitLength bits
- result = setBit(bitLength - 1);
+ result.init(bitLength, rnd);
+ result = result.setBit(bitLength - 1);
+ if (result.isProbablePrime(certainty))
+ break;
+ }
+
+ if (USING_NATIVE)
+ this.mpz.fromBI(result);
+ else
+ {
this.ival = result.ival;
this.words = result.words;
- if (isProbablePrime(certainty))
- return;
-
- init(bitLength, rnd);
}
}
@@ -272,6 +386,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
/** Return a (possibly-shared) BigInteger with a given long value. */
public static BigInteger valueOf(long val)
{
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ result.mpz.fromLong(val);
+ return result;
+ }
+
if (val >= minFixNum && val <= maxFixNum)
return smallFixNums[(int) val - minFixNum];
int i = (int) val;
@@ -284,6 +405,31 @@ public class BigInteger extends Number implements Comparable<BigInteger>
return result;
}
+ /**
+ * @return <code>true</code> if the GMP-based native implementation library
+ * was successfully loaded. Returns <code>false</code> otherwise.
+ */
+ private static boolean initializeLibrary()
+ {
+ boolean result;
+ try
+ {
+ System.loadLibrary("javamath");
+ VMBigInteger.natInitializeLibrary();
+ result = true;
+ }
+ catch (Throwable x)
+ {
+ result = false;
+ if (Configuration.DEBUG)
+ {
+ log.info("Unable to use native BigInteger: " + x);
+ log.info("Will use a pure Java implementation instead");
+ }
+ }
+ return result;
+ }
+
/** Make a canonicalized BigInteger from an array of words.
* The array may be reused (without copying). */
private static BigInteger make(int[] words, int len)
@@ -374,6 +520,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public int signum()
{
+ if (USING_NATIVE)
+ return this.mpz.compare(ZERO);
+
if (ival == 0 && words == null)
return 0;
int top = words == null ? ival : words[ival-1];
@@ -382,6 +531,12 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private static int compareTo(BigInteger x, BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ return x.mpz.compare(y);
+ }
+
if (x.words == null && y.words == null)
return x.ival < y.ival ? -1 : x.ival > y.ival ? 1 : 0;
boolean x_negative = x.isNegative();
@@ -586,11 +741,27 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger add(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ int dummy = val.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.add(val, result);
+ return result;
+ }
+
return add(this, val, 1);
}
public BigInteger subtract(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ int dummy = val.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.subtract(val, result);
+ return result;
+ }
+
return add(this, val, -1);
}
@@ -672,6 +843,14 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger multiply(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.multiply(y, result);
+ return result;
+ }
+
return times(this, y);
}
@@ -947,6 +1126,16 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger divide(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ if (val.compareTo(ZERO) == 0)
+ throw new ArithmeticException("divisor is zero");
+
+ BigInteger result = new BigInteger();
+ this.mpz.quotient(val, result);
+ return result;
+ }
+
if (val.isZero())
throw new ArithmeticException("divisor is zero");
@@ -957,6 +1146,16 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger remainder(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ if (val.compareTo(ZERO) == 0)
+ throw new ArithmeticException("divisor is zero");
+
+ BigInteger result = new BigInteger();
+ this.mpz.remainder(val, result);
+ return result;
+ }
+
if (val.isZero())
throw new ArithmeticException("divisor is zero");
@@ -967,6 +1166,17 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger[] divideAndRemainder(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ if (val.compareTo(ZERO) == 0)
+ throw new ArithmeticException("divisor is zero");
+
+ BigInteger q = new BigInteger();
+ BigInteger r = new BigInteger();
+ this.mpz.quotientAndRemainder(val, q, r);
+ return new BigInteger[] { q, r };
+ }
+
if (val.isZero())
throw new ArithmeticException("divisor is zero");
@@ -981,6 +1191,17 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger mod(BigInteger m)
{
+ if (USING_NATIVE)
+ {
+ int dummy = m.signum; // force NPE check
+ if (m.compareTo(ZERO) < 1)
+ throw new ArithmeticException("non-positive modulus");
+
+ BigInteger result = new BigInteger();
+ this.mpz.modulo(m, result);
+ return result;
+ }
+
if (m.isNegative() || m.isZero())
throw new ArithmeticException("non-positive modulus");
@@ -1000,6 +1221,14 @@ public class BigInteger extends Number implements Comparable<BigInteger>
return ONE;
throw new ArithmeticException("negative exponent");
}
+
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.pow(exponent, result);
+ return result;
+ }
+
if (isZero())
return this;
int plen = words == null ? 1 : ival; // Length of pow2.
@@ -1097,6 +1326,17 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger modInverse(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ if (this.mpz.compare(ZERO) < 1)
+ throw new ArithmeticException("non-positive modulo");
+
+ BigInteger result = new BigInteger();
+ this.mpz.modInverse(y, result);
+ return result;
+ }
+
if (y.isNegative() || y.isZero())
throw new ArithmeticException("non-positive modulo");
@@ -1175,6 +1415,17 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger modPow(BigInteger exponent, BigInteger m)
{
+ if (USING_NATIVE)
+ {
+ int dummy = exponent.signum; // force NPE check
+ if (m.mpz.compare(ZERO) < 1)
+ throw new ArithmeticException("non-positive modulo");
+
+ BigInteger result = new BigInteger();
+ this.mpz.modPow(exponent, m, result);
+ return result;
+ }
+
if (m.isNegative() || m.isZero())
throw new ArithmeticException("non-positive modulo");
@@ -1228,6 +1479,14 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger gcd(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.gcd(y, result);
+ return result;
+ }
+
int xval = ival;
int yval = y.ival;
if (words == null)
@@ -1281,6 +1540,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
if (certainty < 1)
return true;
+ if (USING_NATIVE)
+ return this.mpz.testPrimality(certainty) != 0;
+
/** We'll use the Rabin-Miller algorithm for doing a probabilistic
* primality test. It is fast, easy and has faster decreasing odds of a
* composite passing than with other tests. This means that this
@@ -1460,11 +1722,37 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger shiftLeft(int n)
{
+ if (n == 0)
+ return this;
+
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ if (n < 0)
+ this.mpz.shiftRight(-n, result);
+ else
+ this.mpz.shiftLeft(n, result);
+ return result;
+ }
+
return shift(this, n);
}
public BigInteger shiftRight(int n)
{
+ if (n == 0)
+ return this;
+
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ if (n < 0)
+ this.mpz.shiftLeft(-n, result);
+ else
+ this.mpz.shiftRight(n, result);
+ return result;
+ }
+
return shift(this, -n);
}
@@ -1537,6 +1825,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public String toString(int radix)
{
+ if (USING_NATIVE)
+ return this.mpz.toString(radix);
+
if (words == null)
return Integer.toString(ival, radix);
if (ival <= 2)
@@ -1549,6 +1840,12 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public int intValue()
{
+ if (USING_NATIVE)
+ {
+ int result = this.mpz.absIntValue();
+ return this.mpz.compare(ZERO) < 0 ? - result : result;
+ }
+
if (words == null)
return ival;
return words[0];
@@ -1556,6 +1853,15 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public long longValue()
{
+ if (USING_NATIVE)
+ {
+ long result;
+ result = (this.abs().shiftRight(32)).mpz.absIntValue();
+ result <<= 32;
+ result |= this.mpz.absIntValue() & 0xFFFFFFFFL;
+ return this.compareTo(ZERO) < 0 ? - result : result;
+ }
+
if (words == null)
return ival;
if (ival == 1)
@@ -1566,12 +1872,25 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public int hashCode()
{
// FIXME: May not match hashcode of JDK.
+ if (USING_NATIVE)
+ {
+ // TODO: profile to decide whether to make it native
+ byte[] bytes = this.toByteArray();
+ int result = 0;
+ for (int i = 0; i < bytes.length; i++)
+ result ^= (bytes[i] & 0xFF) << (8 * (i % 4));
+ return result;
+ }
+
return words == null ? ival : (words[0] + words[ival - 1]);
}
/* Assumes x and y are both canonicalized. */
private static boolean equals(BigInteger x, BigInteger y)
{
+ if (USING_NATIVE)
+ return x.mpz.compare(y) == 0;
+
if (x.words == null && y.words == null)
return x.ival == y.ival;
if (x.words == null || y.words == null || x.ival != y.ival)
@@ -1592,43 +1911,6 @@ public class BigInteger extends Number implements Comparable<BigInteger>
return equals(this, (BigInteger) obj);
}
- private static BigInteger valueOf(String s, int radix)
- throws NumberFormatException
- {
- int len = s.length();
- // Testing (len < MPN.chars_per_word(radix)) would be more accurate,
- // but slightly more expensive, for little practical gain.
- if (len <= 15 && radix <= 16)
- return valueOf(Long.parseLong(s, radix));
-
- int i, digit;
- boolean negative;
- byte[] bytes;
- char ch = s.charAt(0);
- if (ch == '-')
- {
- negative = true;
- i = 1;
- bytes = new byte[len - 1];
- }
- else
- {
- negative = false;
- i = 0;
- bytes = new byte[len];
- }
- int byte_len = 0;
- for ( ; i < len; i++)
- {
- ch = s.charAt(i);
- digit = Character.digit(ch, radix);
- if (digit < 0)
- throw new NumberFormatException();
- bytes[byte_len++] = (byte) digit;
- }
- return valueOf(bytes, byte_len, negative, radix);
- }
-
private static BigInteger valueOf(byte[] digits, int byte_len,
boolean negative, int radix)
{
@@ -1646,6 +1928,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public double doubleValue()
{
+ if (USING_NATIVE)
+ return this.mpz.doubleValue();
+
if (words == null)
return (double) ival;
if (ival <= 2)
@@ -1827,6 +2112,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger abs()
{
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.abs(result);
+ return result;
+ }
+
return abs(this);
}
@@ -1841,6 +2133,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public BigInteger negate()
{
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.negate(result);
+ return result;
+ }
+
return neg(this);
}
@@ -1849,6 +2148,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
*/
public int bitLength()
{
+ if (USING_NATIVE)
+ return this.mpz.bitLength();
+
if (words == null)
return MPN.intLength(ival);
return MPN.intLength(words, ival);
@@ -1856,6 +2158,25 @@ public class BigInteger extends Number implements Comparable<BigInteger>
public byte[] toByteArray()
{
+ if (signum() == 0)
+ return new byte[1];
+
+ if (USING_NATIVE)
+ {
+ // the minimal number of bytes required to represent the MPI is function
+ // of (a) its bit-length, and (b) its sign. only when this MPI is both
+ // positive, and its bit-length is a multiple of 8 do we add one zero
+ // bit for its sign. we do this so if we construct a new MPI from the
+ // resulting byte array, we wouldn't mistake a positive number, whose
+ // bit-length is a multiple of 8, for a similar-length negative one.
+ int bits = this.bitLength();
+ if (bits % 8 == 0 || this.signum() == 1)
+ bits++;
+ byte[] bytes = new byte[(bits + 7) / 8];
+ this.mpz.toByteArray(bytes);
+ return bytes;
+ }
+
// Determine number of bytes needed. The method bitlength returns
// the size without the sign bit, so add one bit for that and then
// add 7 more to emulate the ceil function using integer math.
@@ -2112,6 +2433,14 @@ public class BigInteger extends Number implements Comparable<BigInteger>
/** Return the logical (bit-wise) "and" of two BigIntegers. */
public BigInteger and(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.and(y, result);
+ return result;
+ }
+
if (y.words == null)
return and(this, y.ival);
else if (words == null)
@@ -2135,23 +2464,54 @@ public class BigInteger extends Number implements Comparable<BigInteger>
/** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */
public BigInteger or(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.or(y, result);
+ return result;
+ }
+
return bitOp(7, this, y);
}
/** Return the logical (bit-wise) "exclusive or" of two BigIntegers. */
public BigInteger xor(BigInteger y)
{
+ if (USING_NATIVE)
+ {
+ int dummy = y.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.xor(y, result);
+ return result;
+ }
+
return bitOp(6, this, y);
}
/** Return the logical (bit-wise) negation of a BigInteger. */
public BigInteger not()
{
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.not(result);
+ return result;
+ }
+
return bitOp(12, this, ZERO);
}
public BigInteger andNot(BigInteger val)
{
+ if (USING_NATIVE)
+ {
+ int dummy = val.signum; // force NPE check
+ BigInteger result = new BigInteger();
+ this.mpz.andNot(val, result);
+ return result;
+ }
+
return and(val.not());
}
@@ -2160,6 +2520,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
if (n < 0)
throw new ArithmeticException();
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.setBit(n, false, result);
+ return result;
+ }
+
return and(ONE.shiftLeft(n).not());
}
@@ -2168,6 +2535,13 @@ public class BigInteger extends Number implements Comparable<BigInteger>
if (n < 0)
throw new ArithmeticException();
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.setBit(n, true, result);
+ return result;
+ }
+
return or(ONE.shiftLeft(n));
}
@@ -2176,6 +2550,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
if (n < 0)
throw new ArithmeticException();
+ if (USING_NATIVE)
+ return this.mpz.testBit(n) != 0;
+
return !and(ONE.shiftLeft(n)).isZero();
}
@@ -2184,11 +2561,21 @@ public class BigInteger extends Number implements Comparable<BigInteger>
if (n < 0)
throw new ArithmeticException();
+ if (USING_NATIVE)
+ {
+ BigInteger result = new BigInteger();
+ this.mpz.flipBit(n, result);
+ return result;
+ }
+
return xor(ONE.shiftLeft(n));
}
public int getLowestSetBit()
{
+ if (USING_NATIVE)
+ return this.mpz.compare(ZERO) == 0 ? -1 : this.mpz.lowestSetBit();
+
if (isZero())
return -1;
@@ -2225,6 +2612,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
* If argument is negative, count zero bits instead. */
public int bitCount()
{
+ if (USING_NATIVE)
+ return this.mpz.bitCount();
+
int i, x_len;
int[] x_words = words;
if (x_words == null)
@@ -2243,19 +2633,30 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
- s.defaultReadObject();
- if (magnitude.length == 0 || signum == 0)
+ if (USING_NATIVE)
{
- this.ival = 0;
- this.words = null;
+ this.mpz = new VMBigInteger();
+ s.defaultReadObject();
+ if (signum != 0)
+ this.mpz.fromByteArray(magnitude);
+ // else it's zero and we need to do nothing
}
else
{
- words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0);
- BigInteger result = make(words, words.length);
- this.ival = result.ival;
- this.words = result.words;
- }
+ s.defaultReadObject();
+ if (magnitude.length == 0 || signum == 0)
+ {
+ this.ival = 0;
+ this.words = null;
+ }
+ else
+ {
+ words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0);
+ BigInteger result = make(words, words.length);
+ this.ival = result.ival;
+ this.words = result.words;
+ }
+ }
}
private void writeObject(ObjectOutputStream s)
@@ -2264,5 +2665,9 @@ public class BigInteger extends Number implements Comparable<BigInteger>
signum = signum();
magnitude = signum == 0 ? new byte[0] : toByteArray();
s.defaultWriteObject();
+ magnitude = null; // not needed anymore
}
+
+ // inner class(es) ..........................................................
+
}
diff --git a/native/jni/Makefile.am b/native/jni/Makefile.am
index f37e73864..dde5eda6a 100644
--- a/native/jni/Makefile.am
+++ b/native/jni/Makefile.am
@@ -1,7 +1,7 @@
## Input file for automake to generate the Makefile.in used by configure
if CREATE_CORE_JNI_LIBRARIES
- JNIDIRS = native-lib java-io java-lang java-net java-nio java-util
+ JNIDIRS = native-lib java-io java-lang java-math java-net java-nio java-util
endif
if CREATE_ALSA_LIBRARIES
diff --git a/native/jni/java-math/.cvsignore b/native/jni/java-math/.cvsignore
new file mode 100644
index 000000000..668a982d6
--- /dev/null
+++ b/native/jni/java-math/.cvsignore
@@ -0,0 +1,7 @@
+.deps
+.libs
+*.lo
+*.loT
+*.la
+Makefile
+Makefile.in
diff --git a/native/jni/java-math/Makefile.am b/native/jni/java-math/Makefile.am
new file mode 100644
index 000000000..a8006477f
--- /dev/null
+++ b/native/jni/java-math/Makefile.am
@@ -0,0 +1,11 @@
+nativeexeclib_LTLIBRARIES = libjavamath.la
+
+libjavamath_la_SOURCES = java_math_VMBigInteger.c
+
+libjavamath_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo
+
+libjavamath_la_LDFLAGS = -avoid-version
+
+AM_LDFLAGS = @CLASSPATH_MODULE@ @GMP_LIBS@
+AM_CPPFLAGS = @CLASSPATH_INCLUDES@
+AM_CFLAGS = @WARNING_CFLAGS@ @ERROR_CFLAGS@ @GMP_CFLAGS@
diff --git a/native/jni/java-math/java_math_VMBigInteger.c b/native/jni/java-math/java_math_VMBigInteger.c
new file mode 100644
index 000000000..01bbb2e03
--- /dev/null
+++ b/native/jni/java-math/java_math_VMBigInteger.c
@@ -0,0 +1,1396 @@
+/* java_math_BigInteger_NativeMPI.c -- Native MPI implemenetation over GNU MP
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "java_math_VMBigInteger.h"
+#include <jcl.h>
+
+#if defined(HAVE_GMP_H)
+#include <gmp.h>
+#endif /* defined(HAVE_GMP_H) */
+
+#if defined(WITH_GNU_MP)
+#else
+#warning GNU MP not available or wanted!
+#warning Invocation of natXXX() methods will raise an exception
+#endif
+
+/*
+ * This is the implementation of the native BigInteger$NativeMPI methods which
+ * use the GNU MP (GMP) library.
+ *
+ * In all the Java non-statically declared native methods, the second argument,
+ * an instance of jobject, refers to the current NativeMPI instance; i.e.
+ * "this" in Java parlance. The corresponding allocated data structure
+ * representing the GMP's counter-part is pointed-to by the pointer stored in a
+ * transient java field named "native_ptr". The first thing these methods do is
+ * (a) access that field with a JNI GetObjectField() call to obtain the
+ * reference to the gnu.classpath.Pointer subclass instance, then (b) obtain
+ * the native GMP pointer (an mpz_ptr), in order to perform their job; e.g.
+ *
+ * JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr))
+ *
+ * For static methods the second argument, an instance of jclass, is almost
+ * always unused --except when initializing the library, which is the only time
+ * we get hold of the native pointer field.
+ *
+ * This code was written and tested with GNU MP version 4.1.2. More recent
+ * versions of that library offer more operations; e.g. in the implementation
+ * of the method Java_java_math_BigInteger_00024NativeMPI_natFlipBit, mpz_combit()
+ * should be used with GNU MP versions later than 4.2. As a consequence, this
+ * code should be reviewed, from time to time, to use newer features of the GNU
+ * MP library.
+ */
+
+static jfieldID native_ptr;
+
+#ifdef DEBUG
+#define TRACE(msg) fprintf (stderr, "%s(%s:%d) -- %s\n", __FUNCTION__, __FILE__, __LINE__, msg)
+#else
+#define TRACE(msg)
+#endif
+
+#define throw_config_exception(env) JCL_ThrowException (env, "java/lang/Error", "GNU MP was not specified/found by configure")
+
+/*
+ * Initialize the native library. Specifically this method:
+ *
+ * a. Pass NULLs to the mp_set_memory_functions implying that GMP should use
+ * malloc, realloc and free for memory allocation, and if they fail GMP
+ * will print a message to the standard error output and terminates the
+ * program.
+ * b. Find out and store the reference to the NativeMPI class's 'native_ptr'
+ * field. This is done so later in the method invocations we can access that
+ * field and acquire the native value associated with that Pointer instance.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natInitializeLibrary (JNIEnv *env,
+ jclass nativeMPI)
+{
+#if defined(WITH_GNU_MP)
+ TRACE("Loading GMP-based BigInteger native library");
+ mp_set_memory_functions (NULL, NULL, NULL);
+ native_ptr = (*env)->GetFieldID (env, nativeMPI, "native_ptr",
+ "Lgnu/classpath/Pointer;");
+ TRACE("Loaded GMP-based BigInteger native library");
+#else /* !defined(WITH_GNU_MP) */
+ (void) nativeMPI;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * Allocate and initialize the data structure for an instance of a NativeMPI.
+ *
+ * @param this an instance of NativeMPI.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natInitialize(JNIEnv *env, jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_malloc (env, sizeof (mpz_t));
+ /* initialize --GMP sets the value to zero. */
+ mpz_init (_this);
+ /* instantiate the Pointer instance for this NativeMPI. */
+ jobject native_ptr_fld = JCL_NewRawDataObject (env, _this);
+ /* ... and assign it to the native_ptr field. */
+ (*env)->SetObjectField (env, this, native_ptr, native_ptr_fld);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * Clear and free the data structure for an instance of a NativeMPI.
+ *
+ * @param this an instance of NativeMPI.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFinalize(JNIEnv *env, jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ if (_this != NULL)
+ {
+ mpz_clear (_this);
+ free (_this);
+ _this = NULL;
+ }
+ else
+ {
+ TRACE("WARNING: Already cleared + freed");
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+
+/*
+ * @param this an instance of NativeMPI. On exit, this will have a value of n.
+ * @param n a Java long primitive value.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFromLong(JNIEnv *env, jobject this,
+ jlong n)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ /* the size of jlong (64-bit) is either the same as a long, or that of a long long.
+ * if it's the former, we use as is. */
+ if (sizeof (jlong) == sizeof (long))
+ {
+ mpz_set_si (_this, (signed long)n);
+ }
+ else
+ {
+ /* ...otherwise, we operate on the two halves of the long long, each half
+ * being 32-bit wide. for simplicity, we work with positive
+ * values negating, if necessary, the final outcome.
+ */
+ const int isnegative = n < 0 ? 1 : 0;
+ if (isnegative)
+ {
+ n = -n;
+ }
+ mpz_set_ui (_this, (unsigned long)(((unsigned long long)n) >> 32));
+ mpz_mul_2exp (_this, _this, 32); /* shift left by 32 bits */
+ mpz_add_ui (_this, _this, (unsigned long)n);
+ if (isnegative)
+ {
+ mpz_neg (_this, _this);
+ }
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) n;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI. On exit, this will have the same
+ * value as x.
+ * @param x an instance of a NativeMPI's Pointer.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFromBI(JNIEnv *env, jobject this,
+ jobject x)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+ mpz_srcptr _x;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ mpz_set (_this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI. On exit, this will have the value
+ * represented by the v Java byte array (in 2's complement with most
+ * significant byte at index position 0). The sign is implied by the
+ * value of the most significant byte.
+ * @param v a Java byte array containing the byte representation, in 2's
+ * complement of the signed value to assign to this.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFromByteArray(JNIEnv *env,
+ jobject this,
+ jbyteArray v)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+ jbyte *_v;
+ unsigned long b;
+ int vlength, isnegative, i;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _v = (*env)->GetByteArrayElements (env, v, NULL);
+ vlength = (*env)->GetArrayLength (env, v);
+ b = (unsigned long)(_v[0] & 0xFF);
+ isnegative = (b > 0x7F) ? 1 : 0;
+ mpz_set_ui (_this, 0);
+ for (i = 0; i < vlength; i++)
+ {
+ mpz_mul_2exp (_this, _this, 8); /* shift left 8 positions. */
+ b = (unsigned long)(_v[i] & 0xFF);
+ b = (isnegative) ? ~b : b;
+ mpz_add_ui (_this, _this, (unsigned long)(b & 0xFF));
+ }
+ (*env)->ReleaseByteArrayElements (env, v, _v, JNI_ABORT);
+ if (isnegative)
+ {
+ mpz_add_ui (_this, _this, 1);
+ mpz_neg (_this, _this);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) v;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI. On exit, this will have the value
+ * represented by the s Java string.
+ * @param s a Java string containing, a possibly signed, value to assign to
+ * this.
+ * @param rdx the base in which the symbols, in s, are represented.
+ * @return 0 if the entire string is a valid number in base rdx. Otherwise it
+ * returns -1.
+ *
+ * Implementation note:
+ * While the GMP library is more tolerant in what it accepts as parameter values
+ * for conversions from strings, the BigInteger code, which calls this method,
+ * ensures that the contract described in the RI's documentation is respected;
+ * e.g. no white spaces in the middle, limited valid radix values, etc...
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natFromString(JNIEnv *env,
+ jobject this, jstring s,
+ jint rdx)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+ const char *_s;
+ int result;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _s = (*env)->GetStringUTFChars (env, s, NULL);
+ result = mpz_set_str (_this, _s, (int)rdx);
+ JCL_free_cstring (env, s, _s);
+ TRACE("end");
+ return (result);
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) s;
+ (void) rdx;
+ throw_config_exception(env);
+ return (-1);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI. On exit, this will have the value
+ * represented by the m Java byte array (most significant byte at
+ * index position 0). It will be positive, or negative, depending on
+ * the value of isnegative.
+ * @param m a Java byte array containing the byte representation of the
+ * absolute value (most significant byte being at index position 0)
+ * to assign to this.
+ * @param isnegative true if this should be negative and false if it should
+ * be positive.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFromSignedMagnitude(JNIEnv *env,
+ jobject this,
+ jbyteArray m,
+ jboolean isnegative)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this;
+ jbyte *_m;
+ int mlength, i;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _m = (*env)->GetByteArrayElements (env, m, NULL);
+ mlength = (*env)->GetArrayLength (env, m);
+ mpz_set_ui (_this, 0);
+ for (i = 0; i < mlength; i++)
+ {
+ mpz_mul_2exp (_this, _this, 8);
+ mpz_add_ui (_this, _this, (unsigned long)(_m[i] & 0xFF));
+ }
+ (*env)->ReleaseByteArrayElements (env, m, _m, JNI_ABORT);
+ if (isnegative == JNI_TRUE)
+ {
+ mpz_neg (_this, _this);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) m;
+ (void) isnegative;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the base in which to represent this.
+ * @return the Java string representing the value of this in base n.
+ */
+JNIEXPORT jstring JNICALL
+Java_java_math_VMBigInteger_natToString(JNIEnv *env, jobject this,
+ jint n)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ char *cstr;
+ jstring result;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ cstr = mpz_get_str (NULL, (int)n, _this);
+ result = (*env)->NewStringUTF (env, cstr);
+ free (cstr);
+ TRACE("end");
+ return (result);
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ throw_config_exception(env);
+ return (NULL);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this a non-ZERO instance of NativeMPI.
+ *
+ * output:
+ * @param r a Java byte array which shall contain the byte representation of
+ * this.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natToByteArray(JNIEnv *env,
+ jobject this,
+ jbyteArray r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_t _w; /* a temporary work mpi */
+ jbyte *_r;
+ int rlength, sign, i;
+ unsigned long b;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (*env)->GetByteArrayElements (env, r, NULL);
+ rlength = (*env)->GetArrayLength (env, r);
+ mpz_init (_w);
+ /* if this is negative set w to its 2's complement otherwise use as is. */
+ sign = mpz_sgn (_this);
+ if (sign == 1)
+ {
+ mpz_set (_w, _this);
+ }
+ else
+ {
+ mpz_neg (_w, _this);
+ mpz_sub_ui (_w, _w, 1);
+ }
+ /* _w SHOULD be >= 0.
+ * start filling the array starting from the least significant byte. */
+ for (i = rlength; --i >= 0; )
+ {
+ b = mpz_tdiv_q_ui (_w, _w, 256);
+ b = (sign == -1) ? ~b : b;
+ _r[i] = (unsigned long)(b & 0xFF);
+ }
+ (*env)->ReleaseByteArrayElements (env, r, _r, JNI_COMMIT);
+ /* if _w > 0 the byte array was short. */
+ if (mpz_cmp_ui (_w, 0) > 0)
+ {
+ TRACE("WARNING: byte array is too short");
+ }
+ mpz_clear (_w);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @return the "int" value (least significant 32 bits) of the absolute value
+ * of this NativeMPI. The calling code MUST handle the sign. We do
+ * this so we can use the same method when computing the "long" value
+ * as well.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natAbsIntValue(JNIEnv *env,
+ jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jint)mpz_get_ui (_this));
+#else /* !defined(WITH_GNU_MP) */
+ (void) s;
+ throw_config_exception(env);
+ return (-1);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @return the, eventually truncated, double value of this NativeMPI.
+ */
+JNIEXPORT jdouble JNICALL
+Java_java_math_VMBigInteger_natDoubleValue(JNIEnv *env,
+ jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jdouble)mpz_get_d (_this));
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+ return (0.0);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this a NativeMPI instance.
+ * @param x an instance of NativeMPI's Pointer.
+ * @return -1, 0, +1 if x is respectively less than, equal to, or greater
+ * than y.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natCompare(JNIEnv *env, jobject this,
+ jobject x)
+{
+#if defined(WITH_GNU_MP)
+ mpz_ptr _this, _x;
+ int res;
+
+ TRACE("begin");
+ _this = (mpz_ptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_ptr)JCL_GetRawData (env, x);
+ res = mpz_cmp (_this, _x);
+ TRACE("end");
+ if (res == 0)
+ return ((jint)0);
+ else if (res < 0)
+ return ((jint)-1);
+ else
+ return ((jint)1);
+#else /* !defined(WITH_GNU_MP) */
+ (void) x;
+ (void) y;
+ throw_config_exception(env);
+ return (0);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this + x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natAdd(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_add (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this - x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natSubtract(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_sub (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this * x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natMultiply(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_mul (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this div x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natQuotient(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_tdiv_q (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this mod x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natRemainder(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_tdiv_r (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param q a NativeMPI's Pointer such that q = this div x.
+ * @param r a NativeMPI's Pointer such that r = this mod x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natQuotientAndRemainder(JNIEnv *env,
+ jobject this,
+ jobject x,
+ jobject q,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _q, _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _q = (mpz_ptr)JCL_GetRawData (env, q);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_tdiv_qr (_q, _r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) q;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this mod x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natModulo(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_mod (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n a non-negative number to raise this to.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this ** n.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natPow(JNIEnv *env, jobject this,
+ jint n, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_pow_ui (_r, _this, (unsigned long)n);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param e an instance of NativeMPI's Pointer.
+ * @param m another instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = (this**e) mod m.
+ *
+ * @throws java.lang.ArithmeticException if e is negative and (1 / this) mod m
+ * has no multiplicative inverse.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natModPow(JNIEnv *env, jobject this,
+ jobject e, jobject m,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _e, _m;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _e = (mpz_srcptr)JCL_GetRawData (env, e);
+ _m = (mpz_srcptr)JCL_GetRawData (env, m);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ /* the documentation of mpz_powm(rop, b, e, m) states that it: "Set rop to
+ * (b raised to e) modulo m. Negative e is supported if an inverse b^-1 mod m
+ * exists.... If an inverse doesn't exist then a divide by zero is raised."
+ * to work around this case we use the same code as in the pure java class;
+ * i.e.:
+ * if (e.isNegative())
+ * return this.modInverse(m).modPow(e.negate(), m); */
+ if (mpz_sgn (_e) == -1)
+ {
+ mpz_t _w; /* a temporary work mpi */
+ const int res = mpz_invert (_r, _this, _m);
+ if (res == 0)
+ {
+ JCL_ThrowException (env, "java/lang/ArithmeticException",
+ "No multiplicative inverse modulo the designated number exists");
+ }
+ mpz_init (_w);
+ mpz_neg (_w, _e);
+ mpz_powm (_r, _r, _w, _m);
+ mpz_clear (_w);
+ }
+ else
+ {
+ mpz_powm (_r, _this, _e, _m);
+ }
+
+ while (mpz_sgn (_r) == -1)
+ {
+ mpz_add (_r, _r, _m);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) e;
+ (void) m;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param m an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = (1 / this) mod m.
+ * @throws java.lang.ArithmeticException if (1 / this) mod m has no
+ * multiplicative inverse.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natModInverse(JNIEnv *env,
+ jobject this,
+ jobject m, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _m;
+ mpz_ptr _r;
+ int res;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _m = (mpz_srcptr)JCL_GetRawData (env, m);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ res = mpz_invert (_r, _this, _m);
+ if (res == 0)
+ {
+ JCL_ThrowException (env, "java/lang/ArithmeticException",
+ "No multiplicative inverse modulo the designated number exists");
+ }
+
+ while (mpz_sgn (_r) == -1)
+ {
+ mpz_add (_r, _r, _m);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r is the GCD of this and x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natGCD(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_gcd (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n number of Miller-Rabin tests to conduct.
+ * @return 2 if this is definitely prime. Returns 1 if this is probably prime
+ * (without being certain). Finally, returns 0 if this is definitely
+ * composite.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natTestPrimality(JNIEnv *env,
+ jobject this, jint n)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jint)mpz_probab_prime_p (_this, (int)n));
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ throw_config_exception(env);
+ return (0);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the non-negative number of positions to shift right this by.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this * 2**n.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natShiftLeft(JNIEnv *env, jobject this,
+ jint n, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_mul_2exp (_r, _this, (unsigned long)n);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the non-negative number of positions to shift left this by.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = floor(this / 2**n).
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natShiftRight(JNIEnv *env,
+ jobject this, jint n,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_fdiv_q_2exp (_r, _this, (unsigned long)n);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @return the 0-based index of the lowest significant bit set (to 1) in this.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natLowestSetBit(JNIEnv *env,
+ jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jint)mpz_scan1 (_this, 0));
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+ return (-1);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = abs(x).
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natAbs(JNIEnv *env, jobject this,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_abs (_r, _this);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = -x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natNegate(JNIEnv *env, jobject this,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_neg (_r, _this);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @return the number of bits needed to represent this.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natBitLength(JNIEnv *env, jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jint)mpz_sizeinbase (_this, 2));
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+ return (-1);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI. It MUST be >= ZERO.
+ * @return the number of bits set (to 1) in this.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natSetBitCount(JNIEnv *env,
+ jobject this)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _bi;
+ unsigned long res;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ switch (mpz_sgn (_this))
+ {
+ case -1:
+ /* initialize --GMP sets the value to zero. */
+ _bi = (mpz_ptr)JCL_malloc (env, sizeof (mpz_t));
+ mpz_init (_bi);
+ mpz_neg (_bi, _this);
+ res = mpz_popcount (_bi);
+ mpz_clear (_bi);
+ free (_bi);
+ break;
+ case 0:
+ res = 0;
+ break;
+ case 1:
+ res = mpz_popcount (_this);
+ default:
+ JCL_ThrowException (env, "java/lang/Error",
+ "Unexpected sign value for a native MPI");
+ }
+ TRACE("end");
+ return ((jint)res);
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ throw_config_exception(env);
+ return (ULONG_MAX);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this ^ x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natXor(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_xor (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this | x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natOr(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_ior (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this & x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natAnd(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_and (_r, _this, _x);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param x an instance of NativeMPI's Pointer.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = this & ~x.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natAndNot(JNIEnv *env, jobject this,
+ jobject x, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this, _x;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _x = (mpz_srcptr)JCL_GetRawData (env, x);
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_com (_r, _x);
+ mpz_and (_r, _this, _r);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) x;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the 0-based index position of the bit to flip in this. n MUST be
+ * greater than, or equal to 0.
+ *
+ * output:
+ * @param r a copy of this NativeMPI's Pointer with its n-th bit flipped.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natFlipBit(JNIEnv *env, jobject this,
+ jint n, jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_set (_r, _this);
+ /* GNU MP versions earlier than 4.2 do not define this method:
+ * mpz_combit (_r, (unsigned long)n); */
+ if (mpz_tstbit (_r, (unsigned long)n) == 1)
+ {
+ mpz_clrbit (_r, (unsigned long)n);
+ }
+ else
+ {
+ mpz_setbit (_r, (unsigned long)n);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the 0-based index position of the bit to test in this. n MUST be
+ * greater than, or equal to 0.
+ * @return +1, or -1 depending on whether the n-th bit in this is set or not
+ * respectively.
+ */
+JNIEXPORT jint JNICALL
+Java_java_math_VMBigInteger_natTestBit(JNIEnv *env, jobject this,
+ jint n)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ TRACE("end");
+ return ((jint)mpz_tstbit (_this, (unsigned long)n));
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ throw_config_exception(env);
+ return (-1);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ * @param n the 0-based index position of the bit to set, or clear, in this.
+ * n MUST be greater than, or equal to 0.
+ * @param setIt if true, then the n-th bit in this will be set, otherwise it
+ * will be cleared.
+ *
+ * output:
+ * @param r a copy of this NativeMPI's Pointer with its n-th bit set or cleared
+ * as requested.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natSetBit(JNIEnv *env, jobject this,
+ jint n, jboolean setIt,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_set (_r, _this);
+ if (setIt == JNI_TRUE)
+ {
+ mpz_setbit (_r, (unsigned long)n);
+ }
+ else
+ {
+ mpz_clrbit (_r, (unsigned long)n);
+ }
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) n;
+ (void) setIt;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
+
+/*
+ * @param this an instance of NativeMPI.
+ *
+ * output:
+ * @param r a NativeMPI's Pointer such that r = ~this.
+ */
+JNIEXPORT void JNICALL
+Java_java_math_VMBigInteger_natNot(JNIEnv *env, jobject this,
+ jobject r)
+{
+#if defined(WITH_GNU_MP)
+ mpz_srcptr _this;
+ mpz_ptr _r;
+
+ TRACE("begin");
+ _this = (mpz_srcptr)JCL_GetRawData (env, (*env)->GetObjectField (env, this, native_ptr));
+ _r = (mpz_ptr)JCL_GetRawData (env, r);
+ mpz_com (_r, _this);
+ TRACE("end");
+#else /* !defined(WITH_GNU_MP) */
+ (void) this;
+ (void) r;
+ throw_config_exception(env);
+#endif /* defined(WITH_GNU_MP) */
+}
diff --git a/vm/reference/java/math/VMBigInteger.java b/vm/reference/java/math/VMBigInteger.java
new file mode 100644
index 000000000..6b5ab485d
--- /dev/null
+++ b/vm/reference/java/math/VMBigInteger.java
@@ -0,0 +1,474 @@
+/* java.math.VMBigInteger -- Arbitary precision integers using GMP
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.math;
+
+import gnu.classpath.Pointer;
+
+/**
+ * Implement BigInteger using GMP
+ */
+final class VMBigInteger
+{
+ private Pointer native_ptr;
+ private int refCount = 1;
+
+ VMBigInteger()
+ {
+ super();
+
+ natInitialize();
+ }
+
+ private synchronized void acquireRef()
+ {
+ refCount++;
+ }
+
+ private synchronized void releaseRef()
+ {
+ refCount--;
+ if (refCount == 0)
+ {
+ natFinalize();
+ native_ptr = null;
+ }
+ }
+
+ protected void finalize()
+ {
+ releaseRef();
+ }
+
+
+ void fromByteArray(byte[] v)
+ {
+ this.acquireRef();
+ natFromByteArray(v);
+ this.releaseRef();
+ }
+
+ void fromBI(BigInteger x)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ natFromBI(x.mpz.native_ptr);
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void fromLong(long n)
+ {
+ this.acquireRef();
+ natFromLong(n);
+ this.releaseRef();
+ }
+
+ int fromString(String s, int rdx)
+ {
+ this.acquireRef();
+ int result = natFromString(s, rdx);
+ this.releaseRef();
+ return result;
+ }
+
+ void fromSignedMagnitude(byte[] m, boolean isNegative)
+ {
+ this.acquireRef();
+ natFromSignedMagnitude(m, isNegative);
+ this.releaseRef();
+ }
+
+ String toString(int b)
+ {
+ this.acquireRef();
+ String result = natToString(b);
+ this.releaseRef();
+ return result;
+ }
+
+ void toByteArray(byte[] r)
+ {
+ this.acquireRef();
+ natToByteArray(r);
+ this.releaseRef();
+ }
+
+ double doubleValue()
+ {
+ this.acquireRef();
+ double result = natDoubleValue();
+ this.releaseRef();
+ return result;
+ }
+
+ int absIntValue()
+ {
+ this.acquireRef();
+ int result = natAbsIntValue();
+ this.releaseRef();
+ return result;
+ }
+
+ int compare(BigInteger x)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ int result = natCompare(x.mpz.native_ptr);
+ x.mpz.releaseRef();
+ this.releaseRef();
+ return result;
+ }
+
+ void add(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natAdd(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void subtract(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natSubtract(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void multiply(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natMultiply(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void quotient(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natQuotient(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void remainder(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natRemainder(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void quotientAndRemainder(BigInteger x, BigInteger q, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ q.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natQuotientAndRemainder(x.mpz.native_ptr, q.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ q.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void modulo(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natModulo(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void pow(int n, BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natPow(n, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void modPow(BigInteger e, BigInteger m, BigInteger r)
+ {
+ this.acquireRef();
+ e.mpz.acquireRef();
+ m.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natModPow(e.mpz.native_ptr, m.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ m.mpz.releaseRef();
+ e.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void modInverse(BigInteger m, BigInteger r)
+ {
+ this.acquireRef();
+ m.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natModInverse(m.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ m.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void gcd(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natGCD(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void shiftLeft(int n, BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natShiftLeft(n, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void shiftRight(int n, BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natShiftRight(n, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void abs(BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natAbs(r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void negate(BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natNegate(r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ int bitLength()
+ {
+ this.acquireRef();
+ int result = natBitLength();
+ this.releaseRef();
+ return result;
+ }
+
+ int bitCount()
+ {
+ this.acquireRef();
+ int result = natSetBitCount();
+ this.releaseRef();
+ return result;
+ }
+
+ void and(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natAnd(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void or(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natOr(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void xor(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natXor(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void andNot(BigInteger x, BigInteger r)
+ {
+ this.acquireRef();
+ x.mpz.acquireRef();
+ r.mpz.acquireRef();
+ natAndNot(x.mpz.native_ptr, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ x.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void not(BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natNot(r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ void flipBit(int n, BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natFlipBit(n, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ int testBit(int n)
+ {
+ this.acquireRef();
+ int result = natTestBit(n);
+ this.releaseRef();
+ return result;
+ }
+
+ void setBit(int n, boolean setIt, BigInteger r)
+ {
+ this.acquireRef();
+ r.mpz.acquireRef();
+ natSetBit(n, setIt, r.mpz.native_ptr);
+ r.mpz.releaseRef();
+ this.releaseRef();
+ }
+
+ int testPrimality(int certainty)
+ {
+ this.acquireRef();
+ int result = natTestPrimality(certainty);
+ this.releaseRef();
+ return result;
+ }
+
+ int lowestSetBit()
+ {
+ this.acquireRef();
+ int result = natLowestSetBit();
+ this.releaseRef();
+ return result;
+ }
+
+ // Native methods .........................................................
+
+ static native void natInitializeLibrary();
+
+ native void natInitialize();
+ native void natFinalize();
+
+ native void natFromLong(long n);
+ native void natFromBI(Pointer x);
+ native void natFromByteArray(byte[] v);
+ native int natFromString(String s, int rdx);
+ native void natFromSignedMagnitude(byte[] m, boolean isNegative);
+
+ native String natToString(int base);
+ native void natToByteArray(byte[] r);
+ native int natAbsIntValue();
+ native double natDoubleValue();
+
+ native int natCompare(Pointer y);
+ native void natAdd(Pointer x, Pointer r);
+ native void natSubtract(Pointer x, Pointer r);
+ native void natMultiply(Pointer x, Pointer r);
+ native void natQuotient(Pointer x, Pointer r);
+ native void natRemainder(Pointer x, Pointer r);
+ native void natQuotientAndRemainder(Pointer x, Pointer q, Pointer r);
+ native void natModulo(Pointer m, Pointer r);
+ native void natPow(int n, Pointer r);
+ native void natModPow(Pointer e, Pointer m, Pointer r);
+ native void natModInverse(Pointer x, Pointer r);
+ native void natGCD(Pointer x, Pointer r);
+ native int natTestPrimality(int c);
+ native void natShiftLeft(int n, Pointer r);
+ native void natShiftRight(int n, Pointer r);
+ native int natLowestSetBit();
+ native void natAbs(Pointer r);
+ native void natNegate(Pointer r);
+ native int natBitLength();
+ native int natSetBitCount();
+ native void natXor(Pointer x, Pointer r);
+ native void natOr(Pointer x, Pointer r);
+ native void natAnd(Pointer x, Pointer r);
+ native void natAndNot(Pointer x, Pointer r);
+ native void natFlipBit(int n, Pointer r);
+ native int natTestBit(int n);
+ native void natSetBit(int n, boolean setIt, Pointer r);
+ native void natNot(Pointer r);
+}