📄 biginteger.java
字号:
package java.math;import java.util.Random;import java.util.Stack;public class BigInteger{ private int sign; // -1 means -ve; +1 means +ve; 0 means 0; private int[] magnitude; // array of ints with [0] being the most significant private int nBits = -1; // cache bitCount() value private int nBitLength = -1; // cache bitLength() value private static final long IMASK = 0xffffffffL; private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) private BigInteger() { } private BigInteger(int signum, int[] mag) { sign = signum; if (mag.length > 0) { int i = 0; while (i < mag.length && mag[i] == 0) { i++; } if (i == 0) { magnitude = mag; } else { // strip leading 0 bytes int[] newMag = new int[mag.length - i]; System.arraycopy(mag, i, newMag, 0, newMag.length); magnitude = newMag; if (newMag.length == 0) sign = 0; } } else { magnitude = mag; sign = 0; } } public BigInteger(String sval) throws NumberFormatException { this(sval, 10); } public BigInteger(String sval, int rdx) throws NumberFormatException { if (sval.length() == 0) { throw new NumberFormatException("Zero length BigInteger"); } if (rdx < Character.MIN_RADIX || rdx > Character.MAX_RADIX) { throw new NumberFormatException("Radix out of range"); } int index = 0; sign = 1; if (sval.charAt(0) == '-') { if (sval.length() == 1) { throw new NumberFormatException("Zero length BigInteger"); } sign = -1; index = 1; } // strip leading zeros from the string value while (index < sval.length() && Character.digit(sval.charAt(index), rdx) == 0) { index++; } if (index >= sval.length()) { // zero value - we're done sign = 0; magnitude = new int[0]; return; } ////// // could we work out the max number of ints required to store // sval.length digits in the given base, then allocate that // storage in one hit?, then generate the magnitude in one hit too? ////// BigInteger b = BigInteger.ZERO; BigInteger r = valueOf(rdx); while (index < sval.length()) { // (optimise this by taking chunks of digits instead?) b = b.multiply(r).add(valueOf(Character.digit(sval.charAt(index), rdx))); index++; } magnitude = b.magnitude; return; } public BigInteger(byte[] bval) throws NumberFormatException { if (bval.length == 0) { throw new NumberFormatException("Zero length BigInteger"); } sign = 1; if (bval[0] < 0) { sign = -1; } magnitude = makeMagnitude(bval, sign); if (magnitude.length == 0) { sign = 0; } } /** * If sign >= 0, packs bytes into an array of ints, most significant first * If sign < 0, packs 2's complement of bytes into * an array of ints, most significant first, * adding an extra most significant byte in case bval = {0x80, 0x00, ..., 0x00} * * @param bval * @param sign * @return */ private int[] makeMagnitude(byte[] bval, int sign) { if (sign >= 0) { int i; int[] mag; int firstSignificant; // strip leading zeros for (firstSignificant = 0; firstSignificant < bval.length && bval[firstSignificant] == 0; firstSignificant++); if (firstSignificant >= bval.length) { return new int[0]; } int nInts = (bval.length - firstSignificant + 3) / 4; int bCount = (bval.length - firstSignificant) % 4; if (bCount == 0) bCount = 4; // n = k * (n / k) + n % k // bval.length - firstSignificant + 3 = 4 * nInts + bCount - 1 // bval.length - firstSignificant + 4 - bCount = 4 * nInts mag = new int[nInts]; int v = 0; int magnitudeIndex = 0; for (i = firstSignificant; i < bval.length; i++) { // bval.length + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts // 1 <= bCount <= 4 v <<= 8; v |= bval[i] & 0xff; bCount--; if (bCount <= 0) { mag[magnitudeIndex] = v; magnitudeIndex++; bCount = 4; v = 0; } } // 4 - bCount + 4 * magnitudeIndex = 4 * nInts // bCount = 4 * (1 + magnitudeIndex - nInts) // 1 <= bCount <= 4 // So bCount = 4 and magnitudeIndex = nInts = mag.length// if (magnitudeIndex < mag.length)// {// mag[magnitudeIndex] = v;// } return mag; } else { int i; int[] mag; int firstSignificant; // strip leading -1's for (firstSignificant = 0; firstSignificant < bval.length - 1 && bval[firstSignificant] == 0xff; firstSignificant++); int nBytes = bval.length; boolean leadingByte = false; // check for -2^(n-1) if (bval[firstSignificant] == 0x80) { for (i = firstSignificant + 1; i < bval.length; i++) { if (bval[i] != 0) { break; } } if (i == bval.length) { nBytes++; leadingByte = true; } } int nInts = (nBytes - firstSignificant + 3) / 4; int bCount = (nBytes - firstSignificant) % 4; if (bCount == 0) bCount = 4; // n = k * (n / k) + n % k // nBytes - firstSignificant + 3 = 4 * nInts + bCount - 1 // nBytes - firstSignificant + 4 - bCount = 4 * nInts // 1 <= bCount <= 4 mag = new int[nInts]; int v = 0; int magnitudeIndex = 0; // nBytes + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts // 1 <= bCount <= 4 if (leadingByte) { // bval.length + 1 + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts bCount--; // bval.length + 1 + 4 - (bCount + 1) - i + 4 * magnitudeIndex = 4 * nInts // bval.length + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts if (bCount <= 0) { magnitudeIndex++; bCount = 4; } // bval.length + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts // 1 <= bCount <= 4 } for (i = firstSignificant; i < bval.length; i++) { // bval.length + 4 - bCount - i + 4 * magnitudeIndex = 4 * nInts // 1 <= bCount <= 4 v <<= 8; v |= ~bval[i] & 0xff; bCount--; if (bCount <= 0) { mag[magnitudeIndex] = v; magnitudeIndex++; bCount = 4; v = 0; } } // 4 - bCount + 4 * magnitudeIndex = 4 * nInts // 1 <= bCount <= 4 // bCount = 4 * (1 + magnitudeIndex - nInts) // 1 <= bCount <= 4 // So bCount = 4 and magnitudeIndex = nInts = mag.length// if (magnitudeIndex < mag.length)// {// mag[magnitudeIndex] = v;// } return inc(mag); } } public BigInteger(int sign, byte[] mag) throws NumberFormatException { if (sign < -1 || sign > 1) { throw new NumberFormatException("Invalid sign value"); } if (sign == 0) { this.sign = 0; this.magnitude = new int[0]; return; } // copy bytes this.magnitude = makeMagnitude(mag, 1); this.sign = sign; } public BigInteger(int numBits, Random rnd) throws IllegalArgumentException { if (numBits < 0) { throw new IllegalArgumentException("numBits must be non-negative"); } int nBytes = (numBits + 7) / 8; byte[] b = new byte[nBytes]; if (nBytes > 0) { nextRndBytes(rnd, b); // strip off any excess bits in the MSB b[0] &= rndMask[8 * nBytes - numBits]; } this.magnitude = makeMagnitude(b, 1); this.sign = 1; this.nBits = -1; this.nBitLength = -1; } private static final int BITS_PER_BYTE = 8; private static final int BYTES_PER_INT = 4; /** * strictly speaking this is a little dodgey from a compliance * point of view as it forces people to be using SecureRandom as * well, that being said - this implementation is for a crypto * library and you do have the source! */ private void nextRndBytes(Random rnd, byte[] bytes) { int numRequested = bytes.length; int numGot = 0, r = 0; if (rnd instanceof java.security.SecureRandom) { ((java.security.SecureRandom)rnd).nextBytes(bytes); } else { for (; ; ) { for (int i = 0; i < BYTES_PER_INT; i++) { if (numGot == numRequested) { return; } r = (i == 0 ? rnd.nextInt() : r >> BITS_PER_BYTE); bytes[numGot++] = (byte)r; } } } } private static final byte[] rndMask = {(byte)255, 127, 63, 31, 15, 7, 3, 1}; public BigInteger(int bitLength, int certainty, Random rnd) throws ArithmeticException { int nBytes = (bitLength + 7) / 8; byte[] b = new byte[nBytes]; do { if (nBytes > 0) { nextRndBytes(rnd, b); // strip off any excess bits in the MSB int xBits = 8 * nBytes - bitLength; b[0] &= rndMask[xBits]; b[0] |= (byte)(1 << (7 - xBits)); } this.magnitude = makeMagnitude(b, 1); this.sign = 1; this.nBits = -1; this.nBitLength = -1; this.mQuote = -1L; if (certainty > 0 && bitLength > 2) { this.magnitude[this.magnitude.length - 1] |= 1; } } while (this.bitLength() != bitLength || !this.isProbablePrime(certainty)); } public BigInteger abs() { return (sign >= 0) ? this : this.negate(); } /** * return a = a + b - b preserved. */ private int[] add(int[] a, int[] b) { int tI = a.length - 1; int vI = b.length - 1; long m = 0; while (vI >= 0) { m += (((long)a[tI]) & IMASK) + (((long)b[vI--]) & IMASK); a[tI--] = (int)m; m >>>= 32; } while (tI >= 0 && m != 0) { m += (((long)a[tI]) & IMASK); a[tI--] = (int)m; m >>>= 32; } return a; } /** * return a = a + 1. */ private int[] inc(int[] a) { int tI = a.length - 1; long m = 0; m = (((long)a[tI]) & IMASK) + 1L; a[tI--] = (int)m; m >>>= 32; while (tI >= 0 && m != 0) { m += (((long)a[tI]) & IMASK); a[tI--] = (int)m; m >>>= 32; } return a; } public BigInteger add(BigInteger val) throws ArithmeticException { if (val.sign == 0 || val.magnitude.length == 0) return this; if (this.sign == 0 || this.magnitude.length == 0) return val; if (val.sign < 0) { if (this.sign > 0) return this.subtract(val.negate()); } else { if (this.sign < 0) return val.subtract(this.negate()); } return addToMagnitude(val.magnitude); } private BigInteger addToMagnitude( int[] magToAdd) { int[] big, small; if (this.magnitude.length < magToAdd.length) { big = magToAdd; small = this.magnitude; } else { big = this.magnitude; small = magToAdd; } // Conservatively avoid over-allocation when no overflow possible int limit = Integer.MAX_VALUE; if (big.length == small.length) limit -= small[0]; boolean possibleOverflow = (big[0] ^ (1 << 31)) >= limit; int extra = possibleOverflow ? 1 : 0; int[] bigCopy = new int[big.length + extra]; System.arraycopy(big, 0, bigCopy, extra, big.length); bigCopy = add(bigCopy, small); return new BigInteger(this.sign, bigCopy); } public int bitCount() { if (nBits == -1) { nBits = 0; for (int i = 0; i < magnitude.length; i++) { nBits += bitCounts[magnitude[i] & 0xff]; nBits += bitCounts[(magnitude[i] >> 8) & 0xff]; nBits += bitCounts[(magnitude[i] >> 16) & 0xff]; nBits += bitCounts[(magnitude[i] >> 24) & 0xff]; } } return nBits; } private final static byte[] bitCounts = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; private int bitLength(int indx, int[] mag) { int bitLength; if (mag.length == 0) { return 0; } else { while (indx != mag.length && mag[indx] == 0) { indx++; } if (indx == mag.length) { return 0; } // bit length for everything after the first int bitLength = 32 * ((mag.length - indx) - 1); // and determine bitlength of first int bitLength += bitLen(mag[indx]); if (sign < 0) { // Check if magnitude is a power of two boolean pow2 = ((bitCounts[mag[indx] & 0xff]) + (bitCounts[(mag[indx] >> 8) & 0xff]) + (bitCounts[(mag[indx] >> 16) & 0xff]) + (bitCounts[(mag[indx] >> 24) & 0xff])) == 1; for (int i = indx + 1; i < mag.length && pow2; i++) { pow2 = (mag[i] == 0); } bitLength -= (pow2 ? 1 : 0); } } return bitLength; } public int bitLength() { if (nBitLength == -1) { if (sign == 0) { nBitLength = 0; } else { nBitLength = bitLength(0, magnitude); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -