Overhaul BigInteger implementation.
This provides a faster code path for #valueOf(long) and some other
operations, cleans up constructors and also removes the JavaScript
specific native code.
PiperOrigin-RevId: 361980135
Change-Id: Ib72cc15e798ab2eb0a5c83a636278ff936440a8e
diff --git a/user/super/com/google/gwt/emul/java/math/BigDecimal.java b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
index 0802895..9f310cd 100644
--- a/user/super/com/google/gwt/emul/java/math/BigDecimal.java
+++ b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
@@ -2572,7 +2572,7 @@
private BigInteger getUnscaledValue() {
if (intVal == null) {
- intVal = BigInteger.valueOf(smallValue);
+ intVal = BigInteger.valueOf((long) smallValue);
}
return intVal;
}
diff --git a/user/super/com/google/gwt/emul/java/math/BigInteger.java b/user/super/com/google/gwt/emul/java/math/BigInteger.java
index 4f27600..8fe9f77 100644
--- a/user/super/com/google/gwt/emul/java/math/BigInteger.java
+++ b/user/super/com/google/gwt/emul/java/math/BigInteger.java
@@ -34,6 +34,7 @@
*/
package java.math;
+import static javaemul.internal.Coercions.ensureInt;
import static javaemul.internal.InternalPreconditions.checkCriticalArgument;
import static javaemul.internal.InternalPreconditions.checkNotNull;
@@ -96,11 +97,6 @@
static final BigInteger MINUS_ONE = new BigInteger(-1, 1);
/**
- * 2^32.
- */
- static final double POW32 = 4294967296d;
-
- /**
* All the {@code BigInteger} numbers in the range [0,10] are cached.
*/
static final BigInteger[] SMALL_VALUES = {
@@ -139,17 +135,19 @@
}
public static BigInteger valueOf(long val) {
- if (val < 0) {
- if (val != -1) {
- return new BigInteger(-1, -val);
- }
- return MINUS_ONE;
- } else if (val <= 10) {
- return SMALL_VALUES[(int) val];
- } else {
- // (val > 10)
- return new BigInteger(1, val);
+ return val >= 0 ? BigInteger.fromBits(val) : BigInteger.fromBits(-val).negate();
+ }
+
+ private static BigInteger fromBits(long bits) {
+ int lowBits = (int) bits;
+ int highBits = LongUtils.getHighBits(bits);
+ if (highBits != 0) {
+ return new BigInteger(1, lowBits, highBits);
}
+ if (lowBits > 10 || lowBits < 0) {
+ return new BigInteger(1, lowBits);
+ }
+ return SMALL_VALUES[lowBits];
}
static BigInteger getPowerOfTwo(int exp) {
@@ -163,20 +161,6 @@
return new BigInteger(1, intCount + 1, resDigits);
}
- public static BigInteger valueOf(double val) {
- if (val < 0) {
- if (val != -1) {
- return new BigInteger(-1, -val);
- }
- return MINUS_ONE;
- } else if (val <= 10) {
- return SMALL_VALUES[(int) val];
- } else {
- // (val > 10)
- return new BigInteger(1, val);
- }
- }
-
/**
* @see BigInteger#BigInteger(String, int)
*/
@@ -235,18 +219,6 @@
}
/**
- * Converts an integral double to an unsigned integer; ie 2^31 will be
- * returned as 0x80000000.
- *
- * @param val
- * @return val as an unsigned int
- */
- @SuppressWarnings("unusable-by-js")
- private static native int toUnsignedInt(double val) /*-{
- return val | 0;
- }-*/;
-
- /**
* The magnitude of this big integer. This array is in little endian order and
* each "digit" is a 32-bit unsigned integer. For example: {@code 13} is
* represented as [ 13 ] {@code -13} is represented as [ 13 ] {@code 2^32 +
@@ -438,16 +410,17 @@
* @param sign the sign of the number
* @param value the only one digit of array
*/
- BigInteger(int sign, int value) {
- this.sign = sign;
- numberLength = 1;
- digits = new int[] {value};
+ BigInteger(int sign, int bits) {
+ this(sign, 1, new int[] {bits});
+ }
+
+ BigInteger(int sign, int lowBits, int highBits) {
+ this(sign, 2, new int[] {lowBits, highBits});
}
/**
- * Creates a new {@code BigInteger} with the given sign and magnitude. This
- * constructor does not create a copy, so any changes to the reference will
- * affect the new number.
+ * Creates a new {@code BigInteger} with the given sign and magnitude. This constructor does not
+ * create a copy, so any changes to the reference will affect the new number.
*
* @param signum The sign of the number represented by {@code digits}
* @param digits The magnitude of the number
@@ -466,8 +439,8 @@
}
/**
- * Constructs a number without to create new space. This construct should be
- * used only if the three fields of representation are known.
+ * Constructs a number without to create new space. This construct should be used only if the
+ * three fields of representation are known.
*
* @param sign the sign of the number
* @param numberLength the length of the internal array
@@ -480,53 +453,13 @@
}
/**
- * Creates a new {@code BigInteger} whose value is equal to the specified
- * {@code long}.
- *
- * @param sign the sign of the number
- * @param val the value of the new {@code BigInteger}.
- */
- BigInteger(int sign, long val) {
- // PRE: (val >= 0) && (sign >= -1) && (sign <= 1)
- this.sign = sign;
- if (LongUtils.getHighBits(val) == 0) {
- // It fits in one 'int'
- numberLength = 1;
- digits = new int[] {(int) val};
- } else {
- numberLength = 2;
- digits = new int[] {(int) val, (int) (val >> 32)};
- }
- }
-
- /**
- * Creates a new {@code BigInteger} whose value is equal to the specified
- * {@code double} (which must be an integral value).
- *
- * @param sign the sign of the number
- * @param val the value of the new {@code BigInteger}.
- */
- private BigInteger(int sign, double val) {
- // PRE: (val >= 0) && (sign >= -1) && (sign <= 1)
- this.sign = sign;
- if (val < POW32) {
- // It fits in one 'int'
- numberLength = 1;
- digits = new int[] { toUnsignedInt(val) };
- } else {
- numberLength = 2;
- digits = new int[] { toUnsignedInt(val % POW32), toUnsignedInt(val / POW32) };
- }
- }
-
- /**
* Returns a (new) {@code BigInteger} whose value is the absolute value of
* {@code this}.
*
* @return {@code abs(this)}.
*/
public BigInteger abs() {
- return ((sign < 0) ? new BigInteger(1, numberLength, digits) : this);
+ return sign < 0 ? negate() : this;
}
/**
@@ -913,7 +846,7 @@
public int intValue() {
int i = digits[0];
// i is always positive except for Integer.MIN_VALUE because of int overflow
- return (sign > 0 || i == Integer.MIN_VALUE) ? i : -i;
+ return sign > 0 ? i : ensureInt(-i);
}
/**
@@ -1113,10 +1046,7 @@
*/
public BigInteger multiply(BigInteger val) {
// This let us to throw NullPointerException when val == null
- if (val.sign == 0) {
- return ZERO;
- }
- if (sign == 0) {
+ if (val.sign == 0 || sign == 0) {
return ZERO;
}
return Multiplication.multiply(this, val);
@@ -1128,7 +1058,7 @@
* @return {@code -this}.
*/
public BigInteger negate() {
- return ((sign == 0) ? this : new BigInteger(-sign, numberLength, digits));
+ return sign == 0 ? this : new BigInteger(-sign, numberLength, digits);
}
/**
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
index 3229ee3..c3992e5 100644
--- a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
@@ -38,9 +38,6 @@
package com.google.gwt.emultest.java.math;
import com.google.gwt.emultest.java.util.EmulTestBase;
-import com.google.gwt.testing.TestUtils;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
import java.math.BigInteger;
import java.util.Random;
@@ -778,48 +775,4 @@
}
assertEquals("incorrect sign", 1, aNumber.signum());
}
-
- /**
- * Test internal static factory method.
- */
- public void testValueOfDouble() {
- if (TestUtils.isJvm()) {
- // JRE implementation doesn't have the method tested here
- return;
- }
- BigInteger val = BigInteger.valueOf(noopToCompileForJvm(1.0));
- assertEquals("1", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(100.0));
- assertEquals("100", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(2147483647.0));
- assertEquals("2147483647", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(-2147483647.0));
- assertEquals("-2147483647", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(2147483648.0));
- assertEquals("2147483648", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(-2147483648.0));
- assertEquals("-2147483648", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(4294967295.0));
- assertEquals("4294967295", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(-4294967295.0));
- assertEquals("-4294967295", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(4294967296.0));
- assertEquals("4294967296", val.toString());
- val = BigInteger.valueOf(noopToCompileForJvm(-4294967296.0));
- assertEquals("-4294967296", val.toString());
- }
-
- @Target({ElementType.METHOD})
- private @interface GwtIncompatible {}
-
- @GwtIncompatible
- private static long noopToCompileForJvm(double d) {
- // The BigInteger.valueOf(double) doesn't exist on JVM. This methods exists to so that this test
- // can be compiled with the standard JRE.
- throw new AssertionError();
- }
-
- private static double noopToCompileForJvm(Double d) {
- return d;
- }
}