package java.math;

import java.util.*;

public class BigInteger extends Number implements Comparable {

	private final long ptr;

	/**
 	 * This method (which should only be called once, from a static block) registers
 	 * the "System" object.  Since "System" is not something which will be changed in
 	 * a single runtime (ie: the object won't be unloaded), the native method keeps a
 	 * reference to it in order to cache System.gc() calls.  This method also caches
 	 * this object class (making it impossible to unload it) and caches the lookup
 	 * for ptr.  Without it, a lot of the speed advantage is lost due to the overhead
 	 * associated with the JNI.
	 */
	private static final native void registerSystem(Class c);
	static {
		final String system = "java.lang.System";
		try {
			registerSystem(Class.forName(system));
		} catch(ClassNotFoundException cnfe) {
			// This should never happen -- explode
			throw new RuntimeException(system + " could not be found.");
		}
	}


    //Constructors

    /**
     * Translates a byte array containing the two's-complement binary
     * representation of a BigInteger into a BigInteger.  The input array is
     * assumed to be in <i>big-endian</i> byte-order: the most significant
     * byte is in the zeroth element.
     *
     * @param  val big-endian two's-complement binary representation of
     *	       BigInteger.
     * @throws NumberFormatException <tt>val</tt> is zero bytes long.
     */
    public BigInteger(byte[] val) {
		if(val == null) throw new NullPointerException("Byte array null in BigInteger constructor");
		if(val.length == 0) throw new NumberFormatException("Byte array may not have 0 length");
		ptr = allocateNativeBytes(val);
    }
    private static final native long allocateNativeBytes(byte[] array);

    /**
     * Translates the sign-magnitude representation of a BigInteger into a
     * BigInteger.  The sign is represented as an integer signum value: -1 for
     * negative, 0 for zero, or 1 for positive.  The magnitude is a byte array
     * in <i>big-endian</i> byte-order: the most significant byte is in the
     * zeroth element.  A zero-length magnitude array is permissible, and will
     * result in in a BigInteger value of 0, whether signum is -1, 0 or 1.
     *
     * @param  signum signum of the number (-1 for negative, 0 for zero, 1
     * 	       for positive).
     * @param  magnitude big-endian binary representation of the magnitude of
     * 	       the number.
     * @throws NumberFormatException <tt>signum</tt> is not one of the three
     *	       legal values (-1, 0, and 1), or <tt>signum</tt> is 0 and
     *	       <tt>magnitude</tt> contains one or more non-zero bytes.
     */
    public BigInteger(int signum, byte[] magnitude) {
		if(magnitude == null) throw new NullPointerException("Byte array null in BigInteger constructor");
		switch(signum) {
			case 0:
				for(int i = 0; i < magnitude.length; i++) {
					if(magnitude[i] != 0) {
						throw new NumberFormatException("Non-0 bytes in 0-sign magnitude");
					}
				}
			case 1:
			case -1:
				break;
			default:
				throw new NumberFormatException("Sign number must be -1, 0, or 1");
		}
		ptr = allocateNativeSignum(signum,magnitude);
    }
    private static final native long allocateNativeSignum(int signum, byte[] array);

    /**
     * Translates the String representation of a BigInteger in the specified
     * radix into a BigInteger.  The String representation consists of an
     * optional minus sign followed by a sequence of one or more digits in the
     * specified radix.  The character-to-digit mapping is provided by
     * <tt>Character.digit</tt>.  The String may not contain any extraneous
     * characters (whitespace, for example).
     *
     * @param val String representation of BigInteger.
     * @param radix radix to be used in interpreting <tt>val</tt>.
     * @throws NumberFormatException <tt>val</tt> is not a valid representation
     *	       of a BigInteger in the specified radix, or <tt>radix</tt> is
     *	       outside the range from <tt>Character.MIN_RADIX</tt> (2) to
     *	       <tt>Character.MAX_RADIX</tt> (36), inclusive.
     * @see    Character#digit
     */
    public BigInteger(String val, int radix) {
		if(radix < 2 || radix > 36) {
			throw new NumberFormatException("Constructor radix is beyond the valid range.");
		}
		if(val == null) {
			throw new NullPointerException("Null String passed to BigInteger constructor.");
		}
		int test;
		final int len = val.length();
		for(int i = 0; i < len; i++) {
			test = Character.digit(val.charAt(i),radix);
			if(test == -1) {
				throw new NumberFormatException("Invalid character ('"
												+ val.charAt(i)
												+ "') at index "
												+ i
												+ " in BigInteger constructor.");
			}
		}
		ptr = allocateNativeString(val,radix);
    }
    private static final native long allocateNativeString(String val, int radix);

    /**
     * Translates the decimal String representation of a BigInteger into a
     * BigInteger.  The String representation consists of an optional minus
     * sign followed by a sequence of one or more decimal digits.  The
     * character-to-digit mapping is provided by <tt>Character.digit</tt>.
     * The String may not contain any extraneous characters (whitespace, for
     * example).
     *
     * @param val decimal String representation of BigInteger.
     * @throws NumberFormatException <tt>val</tt> is not a valid representation
     *	       of a BigInteger.
     * @see    Character#digit
     */
    public BigInteger(String val) {	this(val, 10);	}

    /**
     * Constructs a randomly generated BigInteger, uniformly distributed over
     * the range <tt>0</tt> to <tt>(2<sup>numBits</sup> - 1)</tt>, inclusive.
     * The uniformity of the distribution assumes that a fair source of random
     * bits is provided in <tt>rnd</tt>.  Note that this constructor always
     * constructs a non-negative BigInteger.
     *
     * @param  numBits maximum bitLength of the new BigInteger.
     * @param  rnd source of randomness to be used in computing the new
     *	       BigInteger.
     * @throws IllegalArgumentException <tt>numBits</tt> is negative.
     * @see #bitLength
     */
    public BigInteger(int numBits, Random rnd) {
		if(rnd == null) {
			throw new NullPointerException("Null Random passed to BigInteger constructor.");
		}
		if(numBits < 0) throw new IllegalArgumentException("Cannot have negative bitlength");
		byte[] array = new byte[(int)Math.ceil(numBits/8)];
		ptr = allocateNativeBlock(numBits,array);
	}
	private static final native long allocateNativeBlock(int numBits, byte[] array);

    /**
     * Constructs a randomly generated positive BigInteger that is probably
     * prime, with the specified bitLength.<p>
     *
     * It is recommended that the probablePrime method be used in preference
     * to this constructor unless there is a compelling need to specify a
     * certainty.
     *
     * @param  bitLength bitLength of the returned BigInteger.
     * @param  certainty a measure of the uncertainty that the caller is
     *         willing to tolerate.  The probability that the new BigInteger
     *	       represents a prime number will exceed
     *	       <tt>(1 - 1/2<sup>certainty</sup></tt>).  The execution time of
     *	       this constructor is proportional to the value of this parameter.
     * @param  rnd source of random bits used to select candidates to be
     *	       tested for primality.
     * @throws ArithmeticException <tt>bitLength &lt; 2</tt>.
     * @see    #bitLength
     */
    public BigInteger(int bitLength, int certainty, Random rnd) {
		if(rnd == null) {
			throw new NullPointerException("Null Random passed to BigInteger constructor.");
		}
		if(bitLength < 2) throw new ArithmeticException("Bit length must be greater than 2.");
		ptr = allocateNativeRandom(bitLength,certainty,rnd);
	}
	private static final native long allocateNativeRandom(int bitLength, int certainty, Random rnd);

	/**
	 * Simple assignment constructor intended for private use.
	 */
	private BigInteger(long lng) { ptr = lng; }


    // Constants built off of valueOfNative (defined below by valueOf)
    /**
     * The BigInteger constant zero.
     *
     * @since   1.2
     */
    public static final BigInteger ZERO = new BigInteger(valueOfNative((long)0));

    /**
     * The BigInteger constant one.
     *
     * @since   1.2
     */
    public static final BigInteger ONE = new BigInteger(valueOfNative((long)1));


    //Static Factory Methods
    /**
     * Returns a BigInteger whose value is equal to that of the specified
     * long.  This "static factory method" is provided in preference to a
     * (long) constructor because it allows for reuse of frequently used
     * BigIntegers.
     *
     * @param  val value of the BigInteger to return.
     * @return a BigInteger with the specified value.
     */
    private static final Map /* Long => BigInteger */ cacheMap = new WeakHashMap();
    static {
		cacheMap.put(new Long(0),ZERO);
		cacheMap.put(new Long(1),ONE);
	}
    public static BigInteger valueOf(long val) {
		final Long valObj = new Long(val);
		BigInteger cached = null;
		try {
			cached = (BigInteger)cacheMap.get(new Long(val));
		} catch(Exception e) {
			// Do nothing; cache didn't work, no big deal.
		}
		if(cached == null) {
			cached = new BigInteger(valueOfNative(val));
			cacheMap.put(valObj,cached);
		}
		return cached;
    }
    private static final native long valueOfNative(long val);

    // Arithmetic Operations

    /**
     * Returns a BigInteger whose value is <tt>(this + val)</tt>.
     *
     * @param  val value to be added to this BigInteger.
     * @return <tt>this + val</tt>
     */
    public BigInteger add(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(addNative(this.ptr, val.ptr));
	}
	private static final native long addNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this - val)</tt>.
     *
     * @param  val value to be subtracted from this BigInteger.
     * @return <tt>this - val</tt>
     */
    public BigInteger subtract(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(subtractNative(this.ptr, val.ptr));
	}
	private static final native long subtractNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this * val)</tt>.
     *
     * @param  val value to be multiplied by this BigInteger.
     * @return <tt>this * val</tt>
     */
    public BigInteger multiply(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(multiplyNative(this.ptr, val.ptr));
	}
	private static final native long multiplyNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this / val)</tt>.
     *
     * @param  val value by which this BigInteger is to be divided.
     * @return <tt>this / val</tt>
     * @throws ArithmeticException <tt>val==0</tt>
     */
    public BigInteger divide(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		if(val.equals(ZERO)) throw new ArithmeticException("BigInteger divide by zero");
		return new BigInteger(divideNative(this.ptr, val.ptr));
	}
	private static final native long divideNative(long melong, long themlong);

    /**
     * Returns an array of two BigIntegers containing <tt>(this / val)</tt>
     * followed by <tt>(this % val)</tt>.
     *
     * @param  val value by which this BigInteger is to be divided, and the
     *	       remainder computed.
     * @return an array of two BigIntegers: the quotient <tt>(this / val)</tt>
     *	       is the initial element, and the remainder <tt>(this % val)</tt>
     *	       is the final element.
     * @throws ArithmeticException <tt>val==0</tt>
     */
    public BigInteger[] divideAndRemainder(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		if(val.equals(ZERO)) throw new ArithmeticException("BigInteger divide by zero");
		long[] out = new long[2];
		divideAndRemainderNative(out,this.ptr, val.ptr);
		BigInteger[] realOut = new BigInteger[2];
		realOut[0] = new BigInteger(out[0]);
		realOut[1] = new BigInteger(out[1]);
		return realOut;
    }
    private static final native void divideAndRemainderNative(long[] out,
    														  long melong,
    														  long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this % val)</tt>.
     *
     * @param  val value by which this BigInteger is to be divided, and the
     *	       remainder computed.
     * @return <tt>this % val</tt>
     * @throws ArithmeticException <tt>val==0</tt>
     */
    public BigInteger remainder(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		if(val.equals(ZERO)) throw new ArithmeticException("BigInteger divide by zero");
		return new BigInteger(remainderNative(this.ptr, val.ptr));
    }
    private static final native long remainderNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
     * Note that <tt>exponent</tt> is an integer rather than a BigInteger.
     *
     * @param  exponent exponent to which this BigInteger is to be raised.
     * @return <tt>this<sup>exponent</sup></tt>
     * @throws ArithmeticException <tt>exponent</tt> is negative.  (This would
     *	       cause the operation to yield a non-integer value.)
     */
    public BigInteger pow(int exponent) {
		if(exponent < 0) throw new ArithmeticException("Negative exponents are invalid");
		return new BigInteger(powNative(this.ptr,exponent));
    }
    private static final native long powNative(long melong, int exp);

    /**
     * Returns a BigInteger whose value is the greatest common divisor of
     * <tt>abs(this)</tt> and <tt>abs(val)</tt>.  Returns 0 if
     * <tt>this==0 &amp;&amp; val==0</tt>.
     *
     * @param  val value with with the GCD is to be computed.
     * @return <tt>GCD(abs(this), abs(val))</tt>
     */
    public BigInteger gcd(BigInteger val) {
		if(val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(gcdNative(this.ptr,val.ptr));
    }
    private static final native long gcdNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is the absolute value of this
     * BigInteger.
     *
     * @return <tt>abs(this)</tt>
     */
    public BigInteger abs() {
		if(this.signum() < 0) return this.negate();
		return this;
    }

    /**
     * Returns a BigInteger whose value is <tt>(-this)</tt>.
     *
     * @return <tt>-this</tt>
     */
    public BigInteger negate() {
		return new BigInteger(negateNative(this.ptr));
    }
    private static final native long negateNative(long melong);

    /**
     * Returns the signum function of this BigInteger.
     *
     * @return -1, 0 or 1 as the value of this BigInteger is negative, zero or
     *	       positive.
     */
    public native int signum();

    // Modular Arithmetic Operations

    /**
     * Returns a BigInteger whose value is <tt>(this mod m</tt>).  This method
     * differs from <tt>remainder</tt> in that it always returns a
     * <i>non-negative</i> BigInteger.
     *
     * @param  m the modulus.
     * @return <tt>this mod m</tt>
     * @throws ArithmeticException <tt>m &lt;= 0</tt>
     * @see    #remainder
     */
    public BigInteger mod(BigInteger m) {
		if (m == null) throw new NullPointerException("Null parameter");
		if (m.signum() <= 0) throw new ArithmeticException("Invalid modulus");
		return new BigInteger(modNative(this.ptr,m.ptr));
    }
    private static final native long modNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is
     * <tt>(this<sup>exponent</sup> mod m)</tt>.  (Unlike <tt>pow</tt>, this
     * method permits negative exponents.)
     *
     * @param  exponent the exponent.
     * @param  m the modulus.
     * @return <tt>this<sup>exponent</sup> mod m</tt>
     * @throws ArithmeticException <tt>m &lt;= 0</tt>
     * @see    #modInverse
     */
    public BigInteger modPow(BigInteger exponent, BigInteger m) {
		if (exponent == null) throw new NullPointerException("Null first parameter");
		if (m == null) throw new NullPointerException("Null second parameter");
		if (m.signum() <= 0) throw new ArithmeticException("Invalid modulus");
		return new BigInteger(modPowNative(this.ptr,exponent.ptr,m.ptr));
    }
    private static final native long modPowNative(long melong, long explong, long modlong);

    /**
     * Returns a BigInteger whose value is <tt>(this<sup>-1</sup> mod m)</tt>.
     *
     * @param  m the modulus.
     * @return <tt>this<sup>-1</sup> mod m</tt>.
     * @throws ArithmeticException <tt> m &lt;= 0</tt>, or this BigInteger
     *	       has no multiplicative inverse mod m (that is, this BigInteger
     *	       is not <i>relatively prime</i> to m).
     */
    public BigInteger modInverse(BigInteger m) {
		if (m == null) throw new NullPointerException("Null parameter");
		if (m.signum() <= 0) throw new ArithmeticException("Invalid modulus");
		long out = modInverseNative(this.ptr,m.ptr);
		if(out == 0) throw new ArithmeticException("BigInteger has no multiplicative inverse");
		return new BigInteger(out);
    }
    private static final native long modInverseNative(long melong, long modlong);


    // Shift Operations

    /**
     * Returns a BigInteger whose value is <tt>(this &lt;&lt; n)</tt>.
     * The shift distance, <tt>n</tt>, may be negative, in which case
     * this method performs a right shift.
     * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.)
     *
     * @param  n shift distance, in bits.
     * @return <tt>this &lt;&lt; n</tt>
     * @see #shiftRight
     */
    public BigInteger shiftLeft(int n) {
		if(n == 0) return this;
		if(n < 0) return new BigInteger(shiftRightNative(this.ptr,-n));
		return new BigInteger(shiftLeftNative(this.ptr,n));
	}
	private static final native long shiftLeftNative(long melong, int dist);

    /**
     * Returns a BigInteger whose value is <tt>(this &gt;&gt; n)</tt>.  Sign
     * extension is performed.  The shift distance, <tt>n</tt>, may be
     * negative, in which case this method performs a left shift.
     * (Computes <tt>floor(this / 2<sup>n</sup>)</tt>.)
     *
     * @param  n shift distance, in bits.
     * @return <tt>this &gt;&gt; n</tt>
     * @see #shiftLeft
     */
    public BigInteger shiftRight(int n) {
        if (n == 0) return this;
		if(n < 0) return new BigInteger(shiftLeftNative(this.ptr,-n));
		return new BigInteger(shiftRightNative(this.ptr,n));
	}
	private static final native long shiftRightNative(long melong, int dist);


    // Bitwise Operations

    /**
     * Returns a BigInteger whose value is <tt>(this &amp; val)</tt>.  (This
     * method returns a negative BigInteger if and only if this and val are
     * both negative.)
     *
     * @param val value to be AND'ed with this BigInteger.
     * @return <tt>this &amp; val</tt>
     */
    public BigInteger and(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(andNative(this.ptr,val.ptr));
    }
	private static final native long andNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this | val)</tt>.  (This method
     * returns a negative BigInteger if and only if either this or val is
     * negative.)
     *
     * @param val value to be OR'ed with this BigInteger.
     * @return <tt>this | val</tt>
     */
    public BigInteger or(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(orNative(this.ptr,val.ptr));
    }
	private static final native long orNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(this ^ val)</tt>.  (This method
     * returns a negative BigInteger if and only if exactly one of this and
     * val are negative.)
     *
     * @param val value to be XOR'ed with this BigInteger.
     * @return <tt>this ^ val</tt>
     */
    public BigInteger xor(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(xorNative(this.ptr,val.ptr));
    }
	private static final native long xorNative(long melong, long themlong);

    /**
     * Returns a BigInteger whose value is <tt>(~this)</tt>.  (This method
     * returns a negative value if and only if this BigInteger is
     * non-negative.)
     *
     * @return <tt>~this</tt>
     */
    public BigInteger not() {
		return new BigInteger(notNative(this.ptr));
    }
	private static final native long notNative(long melong);

    /**
     * Returns a BigInteger whose value is <tt>(this &amp; ~val)</tt>.  This
     * method, which is equivalent to <tt>and(val.not())</tt>, is provided as
     * a convenience for masking operations.  (This method returns a negative
     * BigInteger if and only if <tt>this</tt> is negative and <tt>val</tt> is
     * positive.)
     *
     * @param val value to be complemented and AND'ed with this BigInteger.
     * @return <tt>this &amp; ~val</tt>
     */
    public BigInteger andNot(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		return new BigInteger(andNotNative(this.ptr,val.ptr));
    }
	private static final native long andNotNative(long melong, long themlong);


    // Single Bit Operations

    /**
     * Returns <tt>true</tt> if and only if the designated bit is set.
     * (Computes <tt>((this &amp; (1&lt;&lt;n)) != 0)</tt>.)
     *
     * @param  n index of bit to test.
     * @return <tt>true</tt> if and only if the designated bit is set.
     * @throws ArithmeticException <tt>n</tt> is negative.
     */
    public native boolean testBit(int n);

    /**
     * Returns a BigInteger whose value is equivalent to this BigInteger
     * with the designated bit set.  (Computes <tt>(this | (1&lt;&lt;n))</tt>.)
     *
     * @param  n index of bit to set.
     * @return <tt>this | (1&lt;&lt;n)</tt>
     * @throws ArithmeticException <tt>n</tt> is negative.
     */
    public BigInteger setBit(int n) {
		if(n < 0) throw new ArithmeticException("Negative bit index");
		return new BigInteger(setBitNative(this.ptr,n));
    }
	private static final native long setBitNative(long melong, int n);

    /**
     * Returns a BigInteger whose value is equivalent to this BigInteger
     * with the designated bit cleared.
     * (Computes <tt>(this &amp; ~(1&lt;&lt;n))</tt>.)
     *
     * @param  n index of bit to clear.
     * @return <tt>this & ~(1&lt;&lt;n)</tt>
     * @throws ArithmeticException <tt>n</tt> is negative.
     */
    public BigInteger clearBit(int n) {
		if(n < 0) throw new ArithmeticException("Negative bit index");
		return new BigInteger(clearBitNative(this.ptr,n));
    }
	private static final native long clearBitNative(long melong, int n);

    /**
     * Returns a BigInteger whose value is equivalent to this BigInteger
     * with the designated bit flipped.
     * (Computes <tt>(this ^ (1&lt;&lt;n))</tt>.)
     *
     * @param  n index of bit to flip.
     * @return <tt>this ^ (1&lt;&lt;n)</tt>
     * @throws ArithmeticException <tt>n</tt> is negative.
     */
    public BigInteger flipBit(int n) {
		if(n < 0) throw new ArithmeticException("Negative bit index");
		return new BigInteger(flipBitNative(this.ptr,n));
    }
	private static final native long flipBitNative(long melong, int n);

    /**
     * Returns the index of the rightmost (lowest-order) one bit in this
     * BigInteger (the number of zero bits to the right of the rightmost
     * one bit).  Returns -1 if this BigInteger contains no one bits.
     * (Computes <tt>(this==0? -1 : log<sub>2</sub>(this &amp; -this))</tt>.)
     *
     * @return index of the rightmost one bit in this BigInteger.
     */
    public native int getLowestSetBit();

    // Miscellaneous Bit Operations

    /**
     * Returns the number of bits in the minimal two's-complement
     * representation of this BigInteger, <i>excluding</i> a sign bit.
     * For positive BigIntegers, this is equivalent to the number of bits in
     * the ordinary binary representation.  (Computes
     * <tt>(ceil(log<sub>2</sub>(this &lt; 0 ? -this : this+1)))</tt>.)
     *
     * @return number of bits in the minimal two's-complement
     *         representation of this BigInteger, <i>excluding</i> a sign bit.
     */
    public native int bitLength();

    /**
     * Returns the number of bits in the two's complement representation
     * of this BigInteger that differ from its sign bit.  This method is
     * useful when implementing bit-vector style sets atop BigIntegers.
     *
     * @return number of bits in the two's complement representation
     *         of this BigInteger that differ from its sign bit.
     */
    public native int bitCount();

    // Primality Testing

    /**
     * Returns <tt>true</tt> if this BigInteger is probably prime,
     * <tt>false</tt> if it's definitely composite.
     *
     * @param  certainty a measure of the uncertainty that the caller is
     *	       willing to tolerate: if the call returns <tt>true</tt>
     *	       the probability that this BigInteger is prime exceeds
     *	       <tt>(1 - 1/2<sup>certainty</sup>)</tt>.  The execution time of
     * 	       this method is proportional to the value of this parameter.
     * @return <tt>true</tt> if this BigInteger is probably prime,
     * 	       <tt>false</tt> if it's definitely composite.
     */
    public native boolean isProbablePrime(int certainty);

    // Comparison Operations

    /**
     * Compares this BigInteger with the specified BigInteger.  This method is
     * provided in preference to individual methods for each of the six
     * boolean comparison operators (&lt;, ==, &gt;, &gt;=, !=, &lt;=).  The
     * suggested idiom for performing these comparisons is:
     * <tt>(x.compareTo(y)</tt> &lt;<i>op</i>&gt; <tt>0)</tt>,
     * where &lt;<i>op</i>&gt; is one of the six comparison operators.
     *
     * @param  val BigInteger to which this BigInteger is to be compared.
     * @return -1, 0 or 1 as this BigInteger is numerically less than, equal
     *         to, or greater than <tt>val</tt>.
     */
    public native int compareTo(BigInteger val);

    /**
     * Compares this BigInteger with the specified Object.  If the Object is a
     * BigInteger, this method behaves like <tt>compareTo(BigInteger)</tt>.
     * Otherwise, it throws a <tt>ClassCastException</tt> (as BigIntegers are
     * comparable only to other BigIntegers).
     *
     * @param   o Object to which this BigInteger is to be compared.
     * @return  a negative number, zero, or a positive number as this
     *		BigInteger is numerically less than, equal to, or greater
     *		than <tt>o</tt>, which must be a BigInteger.
     * @throws  ClassCastException <tt>o</tt> is not a BigInteger.
     * @see     #compareTo(java.math.BigInteger)
     * @see     Comparable
     * @since   1.2
     */
    public int compareTo(Object o) {
		return compareTo((BigInteger)o);
    }

    /**
     * Compares this BigInteger with the specified Object for equality.
     *
     * @param  x Object to which this BigInteger is to be compared.
     * @return <tt>true</tt> if and only if the specified Object is a
     *	       BigInteger whose value is numerically equal to this BigInteger.
     */
    public boolean equals(Object x) {
		try {
			return (this.compareTo(x) == 0);
		} catch(Exception e) {
			return false;
		}
    }

    /**
     * Returns the minimum of this BigInteger and <tt>val</tt>.
     *
     * @param  val value with with the minimum is to be computed.
     * @return the BigInteger whose value is the lesser of this BigInteger and
     *	       <tt>val</tt>.  If they are equal, either may be returned.
     */
    public BigInteger min(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		if(this.compareTo(val) == 1) return val;
		return this;
    }

    /**
     * Returns the maximum of this BigInteger and <tt>val</tt>.
     *
     * @param  val value with with the maximum is to be computed.
     * @return the BigInteger whose value is the greater of this and
     *         <tt>val</tt>.  If they are equal, either may be returned.
     */
    public BigInteger max(BigInteger val) {
		if (val == null) throw new NullPointerException("Null parameter");
		if(this.compareTo(val) == -1) return val;
		return this;
    }


    // Hash Function

    /**
     * Returns the hash code for this BigInteger.
     *
     * @return hash code for this BigInteger.
     */
    private int hash = Integer.MAX_VALUE;
    public int hashCode() {
		if(hash == Integer.MAX_VALUE) hash = hashCodeNative(this.ptr);
		return hash;
	}
	private static final native int hashCodeNative(long melong);

    /**
     * Returns the String representation of this BigInteger in the given radix.
     * If the radix is outside the range from <tt>Character.MIN_RADIX</tt> (2)
     * to <tt>Character.MAX_RADIX</tt> (36) inclusive, it will default to 10
     * (as is the case for <tt>Integer.toString</tt>).  The digit-to-character
     * mapping provided by <tt>Character.forDigit</tt> is used, and a minus
     * sign is prepended if appropriate.  (This representation is compatible
     * with the (String, int) constructor.)
     *
     * @param  radix  radix of the String representation.
     * @return String representation of this BigInteger in the given radix.
     * @see    Integer#toString
     * @see    Character#forDigit
     * @see    #BigInteger(java.lang.String, int)
     */
    public native String toString(int radix);

    /**
     * Returns the decimal String representation of this BigInteger.  The
     * digit-to-character mapping provided by <tt>Character.forDigit</tt> is
     * used, and a minus sign is prepended if appropriate.  (This
     * representation is compatible with the (String) constructor, and allows
     * for String concatenation with Java's + operator.)
     *
     * @return decimal String representation of this BigInteger.
     * @see    Character#forDigit
     * @see    #BigInteger(java.lang.String)
     */
    public native String toString();

    /**
     * Returns a byte array containing the two's-complement representation of
     * this BigInteger.  The byte array will be in <i>big-endian</i>
     * byte-order: the most significant byte is in the zeroth element.  The
     * array will contain the minimum number of bytes required to represent
     * this BigInteger, including at least one sign bit,  which is
     * <tt>(ceil((this.bitLength() + 1)/8))</tt>.  (This representation is
     * compatible with the (byte[]) constructor.)
     *
     * @return a byte array containing the two's-complement representation of
     *	       this BigInteger.
     * @see    #BigInteger(byte[])
     */
    public native byte[] toByteArray();

    /**
     * Converts this BigInteger to an int.  Standard <i>narrowing primitive
     * conversion</i> as defined in <i>The Java Language Specification</i>:
     * if this BigInteger is too big to fit in an int, only the low-order
     * 32 bits are returned.
     *
     * @return this BigInteger converted to an int.
     */
    public int intValue() {
		return new Long(this.longValue()).intValue();
    }

    /**
     * Converts this BigInteger to a long.  Standard <i>narrowing primitive
     * conversion</i> as defined in <i>The Java Language Specification</i>:
     * if this BigInteger is too big to fit in a long, only the low-order
     * 64 bits are returned.
     *
     * @return this BigInteger converted to a long.
     */
    public native long longValue();

    /**
     * Converts this BigInteger to a float.  Similar to the double-to-float
     * <i>narrowing primitive conversion</i> defined in <i>The Java Language
     * Specification</i>: if this BigInteger has too great a magnitude to
     * represent as a float, it will be converted to infinity or negative
     * infinity, as appropriate.
     *
     * @return this BigInteger converted to a float.
     */
    public float floatValue() {
		return new Float(this.doubleValue()).floatValue();
    }

    /**
     * Converts this BigInteger to a double.  Similar to the double-to-float
     * <i>narrowing primitive conversion</i> defined in <i>The Java Language
     * Specification</i>: if this BigInteger has too great a magnitude to
     * represent as a double, it will be converted to infinity or negative
     * infinity, as appropriate.
     *
     * @return this BigInteger converted to a double.
     */
    public native double doubleValue();

    protected void finalize() throws Throwable {
		finalizeNative(this.ptr);
		super.finalize();
	}
    private static final native void finalizeNative(long melong);
}
