biginteger.java

来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,801 行 · 第 1/3 页

JAVA
1,801
字号
        int     xyCmp = compareTo(0, x, 0, y);        int[]   count;        if (xyCmp > 0)        {            int[]   c;            int     shift = bitLength(0, x) - bitLength(0, y);            if (shift > 1)            {                c = shiftLeft(y, shift - 1);                count = shiftLeft(ONE.magnitude, shift - 1);            }            else            {                c = new int[x.length];                count = new int[1];                System.arraycopy(y, 0, c, c.length - y.length, y.length);                count[0] = 1;            }            int[]   iCount = new int[count.length];            subtract(0, x, 0, c);            System.arraycopy(count, 0, iCount, 0, count.length);            int xStart = 0;            int cStart = 0;            int iCountStart = 0;            for (;;)            {                int cmp = compareTo(xStart, x, cStart, c);                while (cmp >= 0)                {                    subtract(xStart, x, cStart, c);                    add(count, iCount);                    cmp = compareTo(xStart, x, cStart, c);                }                xyCmp = compareTo(xStart, x, 0, y);                if (xyCmp > 0)                {                    if (x[xStart] == 0)                    {                        xStart++;                    }                    shift = bitLength(cStart, c) - bitLength(xStart, x);                    if (shift == 0)                    {                        c = shiftRightOne(cStart, c);                        iCount = shiftRightOne(iCountStart, iCount);                    }                    else                    {                        c = shiftRight(cStart, c, shift);                        iCount = shiftRight(iCountStart, iCount, shift);                    }                    if (c[cStart] == 0)                    {                        cStart++;                    }                    if (iCount[iCountStart] == 0)                    {                        iCountStart++;                    }                }                else if (xyCmp == 0)                {                    add(count, ONE.magnitude);                    for (int i = xStart; i != x.length; i++)                    {                        x[i] = 0;                    }                    break;                }                else                {                    break;                }            }        }        else if (xyCmp == 0)        {            count = new int[1];            count[0] = 1;        }        else        {            count = new int[1];            count[0] = 0;        }           return count;    }	public BigInteger divide(		BigInteger val)		throws ArithmeticException	{		if (val.sign == 0)        {			throw new ArithmeticException("Divide by zero");        }		if (sign == 0)        {            return BigInteger.ZERO;        }		if (val.compareTo(BigInteger.ONE) == 0)        {            return this;        }        int[]   mag = new int[this.magnitude.length];        System.arraycopy(this.magnitude, 0, mag, 0, mag.length);        return new BigInteger(this.sign * val.sign, divide(mag, val.magnitude));	}	public BigInteger[] divideAndRemainder(		BigInteger val)		throws ArithmeticException	{		if (val.sign == 0)        {			throw new ArithmeticException("Divide by zero");        }		BigInteger biggies[] = new BigInteger[2];		if (sign == 0)        {			biggies[0] = biggies[1] = BigInteger.ZERO;			return biggies;        }		if (val.compareTo(BigInteger.ONE) == 0)        {			biggies[0] = this;			biggies[1] = BigInteger.ZERO;			return biggies;        }        int[]   remainder = new int[this.magnitude.length];        System.arraycopy(this.magnitude, 0, remainder, 0, remainder.length);        int[]   quotient = divide(remainder, val.magnitude);        biggies[0] = new BigInteger(this.sign * val.sign, quotient);        biggies[1] = new BigInteger(this.sign, remainder);        return biggies;	}	public boolean equals(		Object val)	{		if (val == this) return true;		if (!(val instanceof BigInteger)) return false;		BigInteger biggie = (BigInteger)val;		if (biggie.sign != sign || biggie.magnitude.length != magnitude.length)			return false;		for (int i = 0; i < magnitude.length; i++) {			if (biggie.magnitude[i] != magnitude[i]) return false;			}		return true;	}	public BigInteger gcd(		BigInteger val)	{		if (val.sign == 0) return this.abs();		else if (sign == 0) return val.abs();		BigInteger r;		BigInteger u = this;		BigInteger v = val;		while (v.sign != 0) {			r = u.mod(v);			u = v;			v = r;		}		return u;	}	public int hashCode()	{		return 0;	}	public int intValue()	{        if (magnitude.length == 0)        {            return 0;        }        if (sign < 0)        {            return -magnitude[magnitude.length - 1];        }        else        {            return magnitude[magnitude.length - 1];        }	}    /**     * return whether or not a BigInteger is probably prime with a      * probability of 1 - (1/2)**certainty.     * <p>     * From Knuth Vol 2, pg 395.     */	public boolean isProbablePrime(		int certainty)	{        if (certainty == 0)        {            return true;        }                BigInteger n = this.abs();        if (n.equals(TWO))        {            return true;        }        if (n.equals(ONE) || !n.testBit(0))        {            return false;        }	if ((certainty & 0x1) == 1)	{		certainty = certainty / 2 + 1;	}	else	{		certainty /= 2;	}        //        // let n = 1 + 2^kq        //        BigInteger  q = n.subtract(ONE);        int         k = q.getLowestSetBit();        q = q.shiftRight(k);        Random  rnd = new Random();        for (int i = 0; i <= certainty; i++)        {            BigInteger x;            do            {                x = new BigInteger(n.bitLength(), rnd);            }            while (x.compareTo(ONE) <= 0 || x.compareTo(n) >= 0);            int         j = 0;            BigInteger  y = x.modPow(q, n);            while (!((j == 0 && y.equals(ONE)) || y.equals(n.subtract(ONE))))            {                if (j > 0 && y.equals(ONE))                {                    return false;                }                if (++j == k)                {                    return false;                }                y = y.modPow(TWO, n);            }        }        		return true;	}	public long longValue()	{        long    val = 0;        if (magnitude.length == 0)        {            return 0;        }        if (magnitude.length > 1)        {            val = magnitude[magnitude.length - 2] << 32                         | (magnitude[magnitude.length - 1] & IMASK);        }        else        {            val = (magnitude[magnitude.length - 1] & IMASK);        }        if (sign < 0)        {            return -val;        }        else        {            return val;        }	}	public BigInteger max(		BigInteger val)	{		return (compareTo(val) > 0) ? this : val;	}	public BigInteger min(		BigInteger val)	{		return (compareTo(val) < 0) ? this : val;	}	public BigInteger mod(		BigInteger m)		throws ArithmeticException	{		if (m.sign <= 0)        {             throw new ArithmeticException("BigInteger: modulus is not positive");        }		BigInteger biggie = this.remainder(m);		return (biggie.sign >= 0 ? biggie : biggie.add(m));	}	public BigInteger modInverse(		BigInteger m)		throws ArithmeticException	{		if (m.sign != 1)        {			throw new ArithmeticException("Modulus must be positive");        }        BigInteger x = new BigInteger();        BigInteger y = new BigInteger();        BigInteger gcd = BigInteger.extEuclid(this, m, x, y);        if (!gcd.equals(BigInteger.ONE))        {                throw new ArithmeticException("Numbers not relatively prime.");        }        if (x.compareTo(BigInteger.ZERO) < 0)        {            x = x.add(m);        }        return x;	}	/**	 * Calculate the numbers u1, u2, and u3 such that:	 *	 * u1 * a + u2 * b = u3	 *	 * where u3 is the greatest common divider of a and b.	 * a and b using the extended Euclid algorithm (refer p. 323	 * of The Art of Computer Programming vol 2, 2nd ed).	 * This also seems to have the side effect of calculating	 * some form of multiplicative inverse.	 *	 * @param a    First number to calculate gcd for	 * @param b    Second number to calculate gcd for	 * @param u1Out      the return object for the u1 value	 * @param u2Out      the return object for the u2 value	 * @return     The greatest common divisor of a and b	 */	private static BigInteger extEuclid(		BigInteger a,		BigInteger b,		BigInteger u1Out,		BigInteger u2Out)	{		BigInteger  res;		BigInteger u1 = BigInteger.ONE;		BigInteger u3 = a;		BigInteger v1 = BigInteger.ZERO;		BigInteger v3 = b;		while (v3.compareTo(BigInteger.ZERO) > 0)        {            BigInteger q, tn, tv;            q = u3.divide(v3);            tn = u1.subtract(v1.multiply(q));            u1 = v1;            v1 = tn;            tn = u3.subtract(v3.multiply(q));            u3 = v3;            v3 = tn;        }		u1Out.sign = u1.sign;		u1Out.magnitude = u1.magnitude;		res = u3.subtract(u1.multiply(a)).divide(b);		u2Out.sign = res.sign;		u2Out.magnitude = res.magnitude;		return u3;	}    /**     * zero out the array x     */    private void zero(        int[]   x)    {        for (int i = 0; i != x.length; i++)        {            x[i] = 0;        }    }	public BigInteger modPow(		BigInteger exponent,		BigInteger m)		throws ArithmeticException	{        int[]       zAccum, zVal;        int[]       yAccum, yVal;        if (magnitude.length <= m.magnitude.length)        {            zAccum = new int[m.magnitude.length * 2];            zVal = new int[m.magnitude.length];            System.arraycopy(magnitude, 0, zVal,                zVal.length - magnitude.length, magnitude.length);        }        else        {            //            // in normal practice we'll never see this...            //            BigInteger  tmp = this.remainder(m);            zAccum = new int[m.magnitude.length * 2];            zVal = new int[m.magnitude.length];            System.arraycopy(tmp.magnitude, 0, zVal,                zVal.length - tmp.magnitude.length, tmp.magnitude.length);        }        yAccum = new int[m.magnitude.length * 2];        yVal = new int[m.magnitude.length];        //		// from LSW to MSW        //		for (int i = 0; i < exponent.magnitude.length; i++)        {			int v = exponent.magnitude[i];			int bits = 0;            if (i == 0)            {                while (v > 0)                {				    v <<= 1;                    bits++;                }                //                // first time in initialise y                //                System.arraycopy(zVal, 0, yVal, 0, zVal.length);                v <<= 1;                bits++;            }			while (v != 0)            {                square(yAccum, yVal);                remainder(yAccum, m.magnitude);                System.arraycopy(yAccum, yAccum.length - yVal.length,                                                  yVal, 0, yVal.length);                zero(yAccum);                bits++;				if (v < 0)                {                    multiply(yAccum, yVal, zVal);                    remainder(yAccum, m.magnitude);                    System.arraycopy(yAccum, yAccum.length - yVal.length,                                                      yVal, 0, yVal.length);                    zero(yAccum);                }				v <<= 1;            }            while (bits < 32)            {                square(yAccum, yVal);                remainder(yAccum, m.magnitude);                System.arraycopy(yAccum, yAccum.length - yVal.length,                                                   yVal, 0, yVal.length);                zero(yAccum);                bits++;            }        }        return new BigInteger(1, yVal);	}    /**     * return w with w = x * x - w is assumed to have enough space.     */	private int[] square(        int[]   w,        int[]   x)	{        long    u1, u2, c;        if (w.length != 2 * x.length)        {            throw new IllegalArgumentException("no I don't think so...");        }        for (int i = x.length - 1; i != 0; i--)        {            long    v = (x[i] & IMASK);            u1 = v * v;            u2 = u1 >>> 32;            u1 = u1 & IMASK;            u1 += (w[2 * i + 1] & IMASK);            w[2 * i + 1] = (int)u1;            c = u2 + (u1 >> 32);            for (int j = i - 1; j >= 0; j--)            {                u1 = (x[j] & IMASK) * v;                u2 = u1 >>> 31;                     // multiply by 2!                u1 = (u1 & 0x7fffffff) << 1;        // multiply by 2!                u1 += (w[i + j + 1] & IMASK) + c;                w[i + j + 1] = (int)u1;                c = u2 + (u1 >>> 32);            }            c += w[i] & IMASK;            w[i] = (int)c;            w[i - 1] = (int)(c >> 32);        }        u1 = (x[0] & IMASK);        u1 = u1 * u1;        u2 = u1 >>> 32;        u1 = u1 & IMASK;        u1 += (w[1] & IMASK);        w[1] = (int)u1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?