# HG changeset patch
# User bpb
# Date 1534978504 25200
# Node ID 620b31ed8807a43ebe9e628ceea75da13f094604
# Parent 0060e9d7c450a8959a87a52b4ebf04d8dfe0c2d1
8200659: Improve BigDecimal support
Reviewed-by: darcy, rhalade, mschoene
diff -r 0060e9d7c450 -r 620b31ed8807 src/java.base/share/classes/java/math/BigDecimal.java
--- a/src/java.base/share/classes/java/math/BigDecimal.java Sat Sep 29 10:08:42 2018 +0800
+++ b/src/java.base/share/classes/java/math/BigDecimal.java Wed Aug 22 15:55:04 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
import static java.math.BigInteger.LONG_MASK;
import java.util.Arrays;
+import java.util.Objects;
/**
* Immutable, arbitrary-precision signed decimal numbers. A
@@ -424,9 +425,14 @@
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
- // protect against huge length.
- if (offset + len > in.length || offset < 0)
- throw new NumberFormatException("Bad offset or len arguments for char[] input.");
+ // protect against huge length, negative values, and integer overflow
+ try {
+ Objects.checkFromIndexSize(offset, len, in.length);
+ } catch (IndexOutOfBoundsException e) {
+ throw new NumberFormatException
+ ("Bad offset or len arguments for char[] input.");
+ }
+
// This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate
diff -r 0060e9d7c450 -r 620b31ed8807 src/java.base/share/classes/java/math/BigInteger.java
--- a/src/java.base/share/classes/java/math/BigInteger.java Sat Sep 29 10:08:42 2018 +0800
+++ b/src/java.base/share/classes/java/math/BigInteger.java Wed Aug 22 15:55:04 2018 -0700
@@ -307,10 +307,8 @@
public BigInteger(byte[] val, int off, int len) {
if (val.length == 0) {
throw new NumberFormatException("Zero length BigInteger");
- } else if ((off < 0) || (off >= val.length) || (len < 0) ||
- (len > val.length - off)) { // 0 <= off < val.length
- throw new IndexOutOfBoundsException();
}
+ Objects.checkFromIndexSize(off, len, val.length);
if (val[off] < 0) {
mag = makePositive(val, off, len);
@@ -395,12 +393,8 @@
public BigInteger(int signum, byte[] magnitude, int off, int len) {
if (signum < -1 || signum > 1) {
throw(new NumberFormatException("Invalid signum value"));
- } else if ((off < 0) || (len < 0) ||
- (len > 0 &&
- ((off >= magnitude.length) ||
- (len > magnitude.length - off)))) { // 0 <= off < magnitude.length
- throw new IndexOutOfBoundsException();
}
+ Objects.checkFromIndexSize(off, len, magnitude.length);
// stripLeadingZeroBytes() returns a zero length array if len == 0
this.mag = stripLeadingZeroBytes(magnitude, off, len);
@@ -1239,6 +1233,14 @@
private static final double LOG_TWO = Math.log(2.0);
static {
+ assert 0 < KARATSUBA_THRESHOLD
+ && KARATSUBA_THRESHOLD < TOOM_COOK_THRESHOLD
+ && TOOM_COOK_THRESHOLD < Integer.MAX_VALUE
+ && 0 < KARATSUBA_SQUARE_THRESHOLD
+ && KARATSUBA_SQUARE_THRESHOLD < TOOM_COOK_SQUARE_THRESHOLD
+ && TOOM_COOK_SQUARE_THRESHOLD < Integer.MAX_VALUE :
+ "Algorithm thresholds are inconsistent";
+
for (int i = 1; i <= MAX_CONSTANT; i++) {
int[] magnitude = new int[1];
magnitude[0] = i;
@@ -1562,6 +1564,18 @@
* @return {@code this * val}
*/
public BigInteger multiply(BigInteger val) {
+ return multiply(val, false);
+ }
+
+ /**
+ * Returns a BigInteger whose value is {@code (this * val)}. If
+ * the invocation is recursive certain overflow checks are skipped.
+ *
+ * @param val value to be multiplied by this BigInteger.
+ * @param isRecursion whether this is a recursive invocation
+ * @return {@code this * val}
+ */
+ private BigInteger multiply(BigInteger val, boolean isRecursion) {
if (val.signum == 0 || signum == 0)
return ZERO;
@@ -1589,6 +1603,63 @@
if ((xlen < TOOM_COOK_THRESHOLD) && (ylen < TOOM_COOK_THRESHOLD)) {
return multiplyKaratsuba(this, val);
} else {
+ //
+ // In "Hacker's Delight" section 2-13, p.33, it is explained
+ // that if x and y are unsigned 32-bit quantities and m and n
+ // are their respective numbers of leading zeros within 32 bits,
+ // then the number of leading zeros within their product as a
+ // 64-bit unsigned quantity is either m + n or m + n + 1. If
+ // their product is not to overflow, it cannot exceed 32 bits,
+ // and so the number of leading zeros of the product within 64
+ // bits must be at least 32, i.e., the leftmost set bit is at
+ // zero-relative position 31 or less.
+ //
+ // From the above there are three cases:
+ //
+ // m + n leftmost set bit condition
+ // ----- ---------------- ---------
+ // >= 32 x <= 64 - 32 = 32 no overflow
+ // == 31 x >= 64 - 32 = 32 possible overflow
+ // <= 30 x >= 64 - 31 = 33 definite overflow
+ //
+ // The "possible overflow" condition cannot be detected by
+ // examning data lengths alone and requires further calculation.
+ //
+ // By analogy, if 'this' and 'val' have m and n as their
+ // respective numbers of leading zeros within 32*MAX_MAG_LENGTH
+ // bits, then:
+ //
+ // m + n >= 32*MAX_MAG_LENGTH no overflow
+ // m + n == 32*MAX_MAG_LENGTH - 1 possible overflow
+ // m + n <= 32*MAX_MAG_LENGTH - 2 definite overflow
+ //
+ // Note however that if the number of ints in the result
+ // were to be MAX_MAG_LENGTH and mag[0] < 0, then there would
+ // be overflow. As a result the leftmost bit (of mag[0]) cannot
+ // be used and the constraints must be adjusted by one bit to:
+ //
+ // m + n > 32*MAX_MAG_LENGTH no overflow
+ // m + n == 32*MAX_MAG_LENGTH possible overflow
+ // m + n < 32*MAX_MAG_LENGTH definite overflow
+ //
+ // The foregoing leading zero-based discussion is for clarity
+ // only. The actual calculations use the estimated bit length
+ // of the product as this is more natural to the internal
+ // array representation of the magnitude which has no leading
+ // zero elements.
+ //
+ if (!isRecursion) {
+ // The bitLength() instance method is not used here as we
+ // 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 (bitLength(mag, mag.length) +
+ bitLength(val.mag, val.mag.length) >
+ 32L*MAX_MAG_LENGTH) {
+ reportOverflow();
+ }
+ }
+
return multiplyToomCook3(this, val);
}
}
@@ -1674,7 +1745,7 @@
int ystart = ylen - 1;
if (z == null || z.length < (xlen+ ylen))
- z = new int[xlen+ylen];
+ z = new int[xlen+ylen];
long carry = 0;
for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) {
@@ -1808,16 +1879,16 @@
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1, db1;
- v0 = a0.multiply(b0);
+ v0 = a0.multiply(b0, true);
da1 = a2.add(a0);
db1 = b2.add(b0);
- vm1 = da1.subtract(a1).multiply(db1.subtract(b1));
+ vm1 = da1.subtract(a1).multiply(db1.subtract(b1), true);
da1 = da1.add(a1);
db1 = db1.add(b1);
- v1 = da1.multiply(db1);
+ v1 = da1.multiply(db1, true);
v2 = da1.add(a2).shiftLeft(1).subtract(a0).multiply(
- db1.add(b2).shiftLeft(1).subtract(b0));
- vinf = a2.multiply(b2);
+ db1.add(b2).shiftLeft(1).subtract(b0), true);
+ vinf = a2.multiply(b2, true);
// The algorithm requires two divisions by 2 and one by 3.
// All divisions are known to be exact, that is, they do not produce
@@ -1983,6 +2054,17 @@
* @return {@code this2}
*/
private BigInteger square() {
+ return square(false);
+ }
+
+ /**
+ * Returns a BigInteger whose value is {@code (this2)}. If
+ * the invocation is recursive certain overflow checks are skipped.
+ *
+ * @param isRecursion whether this is a recursive invocation
+ * @return {@code this2}
+ */
+ private BigInteger square(boolean isRecursion) {
if (signum == 0) {
return ZERO;
}
@@ -1995,6 +2077,15 @@
if (len < TOOM_COOK_SQUARE_THRESHOLD) {
return squareKaratsuba();
} else {
+ //
+ // For a discussion of overflow detection see multiply()
+ //
+ if (!isRecursion) {
+ if (bitLength(mag, mag.length) > 16L*MAX_MAG_LENGTH) {
+ reportOverflow();
+ }
+ }
+
return squareToomCook3();
}
}
@@ -2146,13 +2237,13 @@
a0 = getToomSlice(k, r, 2, len);
BigInteger v0, v1, v2, vm1, vinf, t1, t2, tm1, da1;
- v0 = a0.square();
+ v0 = a0.square(true);
da1 = a2.add(a0);
- vm1 = da1.subtract(a1).square();
+ vm1 = da1.subtract(a1).square(true);
da1 = da1.add(a1);
- v1 = da1.square();
- vinf = a2.square();
- v2 = da1.add(a2).shiftLeft(1).subtract(a0).square();
+ v1 = da1.square(true);
+ vinf = a2.square(true);
+ v2 = da1.add(a2).shiftLeft(1).subtract(a0).square(true);
// The algorithm requires two divisions by 2 and one by 3.
// All divisions are known to be exact, that is, they do not produce
@@ -2323,10 +2414,11 @@
// The remaining part can then be exponentiated faster. The
// powers of two will be multiplied back at the end.
int powersOfTwo = partToSquare.getLowestSetBit();
- long bitsToShift = (long)powersOfTwo * exponent;
- if (bitsToShift > Integer.MAX_VALUE) {
+ long bitsToShiftLong = (long)powersOfTwo * exponent;
+ if (bitsToShiftLong > Integer.MAX_VALUE) {
reportOverflow();
}
+ int bitsToShift = (int)bitsToShiftLong;
int remainingBits;
@@ -2336,9 +2428,9 @@
remainingBits = partToSquare.bitLength();
if (remainingBits == 1) { // Nothing left but +/- 1?
if (signum < 0 && (exponent&1) == 1) {
- return NEGATIVE_ONE.shiftLeft(powersOfTwo*exponent);
+ return NEGATIVE_ONE.shiftLeft(bitsToShift);
} else {
- return ONE.shiftLeft(powersOfTwo*exponent);
+ return ONE.shiftLeft(bitsToShift);
}
}
} else {
@@ -2383,13 +2475,16 @@
if (bitsToShift + scaleFactor <= 62) { // Fits in long?
return valueOf((result << bitsToShift) * newSign);
} else {
- return valueOf(result*newSign).shiftLeft((int) bitsToShift);
+ return valueOf(result*newSign).shiftLeft(bitsToShift);
}
- }
- else {
+ } else {
return valueOf(result*newSign);
}
} else {
+ if ((long)bitLength() * exponent / Integer.SIZE > MAX_MAG_LENGTH) {
+ reportOverflow();
+ }
+
// Large number algorithm. This is basically identical to
// the algorithm above, but calls multiply() and square()
// which may use more efficient algorithms for large numbers.
@@ -2409,7 +2504,7 @@
// Multiply back the (exponentiated) powers of two (quickly,
// by shifting left)
if (powersOfTwo > 0) {
- answer = answer.shiftLeft(powersOfTwo*exponent);
+ answer = answer.shiftLeft(bitsToShift);
}
if (signum < 0 && (exponent&1) == 1) {
@@ -3584,7 +3679,7 @@
for (int i=1; i< len && pow2; i++)
pow2 = (mag[i] == 0);
- n = (pow2 ? magBitLength -1 : magBitLength);
+ n = (pow2 ? magBitLength - 1 : magBitLength);
} else {
n = magBitLength;
}
diff -r 0060e9d7c450 -r 620b31ed8807 test/jdk/java/math/BigDecimal/AddTests.java
--- a/test/jdk/java/math/BigDecimal/AddTests.java Sat Sep 29 10:08:42 2018 +0800
+++ b/test/jdk/java/math/BigDecimal/AddTests.java Wed Aug 22 15:55:04 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6362557
+ * @bug 6362557 8200698
* @summary Some tests of add(BigDecimal, mc)
* @author Joseph D. Darcy
*/
@@ -290,12 +290,35 @@
return failures;
}
+ private static int arithmeticExceptionTest() {
+ int failures = 0;
+ BigDecimal x;
+ try {
+ //
+ // The string representation "1e2147483647", which is equivalent
+ // to 10^Integer.MAX_VALUE, is used to create an augend with an
+ // unscaled value of 1 and a scale of -Integer.MAX_VALUE. The
+ // addend "1" has an unscaled value of 1 with a scale of 0. The
+ // addition is performed exactly and is specified to have a
+ // preferred scale of max(-Integer.MAX_VALUE, 0). As the scale
+ // of the result is 0, a value with Integer.MAX_VALUE + 1 digits
+ // would need to be created. Therefore the next statement is
+ // expected to overflow with an ArithmeticException.
+ //
+ x = new BigDecimal("1e2147483647").add(new BigDecimal(1));
+ failures++;
+ } catch (ArithmeticException ae) {
+ }
+ return failures;
+ }
+
public static void main(String argv[]) {
int failures = 0;
failures += extremaTests();
failures += roundingGradationTests();
failures += precisionConsistencyTest();
+ failures += arithmeticExceptionTest();
if (failures > 0) {
throw new RuntimeException("Incurred " + failures +
diff -r 0060e9d7c450 -r 620b31ed8807 test/jdk/java/math/BigDecimal/Constructor.java
--- a/test/jdk/java/math/BigDecimal/Constructor.java Sat Sep 29 10:08:42 2018 +0800
+++ b/test/jdk/java/math/BigDecimal/Constructor.java Wed Aug 22 15:55:04 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,20 +23,48 @@
/*
* @test
- * @bug 4259453
- * @summary Test string constructor of BigDecimal
+ * @bug 4259453 8200698
+ * @summary Test constructors of BigDecimal
+ * @library ..
+ * @run testng Constructor
*/
+
import java.math.BigDecimal;
+import org.testng.annotations.Test;
public class Constructor {
- public static void main(String[] args) throws Exception {
- boolean nfe = false;
+ @Test(expectedExceptions=NumberFormatException.class)
+ public void stringConstructor() {
+ BigDecimal bd = new BigDecimal("1.2e");
+ }
+
+ @Test(expectedExceptions=NumberFormatException.class)
+ public void charArrayConstructorNegativeOffset() {
+ BigDecimal bd = new BigDecimal(new char[5], -1, 4, null);
+ }
+
+ @Test(expectedExceptions=NumberFormatException.class)
+ public void charArrayConstructorNegativeLength() {
+ BigDecimal bd = new BigDecimal(new char[5], 0, -1, null);
+ }
+
+ @Test(expectedExceptions=NumberFormatException.class)
+ public void charArrayConstructorIntegerOverflow() {
try {
- BigDecimal bd = new BigDecimal("1.2e");
- } catch (NumberFormatException e) {
- nfe = true;
+ BigDecimal bd = new BigDecimal(new char[5], Integer.MAX_VALUE - 5,
+ 6, null);
+ } catch (NumberFormatException nfe) {
+ if (nfe.getCause() instanceof IndexOutOfBoundsException) {
+ throw new RuntimeException
+ ("NumberFormatException should not have a cause");
+ } else {
+ throw nfe;
+ }
}
- if (!nfe)
- throw new Exception("Didn't throw NumberFormatException");
+ }
+
+ @Test(expectedExceptions=NumberFormatException.class)
+ public void charArrayConstructorIndexOutOfBounds() {
+ BigDecimal bd = new BigDecimal(new char[5], 1, 5, null);
}
}
diff -r 0060e9d7c450 -r 620b31ed8807 test/jdk/java/math/BigInteger/LargeValueExceptions.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/math/BigInteger/LargeValueExceptions.java Wed Aug 22 15:55:04 2018 -0700
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8200698
+ * @summary Tests that exceptions are thrown for ops which would overflow
+ * @requires os.maxMemory >= 4g
+ * @run testng/othervm -Xmx4g LargeValueExceptions
+ */
+import java.math.BigInteger;
+import static java.math.BigInteger.ONE;
+import org.testng.annotations.Test;
+
+//
+// The intent of this test is to probe the boundaries between overflow and
+// non-overflow, principally for multiplication and squaring, specifically
+// the largest values which should not overflow and the smallest values which
+// should. The transition values used are not necessarily at the exact
+// boundaries but should be "close." Quite a few different values were used
+// experimentally before settling on the ones in this test. For multiplication
+// and squaring all cases are exercised: definite overflow and non-overflow
+// which can be detected "up front," and "indefinite" overflow, i.e., overflow
+// which cannot be detected up front so further calculations are required.
+//
+// Testing negative values is unnecessary. For both multiplication and squaring
+// the paths lead to the Toom-Cook algorithm where the signum is used only to
+// determine the sign of the result and not in the intermediate calculations.
+// This is also true for exponentiation.
+//
+// @Test annotations with optional element "enabled" set to "false" should
+// succeed when "enabled" is set to "true" but they take too to run in the
+// course of the typical regression test execution scenario.
+//
+public class LargeValueExceptions {
+ // BigInteger.MAX_MAG_LENGTH
+ private static final int MAX_INTS = 1 << 26;
+
+ // Number of bits corresponding to MAX_INTS
+ private static final long MAX_BITS = (0xffffffffL & MAX_INTS) << 5L;
+
+ // Half BigInteger.MAX_MAG_LENGTH
+ private static final int MAX_INTS_HALF = MAX_INTS / 2;
+
+ // --- squaring ---
+
+ // Largest no overflow determined by examining data lengths alone.
+ @Test(enabled=false)
+ public void squareNoOverflow() {
+ BigInteger x = ONE.shiftLeft(16*MAX_INTS - 1).subtract(ONE);
+ BigInteger y = x.multiply(x);
+ }
+
+ // Smallest no overflow determined by extra calculations.
+ @Test(enabled=false)
+ public void squareIndefiniteOverflowSuccess() {
+ BigInteger x = ONE.shiftLeft(16*MAX_INTS - 1);
+ BigInteger y = x.multiply(x);
+ }
+
+ // Largest overflow detected by extra calculations.
+ @Test(expectedExceptions=ArithmeticException.class,enabled=false)
+ public void squareIndefiniteOverflowFailure() {
+ BigInteger x = ONE.shiftLeft(16*MAX_INTS).subtract(ONE);
+ BigInteger y = x.multiply(x);
+ }
+
+ // Smallest overflow detected by examining data lengths alone.
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void squareDefiniteOverflow() {
+ BigInteger x = ONE.shiftLeft(16*MAX_INTS);
+ BigInteger y = x.multiply(x);
+ }
+
+ // --- multiplication ---
+
+ // Largest no overflow determined by examining data lengths alone.
+ @Test(enabled=false)
+ public void multiplyNoOverflow() {
+ final int halfMaxBits = MAX_INTS_HALF << 5;
+
+ BigInteger x = ONE.shiftLeft(halfMaxBits).subtract(ONE);
+ BigInteger y = ONE.shiftLeft(halfMaxBits - 1).subtract(ONE);
+ BigInteger z = x.multiply(y);
+ }
+
+ // Smallest no overflow determined by extra calculations.
+ @Test(enabled=false)
+ public void multiplyIndefiniteOverflowSuccess() {
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS/2) - 1);
+ long m = MAX_BITS - x.bitLength();
+
+ BigInteger y = ONE.shiftLeft((int)(MAX_BITS/2) - 1);
+ long n = MAX_BITS - y.bitLength();
+
+ if (m + n != MAX_BITS) {
+ throw new RuntimeException("Unexpected leading zero sum");
+ }
+
+ BigInteger z = x.multiply(y);
+ }
+
+ // Largest overflow detected by extra calculations.
+ @Test(expectedExceptions=ArithmeticException.class,enabled=false)
+ public void multiplyIndefiniteOverflowFailure() {
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE);
+ long m = MAX_BITS - x.bitLength();
+
+ BigInteger y = ONE.shiftLeft((int)(MAX_BITS/2)).subtract(ONE);
+ long n = MAX_BITS - y.bitLength();
+
+ if (m + n != MAX_BITS) {
+ throw new RuntimeException("Unexpected leading zero sum");
+ }
+
+ BigInteger z = x.multiply(y);
+ }
+
+ // Smallest overflow detected by examining data lengths alone.
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void multiplyDefiniteOverflow() {
+ // multiply by 4 as MAX_INTS_HALF refers to ints
+ byte[] xmag = new byte[4*MAX_INTS_HALF];
+ xmag[0] = (byte)0xff;
+ BigInteger x = new BigInteger(1, xmag);
+
+ byte[] ymag = new byte[4*MAX_INTS_HALF + 1];
+ ymag[0] = (byte)0xff;
+ BigInteger y = new BigInteger(1, ymag);
+
+ BigInteger z = x.multiply(y);
+ }
+
+ // --- exponentiation ---
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void powOverflow() {
+ BigInteger.TEN.pow(Integer.MAX_VALUE);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void powOverflow1() {
+ int shift = 20;
+ int exponent = 1 << shift;
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent));
+ BigInteger y = x.pow(exponent);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void powOverflow2() {
+ int shift = 20;
+ int exponent = 1 << shift;
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).add(ONE);
+ BigInteger y = x.pow(exponent);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class,enabled=false)
+ public void powOverflow3() {
+ int shift = 20;
+ int exponent = 1 << shift;
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent)).subtract(ONE);
+ BigInteger y = x.pow(exponent);
+ }
+
+ @Test(enabled=false)
+ public void powOverflow4() {
+ int shift = 20;
+ int exponent = 1 << shift;
+ BigInteger x = ONE.shiftLeft((int)(MAX_BITS / exponent - 1)).add(ONE);
+ BigInteger y = x.pow(exponent);
+ }
+}