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; - } }