From c9e6c4d0171ff6f419344f9341747c71416d4ec9 Mon Sep 17 00:00:00 2001 From: Fabio Romano Date: Wed, 28 May 2025 12:48:47 +0000 Subject: [PATCH] 8356891: Some code simplifications in BigInteger Reviewed-by: rgiulietti --- .../share/classes/java/math/BigInteger.java | 258 +++++++----------- 1 file changed, 105 insertions(+), 153 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index b0a7f784aab..a6ce483f3eb 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -203,12 +203,13 @@ public class BigInteger extends Number implements Comparable { private int bitCountPlusOne; /** - * One plus the bitLength of this BigInteger. This is a stable variable. + * One plus the bitLength of the magnitude of this BigInteger. + * This is a stable variable. * (either value is acceptable). * - * @see #bitLength() + * @see #magBitLength() */ - private int bitLengthPlusOne; + private int magBitLengthPlusOne; /** * Two plus the lowest set bit of this BigInteger. This is a stable variable. @@ -223,11 +224,9 @@ public class BigInteger extends Number implements Comparable { * least significant int has int-number 0, the next int in order of * increasing significance has int-number 1, and so forth. * - *

Note: never used for a BigInteger with a magnitude of zero. - * - * @see #firstNonzeroIntNum() + * @see #numberOfTrailingZeroInts() */ - private int firstNonzeroIntNumPlusTwo; + private int numberOfTrailingZeroIntsPlusTwo; /** * This mask is used to obtain the value of an int as if it were unsigned. @@ -490,7 +489,7 @@ public class BigInteger extends Number implements Comparable { * unchanged for the duration of the constructor call. */ private BigInteger(int signum, int[] magnitude) { - this.mag = stripLeadingZeroInts(magnitude); + this.mag = stripLeadingZeroInts(magnitude, false); if (signum < -1 || signum > 1) throw(new NumberFormatException("Invalid signum value")); @@ -841,7 +840,7 @@ public class BigInteger extends Number implements Comparable { private static BigInteger smallPrime(int bitLength, int certainty, Random rnd) { int magLen = (bitLength + 31) >>> 5; int temp[] = new int[magLen]; - int highBit = 1 << ((bitLength+31) & 0x1f); // High bit of high int + int highBit = 1 << (bitLength - 1); // High bit of high int int highMask = (highBit << 1) - 1; // Bits to keep in high int while (true) { @@ -885,7 +884,7 @@ public class BigInteger extends Number implements Comparable { private static BigInteger largePrime(int bitLength, int certainty, Random rnd) { BigInteger p; p = new BigInteger(bitLength, rnd).setBit(bitLength-1); - p.mag[p.mag.length-1] &= 0xfffffffe; + p.mag[p.mag.length-1] &= ~1; // Use a sieve length likely to contain the next prime number int searchLen = getPrimeSearchLen(bitLength); @@ -896,7 +895,7 @@ public class BigInteger extends Number implements Comparable { p = p.add(BigInteger.valueOf(2*searchLen)); if (p.bitLength() != bitLength) p = new BigInteger(bitLength, rnd).setBit(bitLength-1); - p.mag[p.mag.length-1] &= 0xfffffffe; + p.mag[p.mag.length-1] &= ~1; searchSieve = new BitSieve(p, searchLen); candidate = searchSieve.retrieve(p, certainty, rnd); } @@ -1756,9 +1755,8 @@ public class BigInteger extends Number implements Comparable { // are only considering the magnitudes as non-negative. The // Toom-Cook multiplication algorithm determines the sign // at its end from the two signum values. - if ((long)bitLength(mag, mag.length) + - (long)bitLength(val.mag, val.mag.length) > - 32L*MAX_MAG_LENGTH) { + if ((long) this.magBitLength() + val.magBitLength() > + (long) Integer.SIZE * MAX_MAG_LENGTH) { reportOverflow(); } } @@ -1769,7 +1767,7 @@ public class BigInteger extends Number implements Comparable { } private static BigInteger multiplyByInt(int[] x, int y, int sign) { - if (Integer.bitCount(y) == 1) { + if (Integer.lowestOneBit(y) == y) { return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign); } int xlen = x.length; @@ -2271,7 +2269,7 @@ public class BigInteger extends Number implements Comparable { // For a discussion of overflow detection see multiply() // if (!isRecursion) { - if (bitLength(mag, mag.length) > 16L*MAX_MAG_LENGTH) { + if (magBitLength() > (Integer.SIZE / 2) * MAX_MAG_LENGTH) { reportOverflow(); } } @@ -2640,8 +2638,8 @@ public class BigInteger extends Number implements Comparable { ? new BigInteger(result << bitsToShift, newSign) : new BigInteger(result, newSign).shiftLeft(bitsToShift); } - - if ((bitLength() - 1L) * exponent >= Integer.MAX_VALUE) { + // (magBitLength() - 1L) * exponent + 1L > Integer.MAX_VALUE + if (scaleFactor + bitsToShift - exponent >= Integer.MAX_VALUE) { reportOverflow(); } @@ -2824,13 +2822,16 @@ public class BigInteger extends Number implements Comparable { } /** - * Calculate bitlength of contents of the first len elements an int array, - * assuming there are no leading zero ints. + * Calculate bitlength of the magnitude of this {@code BigInteger}. */ - private static int bitLength(int[] val, int len) { - if (len == 0) - return 0; - return ((len - 1) << 5) + bitLengthForInt(val[0]); + private int magBitLength() { + int n = magBitLengthPlusOne - 1; + if (n == -1) { // not initialized + n = mag.length == 0 ? 0 + : mag.length * Integer.SIZE - Integer.numberOfLeadingZeros(mag[0]); + magBitLengthPlusOne = n + 1; + } + return n; } /** @@ -3127,7 +3128,7 @@ public class BigInteger extends Number implements Comparable { // Select an appropriate window size int wbits = 0; - int ebits = bitLength(exp, exp.length); + int ebits = y.magBitLength(); // if exponent is 65537 (0x10001), use minimum window size if ((ebits != 17) || (exp[0] != 65537)) { while (ebits > bnExpModThreshTable[wbits]) { @@ -3180,7 +3181,7 @@ public class BigInteger extends Number implements Comparable { } // Pre load the window that slides over the exponent - int bitpos = 1 << ((ebits-1) & (32-1)); + int bitpos = 1 << ((ebits-1) & 0x1f); int buf = 0; int elen = exp.length; @@ -3190,7 +3191,7 @@ public class BigInteger extends Number implements Comparable { bitpos >>>= 1; if (bitpos == 0) { eIndex++; - bitpos = 1 << (32-1); + bitpos = 1 << 0x1f; elen--; } } @@ -3224,7 +3225,7 @@ public class BigInteger extends Number implements Comparable { bitpos >>>= 1; if (bitpos == 0) { eIndex++; - bitpos = 1 << (32-1); + bitpos = 1 << 0x1f; elen--; } } @@ -3613,14 +3614,11 @@ public class BigInteger extends Number implements Comparable { if (signum < 0) { // Find out whether any one-bits were shifted off the end. - boolean onesLost = false; - for (int i=magLen-1, j=magLen-nInts; i >= j && !onesLost; i--) - onesLost = (mag[i] != 0); - if (!onesLost && nBits != 0) - onesLost = (mag[magLen - nInts - 1] << (32 - nBits) != 0); - - if (onesLost) + int nzInts = numberOfTrailingZeroInts(); + if (nInts > nzInts || nInts == nzInts + && (mag[magLen - nzInts - 1] & ((1 << nBits) - 1)) != 0) { newMag = javaIncrement(newMag); + } } return new BigInteger(newMag, signum); @@ -3637,7 +3635,7 @@ public class BigInteger extends Number implements Comparable { } } - int[] javaIncrement(int[] val) { + static int[] javaIncrement(int[] val) { int lastSum = 0; for (int i=val.length-1; i >= 0 && lastSum == 0; i--) lastSum = (val[i] += 1); @@ -3750,7 +3748,7 @@ public class BigInteger extends Number implements Comparable { if (n < 0) throw new ArithmeticException("Negative bit address"); - return (getInt(n >>> 5) & (1 << (n & 31))) != 0; + return (getInt(n >>> 5) & (1 << (n & 0x1f))) != 0; } /** @@ -3771,7 +3769,7 @@ public class BigInteger extends Number implements Comparable { for (int i=0; i < result.length; i++) result[result.length-i-1] = getInt(i); - result[result.length-intNum-1] |= (1 << (n & 31)); + result[result.length-intNum-1] |= (1 << (n & 0x1f)); return valueOf(result); } @@ -3795,7 +3793,7 @@ public class BigInteger extends Number implements Comparable { for (int i=0; i < result.length; i++) result[result.length-i-1] = getInt(i); - result[result.length-intNum-1] &= ~(1 << (n & 31)); + result[result.length-intNum-1] &= ~(1 << (n & 0x1f)); return valueOf(result); } @@ -3819,7 +3817,7 @@ public class BigInteger extends Number implements Comparable { for (int i=0; i < result.length; i++) result[result.length-i-1] = getInt(i); - result[result.length-intNum-1] ^= (1 << (n & 31)); + result[result.length-intNum-1] ^= (1 << (n & 0x1f)); return valueOf(result); } @@ -3835,15 +3833,11 @@ public class BigInteger extends Number implements Comparable { public int getLowestSetBit() { int lsb = lowestSetBitPlusTwo - 2; if (lsb == -2) { // lowestSetBit not initialized yet - lsb = 0; if (signum == 0) { - lsb -= 1; + lsb = -1; } else { - // Search for lowest order nonzero int - int i,b; - for (i=0; (b = getInt(i)) == 0; i++) - ; - lsb += (i << 5) + Integer.numberOfTrailingZeros(b); + int tz = numberOfTrailingZeroInts(); + lsb = tz * Integer.SIZE + Integer.numberOfTrailingZeros(mag[mag.length - 1 - tz]); } lowestSetBitPlusTwo = lsb + 2; } @@ -3864,29 +3858,11 @@ public class BigInteger extends Number implements Comparable { * representation of this BigInteger, excluding a sign bit. */ public int bitLength() { - int n = bitLengthPlusOne - 1; - if (n == -1) { // bitLength not initialized yet - int[] m = mag; - int len = m.length; - if (len == 0) { - n = 0; // offset by one to initialize - } else { - // Calculate the bit length of the magnitude - int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]); - if (signum < 0) { - // Check if magnitude is a power of two - boolean pow2 = (Integer.bitCount(mag[0]) == 1); - for (int i=1; i< len && pow2; i++) - pow2 = (mag[i] == 0); - - n = (pow2 ? magBitLength - 1 : magBitLength); - } else { - n = magBitLength; - } - } - bitLengthPlusOne = n + 1; - } - return n; + return signum < 0 + // Check if magnitude is a power of two + && Integer.lowestOneBit(mag[0]) == mag[0] + && numberOfTrailingZeroInts() == mag.length - 1 + ? magBitLength() - 1 : magBitLength(); } /** @@ -3901,17 +3877,15 @@ public class BigInteger extends Number implements Comparable { int bc = bitCountPlusOne - 1; if (bc == -1) { // bitCount not initialized yet bc = 0; // offset by one to initialize + + final int firstZeroInt = mag.length - numberOfTrailingZeroInts(); // Count the bits in the magnitude - for (int i=0; i < mag.length; i++) + for (int i = 0; i < firstZeroInt; i++) bc += Integer.bitCount(mag[i]); - if (signum < 0) { - // Count the trailing zeros in the magnitude - int magTrailingZeroCount = 0, j; - for (j=mag.length-1; mag[j] == 0; j--) - magTrailingZeroCount += 32; - magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]); - bc += magTrailingZeroCount - 1; - } + + if (signum < 0) + bc += getLowestSetBit() - 1; // Count the trailing zeros + bitCountPlusOne = bc + 1; } return bc; @@ -4333,10 +4307,9 @@ public class BigInteger extends Number implements Comparable { * @see #BigInteger(byte[]) */ public byte[] toByteArray() { - int byteLen = bitLength()/8 + 1; - byte[] byteArray = new byte[byteLen]; + byte[] byteArray = new byte[(bitLength() >>> 3) + 1]; - for (int i=byteLen-1, bytesCopied=4, nextInt=0, intIndex=0; i >= 0; i--) { + for (int i=byteArray.length-1, bytesCopied=4, nextInt=0, intIndex=0; i >= 0; i--) { if (bytesCopied == 4) { nextInt = getInt(intIndex++); bytesCopied = 1; @@ -4366,9 +4339,7 @@ public class BigInteger extends Number implements Comparable { * @jls 5.1.3 Narrowing Primitive Conversion */ public int intValue() { - int result = 0; - result = getInt(0); - return result; + return getInt(0); } /** @@ -4388,11 +4359,7 @@ public class BigInteger extends Number implements Comparable { * @jls 5.1.3 Narrowing Primitive Conversion */ public long longValue() { - long result = 0; - - for (int i=1; i >= 0; i--) - result = (result << 32) + (getInt(i) & LONG_MASK); - return result; + return ((long) getInt(1) << Integer.SIZE) | (getInt(0) & LONG_MASK); } /** @@ -4416,7 +4383,7 @@ public class BigInteger extends Number implements Comparable { return 0.0f; } - int exponent = ((mag.length - 1) << 5) + bitLengthForInt(mag[0]) - 1; + int exponent = magBitLength() - 1; // exponent == floor(log2(abs(this))) if (exponent < Long.SIZE - 1) { @@ -4501,7 +4468,7 @@ public class BigInteger extends Number implements Comparable { return 0.0; } - int exponent = ((mag.length - 1) << 5) + bitLengthForInt(mag[0]) - 1; + int exponent = magBitLength() - 1; // exponent == floor(log2(abs(this))Double) if (exponent < Long.SIZE - 1) { @@ -4574,30 +4541,24 @@ public class BigInteger extends Number implements Comparable { } /** - * Returns a copy of the input array stripped of any leading zero bytes. + * Returns the input array stripped of any leading zero ints. + * If the source is trusted the copying may be skipped. */ - private static int[] stripLeadingZeroInts(int[] val) { - int vlen = val.length; + private static int[] stripLeadingZeroInts(int[] val, boolean trusted) { int keep; - // Find first nonzero byte - for (keep = 0; keep < vlen && val[keep] == 0; keep++) + // Find first nonzero int + for (keep = 0; keep < val.length && val[keep] == 0; keep++) ; - return Arrays.copyOfRange(val, keep, vlen); + return trusted && keep == 0 ? val : Arrays.copyOfRange(val, keep, val.length); } /** - * Returns the input array stripped of any leading zero bytes. + * Returns the input array stripped of any leading zero ints. * Since the source is trusted the copying may be skipped. */ private static int[] trustedStripLeadingZeroInts(int[] val) { - int vlen = val.length; - int keep; - - // Find first nonzero byte - for (keep = 0; keep < vlen && val[keep] == 0; keep++) - ; - return keep == 0 ? val : Arrays.copyOfRange(val, keep, vlen); + return stripLeadingZeroInts(val, true); } private static int[] stripLeadingZeroBytes(byte[] a, int from, int len) { @@ -4768,7 +4729,7 @@ public class BigInteger extends Number implements Comparable { * returns the minimal (no leading zero ints) unsigned whose value is -a. */ private static int[] makePositive(int[] a) { - int keep, j; + int keep, i; // Find first non-sign (0xffffffff) int of input for (keep=0; keep < a.length && a[keep] == -1; keep++) @@ -4776,20 +4737,20 @@ public class BigInteger extends Number implements Comparable { /* Allocate output array. If all non-sign ints are 0x00, we must * allocate space for one extra output int. */ - for (j=keep; j < a.length && a[j] == 0; j++) + for (i = a.length - 1; a[i] == 0; i--) // Skip trailing zeros ; - int extraInt = (j == a.length ? 1 : 0); - int result[] = new int[a.length - keep + extraInt]; - - /* Copy one's complement of input into output, leaving extra - * int (if it exists) == 0x00 */ - for (int i = keep; i < a.length; i++) - result[i - keep + extraInt] = ~a[i]; - - // Add one to one's complement to generate two's complement - for (int i=result.length-1; ++result[i] == 0; i--) - ; - + int[] result; + if (i < keep) { + result = new int[a.length - keep + 1]; + result[0] = 1; + } else { // Exists a non-sign int that is non-zero + result = new int[a.length - keep]; + // Copy two's complement of input into output + result[i - keep] = -a[i]; + i--; + for (; i >= keep; i--) + result[i - keep] = ~a[i]; + } return result; } @@ -4883,29 +4844,28 @@ public class BigInteger extends Number implements Comparable { int magInt = mag[mag.length-n-1]; return (signum >= 0 ? magInt : - (n <= firstNonzeroIntNum() ? -magInt : ~magInt)); + (n <= numberOfTrailingZeroInts() ? -magInt : ~magInt)); } /** * Returns the index of the int that contains the first nonzero int in the * little-endian binary representation of the magnitude (int 0 is the - * least significant). If the magnitude is zero, return value is undefined. + * least significant). If the magnitude is zero, return value is zero. * - *

Note: never used for a BigInteger with a magnitude of zero. * @see #getInt */ - private int firstNonzeroIntNum() { - int fn = firstNonzeroIntNumPlusTwo - 2; - if (fn == -2) { // firstNonzeroIntNum not initialized yet + private int numberOfTrailingZeroInts() { + int nz = numberOfTrailingZeroIntsPlusTwo - 2; + if (nz == -2) { // numberOfTrailingZeroInts not initialized yet // Search for the first nonzero int int i; - int mlen = mag.length; - for (i = mlen - 1; i >= 0 && mag[i] == 0; i--) + final int lowest = mag.length - 1; + for (i = lowest; i >= 0 && mag[i] == 0; i--) ; - fn = mlen - i - 1; - firstNonzeroIntNumPlusTwo = fn + 2; // offset by two to initialize + nz = lowest - i; + numberOfTrailingZeroIntsPlusTwo = nz + 2; // offset by two to initialize } - return fn; + return nz; } /** use serialVersionUID from JDK 1.1. for interoperability */ @@ -5052,13 +5012,9 @@ public class BigInteger extends Number implements Comparable { * Returns the mag array as an array of bytes. */ private byte[] magSerializedForm() { - int len = mag.length; + byte[] result = new byte[(magBitLength() + 7) >>> 3]; - int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0])); - int byteLen = (bitLen + 7) >>> 3; - byte[] result = new byte[byteLen]; - - for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0; + for (int i = result.length - 1, bytesCopied = 4, intIndex = mag.length - 1, nextInt = 0; i >= 0; i--) { if (bytesCopied == 4) { nextInt = mag[intIndex--]; @@ -5085,10 +5041,10 @@ public class BigInteger extends Number implements Comparable { * @since 1.8 */ public long longValueExact() { - if (mag.length <= 2 && bitLength() <= 63) + if (mag.length <= 2 && bitLength() < Long.SIZE) return longValue(); - else - throw new ArithmeticException("BigInteger out of long range"); + + throw new ArithmeticException("BigInteger out of long range"); } /** @@ -5104,10 +5060,10 @@ public class BigInteger extends Number implements Comparable { * @since 1.8 */ public int intValueExact() { - if (mag.length <= 1 && bitLength() <= 31) + if (mag.length <= 1 && bitLength() < Integer.SIZE) return intValue(); - else - throw new ArithmeticException("BigInteger out of int range"); + + throw new ArithmeticException("BigInteger out of int range"); } /** @@ -5123,11 +5079,9 @@ public class BigInteger extends Number implements Comparable { * @since 1.8 */ public short shortValueExact() { - if (mag.length <= 1 && bitLength() <= 31) { - int value = intValue(); - if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) - return shortValue(); - } + if (mag.length <= 1 && bitLength() < Short.SIZE) + return shortValue(); + throw new ArithmeticException("BigInteger out of short range"); } @@ -5144,11 +5098,9 @@ public class BigInteger extends Number implements Comparable { * @since 1.8 */ public byte byteValueExact() { - if (mag.length <= 1 && bitLength() <= 31) { - int value = intValue(); - if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) - return byteValue(); - } + if (mag.length <= 1 && bitLength() < Byte.SIZE) + return byteValue(); + throw new ArithmeticException("BigInteger out of byte range"); } }