提交 364bf2a3 编写于 作者: X xlu

6622432: RFE: Performance improvements to java.math.BigDecimal

Reviewed-by: darcy
上级 ae34f917
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
package java.math; package java.math;
import java.util.Arrays;
import static java.math.BigInteger.LONG_MASK;
/** /**
* Immutable, arbitrary-precision signed decimal numbers. A * Immutable, arbitrary-precision signed decimal numbers. A
* {@code BigDecimal} consists of an arbitrary precision integer * {@code BigDecimal} consists of an arbitrary precision integer
...@@ -229,8 +232,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -229,8 +232,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @serial * @serial
* @see #scale * @see #scale
*/ */
private int scale = 0; // Note: this may have any value, so private int scale; // Note: this may have any value, so
// calculations must be done in longs // calculations must be done in longs
/** /**
* The number of decimal digits in this BigDecimal, or 0 if the * The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If * number of digits are not known (lookaside information). If
...@@ -240,25 +243,25 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -240,25 +243,25 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* *
* @since 1.5 * @since 1.5
*/ */
private volatile transient int precision = 0; private transient int precision;
/** /**
* Used to store the canonical string representation, if computed. * Used to store the canonical string representation, if computed.
*/ */
private volatile transient String stringCache = null; private transient String stringCache;
/** /**
* Sentinel value for {@link #intCompact} indicating the * Sentinel value for {@link #intCompact} indicating the
* significand information is only available from {@code intVal}. * significand information is only available from {@code intVal}.
*/ */
private static final long INFLATED = Long.MIN_VALUE; static final long INFLATED = Long.MIN_VALUE;
/** /**
* If the absolute value of the significand of this BigDecimal is * If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be * less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations. * compactly stored in this field and used in computations.
*/ */
private transient long intCompact = INFLATED; private transient long intCompact;
// All 18-digit base ten strings fit into a long; not all 19-digit // All 18-digit base ten strings fit into a long; not all 19-digit
// strings will // strings will
...@@ -269,19 +272,47 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -269,19 +272,47 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
/* Appease the serialization gods */ /* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L; private static final long serialVersionUID = 6108874887143696463L;
private static final ThreadLocal<StringBuilderHelper>
threadLocalStringBuilderHelper = new ThreadLocal<StringBuilderHelper>() {
@Override
protected StringBuilderHelper initialValue() {
return new StringBuilderHelper();
}
};
// Cache of common small BigDecimal values. // Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = { private static final BigDecimal zeroThroughTen[] = {
new BigDecimal(BigInteger.ZERO, 0, 0), new BigDecimal(BigInteger.ZERO, 0, 0, 1),
new BigDecimal(BigInteger.ONE, 1, 0), new BigDecimal(BigInteger.ONE, 1, 0, 1),
new BigDecimal(BigInteger.valueOf(2), 2, 0), new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
new BigDecimal(BigInteger.valueOf(3), 3, 0), new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
new BigDecimal(BigInteger.valueOf(4), 4, 0), new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
new BigDecimal(BigInteger.valueOf(5), 5, 0), new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
new BigDecimal(BigInteger.valueOf(6), 6, 0), new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
new BigDecimal(BigInteger.valueOf(7), 7, 0), new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
new BigDecimal(BigInteger.valueOf(8), 8, 0), new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
new BigDecimal(BigInteger.valueOf(9), 9, 0), new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
new BigDecimal(BigInteger.TEN, 10, 0), new BigDecimal(BigInteger.TEN, 10, 0, 2),
};
// Cache of zero scaled by 0 - 15
private static final BigDecimal[] ZERO_SCALED_BY = {
zeroThroughTen[0],
new BigDecimal(BigInteger.ZERO, 0, 1, 1),
new BigDecimal(BigInteger.ZERO, 0, 2, 1),
new BigDecimal(BigInteger.ZERO, 0, 3, 1),
new BigDecimal(BigInteger.ZERO, 0, 4, 1),
new BigDecimal(BigInteger.ZERO, 0, 5, 1),
new BigDecimal(BigInteger.ZERO, 0, 6, 1),
new BigDecimal(BigInteger.ZERO, 0, 7, 1),
new BigDecimal(BigInteger.ZERO, 0, 8, 1),
new BigDecimal(BigInteger.ZERO, 0, 9, 1),
new BigDecimal(BigInteger.ZERO, 0, 10, 1),
new BigDecimal(BigInteger.ZERO, 0, 11, 1),
new BigDecimal(BigInteger.ZERO, 0, 12, 1),
new BigDecimal(BigInteger.ZERO, 0, 13, 1),
new BigDecimal(BigInteger.ZERO, 0, 14, 1),
new BigDecimal(BigInteger.ZERO, 0, 15, 1),
}; };
// Constants // Constants
...@@ -311,6 +342,18 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -311,6 +342,18 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// Constructors // Constructors
/**
* Trusted package private constructor.
* Trusted simply means if val is INFLATED, intVal could not be null and
* if intVal is null, val could not be INFLATED.
*/
BigDecimal(BigInteger intVal, long val, int scale, int prec) {
this.scale = scale;
this.precision = prec;
this.intCompact = val;
this.intVal = intVal;
}
/** /**
* Translates a character array representation of a * Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the * {@code BigDecimal} into a {@code BigDecimal}, accepting the
...@@ -331,10 +374,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -331,10 +374,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(char[] in, int offset, int len) { public BigDecimal(char[] in, int offset, int len) {
// protect against huge length.
if (offset+len > in.length || offset < 0)
throw new NumberFormatException();
// This is the primary string to BigDecimal constructor; all // This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline) // incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate // parsing for speed and generates at most one intermediate
// (temporary) object (a char[] array). // (temporary) object (a char[] array) for non-compact case.
// Use locals for all fields values until completion
int prec = 0; // record precision value
int scl = 0; // record scale value
long rs = 0; // the compact value in long
BigInteger rb = null; // the inflated value in BigInteger
// use array bounds checking to handle too-long, len == 0, // use array bounds checking to handle too-long, len == 0,
// bad offset, etc. // bad offset, etc.
...@@ -351,27 +403,62 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -351,27 +403,62 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} }
// should now be at numeric part of the significand // should now be at numeric part of the significand
int dotoff = -1; // '.' offset, -1 if none boolean dot = false; // true when there is a '.'
int cfirst = offset; // record start of integer int cfirst = offset; // record start of integer
long exp = 0; // exponent long exp = 0; // exponent
if (len > in.length) // protect against huge length char c; // current character
throw new NumberFormatException();
char coeff[] = new char[len]; // integer significand array boolean isCompact = (len <= MAX_COMPACT_DIGITS);
char c; // work // integer significand array & idx is the index to it. The array
// is ONLY used when we can't use a compact representation.
char coeff[] = isCompact ? null : new char[len];
int idx = 0;
for (; len > 0; offset++, len--) { for (; len > 0; offset++, len--) {
c = in[offset]; c = in[offset];
// have digit
if ((c >= '0' && c <= '9') || Character.isDigit(c)) { if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
// have digit // First compact case, we need not to preserve the character
coeff[precision] = c; // and we can just compute the value in place.
precision++; // count of digits if (isCompact) {
int digit = Character.digit(c, 10);
if (digit == 0) {
if (prec == 0)
prec = 1;
else if (rs != 0) {
rs *= 10;
++prec;
} // else digit is a redundant leading zero
} else {
if (prec != 1 || rs != 0)
++prec; // prec unchanged if preceded by 0s
rs = rs * 10 + digit;
}
} else { // the unscaled value is likely a BigInteger object.
if (c == '0' || Character.digit(c, 10) == 0) {
if (prec == 0) {
coeff[idx] = c;
prec = 1;
} else if (idx != 0) {
coeff[idx++] = c;
++prec;
} // else c must be a redundant leading zero
} else {
if (prec != 1 || idx != 0)
++prec; // prec unchanged if preceded by 0s
coeff[idx++] = c;
}
}
if (dot)
++scl;
continue; continue;
} }
// have dot
if (c == '.') { if (c == '.') {
// have dot // have dot
if (dotoff >= 0) // two dots if (dot) // two dots
throw new NumberFormatException(); throw new NumberFormatException();
dotoff = offset; dot = true;
continue; continue;
} }
// exponent expected // exponent expected
...@@ -380,10 +467,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -380,10 +467,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
offset++; offset++;
c = in[offset]; c = in[offset];
len--; len--;
boolean negexp = false; boolean negexp = (c == '-');
// optional sign // optional sign
if (c == '-' || c == '+') { if (negexp || c == '+') {
negexp = (c == '-');
offset++; offset++;
c = in[offset]; c = in[offset];
len--; len--;
...@@ -392,9 +478,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -392,9 +478,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new NumberFormatException(); throw new NumberFormatException();
// skip leading zeros in the exponent // skip leading zeros in the exponent
while (len > 10 && Character.digit(c, 10) == 0) { while (len > 10 && Character.digit(c, 10) == 0) {
offset++; offset++;
c = in[offset]; c = in[offset];
len--; len--;
} }
if (len > 10) // too many nonzero exponent digits if (len > 10) // too many nonzero exponent digits
throw new NumberFormatException(); throw new NumberFormatException();
...@@ -420,55 +506,46 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -420,55 +506,46 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if ((int)exp != exp) // overflow if ((int)exp != exp) // overflow
throw new NumberFormatException(); throw new NumberFormatException();
break; // [saves a test] break; // [saves a test]
} }
// here when no characters left // here when no characters left
if (precision == 0) // no digits found if (prec == 0) // no digits found
throw new NumberFormatException(); throw new NumberFormatException();
if (dotoff >= 0) { // had dot; set scale // Adjust scale if exp is not zero.
scale = precision - (dotoff - cfirst);
// [cannot overflow]
}
if (exp != 0) { // had significant exponent if (exp != 0) { // had significant exponent
try { // Can't call checkScale which relies on proper fields value
scale = checkScale(-exp + scale); // adjust long adjustedScale = scl - exp;
} catch (ArithmeticException e) { if (adjustedScale > Integer.MAX_VALUE ||
adjustedScale < Integer.MIN_VALUE)
throw new NumberFormatException("Scale out of range."); throw new NumberFormatException("Scale out of range.");
} scl = (int)adjustedScale;
} }
// Remove leading zeros from precision (digits count) // Remove leading zeros from precision (digits count)
int first = 0; if (isCompact) {
for (; (coeff[first] == '0' || Character.digit(coeff[first], 10) == 0) && rs = isneg ? -rs : rs;
precision > 1;
first++)
precision--;
// Set the significand ..
// Copy significand to exact-sized array, with sign if
// negative
// Later use: BigInteger(coeff, first, precision) for
// both cases, by allowing an extra char at the front of
// coeff.
char quick[];
if (!isneg) {
quick = new char[precision];
System.arraycopy(coeff, first, quick, 0, precision);
} else { } else {
quick = new char[precision+1]; char quick[];
quick[0] = '-'; if (!isneg) {
System.arraycopy(coeff, first, quick, 1, precision); quick = (coeff.length != prec) ?
Arrays.copyOf(coeff, prec) : coeff;
} else {
quick = new char[prec + 1];
quick[0] = '-';
System.arraycopy(coeff, 0, quick, 1, prec);
}
rb = new BigInteger(quick);
rs = compactValFor(rb);
} }
if (precision <= MAX_COMPACT_DIGITS)
intCompact = Long.parseLong(new String(quick));
else
intVal = new BigInteger(quick);
// System.out.println(" new: " +intVal+" ["+scale+"] "+precision);
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException(); throw new NumberFormatException();
} catch (NegativeArraySizeException e) { } catch (NegativeArraySizeException e) {
throw new NumberFormatException(); throw new NumberFormatException();
} }
this.scale = scl;
this.precision = prec;
this.intCompact = rs;
this.intVal = (rs != INFLATED) ? null : rb;
} }
/** /**
...@@ -754,16 +831,18 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -754,16 +831,18 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} }
// Calculate intVal and scale // Calculate intVal and scale
intVal = BigInteger.valueOf(sign*significand); long s = sign * significand;
BigInteger b;
if (exponent < 0) { if (exponent < 0) {
intVal = intVal.multiply(BigInteger.valueOf(5).pow(-exponent)); b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
scale = -exponent; scale = -exponent;
} else if (exponent > 0) { } else if (exponent > 0) {
intVal = intVal.multiply(BigInteger.valueOf(2).pow(exponent)); b = BigInteger.valueOf(2).pow(exponent).multiply(s);
} } else {
if (intVal.bitLength() <= MAX_BIGINT_BITS) { b = BigInteger.valueOf(s);
intCompact = intVal.longValue();
} }
intCompact = compactValFor(b);
intVal = (intCompact != INFLATED) ? null : b;
} }
/** /**
...@@ -798,10 +877,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -798,10 +877,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code BigDecimal}. * {@code BigDecimal}.
*/ */
public BigDecimal(BigInteger val) { public BigDecimal(BigInteger val) {
intVal = val; intCompact = compactValFor(val);
if (val.bitLength() <= MAX_BIGINT_BITS) { intVal = (intCompact != INFLATED) ? null : val;
intCompact = val.longValue();
}
} }
/** /**
...@@ -817,7 +894,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -817,7 +894,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(BigInteger val, MathContext mc) { public BigDecimal(BigInteger val, MathContext mc) {
intVal = val; this(val);
if (mc.precision > 0) if (mc.precision > 0)
roundThis(mc); roundThis(mc);
} }
...@@ -833,11 +910,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -833,11 +910,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal(BigInteger unscaledVal, int scale) { public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed // Negative scales are now allowed
intVal = unscaledVal; this(unscaledVal);
this.scale = scale; this.scale = scale;
if (unscaledVal.bitLength() <= MAX_BIGINT_BITS) {
intCompact = unscaledVal.longValue();
}
} }
/** /**
...@@ -856,7 +930,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -856,7 +930,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
intVal = unscaledVal; this(unscaledVal);
this.scale = scale; this.scale = scale;
if (mc.precision > 0) if (mc.precision > 0)
roundThis(mc); roundThis(mc);
...@@ -899,10 +973,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -899,10 +973,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(long val) { public BigDecimal(long val) {
if (compactLong(val)) this.intCompact = val;
intCompact = val; this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
else
intVal = BigInteger.valueOf(val);
} }
/** /**
...@@ -917,31 +989,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -917,31 +989,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(long val, MathContext mc) { public BigDecimal(long val, MathContext mc) {
if (compactLong(val)) this(val);
intCompact = val;
else
intVal = BigInteger.valueOf(val);
if (mc.precision > 0) if (mc.precision > 0)
roundThis(mc); roundThis(mc);
} }
/**
* Trusted internal constructor
*/
private BigDecimal(long val, int scale) {
this.intCompact = val;
this.scale = scale;
}
/**
* Trusted internal constructor
*/
private BigDecimal(BigInteger intVal, long val, int scale) {
this.intVal = intVal;
this.intCompact = val;
this.scale = scale;
}
// Static Factory Methods // Static Factory Methods
/** /**
...@@ -957,12 +1009,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -957,12 +1009,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* <tt>(unscaledVal &times; 10<sup>-scale</sup>)</tt>. * <tt>(unscaledVal &times; 10<sup>-scale</sup>)</tt>.
*/ */
public static BigDecimal valueOf(long unscaledVal, int scale) { public static BigDecimal valueOf(long unscaledVal, int scale) {
if (scale == 0 && unscaledVal >= 0 && unscaledVal <= 10) { if (scale == 0)
return zeroThroughTen[(int)unscaledVal]; return valueOf(unscaledVal);
else if (unscaledVal == 0) {
if (scale > 0 && scale < ZERO_SCALED_BY.length)
return ZERO_SCALED_BY[scale];
else
return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
} }
if (compactLong(unscaledVal)) return new BigDecimal(unscaledVal == INFLATED ?
return new BigDecimal(unscaledVal, scale); BigInteger.valueOf(unscaledVal) : null,
return new BigDecimal(BigInteger.valueOf(unscaledVal), scale); unscaledVal, scale, 0);
} }
/** /**
...@@ -976,7 +1033,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -976,7 +1033,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return a {@code BigDecimal} whose value is {@code val}. * @return a {@code BigDecimal} whose value is {@code val}.
*/ */
public static BigDecimal valueOf(long val) { public static BigDecimal valueOf(long val) {
return valueOf(val, 0); if (val >= 0 && val < zeroThroughTen.length)
return zeroThroughTen[(int)val];
else if (val != INFLATED)
return new BigDecimal(null, val, 0, 0);
return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
} }
/** /**
...@@ -1014,27 +1075,42 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1014,27 +1075,42 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this + augend} * @return {@code this + augend}
*/ */
public BigDecimal add(BigDecimal augend) { public BigDecimal add(BigDecimal augend) {
BigDecimal arg[] = {this, augend}; long xs = this.intCompact;
matchScale(arg); long ys = augend.intCompact;
BigInteger fst = (xs != INFLATED) ? null : this.intVal;
long x = arg[0].intCompact; BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
long y = arg[1].intCompact; int rscale = this.scale;
// Might be able to do a more clever check incorporating the long sdiff = (long)rscale - augend.scale;
// inflated check into the overflow computation. if (sdiff != 0) {
if (x != INFLATED && y != INFLATED) { if (sdiff < 0) {
long sum = x + y; int raise = checkScale(-sdiff);
/* rscale = augend.scale;
* If the sum is not an overflowed value, continue to use if (xs == INFLATED ||
* the compact representation. if either of x or y is (xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
* INFLATED, the sum should also be regarded as an fst = bigMultiplyPowerTen(raise);
* overflow. See "Hacker's Delight" section 2-12 for } else {
* explanation of the overflow test. int raise = augend.checkScale(sdiff);
*/ if (ys == INFLATED ||
if ( (((sum ^ x) & (sum ^ y)) >> 63) == 0L ) // not overflowed (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
return BigDecimal.valueOf(sum, arg[0].scale); snd = augend.bigMultiplyPowerTen(raise);
}
}
if (xs != INFLATED && ys != INFLATED) {
long sum = xs + ys;
// See "Hacker's Delight" section 2-12 for explanation of
// the overflow test.
if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
return new BigDecimal(null, sum, rscale, 0);
} }
return new BigDecimal(arg[0].inflate().intVal.add(arg[1].inflate().intVal), arg[0].scale); if (fst == null)
fst = BigInteger.valueOf(xs);
if (snd == null)
snd = BigInteger.valueOf(ys);
BigInteger sum = fst.add(snd);
return (fst.signum == snd.signum) ?
new BigDecimal(sum, INFLATED, rscale, 0) :
new BigDecimal(sum, rscale);
} }
/** /**
...@@ -1072,17 +1148,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1072,17 +1148,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// Could use a factory for zero instead of a new object // Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero) if (lhsIsZero && augendIsZero)
return new BigDecimal(BigInteger.ZERO, 0, preferredScale); return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
result = lhsIsZero ? augend.doRound(mc) : lhs.doRound(mc);
if (result.scale() == preferredScale) if (result.scale() == preferredScale)
return result; return result;
else if (result.scale() > preferredScale) else if (result.scale() > preferredScale) {
return new BigDecimal(result.intVal, result.intCompact, result.scale). BigDecimal scaledResult =
stripZerosToMatchScale(preferredScale); new BigDecimal(result.intVal, result.intCompact,
else { // result.scale < preferredScale result.scale, 0);
scaledResult.stripZerosToMatchScale(preferredScale);
return scaledResult;
} else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision(); int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale(); int scaleDiff = preferredScale - result.scale();
...@@ -1102,8 +1180,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1102,8 +1180,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
augend = arg[1]; augend = arg[1];
} }
return new BigDecimal(lhs.inflate().intVal.add(augend.inflate().intVal), BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
lhs.scale).doRound(mc); lhs.scale);
return doRound(d, mc);
} }
/** /**
...@@ -1181,28 +1260,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1181,28 +1260,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this - subtrahend} * @return {@code this - subtrahend}
*/ */
public BigDecimal subtract(BigDecimal subtrahend) { public BigDecimal subtract(BigDecimal subtrahend) {
BigDecimal arg[] = {this, subtrahend}; return add(subtrahend.negate());
matchScale(arg);
long x = arg[0].intCompact;
long y = arg[1].intCompact;
// Might be able to do a more clever check incorporating the
// inflated check into the overflow computation.
if (x != INFLATED && y != INFLATED) {
long difference = x - y;
/*
* If the difference is not an overflowed value, continue
* to use the compact representation. if either of x or y
* is INFLATED, the difference should also be regarded as
* an overflow. See "Hacker's Delight" section 2-12 for
* explanation of the overflow test.
*/
if ( ((x ^ y) & (difference ^ x) ) >> 63 == 0L ) // not overflowed
return BigDecimal.valueOf(difference, arg[0].scale);
}
return new BigDecimal(arg[0].inflate().intVal.subtract(arg[1].inflate().intVal),
arg[0].scale);
} }
/** /**
...@@ -1220,14 +1278,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1220,14 +1278,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
BigDecimal nsubtrahend = subtrahend.negate();
if (mc.precision == 0) if (mc.precision == 0)
return subtract(subtrahend); return add(nsubtrahend);
// share the special rounding code in add() // share the special rounding code in add()
this.inflate(); return add(nsubtrahend, mc);
subtrahend.inflate();
BigDecimal rhs = new BigDecimal(subtrahend.intVal.negate(), subtrahend.scale);
rhs.precision = subtrahend.precision;
return add(rhs, mc);
} }
/** /**
...@@ -1241,7 +1296,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1241,7 +1296,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal multiply(BigDecimal multiplicand) { public BigDecimal multiply(BigDecimal multiplicand) {
long x = this.intCompact; long x = this.intCompact;
long y = multiplicand.intCompact; long y = multiplicand.intCompact;
int productScale = checkScale((long)scale+multiplicand.scale); int productScale = checkScale((long)scale + multiplicand.scale);
// Might be able to do a more clever check incorporating the // Might be able to do a more clever check incorporating the
// inflated check into the overflow computation. // inflated check into the overflow computation.
...@@ -1250,16 +1305,26 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1250,16 +1305,26 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* If the product is not an overflowed value, continue * If the product is not an overflowed value, continue
* to use the compact representation. if either of x or y * to use the compact representation. if either of x or y
* is INFLATED, the product should also be regarded as * is INFLATED, the product should also be regarded as
* an overflow. See "Hacker's Delight" section 2-12 for * an overflow. Before using the overflow test suggested in
* explanation of the overflow test. * "Hacker's Delight" section 2-12, we perform quick checks
* using the precision information to see whether the overflow
* would occur since division is expensive on most CPUs.
*/ */
long product = x * y; long product = x * y;
if ( !(y != 0L && product/y != x) ) // not overflowed int prec = this.precision() + multiplicand.precision();
return BigDecimal.valueOf(product, productScale); if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
return new BigDecimal(null, product, productScale, 0);
return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
productScale, 0);
} }
BigInteger rb;
BigDecimal result = new BigDecimal(this.inflate().intVal.multiply(multiplicand.inflate().intVal), productScale); if (x == INFLATED && y == INFLATED)
return result; rb = this.intVal.multiply(multiplicand.intVal);
else if (x != INFLATED)
rb = multiplicand.intVal.multiply(x);
else
rb = this.intVal.multiply(y);
return new BigDecimal(rb, INFLATED, productScale, 0);
} }
/** /**
...@@ -1276,8 +1341,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1276,8 +1341,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0) if (mc.precision == 0)
return multiply(multiplicand); return multiply(multiplicand);
BigDecimal lhs = this; return doRound(this.multiply(multiplicand), mc);
return lhs.inflate().multiply(multiplicand.inflate()).doRound(mc);
} }
/** /**
...@@ -1311,7 +1375,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1311,7 +1375,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
/* /*
* IMPLEMENTATION NOTE: This method *must* return a new object * IMPLEMENTATION NOTE: This method *must* return a new object
* since dropDigits uses divide to generate a value whose * since divideAndRound uses divide to generate a value whose
* scale is then modified. * scale is then modified.
*/ */
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY) if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
...@@ -1321,87 +1385,103 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1321,87 +1385,103 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* produce correctly scaled quotient). * produce correctly scaled quotient).
* Take care to detect out-of-range scales * Take care to detect out-of-range scales
*/ */
BigDecimal dividend; BigDecimal dividend = this;
if (checkScale((long)scale + divisor.scale) >= this.scale) { if (checkScale((long)scale + divisor.scale) > this.scale)
dividend = this.setScale(scale + divisor.scale); dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
} else { else
dividend = this; divisor = divisor.setScale(checkScale((long)this.scale - scale),
divisor = divisor.setScale(checkScale((long)this.scale - scale)); ROUND_UNNECESSARY);
} return divideAndRound(dividend.intCompact, dividend.intVal,
divisor.intCompact, divisor.intVal,
boolean compact = dividend.intCompact != INFLATED && divisor.intCompact != INFLATED; scale, roundingMode, scale);
long div = INFLATED; }
long rem = INFLATED;;
BigInteger q=null, r=null; /**
* Internally used for division operation. The dividend and divisor are
if (compact) { * passed both in {@code long} format and {@code BigInteger} format. The
div = dividend.intCompact / divisor.intCompact; * returned {@code BigDecimal} object is the quotient whose scale is set to
rem = dividend.intCompact % divisor.intCompact; * the passed in scale. If the remainder is not zero, it will be rounded
} else { * based on the passed in roundingMode. Also, if the remainder is zero and
// Do the division and return result if it's exact. * the last parameter, i.e. preferredScale is NOT equal to scale, the
BigInteger i[] = dividend.inflate().intVal.divideAndRemainder(divisor.inflate().intVal); * trailing zeros of the result is stripped to match the preferredScale.
q = i[0]; */
r = i[1]; private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
} long ldivisor, BigInteger bdivisor,
int scale, int roundingMode,
// Check for exact result int preferredScale) {
if (compact) { boolean isRemainderZero; // record remainder is zero or not
if (rem == 0) int qsign; // quotient sign
return new BigDecimal(div, scale); long q = 0, r = 0; // store quotient & remainder in long
MutableBigInteger mq = null; // store quotient
MutableBigInteger mr = null; // store remainder
MutableBigInteger mdivisor = null;
boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
if (isLongDivision) {
q = ldividend / ldivisor;
if (roundingMode == ROUND_DOWN && scale == preferredScale)
return new BigDecimal(null, q, scale, 0);
r = ldividend % ldivisor;
isRemainderZero = (r == 0);
qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
} else { } else {
if (r.signum() == 0) if (bdividend == null)
return new BigDecimal(q, scale); bdividend = BigInteger.valueOf(ldividend);
} // Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
if (roundingMode == ROUND_UNNECESSARY) // Rounding prohibited mq = new MutableBigInteger();
throw new ArithmeticException("Rounding necessary"); if (ldivisor != INFLATED) {
r = mdividend.divide(ldivisor, mq);
/* Round as appropriate */ isRemainderZero = (r == 0);
int signum = dividend.signum() * divisor.signum(); // Sign of result qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
boolean increment;
if (roundingMode == ROUND_UP) { // Away from zero
increment = true;
} else if (roundingMode == ROUND_DOWN) { // Towards zero
increment = false;
} else if (roundingMode == ROUND_CEILING) { // Towards +infinity
increment = (signum > 0);
} else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
increment = (signum < 0);
} else { // Remaining modes based on nearest-neighbor determination
int cmpFracHalf;
if (compact) {
cmpFracHalf = longCompareTo(Math.abs(2*rem), Math.abs(divisor.intCompact));
} else { } else {
// add(r) here is faster than multiply(2) or shiftLeft(1) mdivisor = new MutableBigInteger(bdivisor.mag);
cmpFracHalf= r.add(r).abs().compareTo(divisor.intVal.abs()); mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
} }
if (cmpFracHalf < 0) { // We're closer to higher digit }
increment = false; boolean increment = false;
} else if (cmpFracHalf > 0) { // We're closer to lower digit if (!isRemainderZero) {
int cmpFracHalf;
/* Round as appropriate */
if (roundingMode == ROUND_UNNECESSARY) { // Rounding prohibited
throw new ArithmeticException("Rounding necessary");
} else if (roundingMode == ROUND_UP) { // Away from zero
increment = true; increment = true;
} else { // We're dead-center } else if (roundingMode == ROUND_DOWN) { // Towards zero
if (roundingMode == ROUND_HALF_UP) increment = false;
} else if (roundingMode == ROUND_CEILING) { // Towards +infinity
increment = (qsign > 0);
} else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
increment = (qsign < 0);
} else {
if (isLongDivision || ldivisor != INFLATED)
cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
else
cmpFracHalf = mr.compareHalf(mdivisor);
if (cmpFracHalf < 0)
increment = false; // We're closer to higher digit
else if (cmpFracHalf > 0) // We're closer to lower digit
increment = true;
else if (roundingMode == ROUND_HALF_UP)
increment = true; increment = true;
else if (roundingMode == ROUND_HALF_DOWN) else if (roundingMode == ROUND_HALF_DOWN)
increment = false; increment = false;
else { // roundingMode == ROUND_HALF_EVEN else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
if (compact) increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
increment = (div & 1L) != 0L;
else
increment = q.testBit(0); // true iff q is odd
}
} }
} }
BigDecimal res;
if (compact) { if (isLongDivision)
res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
else {
if (increment) if (increment)
div += signum; // guaranteed not to overflow mq.add(MutableBigInteger.ONE);
return new BigDecimal(div, scale); res = mq.toBigDecimal(qsign, scale);
} else {
return (increment
? new BigDecimal(q.add(BigInteger.valueOf(signum)), scale)
: new BigDecimal(q, scale));
} }
if (isRemainderZero && preferredScale != scale)
res.stripZerosToMatchScale(preferredScale);
return res;
} }
/** /**
...@@ -1499,10 +1579,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1499,10 +1579,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} }
// Calculate preferred scale // Calculate preferred scale
int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), int preferredScale = saturateLong((long)this.scale - divisor.scale);
Integer.MAX_VALUE), Integer.MIN_VALUE);
if (this.signum() == 0) // 0/y if (this.signum() == 0) // 0/y
return new BigDecimal(0, preferredScale); return (preferredScale >= 0 &&
preferredScale < ZERO_SCALED_BY.length) ?
ZERO_SCALED_BY[preferredScale] :
new BigDecimal(null, 0, preferredScale, 1);
else { else {
this.inflate(); this.inflate();
divisor.inflate(); divisor.inflate();
...@@ -1534,7 +1616,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1534,7 +1616,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// limit, we can add zeros too. // limit, we can add zeros too.
if (preferredScale > quotientScale) if (preferredScale > quotientScale)
return quotient.setScale(preferredScale); return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
return quotient; return quotient;
} }
...@@ -1554,14 +1636,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1554,14 +1636,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal divide(BigDecimal divisor, MathContext mc) { public BigDecimal divide(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0) int mcp = mc.precision;
if (mcp == 0)
return divide(divisor); return divide(divisor);
BigDecimal lhs = this.inflate(); // left-hand-side
BigDecimal rhs = divisor.inflate(); // right-hand-side
BigDecimal result; // work
long preferredScale = (long)lhs.scale() - rhs.scale();
BigDecimal dividend = this;
long preferredScale = (long)dividend.scale - divisor.scale;
// Now calculate the answer. We use the existing // Now calculate the answer. We use the existing
// divide-and-round method, but as this rounds to scale we have // divide-and-round method, but as this rounds to scale we have
// to normalize the values here to achieve the desired result. // to normalize the values here to achieve the desired result.
...@@ -1574,54 +1654,43 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1574,54 +1654,43 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// the right number of digits (except in the case of a result of // the right number of digits (except in the case of a result of
// 1.000... which can arise when x=y, or when rounding overflows // 1.000... which can arise when x=y, or when rounding overflows
// The 1.000... case will reduce properly to 1. // The 1.000... case will reduce properly to 1.
if (rhs.signum() == 0) { // x/0 if (divisor.signum() == 0) { // x/0
if (lhs.signum() == 0) // 0/0 if (dividend.signum() == 0) // 0/0
throw new ArithmeticException("Division undefined"); // NaN throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero"); throw new ArithmeticException("Division by zero");
} }
if (lhs.signum() == 0) // 0/y if (dividend.signum() == 0) // 0/y
return new BigDecimal(BigInteger.ZERO, return new BigDecimal(BigInteger.ZERO, 0,
(int)Math.max(Math.min(preferredScale, saturateLong(preferredScale), 1);
Integer.MAX_VALUE),
Integer.MIN_VALUE)); // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
int xscale = dividend.precision();
BigDecimal xprime = new BigDecimal(lhs.intVal.abs(), lhs.precision()); int yscale = divisor.precision();
BigDecimal yprime = new BigDecimal(rhs.intVal.abs(), rhs.precision()); dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
// xprime and yprime are now both in range 0.1 through 0.999... xscale, xscale);
if (mc.roundingMode == RoundingMode.CEILING || divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
mc.roundingMode == RoundingMode.FLOOR) { yscale, yscale);
// The floor (round toward negative infinity) and ceil if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
// (round toward positive infinity) rounding modes are not yscale = divisor.scale -= 1; // [that is, divisor *= 10]
// invariant under a sign flip. If xprime/yprime has a
// different sign than lhs/rhs, the rounding mode must be // In order to find out whether the divide generates the exact result,
// changed. // we avoid calling the above divide method. 'quotient' holds the
if ((xprime.signum() != lhs.signum()) ^ // return BigDecimal object whose scale will be set to 'scl'.
(yprime.signum() != rhs.signum())) { BigDecimal quotient;
mc = new MathContext(mc.precision, int scl = checkScale(preferredScale + yscale - xscale + mcp);
(mc.roundingMode==RoundingMode.CEILING)? if (checkScale((long)mcp + yscale) > xscale)
RoundingMode.FLOOR:RoundingMode.CEILING); dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
} else
} divisor = divisor.setScale(checkScale((long)xscale - mcp),
ROUND_UNNECESSARY);
if (xprime.compareTo(yprime) > 0) // satisfy constraint (b) quotient = divideAndRound(dividend.intCompact, dividend.intVal,
yprime.scale -= 1; // [that is, yprime *= 10] divisor.intCompact, divisor.intVal,
result = xprime.divide(yprime, mc.precision, mc.roundingMode.oldMode); scl, mc.roundingMode.oldMode,
// correct the scale of the result... checkScale(preferredScale));
result.scale = checkScale((long)yprime.scale - xprime.scale
- (rhs.scale - lhs.scale) + mc.precision);
// apply the sign
if (lhs.signum() != rhs.signum())
result = result.negate();
// doRound, here, only affects 1000000000 case. // doRound, here, only affects 1000000000 case.
result = result.doRound(mc); quotient = doRound(quotient, mc);
if (result.multiply(divisor).compareTo(this) == 0) { return quotient;
// Apply preferred scale rules for exact quotients
return result.stripZerosToMatchScale(preferredScale);
}
else {
return result;
}
} }
/** /**
...@@ -1637,17 +1706,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1637,17 +1706,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal divideToIntegralValue(BigDecimal divisor) { public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale // Calculate preferred scale
int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), int preferredScale = saturateLong((long)this.scale - divisor.scale);
Integer.MAX_VALUE), Integer.MIN_VALUE); if (this.compareMagnitude(divisor) < 0) {
this.inflate();
divisor.inflate();
if (this.abs().compareTo(divisor.abs()) < 0) {
// much faster when this << divisor // much faster when this << divisor
return BigDecimal.valueOf(0, preferredScale); return BigDecimal.valueOf(0, preferredScale);
} }
if(this.signum() == 0 && divisor.signum() != 0) if(this.signum() == 0 && divisor.signum() != 0)
return this.setScale(preferredScale); return this.setScale(preferredScale, ROUND_UNNECESSARY);
// Perform a divide with enough digits to round to a correct // Perform a divide with enough digits to round to a correct
// integer value; then remove any fractional digits // integer value; then remove any fractional digits
...@@ -1656,19 +1722,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1656,19 +1722,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
(long)Math.ceil(10.0*divisor.precision()/3.0) + (long)Math.ceil(10.0*divisor.precision()/3.0) +
Math.abs((long)this.scale() - divisor.scale()) + 2, Math.abs((long)this.scale() - divisor.scale()) + 2,
Integer.MAX_VALUE); Integer.MAX_VALUE);
BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits, BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
RoundingMode.DOWN)); RoundingMode.DOWN));
if (quotient.scale > 0) { if (quotient.scale > 0) {
quotient = quotient.setScale(0, RoundingMode.DOWN). quotient = quotient.setScale(0, RoundingMode.DOWN);
stripZerosToMatchScale(preferredScale); quotient.stripZerosToMatchScale(preferredScale);
} }
if (quotient.scale < preferredScale) { if (quotient.scale < preferredScale) {
// pad with zeros if necessary // pad with zeros if necessary
quotient = quotient.setScale(preferredScale); quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
} }
return quotient; return quotient;
} }
...@@ -1694,12 +1758,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1694,12 +1758,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0 || // exact result if (mc.precision == 0 || // exact result
(this.abs().compareTo(divisor.abs()) < 0) ) // zero result (this.compareMagnitude(divisor) < 0) ) // zero result
return divideToIntegralValue(divisor); return divideToIntegralValue(divisor);
// Calculate preferred scale // Calculate preferred scale
int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), int preferredScale = saturateLong((long)this.scale - divisor.scale);
Integer.MAX_VALUE), Integer.MIN_VALUE);
/* /*
* Perform a normal divide to mc.precision digits. If the * Perform a normal divide to mc.precision digits. If the
...@@ -1708,9 +1771,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1708,9 +1771,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* digits. Next, remove any fractional digits from the * digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value. * quotient and adjust the scale to the preferred value.
*/ */
BigDecimal result = this.divide(divisor, new MathContext(mc.precision, BigDecimal result = this.
RoundingMode.DOWN)); divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
int resultScale = result.scale();
if (result.scale() < 0) { if (result.scale() < 0) {
/* /*
...@@ -1721,7 +1783,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1721,7 +1783,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
BigDecimal product = result.multiply(divisor); BigDecimal product = result.multiply(divisor);
// If the quotient is the full integer value, // If the quotient is the full integer value,
// |dividend-product| < |divisor|. // |dividend-product| < |divisor|.
if (this.subtract(product).abs().compareTo(divisor.abs()) >= 0) { if (this.subtract(product).compareMagnitude(divisor) >= 0) {
throw new ArithmeticException("Division impossible"); throw new ArithmeticException("Division impossible");
} }
} else if (result.scale() > 0) { } else if (result.scale() > 0) {
...@@ -1736,11 +1798,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1736,11 +1798,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int precisionDiff; int precisionDiff;
if ((preferredScale > result.scale()) && if ((preferredScale > result.scale()) &&
(precisionDiff = mc.precision - result.precision()) > 0 ) { (precisionDiff = mc.precision - result.precision()) > 0) {
return result.setScale(result.scale() + return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) ); Math.min(precisionDiff, preferredScale - result.scale) );
} else } else {
return result.stripZerosToMatchScale(preferredScale); result.stripZerosToMatchScale(preferredScale);
return result;
}
} }
/** /**
...@@ -1949,7 +2013,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1949,7 +2013,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int mag = Math.abs(n); // magnitude of n int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) { if (mc.precision > 0) {
int elength = intLength(mag); // length of n in digits int elength = longDigitLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation"); throw new ArithmeticException("Invalid operation");
workmc = new MathContext(mc.precision + elength + 1, workmc = new MathContext(mc.precision + elength + 1,
...@@ -1974,7 +2038,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1974,7 +2038,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (n<0) // [hence mc.precision>0] if (n<0) // [hence mc.precision>0]
acc=ONE.divide(acc, workmc); acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros // round to final precision and strip zeros
return acc.doRound(mc); return doRound(acc, mc);
} }
/** /**
...@@ -2068,7 +2132,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2068,7 +2132,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal plus(MathContext mc) { public BigDecimal plus(MathContext mc) {
if (mc.precision == 0) // no rounding please if (mc.precision == 0) // no rounding please
return this; return this;
return this.doRound(mc); return doRound(this, mc);
} }
/** /**
...@@ -2109,7 +2173,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2109,7 +2173,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public int precision() { public int precision() {
int result = precision; int result = precision;
if (result == 0) { if (result == 0) {
result = digitLength(); long s = intCompact;
if (s != INFLATED)
result = longDigitLength(s);
else
result = bigDigitLength(inflate());
precision = result; precision = result;
} }
return result; return result;
...@@ -2125,7 +2193,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2125,7 +2193,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.2 * @since 1.2
*/ */
public BigInteger unscaledValue() { public BigInteger unscaledValue() {
return this.inflate().intVal; return this.inflate();
} }
// Rounding Modes // Rounding Modes
...@@ -2302,30 +2370,34 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2302,30 +2370,34 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY) if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode"); throw new IllegalArgumentException("Invalid rounding mode");
if (newScale == this.scale) // easy case int oldScale = this.scale;
if (newScale == oldScale) // easy case
return this; return this;
if (this.signum() == 0) // zero can have any scale if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale); return BigDecimal.valueOf(0, newScale);
if (newScale > this.scale) {
// [we can use checkScale to assure multiplier is valid]
int raise = checkScale((long)newScale - this.scale);
if (intCompact != INFLATED) {
long scaledResult = longTenToThe(intCompact, raise);
if (scaledResult != INFLATED)
return BigDecimal.valueOf(scaledResult, newScale);
this.inflate();
}
BigDecimal result = new BigDecimal(intVal.multiply(tenToThe(raise)), long rs = this.intCompact;
newScale); if (newScale > oldScale) {
if (this.precision > 0) int raise = checkScale((long)newScale - oldScale);
result.precision = this.precision + newScale - this.scale; BigInteger rb = null;
return result; if (rs == INFLATED ||
(rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
rb = bigMultiplyPowerTen(raise);
return new BigDecimal(rb, rs, newScale,
(precision > 0) ? precision + raise : 0);
} else {
// newScale < oldScale -- drop some digits
// Can't predict the precision due to the effect of rounding.
int drop = checkScale((long)oldScale - newScale);
if (drop < LONG_TEN_POWERS_TABLE.length)
return divideAndRound(rs, this.intVal,
LONG_TEN_POWERS_TABLE[drop], null,
newScale, roundingMode, newScale);
else
return divideAndRound(rs, this.intVal,
INFLATED, bigTenToThe(drop),
newScale, roundingMode, newScale);
} }
// scale < this.scale
// we cannot perfectly predict the precision after rounding
return divide(ONE, newScale, roundingMode);
} }
/** /**
...@@ -2388,12 +2460,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2388,12 +2460,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal movePointLeft(int n) { public BigDecimal movePointLeft(int n) {
// Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE // Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale + n); int newScale = checkScale((long)scale + n);
BigDecimal num; BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
if (intCompact != INFLATED) return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
num = BigDecimal.valueOf(intCompact, newScale);
else
num = new BigDecimal(intVal, newScale);
return (num.scale<0 ? num.setScale(0) : num);
} }
/** /**
...@@ -2414,12 +2482,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2414,12 +2482,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal movePointRight(int n) { public BigDecimal movePointRight(int n) {
// Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE // Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale - n); int newScale = checkScale((long)scale - n);
BigDecimal num; BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
if (intCompact != INFLATED) return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
num = BigDecimal.valueOf(intCompact, newScale);
else
num = new BigDecimal(intVal, newScale);
return (num.scale<0 ? num.setScale(0) : num);
} }
/** /**
...@@ -2433,10 +2497,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2433,10 +2497,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal scaleByPowerOfTen(int n) { public BigDecimal scaleByPowerOfTen(int n) {
this.inflate(); return new BigDecimal(intVal, intCompact,
BigDecimal num = new BigDecimal(intVal, checkScale((long)scale - n)); checkScale((long)scale - n), precision);
num.precision = precision;
return num;
} }
/** /**
...@@ -2454,7 +2516,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2454,7 +2516,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal stripTrailingZeros() { public BigDecimal stripTrailingZeros() {
this.inflate(); this.inflate();
return (new BigDecimal(intVal, scale)).stripZerosToMatchScale(Long.MIN_VALUE); BigDecimal result = new BigDecimal(intVal, scale);
result.stripZerosToMatchScale(Long.MIN_VALUE);
return result;
} }
// Comparison Operations // Comparison Operations
...@@ -2477,32 +2541,67 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2477,32 +2541,67 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* less than, equal to, or greater than {@code val}. * less than, equal to, or greater than {@code val}.
*/ */
public int compareTo(BigDecimal val) { public int compareTo(BigDecimal val) {
if (this.scale == val.scale && // Quick path for equal scale and non-inflated case.
this.intCompact != INFLATED && if (scale == val.scale) {
val.intCompact != INFLATED) long xs = intCompact;
return longCompareTo(this.intCompact, val.intCompact); long ys = val.intCompact;
if (xs != INFLATED && ys != INFLATED)
// Optimization: would run fine without the next three lines return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
int sigDiff = signum() - val.signum(); }
if (sigDiff != 0) int xsign = this.signum();
return (sigDiff > 0 ? 1 : -1); int ysign = val.signum();
if (xsign != ysign)
// If the (adjusted) exponents are different we do not need to return (xsign > ysign) ? 1 : -1;
// expensively match scales and compare the significands if (xsign == 0)
int aethis = this.precision() - this.scale; // [-1] return 0;
int aeval = val.precision() - val.scale; // [-1] int cmp = compareMagnitude(val);
if (aethis < aeval) return (xsign > 0) ? cmp : -cmp;
return -this.signum(); }
else if (aethis > aeval)
return this.signum(); /**
* Version of compareTo that ignores sign.
// Scale and compare intVals */
BigDecimal arg[] = {this, val}; private int compareMagnitude(BigDecimal val) {
matchScale(arg); // Match scales, avoid unnecessary inflation
if (arg[0].intCompact != INFLATED && long ys = val.intCompact;
arg[1].intCompact != INFLATED) long xs = this.intCompact;
return longCompareTo(arg[0].intCompact, arg[1].intCompact); if (xs == 0)
return arg[0].inflate().intVal.compareTo(arg[1].inflate().intVal); return (ys == 0) ? 0 : -1;
if (ys == 0)
return 1;
int sdiff = this.scale - val.scale;
if (sdiff != 0) {
// Avoid matching scales if the (adjusted) exponents differ
int xae = this.precision() - this.scale; // [-1]
int yae = val.precision() - val.scale; // [-1]
if (xae < yae)
return -1;
if (xae > yae)
return 1;
BigInteger rb = null;
if (sdiff < 0) {
if ( (xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
ys == INFLATED) {
rb = bigMultiplyPowerTen(-sdiff);
return rb.compareMagnitude(val.intVal);
}
} else { // sdiff > 0
if ( (ys == INFLATED ||
(ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
xs == INFLATED) {
rb = val.bigMultiplyPowerTen(sdiff);
return this.intVal.compareMagnitude(rb);
}
}
}
if (xs != INFLATED)
return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
else if (ys != INFLATED)
return 1;
else
return this.intVal.compareMagnitude(val.intVal);
} }
/** /**
...@@ -2521,15 +2620,25 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2521,15 +2620,25 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #compareTo(java.math.BigDecimal) * @see #compareTo(java.math.BigDecimal)
* @see #hashCode * @see #hashCode
*/ */
@Override
public boolean equals(Object x) { public boolean equals(Object x) {
if (!(x instanceof BigDecimal)) if (!(x instanceof BigDecimal))
return false; return false;
BigDecimal xDec = (BigDecimal) x; BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale) if (scale != xDec.scale)
return false; return false;
if (this.intCompact != INFLATED && xDec.intCompact != INFLATED) long s = this.intCompact;
return this.intCompact == xDec.intCompact; long xs = xDec.intCompact;
return this.inflate().intVal.equals(xDec.inflate().intVal); if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflate().equals(xDec.inflate());
} }
/** /**
...@@ -2572,11 +2681,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2572,11 +2681,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return hash code for this {@code BigDecimal}. * @return hash code for this {@code BigDecimal}.
* @see #equals(Object) * @see #equals(Object)
*/ */
@Override
public int hashCode() { public int hashCode() {
if (intCompact != INFLATED) { if (intCompact != INFLATED) {
long val2 = (intCompact < 0)?-intCompact:intCompact; long val2 = (intCompact < 0)? -intCompact : intCompact;
int temp = (int)( ((int)(val2 >>> 32)) * 31 + int temp = (int)( ((int)(val2 >>> 32)) * 31 +
(val2 & 0xffffffffL)); (val2 & LONG_MASK));
return 31*((intCompact < 0) ?-temp:temp) + scale; return 31*((intCompact < 0) ?-temp:temp) + scale;
} else } else
return 31*intVal.hashCode() + scale; return 31*intVal.hashCode() + scale;
...@@ -2683,10 +2793,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2683,10 +2793,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see Character#forDigit * @see Character#forDigit
* @see #BigDecimal(java.lang.String) * @see #BigDecimal(java.lang.String)
*/ */
@Override
public String toString() { public String toString() {
if (stringCache == null) String sc = stringCache;
stringCache = layoutChars(true); if (sc == null)
return stringCache; stringCache = sc = layoutChars(true);
return sc;
} }
/** /**
...@@ -2802,7 +2914,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2802,7 +2914,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigInteger toBigInteger() { public BigInteger toBigInteger() {
// force to an integer, quietly // force to an integer, quietly
return this.setScale(0, ROUND_DOWN).inflate().intVal; return this.setScale(0, ROUND_DOWN).inflate();
} }
/** /**
...@@ -2817,7 +2929,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2817,7 +2929,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigInteger toBigIntegerExact() { public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0 // round to an integer, with Exception if decimal part non-0
return this.setScale(0, ROUND_UNNECESSARY).inflate().intVal; return this.setScale(0, ROUND_UNNECESSARY).inflate();
} }
/** /**
...@@ -2868,10 +2980,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2868,10 +2980,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if ((this.precision() - this.scale) <= 0) if ((this.precision() - this.scale) <= 0)
throw new ArithmeticException("Rounding necessary"); throw new ArithmeticException("Rounding necessary");
// round to an integer, with Exception if decimal part non-0 // round to an integer, with Exception if decimal part non-0
BigDecimal num = this.setScale(0, ROUND_UNNECESSARY).inflate(); BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num); LongOverflow.check(num);
return num.intVal.longValue(); return num.inflate().longValue();
} }
private static class LongOverflow { private static class LongOverflow {
...@@ -2882,6 +2994,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2882,6 +2994,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE); private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
public static void check(BigDecimal num) { public static void check(BigDecimal num) {
num.inflate();
if ((num.intVal.compareTo(LONGMIN) < 0) || if ((num.intVal.compareTo(LONGMIN) < 0) ||
(num.intVal.compareTo(LONGMAX) > 0)) (num.intVal.compareTo(LONGMAX) > 0))
throw new java.lang.ArithmeticException("Overflow"); throw new java.lang.ArithmeticException("Overflow");
...@@ -3037,7 +3150,105 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3037,7 +3150,105 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return BigDecimal.valueOf(1, this.scale()); return BigDecimal.valueOf(1, this.scale());
} }
// Private "Helper" Methods
// Private class to build a string representation for BigDecimal object.
// "StringBuilderHelper" is constructed as a thread local variable so it is
// thread safe. The StringBuilder field acts as a buffer to hold the temporary
// representation of BigDecimal. The cmpCharArray holds all the characters for
// the compact representation of BigDecimal (except for '-' sign' if it is
// negative) if its intCompact field is not INFLATED. It is shared by all
// calls to toString() and its variants in that particular thread.
static class StringBuilderHelper {
final StringBuilder sb; // Placeholder for BigDecimal string
final char[] cmpCharArray; // character array to place the intCompact
StringBuilderHelper() {
sb = new StringBuilder();
// All non negative longs can be made to fit into 19 character array.
cmpCharArray = new char[19];
}
// Accessors.
StringBuilder getStringBuilder() {
sb.setLength(0);
return sb;
}
char[] getCompactCharArray() {
return cmpCharArray;
}
/**
* Places characters representing the intCompact in {@code long} into
* cmpCharArray and returns the offset to the array where the
* representation starts.
*
* @param intCompact the number to put into the cmpCharArray.
* @return offset to the array where the representation starts.
* Note: intCompact must be greater or equal to zero.
*/
int putIntCompact(long intCompact) {
assert intCompact >= 0;
long q;
int r;
// since we start from the least significant digit, charPos points to
// the last character in cmpCharArray.
int charPos = cmpCharArray.length;
// Get 2 digits/iteration using longs until quotient fits into an int
while (intCompact > Integer.MAX_VALUE) {
q = intCompact / 100;
r = (int)(intCompact - q * 100);
intCompact = q;
cmpCharArray[--charPos] = DIGIT_ONES[r];
cmpCharArray[--charPos] = DIGIT_TENS[r];
}
// Get 2 digits/iteration using ints when i2 >= 100
int q2;
int i2 = (int)intCompact;
while (i2 >= 100) {
q2 = i2 / 100;
r = i2 - q2 * 100;
i2 = q2;
cmpCharArray[--charPos] = DIGIT_ONES[r];
cmpCharArray[--charPos] = DIGIT_TENS[r];
}
cmpCharArray[--charPos] = DIGIT_ONES[i2];
if (i2 >= 10)
cmpCharArray[--charPos] = DIGIT_TENS[i2];
return charPos;
}
final static char[] DIGIT_TENS = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
};
final static char[] DIGIT_ONES = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
};
}
/** /**
* Lay out this {@code BigDecimal} into a {@code char[]} array. * Lay out this {@code BigDecimal} into a {@code char[]} array.
...@@ -3054,41 +3265,47 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3054,41 +3265,47 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
Long.toString(intCompact): Long.toString(intCompact):
intVal.toString(); intVal.toString();
StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
char[] coeff;
int offset; // offset is the starting index for coeff array
// Get the significand as an absolute value // Get the significand as an absolute value
char coeff[]; if (intCompact != INFLATED) {
if (intCompact != INFLATED) offset = sbHelper.putIntCompact(Math.abs(intCompact));
coeff = Long.toString(Math.abs(intCompact)).toCharArray(); coeff = sbHelper.getCompactCharArray();
else } else {
coeff = intVal.abs().toString().toCharArray(); offset = 0;
coeff = intVal.abs().toString().toCharArray();
}
// Construct a buffer, with sufficient capacity for all cases. // Construct a buffer, with sufficient capacity for all cases.
// If E-notation is needed, length will be: +1 if negative, +1 // If E-notation is needed, length will be: +1 if negative, +1
// if '.' needed, +2 for "E+", + up to 10 for adjusted exponent. // if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
// Otherwise it could have +1 if negative, plus leading "0.00000" // Otherwise it could have +1 if negative, plus leading "0.00000"
StringBuilder buf=new StringBuilder(coeff.length+14); StringBuilder buf = sbHelper.getStringBuilder();
if (signum() < 0) // prefix '-' if negative if (signum() < 0) // prefix '-' if negative
buf.append('-'); buf.append('-');
long adjusted = -(long)scale + (coeff.length-1); int coeffLen = coeff.length - offset;
long adjusted = -(long)scale + (coeffLen -1);
if ((scale >= 0) && (adjusted >= -6)) { // plain number if ((scale >= 0) && (adjusted >= -6)) { // plain number
int pad = scale - coeff.length; // count of padding zeros int pad = scale - coeffLen; // count of padding zeros
if (pad >= 0) { // 0.xxx form if (pad >= 0) { // 0.xxx form
buf.append('0'); buf.append('0');
buf.append('.'); buf.append('.');
for (; pad>0; pad--) { for (; pad>0; pad--) {
buf.append('0'); buf.append('0');
} }
buf.append(coeff); buf.append(coeff, offset, coeffLen);
} else { // xx.xx form } else { // xx.xx form
buf.append(coeff, 0, -pad); buf.append(coeff, offset, -pad);
buf.append('.'); buf.append('.');
buf.append(coeff, -pad, scale); buf.append(coeff, -pad + offset, scale);
} }
} else { // E-notation is needed } else { // E-notation is needed
if (sci) { // Scientific notation if (sci) { // Scientific notation
buf.append(coeff[0]); // first character buf.append(coeff[offset]); // first character
if (coeff.length > 1) { // more to come if (coeffLen > 1) { // more to come
buf.append('.'); buf.append('.');
buf.append(coeff, 1, coeff.length-1); buf.append(coeff, offset + 1, coeffLen - 1);
} }
} else { // Engineering notation } else { // Engineering notation
int sig = (int)(adjusted % 3); int sig = (int)(adjusted % 3);
...@@ -3112,15 +3329,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3112,15 +3329,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
default: default:
throw new AssertionError("Unexpected sig value " + sig); throw new AssertionError("Unexpected sig value " + sig);
} }
} else if (sig >= coeff.length) { // significand all in integer } else if (sig >= coeffLen) { // significand all in integer
buf.append(coeff, 0, coeff.length); buf.append(coeff, offset, coeffLen);
// may need some zeros, too // may need some zeros, too
for (int i = sig - coeff.length; i > 0; i--) for (int i = sig - coeffLen; i > 0; i--)
buf.append('0'); buf.append('0');
} else { // xx.xxE form } else { // xx.xxE form
buf.append(coeff, 0, sig); buf.append(coeff, offset, sig);
buf.append('.'); buf.append('.');
buf.append(coeff, sig, coeff.length-sig); buf.append(coeff, offset + sig, coeffLen - sig);
} }
} }
if (adjusted != 0) { // [!sci could have made 0] if (adjusted != 0) { // [!sci could have made 0]
...@@ -3139,9 +3356,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3139,9 +3356,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @param n the power of ten to be returned (>=0) * @param n the power of ten to be returned (>=0)
* @return a {@code BigInteger} with the value (10<sup>n</sup>) * @return a {@code BigInteger} with the value (10<sup>n</sup>)
*/ */
private static BigInteger tenToThe(int n) { private static BigInteger bigTenToThe(int n) {
if (n < TENPOWERS.length) // use value from constant array if (n < 0)
return TENPOWERS[n]; return BigInteger.ZERO;
if (n < BIG_TEN_POWERS_TABLE_MAX) {
BigInteger[] pows = BIG_TEN_POWERS_TABLE;
if (n < pows.length)
return pows[n];
else
return expandBigIntegerTenPowers(n);
}
// BigInteger.pow is slow, so make 10**n by constructing a // BigInteger.pow is slow, so make 10**n by constructing a
// BigInteger from a character string (still not very fast) // BigInteger from a character string (still not very fast)
char tenpow[] = new char[n + 1]; char tenpow[] = new char[n + 1];
...@@ -3150,58 +3375,145 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3150,58 +3375,145 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
tenpow[i] = '0'; tenpow[i] = '0';
return new BigInteger(tenpow); return new BigInteger(tenpow);
} }
private static BigInteger TENPOWERS[] = {BigInteger.ONE,
/**
* Expand the BIG_TEN_POWERS_TABLE array to contain at least 10**n.
*
* @param n the power of ten to be returned (>=0)
* @return a {@code BigDecimal} with the value (10<sup>n</sup>) and
* in the meantime, the BIG_TEN_POWERS_TABLE array gets
* expanded to the size greater than n.
*/
private static BigInteger expandBigIntegerTenPowers(int n) {
synchronized(BigDecimal.class) {
BigInteger[] pows = BIG_TEN_POWERS_TABLE;
int curLen = pows.length;
// The following comparison and the above synchronized statement is
// to prevent multiple threads from expanding the same array.
if (curLen <= n) {
int newLen = curLen << 1;
while (newLen <= n)
newLen <<= 1;
pows = Arrays.copyOf(pows, newLen);
for (int i = curLen; i < newLen; i++)
pows[i] = pows[i - 1].multiply(BigInteger.TEN);
// Based on the following facts:
// 1. pows is a private local varible;
// 2. the following store is a volatile store.
// the newly created array elements can be safely published.
BIG_TEN_POWERS_TABLE = pows;
}
return pows[n];
}
}
private static final long[] LONG_TEN_POWERS_TABLE = {
1, // 0 / 10^0
10, // 1 / 10^1
100, // 2 / 10^2
1000, // 3 / 10^3
10000, // 4 / 10^4
100000, // 5 / 10^5
1000000, // 6 / 10^6
10000000, // 7 / 10^7
100000000, // 8 / 10^8
1000000000, // 9 / 10^9
10000000000L, // 10 / 10^10
100000000000L, // 11 / 10^11
1000000000000L, // 12 / 10^12
10000000000000L, // 13 / 10^13
100000000000000L, // 14 / 10^14
1000000000000000L, // 15 / 10^15
10000000000000000L, // 16 / 10^16
100000000000000000L, // 17 / 10^17
1000000000000000000L // 18 / 10^18
};
private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
BigInteger.valueOf(10), BigInteger.valueOf(100), BigInteger.valueOf(10), BigInteger.valueOf(100),
BigInteger.valueOf(1000), BigInteger.valueOf(10000), BigInteger.valueOf(1000), BigInteger.valueOf(10000),
BigInteger.valueOf(100000), BigInteger.valueOf(1000000), BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000), BigInteger.valueOf(100000000), BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
BigInteger.valueOf(1000000000)}; BigInteger.valueOf(1000000000),
BigInteger.valueOf(10000000000L),
BigInteger.valueOf(100000000000L),
BigInteger.valueOf(1000000000000L),
BigInteger.valueOf(10000000000000L),
BigInteger.valueOf(100000000000000L),
BigInteger.valueOf(1000000000000000L),
BigInteger.valueOf(10000000000000000L),
BigInteger.valueOf(100000000000000000L),
BigInteger.valueOf(1000000000000000000L)
};
private static final int BIG_TEN_POWERS_TABLE_INITLEN =
BIG_TEN_POWERS_TABLE.length;
private static final int BIG_TEN_POWERS_TABLE_MAX =
16 * BIG_TEN_POWERS_TABLE_INITLEN;
private static final long THRESHOLDS_TABLE[] = {
Long.MAX_VALUE, // 0
Long.MAX_VALUE/10L, // 1
Long.MAX_VALUE/100L, // 2
Long.MAX_VALUE/1000L, // 3
Long.MAX_VALUE/10000L, // 4
Long.MAX_VALUE/100000L, // 5
Long.MAX_VALUE/1000000L, // 6
Long.MAX_VALUE/10000000L, // 7
Long.MAX_VALUE/100000000L, // 8
Long.MAX_VALUE/1000000000L, // 9
Long.MAX_VALUE/10000000000L, // 10
Long.MAX_VALUE/100000000000L, // 11
Long.MAX_VALUE/1000000000000L, // 12
Long.MAX_VALUE/10000000000000L, // 13
Long.MAX_VALUE/100000000000000L, // 14
Long.MAX_VALUE/1000000000000000L, // 15
Long.MAX_VALUE/10000000000000000L, // 16
Long.MAX_VALUE/100000000000000000L, // 17
Long.MAX_VALUE/1000000000000000000L // 18
};
/** /**
* Compute val * 10 ^ n; return this product if it is * Compute val * 10 ^ n; return this product if it is
* representable as a long, INFLATED otherwise. * representable as a long, INFLATED otherwise.
*/ */
private static long longTenToThe(long val, int n) { private static long longMultiplyPowerTen(long val, int n) {
// System.err.print("\tval " + val + "\t power " + n + "\tresult "); if (val == 0 || n <= 0)
if (n >= 0 && n < thresholds.length) { return val;
if (Math.abs(val) <= thresholds[n][0] ) { long[] tab = LONG_TEN_POWERS_TABLE;
// System.err.println(val * thresholds[n][1]); long[] bounds = THRESHOLDS_TABLE;
return val * thresholds[n][1]; if (n < tab.length && n < bounds.length) {
} long tenpower = tab[n];
if (val == 1)
return tenpower;
if (Math.abs(val) <= bounds[n])
return val * tenpower;
} }
// System.err.println(INFLATED);
return INFLATED; return INFLATED;
} }
private static long thresholds[][] = { /**
{Long.MAX_VALUE, 1L}, // 0 * Compute this * 10 ^ n.
{Long.MAX_VALUE/10L, 10L}, // 1 * Needed mainly to allow special casing to trap zero value
{Long.MAX_VALUE/100L, 100L}, // 2 */
{Long.MAX_VALUE/1000L, 1000L}, // 3 private BigInteger bigMultiplyPowerTen(int n) {
{Long.MAX_VALUE/10000L, 10000L}, // 4 if (n <= 0)
{Long.MAX_VALUE/100000L, 100000L}, // 5 return this.inflate();
{Long.MAX_VALUE/1000000L, 1000000L}, // 6
{Long.MAX_VALUE/10000000L, 10000000L}, // 7
{Long.MAX_VALUE/100000000L, 100000000L}, // 8
{Long.MAX_VALUE/1000000000L, 1000000000L}, // 9
{Long.MAX_VALUE/10000000000L, 10000000000L}, // 10
{Long.MAX_VALUE/100000000000L, 100000000000L}, // 11
{Long.MAX_VALUE/1000000000000L, 1000000000000L},// 12
{Long.MAX_VALUE/100000000000000L, 10000000000000L},// 13
};
private static boolean compactLong(long val) { if (intCompact != INFLATED)
return (val != Long.MIN_VALUE); return bigTenToThe(n).multiply(intCompact);
else
return intVal.multiply(bigTenToThe(n));
} }
/** /**
* Assign appropriate BigInteger to intVal field if intVal is * Assign appropriate BigInteger to intVal field if intVal is
* null, i.e. the compact representation is in use. * null, i.e. the compact representation is in use.
*/ */
private BigDecimal inflate() { private BigInteger inflate() {
if (intVal == null) if (intVal == null)
intVal = BigInteger.valueOf(intCompact); intVal = BigInteger.valueOf(intCompact);
return this; return intVal;
} }
/** /**
...@@ -3218,10 +3530,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3218,10 +3530,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code BigDecimal}s to be aligned. * {@code BigDecimal}s to be aligned.
*/ */
private static void matchScale(BigDecimal[] val) { private static void matchScale(BigDecimal[] val) {
if (val[0].scale < val[1].scale) if (val[0].scale == val[1].scale) {
val[0] = val[0].setScale(val[1].scale); return;
else if (val[1].scale < val[0].scale) } else if (val[0].scale < val[1].scale) {
val[1] = val[1].setScale(val[0].scale); val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
} else if (val[1].scale < val[0].scale) {
val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
}
} }
/** /**
...@@ -3240,9 +3555,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3240,9 +3555,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed] // [all values of scale are now allowed]
} }
// Set intCompact to uninitialized value; could also see if the intCompact = compactValFor(intVal);
// intVal was small enough to fit as a compact value.
intCompact = INFLATED;
} }
/** /**
...@@ -3259,84 +3572,66 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3259,84 +3572,66 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
s.defaultWriteObject(); s.defaultWriteObject();
} }
/** /**
* Returns the length of this {@code BigDecimal}, in decimal digits. * Returns the length of the absolute value of a {@code long}, in decimal
* * digits.
* Notes:
*<ul>
* <li> This is performance-critical; most operations where a
* context is supplied will need at least one call to this
* method.
*
* <li> This should be a method on BigInteger; the call to this
* method in precision() can then be replaced with the
* term: intVal.digitLength(). It could also be called
* precision() in BigInteger.
*
* Better still -- the precision lookaside could be moved to
* BigInteger, too.
* *
* <li> This could/should use MutableBigIntegers directly for the * @param x the {@code long}
* reduction loop. * @return the length of the unscaled value, in deciaml digits.
*<ul>
* @return the length of the unscaled value, in decimal digits
*/ */
private int digitLength() { private static int longDigitLength(long x) {
if (intCompact != INFLATED && Math.abs(intCompact) <= Integer.MAX_VALUE) /*
return intLength(Math.abs((int)intCompact)); * As described in "Bit Twiddling Hacks" by Sean Anderson,
if (signum() == 0) // 0 is one decimal digit * (http://graphics.stanford.edu/~seander/bithacks.html)
* integer log 10 of x is within 1 of
* (1233/4096)* (1 + integer log 2 of x).
* The fraction 1233/4096 approximates log10(2). So we first
* do a version of log2 (a variant of Long class with
* pre-checks and opposite directionality) and then scale and
* check against powers table. This is a little simpler in
* present context than the version in Hacker's Delight sec
* 11-4. Adding one to bit length allows comparing downward
* from the LONG_TEN_POWERS_TABLE that we need anyway.
*/
assert x != INFLATED;
if (x < 0)
x = -x;
if (x < 10) // must screen for 0, might as well 10
return 1; return 1;
this.inflate(); int n = 64; // not 63, to avoid needing to add 1 later
// we have a nonzero magnitude int y = (int)(x >>> 32);
BigInteger work = intVal; if (y == 0) { n -= 32; y = (int)x; }
int digits = 0; // counter if (y >>> 16 == 0) { n -= 16; y <<= 16; }
for (;work.mag.length>1;) { if (y >>> 24 == 0) { n -= 8; y <<= 8; }
// here when more than one integer in the magnitude; divide if (y >>> 28 == 0) { n -= 4; y <<= 4; }
// by a billion (reduce by 9 digits) and try again if (y >>> 30 == 0) { n -= 2; y <<= 2; }
work = work.divide(TENPOWERS[9]); int r = (((y >>> 31) + n) * 1233) >>> 12;
digits += 9; long[] tab = LONG_TEN_POWERS_TABLE;
if (work.signum() == 0) // the division was exact // if r >= length, must have max possible digits for long
return digits; // (a power of a billion) return (r >= tab.length || x < tab[r])? r : r+1;
} }
// down to a simple nonzero integer
digits += intLength(work.mag[0]); /**
// System.out.println("digitLength... "+this+" -> "+digits); * Returns the length of the absolute value of a BigInteger, in
return digits; * decimal digits.
} *
* @param b the BigInteger
private static int[] ilogTable = {
0,
9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
Integer.MAX_VALUE};
/**
* Returns the length of an unsigned {@code int}, in decimal digits.
* @param i the {@code int} (treated as unsigned)
* @return the length of the unscaled value, in decimal digits * @return the length of the unscaled value, in decimal digits
*/ */
private int intLength(int x) { private static int bigDigitLength(BigInteger b) {
int digits; /*
if (x < 0) { // 'negative' is 10 digits unsigned * Same idea as the long version, but we need a better
return 10; * approximation of log10(2). Using 646456993/2^31
} else { // positive integer * is accurate up to max possible reported bitLength.
if (x <= 9) */
return 1; if (b.signum == 0)
// "Hacker's Delight" section 11-4 return 1;
for(int i = -1; ; i++) { int r = (int)((((long)b.bitLength() + 1) * 646456993) >>> 31);
if (x <= ilogTable[i+1]) return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
return i +1;
}
}
} }
/** /**
* Remove insignificant trailing zeros from this * Remove insignificant trailing zeros from this
* {@code BigDecimal} until the preferred scale is reached or no * {@code BigDecimal} until the preferred scale is reached or no
...@@ -3352,10 +3647,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3352,10 +3647,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* to be closed to the preferred scale. * to be closed to the preferred scale.
*/ */
private BigDecimal stripZerosToMatchScale(long preferredScale) { private BigDecimal stripZerosToMatchScale(long preferredScale) {
boolean compact = (intCompact != INFLATED);
this.inflate(); this.inflate();
BigInteger qr[]; // quotient-remainder pair BigInteger qr[]; // quotient-remainder pair
while ( intVal.abs().compareTo(BigInteger.TEN) >= 0 && while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
scale > preferredScale) { scale > preferredScale) {
if (intVal.testBit(0)) if (intVal.testBit(0))
break; // odd number cannot end in 0 break; // odd number cannot end in 0
...@@ -3367,17 +3661,16 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3367,17 +3661,16 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (precision > 0) // adjust precision if known if (precision > 0) // adjust precision if known
precision--; precision--;
} }
if (compact) if (intVal != null)
intCompact = intVal.longValue(); intCompact = compactValFor(intVal);
return this; return this;
} }
/** /**
* Check a scale for Underflow or Overflow. If this BigDecimal is * Check a scale for Underflow or Overflow. If this BigDecimal is
* uninitialized or initialized and nonzero, throw an exception if * nonzero, throw an exception if the scale is outof range. If this
* the scale is out of range. If this is zero, saturate the scale * is zero, saturate the scale to the extreme value of the right
* to the extreme value of the right sign if the scale is out of * sign if the scale is out of range.
* range.
* *
* @param val The new scale. * @param val The new scale.
* @throws ArithmeticException (overflow or underflow) if the new * @throws ArithmeticException (overflow or underflow) if the new
...@@ -3385,19 +3678,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3385,19 +3678,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return validated scale as an int. * @return validated scale as an int.
*/ */
private int checkScale(long val) { private int checkScale(long val) {
if ((int)val != val) { int asInt = (int)val;
if ((this.intCompact != INFLATED && this.intCompact != 0) || if (asInt != val) {
(this.intVal != null && this.signum() != 0) || asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
(this.intVal == null && this.intCompact == INFLATED) ) { BigInteger b;
if (val > Integer.MAX_VALUE) if (intCompact != 0 &&
throw new ArithmeticException("Underflow"); ((b = intVal) == null || b.signum() != 0))
if (val < Integer.MIN_VALUE) throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
throw new ArithmeticException("Overflow");
} else {
return (val > Integer.MAX_VALUE)?Integer.MAX_VALUE:Integer.MIN_VALUE;
}
} }
return (int)val; return asInt;
} }
/** /**
...@@ -3410,7 +3699,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3410,7 +3699,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* rounding mode is {@code UNNECESSARY}. * rounding mode is {@code UNNECESSARY}.
*/ */
private BigDecimal roundOp(MathContext mc) { private BigDecimal roundOp(MathContext mc) {
BigDecimal rounded = doRound(mc); BigDecimal rounded = doRound(this, mc);
return rounded; return rounded;
} }
...@@ -3426,7 +3715,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3426,7 +3715,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code BigDecimal} operation would require rounding. * {@code BigDecimal} operation would require rounding.
*/ */
private void roundThis(MathContext mc) { private void roundThis(MathContext mc) {
BigDecimal rounded = doRound(mc); BigDecimal rounded = doRound(this, mc);
if (rounded == this) // wasn't rounded if (rounded == this) // wasn't rounded
return; return;
this.intVal = rounded.intVal; this.intVal = rounded.intVal;
...@@ -3448,56 +3737,56 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3448,56 +3737,56 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code RoundingMode.UNNECESSARY} and the * {@code RoundingMode.UNNECESSARY} and the
* result is inexact. * result is inexact.
*/ */
private BigDecimal doRound(MathContext mc) { private static BigDecimal doRound(BigDecimal d, MathContext mc) {
this.inflate(); int mcp = mc.precision;
if (precision == 0) { int drop;
if (mc.roundingMax != null // This might (rarely) iterate to cover the 999=>1000 case
&& intVal.compareTo(mc.roundingMax) < 0 while ((drop = d.precision() - mcp) > 0) {
&& intVal.compareTo(mc.roundingMin) > 0) int newScale = d.checkScale((long)d.scale - drop);
return this; // no rounding needed int mode = mc.roundingMode.oldMode;
precision(); // find it if (drop < LONG_TEN_POWERS_TABLE.length)
d = divideAndRound(d.intCompact, d.intVal,
LONG_TEN_POWERS_TABLE[drop], null,
newScale, mode, newScale);
else
d = divideAndRound(d.intCompact, d.intVal,
INFLATED, bigTenToThe(drop),
newScale, mode, newScale);
} }
int drop = precision - mc.precision; // digits to discard return d;
if (drop <= 0) // we fit
return this;
BigDecimal rounded = dropDigits(mc, drop);
// we need to double-check, in case of the 999=>1000 case
return rounded.doRound(mc);
} }
/** /**
* Removes digits from the significand of a {@code BigDecimal}, * Returns the compact value for given {@code BigInteger}, or
* rounding according to the MathContext settings. Does not * INFLATED if too big. Relies on internal representation of
* change {@code this}; a new {@code BigDecimal} is always * {@code BigInteger}.
* created and returned.
*
* <p>Actual rounding is carried out, as before, by the divide
* method, as this minimized code changes. It might be more
* efficient in most cases to move rounding to here, so we can do
* a round-to-length rather than round-to-scale.
*
* @param mc the context to use.
* @param drop the number of digits to drop, must be {@literal >} 0
* @return a {@code BigDecimal} rounded according to the MathContext
* settings. May return {@code this}, if no rounding needed.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* result is inexact.
*/ */
private BigDecimal dropDigits(MathContext mc, int drop) { private static long compactValFor(BigInteger b) {
// here if we need to round; make the divisor = 10**drop) int[] m = b.mag;
// [calculating the BigInteger here saves setScale later] int len = m.length;
BigDecimal divisor = new BigDecimal(tenToThe(drop), 0); if (len == 0)
return 0;
int d = m[0];
if (len > 2 || (len == 2 && d < 0))
return INFLATED;
// divide to same scale to force round to length long u = (len == 2)?
BigDecimal rounded = this.divide(divisor, scale, (((long) m[1] & LONG_MASK) + (((long)d) << 32)) :
mc.roundingMode.oldMode); (((long)d) & LONG_MASK);
rounded.scale = checkScale((long)rounded.scale - drop ); // adjust the scale return (b.signum < 0)? -u : u;
return rounded;
} }
private static int longCompareTo(long x, long y) { private static int longCompareMagnitude(long x, long y) {
return (x < y) ? -1 : (x == y) ? 0 : 1; if (x < 0)
x = -x;
if (y < 0)
y = -y;
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
private static int saturateLong(long s) {
int i = (int)s;
return (s == i) ? i : (s < 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE);
} }
/* /*
...@@ -3527,21 +3816,21 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3527,21 +3816,21 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* *
* <li>If precision is nonzero, it must have the right value. * <li>If precision is nonzero, it must have the right value.
* </ul> * </ul>
*
* Note: Since this is an audit method, we are not supposed to change the
* state of this BigDecimal object.
*/ */
private BigDecimal audit() { private BigDecimal audit() {
// Check precision
if (precision > 0) {
if (precision != digitLength()) {
print("audit", this);
throw new AssertionError("precision mismatch");
}
}
if (intCompact == INFLATED) { if (intCompact == INFLATED) {
if (intVal == null) { if (intVal == null) {
print("audit", this); print("audit", this);
throw new AssertionError("null intVal"); throw new AssertionError("null intVal");
} }
// Check precision
if (precision > 0 && precision != bigDigitLength(intVal)) {
print("audit", this);
throw new AssertionError("precision mismatch");
}
} else { } else {
if (intVal != null) { if (intVal != null) {
long val = intVal.longValue(); long val = intVal.longValue();
...@@ -3551,6 +3840,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3551,6 +3840,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
intCompact + "\t intVal=" + val); intCompact + "\t intVal=" + val);
} }
} }
// Check precision
if (precision > 0 && precision != longDigitLength(intCompact)) {
print("audit", this);
throw new AssertionError("precision mismatch");
}
} }
return this; return this;
} }
......
...@@ -105,7 +105,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -105,7 +105,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* *
* @serial * @serial
*/ */
int signum; final int signum;
/** /**
* The magnitude of this BigInteger, in <i>big-endian</i> order: the * The magnitude of this BigInteger, in <i>big-endian</i> order: the
...@@ -116,61 +116,62 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -116,61 +116,62 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* value. Note that this implies that the BigInteger zero has a * value. Note that this implies that the BigInteger zero has a
* zero-length mag array. * zero-length mag array.
*/ */
int[] mag; final int[] mag;
// These "redundant fields" are initialized with recognizable nonsense // These "redundant fields" are initialized with recognizable nonsense
// values, and cached the first time they are needed (or never, if they // values, and cached the first time they are needed (or never, if they
// aren't needed). // aren't needed).
/** /**
* The bitCount of this BigInteger, as returned by bitCount(), or -1 * One plus the bitCount of this BigInteger. Zeros means unitialized.
* (either value is acceptable).
* *
* @serial * @serial
* @see #bitCount * @see #bitCount
* @deprecated Deprecated since logical value is offset from stored
* value and correction factor is applied in accessor method.
*/ */
private int bitCount = -1; @Deprecated
private int bitCount;
/** /**
* The bitLength of this BigInteger, as returned by bitLength(), or -1 * One plus the bitLength of this BigInteger. Zeros means unitialized.
* (either value is acceptable). * (either value is acceptable).
* *
* @serial * @serial
* @see #bitLength() * @see #bitLength()
* @deprecated Deprecated since logical value is offset from stored
* value and correction factor is applied in accessor method.
*/ */
private int bitLength = -1; @Deprecated
private int bitLength;
/** /**
* The lowest set bit of this BigInteger, as returned by getLowestSetBit(), * Two plus the lowest set bit of this BigInteger, as returned by
* or -2 (either value is acceptable). * getLowestSetBit().
* *
* @serial * @serial
* @see #getLowestSetBit * @see #getLowestSetBit
* @deprecated Deprecated since logical value is offset from stored
* value and correction factor is applied in accessor method.
*/ */
private int lowestSetBit = -2; @Deprecated
private int lowestSetBit;
/**
* The index of the lowest-order byte in the magnitude of this BigInteger
* that contains a nonzero byte, or -2 (either value is acceptable). The
* least significant byte has int-number 0, the next byte in order of
* increasing significance has byte-number 1, and so forth.
*
* @serial
*/
private int firstNonzeroByteNum = -2;
/** /**
* The index of the lowest-order int in the magnitude of this BigInteger * Two plus the index of the lowest-order int in the magnitude of this
* that contains a nonzero int, or -2 (either value is acceptable). The * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
* least significant int has int-number 0, the next int in order of * The least significant int has int-number 0, the next int in order of
* increasing significance has int-number 1, and so forth. * increasing significance has int-number 1, and so forth.
* @deprecated Deprecated since logical value is offset from stored
* value and correction factor is applied in accessor method.
*/ */
private int firstNonzeroIntNum = -2; @Deprecated
private int firstNonzeroIntNum;
/** /**
* This mask is used to obtain the value of an int as if it were unsigned. * This mask is used to obtain the value of an int as if it were unsigned.
*/ */
private final static long LONG_MASK = 0xffffffffL; final static long LONG_MASK = 0xffffffffL;
//Constructors //Constructors
...@@ -295,7 +296,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -295,7 +296,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
throw new NumberFormatException("Zero length BigInteger"); throw new NumberFormatException("Zero length BigInteger");
// Check for at most one leading sign // Check for at most one leading sign
signum = 1; int sign = 1;
int index1 = val.lastIndexOf('-'); int index1 = val.lastIndexOf('-');
int index2 = val.lastIndexOf('+'); int index2 = val.lastIndexOf('+');
if ((index1 + index2) <= -1) { if ((index1 + index2) <= -1) {
...@@ -306,7 +307,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -306,7 +307,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
throw new NumberFormatException("Zero length BigInteger"); throw new NumberFormatException("Zero length BigInteger");
} }
if (index1 == 0) if (index1 == 0)
signum = -1; sign = -1;
} else } else
throw new NumberFormatException("Illegal embedded sign character"); throw new NumberFormatException("Illegal embedded sign character");
...@@ -318,23 +319,24 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -318,23 +319,24 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
signum = 0; signum = 0;
mag = ZERO.mag; mag = ZERO.mag;
return; return;
} else {
numDigits = len - cursor;
} }
numDigits = len - cursor;
signum = sign;
// Pre-allocate array of expected size. May be too large but can // Pre-allocate array of expected size. May be too large but can
// never be too small. Typically exact. // never be too small. Typically exact.
int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1); int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);
int numWords = (numBits + 31) /32; int numWords = (numBits + 31) >>> 5;
mag = new int[numWords]; int[] magnitude = new int[numWords];
// Process first (potentially short) digit group // Process first (potentially short) digit group
int firstGroupLen = numDigits % digitsPerInt[radix]; int firstGroupLen = numDigits % digitsPerInt[radix];
if (firstGroupLen == 0) if (firstGroupLen == 0)
firstGroupLen = digitsPerInt[radix]; firstGroupLen = digitsPerInt[radix];
String group = val.substring(cursor, cursor += firstGroupLen); String group = val.substring(cursor, cursor += firstGroupLen);
mag[mag.length - 1] = Integer.parseInt(group, radix); magnitude[numWords - 1] = Integer.parseInt(group, radix);
if (mag[mag.length - 1] < 0) if (magnitude[numWords - 1] < 0)
throw new NumberFormatException("Illegal digit"); throw new NumberFormatException("Illegal digit");
// Process remaining digit groups // Process remaining digit groups
...@@ -345,10 +347,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -345,10 +347,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
groupVal = Integer.parseInt(group, radix); groupVal = Integer.parseInt(group, radix);
if (groupVal < 0) if (groupVal < 0)
throw new NumberFormatException("Illegal digit"); throw new NumberFormatException("Illegal digit");
destructiveMulAdd(mag, superRadix, groupVal); destructiveMulAdd(magnitude, superRadix, groupVal);
} }
// Required for cases where the array was overallocated. // Required for cases where the array was overallocated.
mag = trustedStripLeadingZeroInts(mag); mag = trustedStripLeadingZeroInts(magnitude);
} }
// Constructs a new BigInteger using a char array with radix=10 // Constructs a new BigInteger using a char array with radix=10
...@@ -357,11 +359,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -357,11 +359,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int len = val.length; int len = val.length;
// Check for leading minus sign // Check for leading minus sign
signum = 1; int sign = 1;
if (val[0] == '-') { if (val[0] == '-') {
if (len == 1) if (len == 1)
throw new NumberFormatException("Zero length BigInteger"); throw new NumberFormatException("Zero length BigInteger");
signum = -1; sign = -1;
cursor = 1; cursor = 1;
} else if (val[0] == '+') { } else if (val[0] == '+') {
if (len == 1) if (len == 1)
...@@ -376,32 +378,33 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -376,32 +378,33 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
signum = 0; signum = 0;
mag = ZERO.mag; mag = ZERO.mag;
return; return;
} else {
numDigits = len - cursor;
} }
numDigits = len - cursor;
signum = sign;
// Pre-allocate array of expected size // Pre-allocate array of expected size
int numWords; int numWords;
if (len < 10) { if (len < 10) {
numWords = 1; numWords = 1;
} else { } else {
int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1); int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1);
numWords = (numBits + 31) /32; numWords = (numBits + 31) >>> 5;
} }
mag = new int[numWords]; int[] magnitude = new int[numWords];
// Process first (potentially short) digit group // Process first (potentially short) digit group
int firstGroupLen = numDigits % digitsPerInt[10]; int firstGroupLen = numDigits % digitsPerInt[10];
if (firstGroupLen == 0) if (firstGroupLen == 0)
firstGroupLen = digitsPerInt[10]; firstGroupLen = digitsPerInt[10];
mag[mag.length-1] = parseInt(val, cursor, cursor += firstGroupLen); magnitude[numWords - 1] = parseInt(val, cursor, cursor += firstGroupLen);
// Process remaining digit groups // Process remaining digit groups
while (cursor < len) { while (cursor < len) {
int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]); int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]);
destructiveMulAdd(mag, intRadix[10], groupVal); destructiveMulAdd(magnitude, intRadix[10], groupVal);
} }
mag = trustedStripLeadingZeroInts(mag); mag = trustedStripLeadingZeroInts(magnitude);
} }
// Create an integer with the digits between the two indexes // Create an integer with the digits between the two indexes
...@@ -842,26 +845,21 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -842,26 +845,21 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
u2 = u.multiply(v).mod(n); u2 = u.multiply(v).mod(n);
v2 = v.square().add(d.multiply(u.square())).mod(n); v2 = v.square().add(d.multiply(u.square())).mod(n);
if (v2.testBit(0)) { if (v2.testBit(0))
v2 = n.subtract(v2); v2 = v2.subtract(n);
v2.signum = - v2.signum;
}
v2 = v2.shiftRight(1); v2 = v2.shiftRight(1);
u = u2; v = v2; u = u2; v = v2;
if (k.testBit(i)) { if (k.testBit(i)) {
u2 = u.add(v).mod(n); u2 = u.add(v).mod(n);
if (u2.testBit(0)) { if (u2.testBit(0))
u2 = n.subtract(u2); u2 = u2.subtract(n);
u2.signum = - u2.signum;
}
u2 = u2.shiftRight(1);
u2 = u2.shiftRight(1);
v2 = v.add(d.multiply(u)).mod(n); v2 = v.add(d.multiply(u)).mod(n);
if (v2.testBit(0)) { if (v2.testBit(0))
v2 = n.subtract(v2); v2 = v2.subtract(n);
v2.signum = - v2.signum;
}
v2 = v2.shiftRight(1); v2 = v2.shiftRight(1);
u = u2; v = v2; u = u2; v = v2;
...@@ -918,11 +916,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -918,11 +916,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
} }
/** /**
* This private constructor differs from its public cousin * This internal constructor differs from its public cousin
* with the arguments reversed in two ways: it assumes that its * with the arguments reversed in two ways: it assumes that its
* arguments are correct, and it doesn't copy the magnitude array. * arguments are correct, and it doesn't copy the magnitude array.
*/ */
private BigInteger(int[] magnitude, int signum) { BigInteger(int[] magnitude, int signum) {
this.signum = (magnitude.length==0 ? 0 : signum); this.signum = (magnitude.length==0 ? 0 : signum);
this.mag = magnitude; this.mag = magnitude;
} }
...@@ -936,22 +934,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -936,22 +934,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
this.mag = stripLeadingZeroBytes(magnitude); this.mag = stripLeadingZeroBytes(magnitude);
} }
/**
* This private constructor is for internal use in converting
* from a MutableBigInteger object into a BigInteger.
*/
BigInteger(MutableBigInteger val, int sign) {
if (val.offset > 0 || val.value.length != val.intLen) {
mag = new int[val.intLen];
for(int i=0; i<val.intLen; i++)
mag[i] = val.value[val.offset+i];
} else {
mag = val.value;
}
this.signum = (val.intLen == 0) ? 0 : sign;
}
//Static Factory Methods //Static Factory Methods
/** /**
...@@ -980,8 +962,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -980,8 +962,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
*/ */
private BigInteger(long val) { private BigInteger(long val) {
if (val < 0) { if (val < 0) {
signum = -1;
val = -val; val = -val;
signum = -1;
} else { } else {
signum = 1; signum = 1;
} }
...@@ -1058,7 +1040,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1058,7 +1040,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @return {@code this + val} * @return {@code this + val}
*/ */
public BigInteger add(BigInteger val) { public BigInteger add(BigInteger val) {
int[] resultMag;
if (val.signum == 0) if (val.signum == 0)
return this; return this;
if (signum == 0) if (signum == 0)
...@@ -1066,14 +1047,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1066,14 +1047,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (val.signum == signum) if (val.signum == signum)
return new BigInteger(add(mag, val.mag), signum); return new BigInteger(add(mag, val.mag), signum);
int cmp = intArrayCmp(mag, val.mag); int cmp = compareMagnitude(val);
if (cmp==0) if (cmp == 0)
return ZERO; return ZERO;
resultMag = (cmp>0 ? subtract(mag, val.mag) int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
: subtract(val.mag, mag)); : subtract(val.mag, mag));
resultMag = trustedStripLeadingZeroInts(resultMag); resultMag = trustedStripLeadingZeroInts(resultMag);
return new BigInteger(resultMag, cmp*signum); return new BigInteger(resultMag, cmp == signum ? 1 : -1);
} }
/** /**
...@@ -1112,12 +1093,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1112,12 +1093,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
// Grow result if necessary // Grow result if necessary
if (carry) { if (carry) {
int newLen = result.length + 1; int bigger[] = new int[result.length + 1];
int temp[] = new int[newLen]; System.arraycopy(result, 0, bigger, 1, result.length);
for (int i = 1; i<newLen; i++) bigger[0] = 0x01;
temp[i] = result[i-1]; return bigger;
temp[0] = 0x01;
result = temp;
} }
return result; return result;
} }
...@@ -1129,7 +1108,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1129,7 +1108,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @return {@code this - val} * @return {@code this - val}
*/ */
public BigInteger subtract(BigInteger val) { public BigInteger subtract(BigInteger val) {
int[] resultMag;
if (val.signum == 0) if (val.signum == 0)
return this; return this;
if (signum == 0) if (signum == 0)
...@@ -1137,13 +1115,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1137,13 +1115,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (val.signum != signum) if (val.signum != signum)
return new BigInteger(add(mag, val.mag), signum); return new BigInteger(add(mag, val.mag), signum);
int cmp = intArrayCmp(mag, val.mag); int cmp = compareMagnitude(val);
if (cmp==0) if (cmp == 0)
return ZERO; return ZERO;
resultMag = (cmp>0 ? subtract(mag, val.mag) int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
: subtract(val.mag, mag)); : subtract(val.mag, mag));
resultMag = trustedStripLeadingZeroInts(resultMag); resultMag = trustedStripLeadingZeroInts(resultMag);
return new BigInteger(resultMag, cmp*signum); return new BigInteger(resultMag, cmp == signum ? 1 : -1);
} }
/** /**
...@@ -1191,12 +1169,54 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1191,12 +1169,54 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int[] result = multiplyToLen(mag, mag.length, int[] result = multiplyToLen(mag, mag.length,
val.mag, val.mag.length, null); val.mag, val.mag.length, null);
result = trustedStripLeadingZeroInts(result); result = trustedStripLeadingZeroInts(result);
return new BigInteger(result, signum*val.signum); return new BigInteger(result, signum == val.signum ? 1 : -1);
}
/**
* Package private methods used by BigDecimal code to multiply a BigInteger
* with a long. Assumes v is not equal to INFLATED.
*/
BigInteger multiply(long v) {
if (v == 0 || signum == 0)
return ZERO;
if (v == BigDecimal.INFLATED)
return multiply(BigInteger.valueOf(v));
int rsign = (v > 0 ? signum : -signum);
if (v < 0)
v = -v;
long dh = v >>> 32; // higher order bits
long dl = v & LONG_MASK; // lower order bits
int xlen = mag.length;
int[] value = mag;
int[] rmag = (dh == 0L) ? (new int[xlen + 1]) : (new int[xlen + 2]);
long carry = 0;
int rstart = rmag.length - 1;
for (int i = xlen - 1; i >= 0; i--) {
long product = (value[i] & LONG_MASK) * dl + carry;
rmag[rstart--] = (int)product;
carry = product >>> 32;
}
rmag[rstart] = (int)carry;
if (dh != 0L) {
carry = 0;
rstart = rmag.length - 2;
for (int i = xlen - 1; i >= 0; i--) {
long product = (value[i] & LONG_MASK) * dh +
(rmag[rstart] & LONG_MASK) + carry;
rmag[rstart--] = (int)product;
carry = product >>> 32;
}
rmag[0] = (int)carry;
}
if (carry == 0L)
rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
return new BigInteger(rmag, rsign);
} }
/** /**
* Multiplies int arrays x and y to the specified lengths and places * Multiplies int arrays x and y to the specified lengths and places
* the result into z. * the result into z. There will be no leading zeros in the resultant array.
*/ */
private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
int xstart = xlen - 1; int xstart = xlen - 1;
...@@ -1316,12 +1336,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1316,12 +1336,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
*/ */
public BigInteger divide(BigInteger val) { public BigInteger divide(BigInteger val) {
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
r = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q, r); a.divide(b, q);
return new BigInteger(q, this.signum * val.signum); return q.toBigInteger(this.signum == val.signum ? 1 : -1);
} }
/** /**
...@@ -1338,12 +1357,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1338,12 +1357,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
public BigInteger[] divideAndRemainder(BigInteger val) { public BigInteger[] divideAndRemainder(BigInteger val) {
BigInteger[] result = new BigInteger[2]; BigInteger[] result = new BigInteger[2];
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
r = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q, r); MutableBigInteger r = a.divide(b, q);
result[0] = new BigInteger(q, this.signum * val.signum); result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
result[1] = new BigInteger(r, this.signum); result[1] = r.toBigInteger(this.signum);
return result; return result;
} }
...@@ -1357,12 +1375,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1357,12 +1375,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
*/ */
public BigInteger remainder(BigInteger val) { public BigInteger remainder(BigInteger val) {
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
r = new MutableBigInteger(),
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q, r); return a.divide(b, q).toBigInteger(this.signum);
return new BigInteger(r, this.signum);
} }
/** /**
...@@ -1418,7 +1434,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1418,7 +1434,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
MutableBigInteger result = a.hybridGCD(b); MutableBigInteger result = a.hybridGCD(b);
return new BigInteger(result, 1); return result.toBigInteger(1);
}
/**
* Package private method to return bit length for an integer.
*/
static int bitLengthForInt(int n) {
return 32 - Integer.numberOfLeadingZeros(n);
} }
/** /**
...@@ -1428,7 +1451,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1428,7 +1451,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
private static int[] leftShift(int[] a, int len, int n) { private static int[] leftShift(int[] a, int len, int n) {
int nInts = n >>> 5; int nInts = n >>> 5;
int nBits = n&0x1F; int nBits = n&0x1F;
int bitsInHighWord = bitLen(a[0]); int bitsInHighWord = bitLengthForInt(a[0]);
// If shift can be done without recopy, do so // If shift can be done without recopy, do so
if (n <= (32-bitsInHighWord)) { if (n <= (32-bitsInHighWord)) {
...@@ -1481,9 +1504,9 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1481,9 +1504,9 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* assuming there are no leading zero ints. * assuming there are no leading zero ints.
*/ */
private static int bitLength(int[] val, int len) { private static int bitLength(int[] val, int len) {
if (len==0) if (len == 0)
return 0; return 0;
return ((len-1)<<5) + bitLen(val[0]); return ((len - 1) << 5) + bitLengthForInt(val[0]);
} }
/** /**
...@@ -1710,11 +1733,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1710,11 +1733,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int[] a = leftShift(base, base.length, modLen << 5); int[] a = leftShift(base, base.length, modLen << 5);
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
r = new MutableBigInteger(),
a2 = new MutableBigInteger(a), a2 = new MutableBigInteger(a),
b2 = new MutableBigInteger(mod); b2 = new MutableBigInteger(mod);
a2.divide(b2, q, r); MutableBigInteger r= a2.divide(b2, q);
table[0] = r.toIntArray(); table[0] = r.toIntArray();
// Pad table[0] with leading zeros so its length is at least modLen // Pad table[0] with leading zeros so its length is at least modLen
...@@ -1976,7 +1998,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1976,7 +1998,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return this; return this;
// Copy remaining ints of mag // Copy remaining ints of mag
int numInts = (p+31)/32; int numInts = (p + 31) >>> 5;
int[] mag = new int[numInts]; int[] mag = new int[numInts];
for (int i=0; i<numInts; i++) for (int i=0; i<numInts; i++)
mag[i] = this.mag[i + (this.mag.length - numInts)]; mag[i] = this.mag[i + (this.mag.length - numInts)];
...@@ -2006,7 +2028,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2006,7 +2028,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
// Calculate (this mod m) // Calculate (this mod m)
BigInteger modVal = this; BigInteger modVal = this;
if (signum < 0 || (intArrayCmp(mag, m.mag) >= 0)) if (signum < 0 || (this.compareMagnitude(m) >= 0))
modVal = this.mod(m); modVal = this.mod(m);
if (modVal.equals(ONE)) if (modVal.equals(ONE))
...@@ -2016,7 +2038,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2016,7 +2038,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
MutableBigInteger b = new MutableBigInteger(m); MutableBigInteger b = new MutableBigInteger(m);
MutableBigInteger result = a.mutableModInverse(b); MutableBigInteger result = a.mutableModInverse(b);
return new BigInteger(result, 1); return result.toBigInteger(1);
} }
// Shift Operations // Shift Operations
...@@ -2241,7 +2263,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2241,7 +2263,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (n<0) if (n<0)
throw new ArithmeticException("Negative bit address"); throw new ArithmeticException("Negative bit address");
return (getInt(n/32) & (1 << (n%32))) != 0; return (getInt(n >>> 5) & (1 << (n & 31))) != 0;
} }
/** /**
...@@ -2256,13 +2278,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2256,13 +2278,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (n<0) if (n<0)
throw new ArithmeticException("Negative bit address"); throw new ArithmeticException("Negative bit address");
int intNum = n/32; int intNum = n >>> 5;
int[] result = new int[Math.max(intLength(), intNum+2)]; int[] result = new int[Math.max(intLength(), intNum+2)];
for (int i=0; i<result.length; i++) for (int i=0; i<result.length; i++)
result[result.length-i-1] = getInt(i); result[result.length-i-1] = getInt(i);
result[result.length-intNum-1] |= (1 << (n%32)); result[result.length-intNum-1] |= (1 << (n & 31));
return valueOf(result); return valueOf(result);
} }
...@@ -2280,13 +2302,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2280,13 +2302,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (n<0) if (n<0)
throw new ArithmeticException("Negative bit address"); throw new ArithmeticException("Negative bit address");
int intNum = n/32; int intNum = n >>> 5;
int[] result = new int[Math.max(intLength(), (n+1)/32+1)]; int[] result = new int[Math.max(intLength(), ((n + 1) >>> 5) + 1)];
for (int i=0; i<result.length; i++) for (int i=0; i<result.length; i++)
result[result.length-i-1] = getInt(i); result[result.length-i-1] = getInt(i);
result[result.length-intNum-1] &= ~(1 << (n%32)); result[result.length-intNum-1] &= ~(1 << (n & 31));
return valueOf(result); return valueOf(result);
} }
...@@ -2304,13 +2326,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2304,13 +2326,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (n<0) if (n<0)
throw new ArithmeticException("Negative bit address"); throw new ArithmeticException("Negative bit address");
int intNum = n/32; int intNum = n >>> 5;
int[] result = new int[Math.max(intLength(), intNum+2)]; int[] result = new int[Math.max(intLength(), intNum+2)];
for (int i=0; i<result.length; i++) for (int i=0; i<result.length; i++)
result[result.length-i-1] = getInt(i); result[result.length-i-1] = getInt(i);
result[result.length-intNum-1] ^= (1 << (n%32)); result[result.length-intNum-1] ^= (1 << (n & 31));
return valueOf(result); return valueOf(result);
} }
...@@ -2324,23 +2346,21 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2324,23 +2346,21 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* @return index of the rightmost one bit in this BigInteger. * @return index of the rightmost one bit in this BigInteger.
*/ */
public int getLowestSetBit() { public int getLowestSetBit() {
/* @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
* Initialize lowestSetBit field the first time this method is if (lsb == -2) { // lowestSetBit not initialized yet
* executed. This method depends on the atomicity of int modifies; lsb = 0;
* without this guarantee, it would have to be synchronized.
*/
if (lowestSetBit == -2) {
if (signum == 0) { if (signum == 0) {
lowestSetBit = -1; lsb -= 1;
} else { } else {
// Search for lowest order nonzero int // Search for lowest order nonzero int
int i,b; int i,b;
for (i=0; (b = getInt(i))==0; i++) for (i=0; (b = getInt(i))==0; i++)
; ;
lowestSetBit = (i << 5) + trailingZeroCnt(b); lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
} }
lowestSetBit = lsb + 2;
} }
return lowestSetBit; return lsb;
} }
...@@ -2357,78 +2377,31 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2357,78 +2377,31 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* representation of this BigInteger, <i>excluding</i> a sign bit. * representation of this BigInteger, <i>excluding</i> a sign bit.
*/ */
public int bitLength() { public int bitLength() {
/* @SuppressWarnings("deprecation") int n = bitLength - 1;
* Initialize bitLength field the first time this method is executed. if (n == -1) { // bitLength not initialized yet
* This method depends on the atomicity of int modifies; without int[] m = mag;
* this guarantee, it would have to be synchronized. int len = m.length;
*/ if (len == 0) {
if (bitLength == -1) { n = 0; // offset by one to initialize
if (signum == 0) { } else {
bitLength = 0;
} else {
// Calculate the bit length of the magnitude // Calculate the bit length of the magnitude
int magBitLength = ((mag.length-1) << 5) + bitLen(mag[0]); int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]);
if (signum < 0) {
if (signum < 0) { // Check if magnitude is a power of two
// Check if magnitude is a power of two boolean pow2 = (Integer.bitCount(mag[0]) == 1);
boolean pow2 = (bitCnt(mag[0]) == 1); for(int i=1; i< len && pow2; i++)
for(int i=1; i<mag.length && pow2; i++) pow2 = (mag[i] == 0);
pow2 = (mag[i]==0);
n = (pow2 ? magBitLength -1 : magBitLength);
bitLength = (pow2 ? magBitLength-1 : magBitLength); } else {
} else { n = magBitLength;
bitLength = magBitLength; }
}
} }
bitLength = n + 1;
} }
return bitLength; return n;
}
/**
* bitLen(val) is the number of bits in val.
*/
static int bitLen(int w) {
// Binary search - decision tree (5 tests, rarely 6)
return
(w < 1<<15 ?
(w < 1<<7 ?
(w < 1<<3 ?
(w < 1<<1 ? (w < 1<<0 ? (w<0 ? 32 : 0) : 1) : (w < 1<<2 ? 2 : 3)) :
(w < 1<<5 ? (w < 1<<4 ? 4 : 5) : (w < 1<<6 ? 6 : 7))) :
(w < 1<<11 ?
(w < 1<<9 ? (w < 1<<8 ? 8 : 9) : (w < 1<<10 ? 10 : 11)) :
(w < 1<<13 ? (w < 1<<12 ? 12 : 13) : (w < 1<<14 ? 14 : 15)))) :
(w < 1<<23 ?
(w < 1<<19 ?
(w < 1<<17 ? (w < 1<<16 ? 16 : 17) : (w < 1<<18 ? 18 : 19)) :
(w < 1<<21 ? (w < 1<<20 ? 20 : 21) : (w < 1<<22 ? 22 : 23))) :
(w < 1<<27 ?
(w < 1<<25 ? (w < 1<<24 ? 24 : 25) : (w < 1<<26 ? 26 : 27)) :
(w < 1<<29 ? (w < 1<<28 ? 28 : 29) : (w < 1<<30 ? 30 : 31)))));
} }
/*
* trailingZeroTable[i] is the number of trailing zero bits in the binary
* representation of i.
*/
final static byte trailingZeroTable[] = {
-25, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
/** /**
* Returns the number of bits in the two's complement representation * Returns the number of bits in the two's complement representation
* of this BigInteger that differ from its sign bit. This method is * of this BigInteger that differ from its sign bit. This method is
...@@ -2438,58 +2411,23 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2438,58 +2411,23 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* of this BigInteger that differ from its sign bit. * of this BigInteger that differ from its sign bit.
*/ */
public int bitCount() { public int bitCount() {
/* @SuppressWarnings("deprecation") int bc = bitCount - 1;
* Initialize bitCount field the first time this method is executed. if (bc == -1) { // bitCount not initialized yet
* This method depends on the atomicity of int modifies; without bc = 0; // offset by one to initialize
* this guarantee, it would have to be synchronized.
*/
if (bitCount == -1) {
// Count the bits in the magnitude // Count the bits in the magnitude
int magBitCount = 0;
for (int i=0; i<mag.length; i++) for (int i=0; i<mag.length; i++)
magBitCount += bitCnt(mag[i]); bc += Integer.bitCount(mag[i]);
if (signum < 0) { if (signum < 0) {
// Count the trailing zeros in the magnitude // Count the trailing zeros in the magnitude
int magTrailingZeroCount = 0, j; int magTrailingZeroCount = 0, j;
for (j=mag.length-1; mag[j]==0; j--) for (j=mag.length-1; mag[j]==0; j--)
magTrailingZeroCount += 32; magTrailingZeroCount += 32;
magTrailingZeroCount += magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
trailingZeroCnt(mag[j]); bc += magTrailingZeroCount - 1;
bitCount = magBitCount + magTrailingZeroCount - 1;
} else {
bitCount = magBitCount;
} }
bitCount = bc + 1;
} }
return bitCount; return bc;
}
static int bitCnt(int val) {
val -= (0xaaaaaaaa & val) >>> 1;
val = (val & 0x33333333) + ((val >>> 2) & 0x33333333);
val = val + (val >>> 4) & 0x0f0f0f0f;
val += val >>> 8;
val += val >>> 16;
return val & 0xff;
}
static int trailingZeroCnt(int val) {
// Loop unrolled for performance
int byteVal = val & 0xff;
if (byteVal != 0)
return trailingZeroTable[byteVal];
byteVal = (val >>> 8) & 0xff;
if (byteVal != 0)
return trailingZeroTable[byteVal] + 8;
byteVal = (val >>> 16) & 0xff;
if (byteVal != 0)
return trailingZeroTable[byteVal] + 16;
byteVal = (val >>> 24) & 0xff;
return trailingZeroTable[byteVal] + 24;
} }
// Primality Testing // Primality Testing
...@@ -2536,29 +2474,41 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2536,29 +2474,41 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* to, or greater than {@code val}. * to, or greater than {@code val}.
*/ */
public int compareTo(BigInteger val) { public int compareTo(BigInteger val) {
return (signum==val.signum if (signum == val.signum) {
? signum*intArrayCmp(mag, val.mag) switch (signum) {
: (signum>val.signum ? 1 : -1)); case 1:
return compareMagnitude(val);
case -1:
return val.compareMagnitude(this);
default:
return 0;
}
}
return signum > val.signum ? 1 : -1;
} }
/* /**
* Returns -1, 0 or +1 as big-endian unsigned int array arg1 is * Compares the magnitude array of this BigInteger with the specified
* less than, equal to, or greater than arg2. * BigInteger's. This is the version of compareTo ignoring sign.
*
* @param val BigInteger whose magnitude array to be compared.
* @return -1, 0 or 1 as this magnitude array is less than, equal to or
* greater than the magnitude aray for the specified BigInteger's.
*/ */
private static int intArrayCmp(int[] arg1, int[] arg2) { final int compareMagnitude(BigInteger val) {
if (arg1.length < arg2.length) int[] m1 = mag;
int len1 = m1.length;
int[] m2 = val.mag;
int len2 = m2.length;
if (len1 < len2)
return -1; return -1;
if (arg1.length > arg2.length) if (len1 > len2)
return 1; return 1;
for (int i = 0; i < len1; i++) {
// Argument lengths are equal; compare the values int a = m1[i];
for (int i=0; i<arg1.length; i++) { int b = m2[i];
long b1 = arg1[i] & LONG_MASK; if (a != b)
long b2 = arg2[i] & LONG_MASK; return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
if (b1 < b2)
return -1;
if (b1 > b2)
return 1;
} }
return 0; return 0;
} }
...@@ -2577,13 +2527,19 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2577,13 +2527,19 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (!(x instanceof BigInteger)) if (!(x instanceof BigInteger))
return false; return false;
BigInteger xInt = (BigInteger) x; BigInteger xInt = (BigInteger) x;
if (xInt.signum != signum)
return false;
if (xInt.signum != signum || xInt.mag.length != mag.length) int[] m = mag;
int len = m.length;
int[] xm = xInt.mag;
if (len != xm.length)
return false; return false;
for (int i=0; i<mag.length; i++) for (int i = 0; i < len; i++)
if (xInt.mag[i] != mag[i]) if (xm[i] != m[i])
return false; return false;
return true; return true;
...@@ -2662,12 +2618,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2662,12 +2618,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
BigInteger d = longRadix[radix]; BigInteger d = longRadix[radix];
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger(),
r = new MutableBigInteger(),
a = new MutableBigInteger(tmp.mag), a = new MutableBigInteger(tmp.mag),
b = new MutableBigInteger(d.mag); b = new MutableBigInteger(d.mag);
a.divide(b, q, r); MutableBigInteger r = a.divide(b, q);
BigInteger q2 = new BigInteger(q, tmp.signum * d.signum); BigInteger q2 = q.toBigInteger(tmp.signum * d.signum);
BigInteger r2 = new BigInteger(r, tmp.signum * d.signum); BigInteger r2 = r.toBigInteger(tmp.signum * d.signum);
digitGroup[numGroups++] = Long.toString(r2.longValue(), radix); digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);
tmp = q2; tmp = q2;
...@@ -2836,18 +2791,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2836,18 +2791,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* Returns a copy of the input array stripped of any leading zero bytes. * Returns a copy of the input array stripped of any leading zero bytes.
*/ */
private static int[] stripLeadingZeroInts(int val[]) { private static int[] stripLeadingZeroInts(int val[]) {
int byteLength = val.length; int vlen = val.length;
int keep; int keep;
// Find first nonzero byte // Find first nonzero byte
for (keep=0; keep<val.length && val[keep]==0; keep++) for (keep = 0; keep < vlen && val[keep] == 0; keep++)
; ;
return java.util.Arrays.copyOfRange(val, keep, vlen);
int result[] = new int[val.length - keep];
for(int i=0; i<val.length - keep; i++)
result[i] = val[keep+i];
return result;
} }
/** /**
...@@ -2855,21 +2805,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2855,21 +2805,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* Since the source is trusted the copying may be skipped. * Since the source is trusted the copying may be skipped.
*/ */
private static int[] trustedStripLeadingZeroInts(int val[]) { private static int[] trustedStripLeadingZeroInts(int val[]) {
int byteLength = val.length; int vlen = val.length;
int keep; int keep;
// Find first nonzero byte // Find first nonzero byte
for (keep=0; keep<val.length && val[keep]==0; keep++) for (keep = 0; keep < vlen && val[keep] == 0; keep++)
; ;
return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen);
// Only perform copy if necessary
if (keep > 0) {
int result[] = new int[val.length - keep];
for(int i=0; i<val.length - keep; i++)
result[i] = val[keep+i];
return result;
}
return val;
} }
/** /**
...@@ -2880,18 +2822,18 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2880,18 +2822,18 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int keep; int keep;
// Find first nonzero byte // Find first nonzero byte
for (keep=0; keep<a.length && a[keep]==0; keep++) for (keep = 0; keep < byteLength && a[keep]==0; keep++)
; ;
// Allocate new array and copy relevant part of input array // Allocate new array and copy relevant part of input array
int intLength = ((byteLength - keep) + 3)/4; int intLength = ((byteLength - keep) + 3) >>> 2;
int[] result = new int[intLength]; int[] result = new int[intLength];
int b = byteLength - 1; int b = byteLength - 1;
for (int i = intLength-1; i >= 0; i--) { for (int i = intLength-1; i >= 0; i--) {
result[i] = a[b--] & 0xff; result[i] = a[b--] & 0xff;
int bytesRemaining = b - keep + 1; int bytesRemaining = b - keep + 1;
int bytesToTransfer = Math.min(3, bytesRemaining); int bytesToTransfer = Math.min(3, bytesRemaining);
for (int j=8; j <= 8*bytesToTransfer; j += 8) for (int j=8; j <= (bytesToTransfer << 3); j += 8)
result[i] |= ((a[b--] & 0xff) << j); result[i] |= ((a[b--] & 0xff) << j);
} }
return result; return result;
...@@ -3037,7 +2979,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3037,7 +2979,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* including space for at least one sign bit. * including space for at least one sign bit.
*/ */
private int intLength() { private int intLength() {
return bitLength()/32 + 1; return (bitLength() >>> 5) + 1;
} }
/* Returns sign bit */ /* Returns sign bit */
...@@ -3074,20 +3016,20 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3074,20 +3016,20 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* least significant). If the magnitude is zero, return value is undefined. * least significant). If the magnitude is zero, return value is undefined.
*/ */
private int firstNonzeroIntNum() { private int firstNonzeroIntNum() {
/* int fn = firstNonzeroIntNum - 2;
* Initialize firstNonzeroIntNum field the first time this method is if (fn == -2) { // firstNonzeroIntNum not initialized yet
* executed. This method depends on the atomicity of int modifies; fn = 0;
* without this guarantee, it would have to be synchronized.
*/ // Search for the first nonzero int
if (firstNonzeroIntNum == -2) { int i;
// Search for the first nonzero int int mlen = mag.length;
int i; for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
for (i=mag.length-1; i>=0 && mag[i]==0; i--) ;
; fn = mlen - i - 1;
firstNonzeroIntNum = mag.length-i-1; firstNonzeroIntNum = fn + 2; // offset by two to initialize
} }
return firstNonzeroIntNum; return fn;
} }
/** use serialVersionUID from JDK 1.1. for interoperability */ /** use serialVersionUID from JDK 1.1. for interoperability */
private static final long serialVersionUID = -8287574255936472291L; private static final long serialVersionUID = -8287574255936472291L;
...@@ -3121,6 +3063,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3121,6 +3063,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* deserialize it). The magnitude is read in as an array of bytes * deserialize it). The magnitude is read in as an array of bytes
* for historical reasons, but it is converted to an array of ints * for historical reasons, but it is converted to an array of ints
* and the byte array is discarded. * and the byte array is discarded.
* Note:
* The current convention is to initialize the cache fields, bitCount,
* bitLength and lowestSetBit, to 0 rather than some other marker value.
* Therefore, no explicit action to set these fields needs to be taken in
* readObject because those fields already have a 0 value be default since
* defaultReadObject is not being used.
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException { throws java.io.IOException, ClassNotFoundException {
...@@ -3136,29 +3084,44 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3136,29 +3084,44 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
ObjectInputStream.GetField fields = s.readFields(); ObjectInputStream.GetField fields = s.readFields();
// Read the alternate persistent fields that we care about // Read the alternate persistent fields that we care about
signum = fields.get("signum", -2); int sign = fields.get("signum", -2);
byte[] magnitude = (byte[])fields.get("magnitude", null); byte[] magnitude = (byte[])fields.get("magnitude", null);
// Validate signum // Validate signum
if (signum < -1 || signum > 1) { if (sign < -1 || sign > 1) {
String message = "BigInteger: Invalid signum value"; String message = "BigInteger: Invalid signum value";
if (fields.defaulted("signum")) if (fields.defaulted("signum"))
message = "BigInteger: Signum not present in stream"; message = "BigInteger: Signum not present in stream";
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
} }
if ((magnitude.length==0) != (signum==0)) { if ((magnitude.length == 0) != (sign == 0)) {
String message = "BigInteger: signum-magnitude mismatch"; String message = "BigInteger: signum-magnitude mismatch";
if (fields.defaulted("magnitude")) if (fields.defaulted("magnitude"))
message = "BigInteger: Magnitude not present in stream"; message = "BigInteger: Magnitude not present in stream";
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
} }
// Set "cached computation" fields to their initial values // Commit final fields via Unsafe
bitCount = bitLength = -1; unsafe.putIntVolatile(this, signumOffset, sign);
lowestSetBit = firstNonzeroByteNum = firstNonzeroIntNum = -2;
// Calculate mag field from magnitude and discard magnitude // Calculate mag field from magnitude and discard magnitude
mag = stripLeadingZeroBytes(magnitude); unsafe.putObjectVolatile(this, magOffset,
stripLeadingZeroBytes(magnitude));
}
// Support for resetting final fields while deserializing
private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
private static final long signumOffset;
private static final long magOffset;
static {
try {
signumOffset = unsafe.objectFieldOffset
(BigInteger.class.getDeclaredField("signum"));
magOffset = unsafe.objectFieldOffset
(BigInteger.class.getDeclaredField("mag"));
} catch (Exception ex) {
throw new Error(ex);
}
} }
/** /**
...@@ -3174,6 +3137,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3174,6 +3137,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
ObjectOutputStream.PutField fields = s.putFields(); ObjectOutputStream.PutField fields = s.putFields();
fields.put("signum", signum); fields.put("signum", signum);
fields.put("magnitude", magSerializedForm()); fields.put("magnitude", magSerializedForm());
// The values written for cached fields are compatible with older
// versions, but are ignored in readObject so don't otherwise matter.
fields.put("bitCount", -1); fields.put("bitCount", -1);
fields.put("bitLength", -1); fields.put("bitLength", -1);
fields.put("lowestSetBit", -2); fields.put("lowestSetBit", -2);
...@@ -3187,12 +3152,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -3187,12 +3152,13 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* Returns the mag array as an array of bytes. * Returns the mag array as an array of bytes.
*/ */
private byte[] magSerializedForm() { private byte[] magSerializedForm() {
int bitLen = (mag.length == 0 ? 0 : int len = mag.length;
((mag.length - 1) << 5) + bitLen(mag[0]));
int byteLen = (bitLen + 7)/8; int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0]));
int byteLen = (bitLen + 7) >>> 3;
byte[] result = new byte[byteLen]; byte[] result = new byte[byteLen];
for (int i=byteLen-1, bytesCopied=4, intIndex=mag.length-1, nextInt=0; for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0;
i>=0; i--) { i>=0; i--) {
if (bytesCopied == 4) { if (bytesCopied == 4) {
nextInt = mag[intIndex--]; nextInt = mag[intIndex--];
......
...@@ -110,13 +110,11 @@ class BitSieve { ...@@ -110,13 +110,11 @@ class BitSieve {
int convertedStep = (step *2) + 1; int convertedStep = (step *2) + 1;
// Construct the large sieve at an even offset specified by base // Construct the large sieve at an even offset specified by base
MutableBigInteger r = new MutableBigInteger(); MutableBigInteger b = new MutableBigInteger(base);
MutableBigInteger q = new MutableBigInteger(); MutableBigInteger q = new MutableBigInteger();
do { do {
// Calculate base mod convertedStep // Calculate base mod convertedStep
r.copyValue(base.mag); start = b.divideOneWord(convertedStep, q);
r.divideOneWord(convertedStep, q);
start = r.value[r.offset];
// Take each multiple of step out of sieve // Take each multiple of step out of sieve
start = convertedStep - start; start = convertedStep - start;
......
...@@ -126,19 +126,6 @@ public final class MathContext implements Serializable { ...@@ -126,19 +126,6 @@ public final class MathContext implements Serializable {
*/ */
final RoundingMode roundingMode; final RoundingMode roundingMode;
/**
* Lookaside for the rounding points (the numbers which determine
* whether the coefficient of a number will require rounding).
* These will be present if {@code precision > 0} and
* {@code precision <= MAX_LOOKASIDE}. In this case they will share the
* {@code BigInteger int[]} array. Note that the transients
* cannot be {@code final} because they are reconstructed on
* deserialization.
*/
transient BigInteger roundingMax = null;
transient BigInteger roundingMin = null;
private static final int MAX_LOOKASIDE = 1000;
/* ----- Constructors ----- */ /* ----- Constructors ----- */
/** /**
...@@ -173,11 +160,6 @@ public final class MathContext implements Serializable { ...@@ -173,11 +160,6 @@ public final class MathContext implements Serializable {
throw new NullPointerException("null RoundingMode"); throw new NullPointerException("null RoundingMode");
precision = setPrecision; precision = setPrecision;
if (precision > 0 && precision <= MAX_LOOKASIDE) {
roundingMax = BigInteger.TEN.pow(precision);
roundingMin = roundingMax.negate();
}
roundingMode = setRoundingMode; roundingMode = setRoundingMode;
return; return;
} }
...@@ -221,10 +203,6 @@ public final class MathContext implements Serializable { ...@@ -221,10 +203,6 @@ public final class MathContext implements Serializable {
throw new IllegalArgumentException("Digits < 0"); throw new IllegalArgumentException("Digits < 0");
// the other parameters cannot be invalid if we got here // the other parameters cannot be invalid if we got here
precision = setPrecision; precision = setPrecision;
if (precision > 0 && precision <= MAX_LOOKASIDE) {
roundingMax = BigInteger.TEN.pow(precision);
roundingMin = roundingMax.negate();
}
} }
/** /**
...@@ -343,11 +321,6 @@ public final class MathContext implements Serializable { ...@@ -343,11 +321,6 @@ public final class MathContext implements Serializable {
String message = "MathContext: null roundingMode in stream"; String message = "MathContext: null roundingMode in stream";
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
} }
// Set the lookaside, if applicable
if (precision <= MAX_LOOKASIDE) {
roundingMax = BigInteger.TEN.pow(precision);
roundingMin = roundingMax.negate();
}
} }
} }
...@@ -41,6 +41,11 @@ package java.math; ...@@ -41,6 +41,11 @@ package java.math;
* @since 1.3 * @since 1.3
*/ */
import java.util.Arrays;
import static java.math.BigInteger.LONG_MASK;
import static java.math.BigDecimal.INFLATED;
class MutableBigInteger { class MutableBigInteger {
/** /**
* Holds the magnitude of this MutableBigInteger in big endian order. * Holds the magnitude of this MutableBigInteger in big endian order.
...@@ -62,10 +67,13 @@ class MutableBigInteger { ...@@ -62,10 +67,13 @@ class MutableBigInteger {
*/ */
int offset = 0; int offset = 0;
// Constants
/** /**
* This mask is used to obtain the value of an int as if it were unsigned. * MutableBigInteger with one element value array with the value 1. Used by
* BigDecimal divideAndRound to increment the quotient. Use this constant
* only when the method is not going to modify this object.
*/ */
private final static long LONG_MASK = 0xffffffffL; static final MutableBigInteger ONE = new MutableBigInteger(1);
// Constructors // Constructors
...@@ -88,15 +96,6 @@ class MutableBigInteger { ...@@ -88,15 +96,6 @@ class MutableBigInteger {
value[0] = val; value[0] = val;
} }
/**
* Construct a new MutableBigInteger with the specified value array
* up to the specified length.
*/
MutableBigInteger(int[] val, int len) {
value = val;
intLen = len;
}
/** /**
* Construct a new MutableBigInteger with the specified value array * Construct a new MutableBigInteger with the specified value array
* up to the length of the array supplied. * up to the length of the array supplied.
...@@ -111,8 +110,8 @@ class MutableBigInteger { ...@@ -111,8 +110,8 @@ class MutableBigInteger {
* specified BigInteger. * specified BigInteger.
*/ */
MutableBigInteger(BigInteger b) { MutableBigInteger(BigInteger b) {
value = b.mag.clone(); intLen = b.mag.length;
intLen = value.length; value = Arrays.copyOf(b.mag, intLen);
} }
/** /**
...@@ -121,10 +120,58 @@ class MutableBigInteger { ...@@ -121,10 +120,58 @@ class MutableBigInteger {
*/ */
MutableBigInteger(MutableBigInteger val) { MutableBigInteger(MutableBigInteger val) {
intLen = val.intLen; intLen = val.intLen;
value = new int[intLen]; value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen);
}
for(int i=0; i<intLen; i++) /**
value[i] = val.value[val.offset+i]; * Internal helper method to return the magnitude array. The caller is not
* supposed to modify the returned array.
*/
private int[] getMagnitudeArray() {
if (offset > 0 || value.length != intLen)
return Arrays.copyOfRange(value, offset, offset + intLen);
return value;
}
/**
* Convert this MutableBigInteger to a long value. The caller has to make
* sure this MutableBigInteger can be fit into long.
*/
private long toLong() {
assert (intLen <= 2) : "this MutableBigInteger exceeds the range of long";
if (intLen == 0)
return 0;
long d = value[offset] & LONG_MASK;
return (intLen == 2) ? d << 32 | (value[offset + 1] & LONG_MASK) : d;
}
/**
* Convert this MutableBigInteger to a BigInteger object.
*/
BigInteger toBigInteger(int sign) {
if (intLen == 0 || sign == 0)
return BigInteger.ZERO;
return new BigInteger(getMagnitudeArray(), sign);
}
/**
* Convert this MutableBigInteger to BigDecimal object with the specified sign
* and scale.
*/
BigDecimal toBigDecimal(int sign, int scale) {
if (intLen == 0 || sign == 0)
return BigDecimal.valueOf(0, scale);
int[] mag = getMagnitudeArray();
int len = mag.length;
int d = mag[0];
// If this MutableBigInteger can't be fit into long, we need to
// make a BigInteger object for the resultant BigDecimal object.
if (len > 2 || (d < 0 && len == 2))
return new BigDecimal(new BigInteger(mag, sign), INFLATED, scale, 0);
long v = (len == 2) ?
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
d & LONG_MASK;
return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
} }
/** /**
...@@ -146,17 +193,21 @@ class MutableBigInteger { ...@@ -146,17 +193,21 @@ class MutableBigInteger {
/** /**
* Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1 * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1
* as this MutableBigInteger is numerically less than, equal to, or * as this MutableBigInteger is numerically less than, equal to, or
* greater than {@code b}. * greater than <tt>b</tt>.
*/ */
final int compare(MutableBigInteger b) { final int compare(MutableBigInteger b) {
if (intLen < b.intLen) int blen = b.intLen;
if (intLen < blen)
return -1; return -1;
if (intLen > b.intLen) if (intLen > blen)
return 1; return 1;
for (int i=0; i<intLen; i++) { // Add Integer.MIN_VALUE to make the comparison act as unsigned integer
int b1 = value[offset+i] + 0x80000000; // comparison.
int b2 = b.value[b.offset+i] + 0x80000000; int[] bval = b.value;
for (int i = offset, j = b.offset; i < intLen + offset; i++, j++) {
int b1 = value[i] + 0x80000000;
int b2 = bval[j] + 0x80000000;
if (b1 < b2) if (b1 < b2)
return -1; return -1;
if (b1 > b2) if (b1 > b2)
...@@ -165,6 +216,46 @@ class MutableBigInteger { ...@@ -165,6 +216,46 @@ class MutableBigInteger {
return 0; return 0;
} }
/**
* Compare this against half of a MutableBigInteger object (Needed for
* remainder tests).
* Assumes no leading unnecessary zeros, which holds for results
* from divide().
*/
final int compareHalf(MutableBigInteger b) {
int blen = b.intLen;
int len = intLen;
if (len <= 0)
return blen <=0 ? 0 : -1;
if (len > blen)
return 1;
if (len < blen - 1)
return -1;
int[] bval = b.value;
int bstart = 0;
int carry = 0;
// Only 2 cases left:len == blen or len == blen - 1
if (len != blen) { // len == blen - 1
if (bval[bstart] == 1) {
++bstart;
carry = 0x80000000;
} else
return -1;
}
// compare values with right-shifted values of b,
// carrying shifted-out bits across words
int[] val = value;
for (int i = offset, j = bstart; i < len + offset;) {
int bv = bval[j++];
long hb = ((bv >>> 1) + carry) & LONG_MASK;
long v = val[i++] & LONG_MASK;
if (v != hb)
return v < hb ? -1 : 1;
carry = (bv & 1) << 31; // carray will be either 0x80000000 or 0
}
return carry == 0? 0 : -1;
}
/** /**
* Return the index of the lowest set bit in this MutableBigInteger. If the * Return the index of the lowest set bit in this MutableBigInteger. If the
* magnitude of this MutableBigInteger is zero, -1 is returned. * magnitude of this MutableBigInteger is zero, -1 is returned.
...@@ -178,7 +269,7 @@ class MutableBigInteger { ...@@ -178,7 +269,7 @@ class MutableBigInteger {
b = value[j+offset]; b = value[j+offset];
if (b==0) if (b==0)
return -1; return -1;
return ((intLen-1-j)<<5) + BigInteger.trailingZeroCnt(b); return ((intLen-1-j)<<5) + Integer.numberOfTrailingZeros(b);
} }
/** /**
...@@ -270,13 +361,11 @@ class MutableBigInteger { ...@@ -270,13 +361,11 @@ class MutableBigInteger {
* Sets this MutableBigInteger's value array to a copy of the specified * Sets this MutableBigInteger's value array to a copy of the specified
* array. The intLen is set to the length of the new array. * array. The intLen is set to the length of the new array.
*/ */
void copyValue(MutableBigInteger val) { void copyValue(MutableBigInteger src) {
int len = val.intLen; int len = src.intLen;
if (value.length < len) if (value.length < len)
value = new int[len]; value = new int[len];
System.arraycopy(src.value, src.offset, value, 0, len);
for(int i=0; i<len; i++)
value[i] = val.value[val.offset+i];
intLen = len; intLen = len;
offset = 0; offset = 0;
} }
...@@ -289,8 +378,7 @@ class MutableBigInteger { ...@@ -289,8 +378,7 @@ class MutableBigInteger {
int len = val.length; int len = val.length;
if (value.length < len) if (value.length < len)
value = new int[len]; value = new int[len];
for(int i=0; i<len; i++) System.arraycopy(val, 0, value, 0, len);
value[i] = val[i];
intLen = len; intLen = len;
offset = 0; offset = 0;
} }
...@@ -320,7 +408,7 @@ class MutableBigInteger { ...@@ -320,7 +408,7 @@ class MutableBigInteger {
* Returns true iff this MutableBigInteger is odd. * Returns true iff this MutableBigInteger is odd.
*/ */
boolean isOdd() { boolean isOdd() {
return ((value[offset + intLen - 1] & 1) == 1); return isZero() ? false : ((value[offset + intLen - 1] & 1) == 1);
} }
/** /**
...@@ -340,7 +428,7 @@ class MutableBigInteger { ...@@ -340,7 +428,7 @@ class MutableBigInteger {
* Returns a String representation of this MutableBigInteger in radix 10. * Returns a String representation of this MutableBigInteger in radix 10.
*/ */
public String toString() { public String toString() {
BigInteger b = new BigInteger(this, 1); BigInteger b = toBigInteger(1);
return b.toString(); return b.toString();
} }
...@@ -356,7 +444,7 @@ class MutableBigInteger { ...@@ -356,7 +444,7 @@ class MutableBigInteger {
this.intLen -= nInts; this.intLen -= nInts;
if (nBits == 0) if (nBits == 0)
return; return;
int bitsInHighWord = BigInteger.bitLen(value[offset]); int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
if (nBits >= bitsInHighWord) { if (nBits >= bitsInHighWord) {
this.primitiveLeftShift(32 - nBits); this.primitiveLeftShift(32 - nBits);
this.intLen--; this.intLen--;
...@@ -379,7 +467,7 @@ class MutableBigInteger { ...@@ -379,7 +467,7 @@ class MutableBigInteger {
return; return;
int nInts = n >>> 5; int nInts = n >>> 5;
int nBits = n&0x1F; int nBits = n&0x1F;
int bitsInHighWord = BigInteger.bitLen(value[offset]); int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
// If shift can be done without moving words, do so // If shift can be done without moving words, do so
if (n <= (32-bitsInHighWord)) { if (n <= (32-bitsInHighWord)) {
...@@ -499,34 +587,41 @@ class MutableBigInteger { ...@@ -499,34 +587,41 @@ class MutableBigInteger {
int[] result = (value.length < resultLen ? new int[resultLen] : value); int[] result = (value.length < resultLen ? new int[resultLen] : value);
int rstart = result.length-1; int rstart = result.length-1;
long sum = 0; long sum;
long carry = 0;
// Add common parts of both numbers // Add common parts of both numbers
while(x>0 && y>0) { while(x>0 && y>0) {
x--; y--; x--; y--;
sum = (value[x+offset] & LONG_MASK) + sum = (value[x+offset] & LONG_MASK) +
(addend.value[y+addend.offset] & LONG_MASK) + (sum >>> 32); (addend.value[y+addend.offset] & LONG_MASK) + carry;
result[rstart--] = (int)sum; result[rstart--] = (int)sum;
carry = sum >>> 32;
} }
// Add remainder of the longer number // Add remainder of the longer number
while(x>0) { while(x>0) {
x--; x--;
sum = (value[x+offset] & LONG_MASK) + (sum >>> 32); if (carry == 0 && result == value && rstart == (x + offset))
return;
sum = (value[x+offset] & LONG_MASK) + carry;
result[rstart--] = (int)sum; result[rstart--] = (int)sum;
carry = sum >>> 32;
} }
while(y>0) { while(y>0) {
y--; y--;
sum = (addend.value[y+addend.offset] & LONG_MASK) + (sum >>> 32); sum = (addend.value[y+addend.offset] & LONG_MASK) + carry;
result[rstart--] = (int)sum; result[rstart--] = (int)sum;
carry = sum >>> 32;
} }
if ((sum >>> 32) > 0) { // Result must grow in length if (carry > 0) { // Result must grow in length
resultLen++; resultLen++;
if (result.length < resultLen) { if (result.length < resultLen) {
int temp[] = new int[resultLen]; int temp[] = new int[resultLen];
for (int i=resultLen-1; i>0; i--) // Result one word longer from carry-out; copy low-order
temp[i] = result[i-1]; // bits into new result.
System.arraycopy(result, 0, temp, 1, result.length);
temp[0] = 1; temp[0] = 1;
result = temp; result = temp;
} else { } else {
...@@ -708,29 +803,26 @@ class MutableBigInteger { ...@@ -708,29 +803,26 @@ class MutableBigInteger {
z.value = zval; z.value = zval;
} }
/** /**
* This method is used for division of an n word dividend by a one word * This method is used for division of an n word dividend by a one word
* divisor. The quotient is placed into quotient. The one word divisor is * divisor. The quotient is placed into quotient. The one word divisor is
* specified by divisor. The value of this MutableBigInteger is the * specified by divisor.
* dividend at invocation but is replaced by the remainder. *
* @return the remainder of the division is returned.
* *
* NOTE: The value of this MutableBigInteger is modified by this method.
*/ */
void divideOneWord(int divisor, MutableBigInteger quotient) { int divideOneWord(int divisor, MutableBigInteger quotient) {
long divLong = divisor & LONG_MASK; long divisorLong = divisor & LONG_MASK;
// Special case of one word dividend // Special case of one word dividend
if (intLen == 1) { if (intLen == 1) {
long remValue = value[offset] & LONG_MASK; long dividendValue = value[offset] & LONG_MASK;
quotient.value[0] = (int) (remValue / divLong); int q = (int) (dividendValue / divisorLong);
quotient.intLen = (quotient.value[0] == 0) ? 0 : 1; int r = (int) (dividendValue - q * divisorLong);
quotient.value[0] = q;
quotient.intLen = (q == 0) ? 0 : 1;
quotient.offset = 0; quotient.offset = 0;
return r;
value[0] = (int) (remValue - (quotient.value[0] * divLong));
offset = 0;
intLen = (value[0] == 0) ? 0 : 1;
return;
} }
if (quotient.value.length < intLen) if (quotient.value.length < intLen)
...@@ -739,15 +831,15 @@ class MutableBigInteger { ...@@ -739,15 +831,15 @@ class MutableBigInteger {
quotient.intLen = intLen; quotient.intLen = intLen;
// Normalize the divisor // Normalize the divisor
int shift = 32 - BigInteger.bitLen(divisor); int shift = Integer.numberOfLeadingZeros(divisor);
int rem = value[offset]; int rem = value[offset];
long remLong = rem & LONG_MASK; long remLong = rem & LONG_MASK;
if (remLong < divLong) { if (remLong < divisorLong) {
quotient.value[0] = 0; quotient.value[0] = 0;
} else { } else {
quotient.value[0] = (int)(remLong/divLong); quotient.value[0] = (int)(remLong / divisorLong);
rem = (int) (remLong - (quotient.value[0] * divLong)); rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
...@@ -757,8 +849,8 @@ class MutableBigInteger { ...@@ -757,8 +849,8 @@ class MutableBigInteger {
long dividendEstimate = (remLong<<32) | long dividendEstimate = (remLong<<32) |
(value[offset + intLen - xlen] & LONG_MASK); (value[offset + intLen - xlen] & LONG_MASK);
if (dividendEstimate >= 0) { if (dividendEstimate >= 0) {
qWord[0] = (int) (dividendEstimate/divLong); qWord[0] = (int) (dividendEstimate / divisorLong);
qWord[1] = (int) (dividendEstimate - (qWord[0] * divLong)); qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
} else { } else {
divWord(qWord, dividendEstimate, divisor); divWord(qWord, dividendEstimate, divisor);
} }
...@@ -767,81 +859,110 @@ class MutableBigInteger { ...@@ -767,81 +859,110 @@ class MutableBigInteger {
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
quotient.normalize();
// Unnormalize // Unnormalize
if (shift > 0) if (shift > 0)
value[0] = rem %= divisor; return rem % divisor;
else else
value[0] = rem; return rem;
intLen = (value[0] == 0) ? 0 : 1;
quotient.normalize();
} }
/** /**
* Calculates the quotient and remainder of this div b and places them * Calculates the quotient of this div b and places the quotient in the
* in the MutableBigInteger objects provided. * provided MutableBigInteger objects and the remainder object is returned.
* *
* Uses Algorithm D in Knuth section 4.3.1. * Uses Algorithm D in Knuth section 4.3.1.
* Many optimizations to that algorithm have been adapted from the Colin * Many optimizations to that algorithm have been adapted from the Colin
* Plumb C library. * Plumb C library.
* It special cases one word divisors for speed. * It special cases one word divisors for speed. The content of b is not
* The contents of a and b are not changed. * changed.
* *
*/ */
void divide(MutableBigInteger b, MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
MutableBigInteger quotient, MutableBigInteger rem) {
if (b.intLen == 0) if (b.intLen == 0)
throw new ArithmeticException("BigInteger divide by zero"); throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero // Dividend is zero
if (intLen == 0) { if (intLen == 0) {
quotient.intLen = quotient.offset = rem.intLen = rem.offset = 0; quotient.intLen = quotient.offset;
return; return new MutableBigInteger();
} }
int cmp = compare(b); int cmp = compare(b);
// Dividend less than divisor // Dividend less than divisor
if (cmp < 0) { if (cmp < 0) {
quotient.intLen = quotient.offset = 0; quotient.intLen = quotient.offset = 0;
rem.copyValue(this); return new MutableBigInteger(this);
return;
} }
// Dividend equal to divisor // Dividend equal to divisor
if (cmp == 0) { if (cmp == 0) {
quotient.value[0] = quotient.intLen = 1; quotient.value[0] = quotient.intLen = 1;
quotient.offset = rem.intLen = rem.offset = 0; quotient.offset = 0;
return; return new MutableBigInteger();
} }
quotient.clear(); quotient.clear();
// Special case one word divisor // Special case one word divisor
if (b.intLen == 1) { if (b.intLen == 1) {
rem.copyValue(this); int r = divideOneWord(b.value[b.offset], quotient);
rem.divideOneWord(b.value[b.offset], quotient); if (r == 0)
return; return new MutableBigInteger();
return new MutableBigInteger(r);
} }
// Copy divisor value to protect divisor // Copy divisor value to protect divisor
int[] d = new int[b.intLen]; int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
for(int i=0; i<b.intLen; i++) return divideMagnitude(div, quotient);
d[i] = b.value[b.offset+i]; }
int dlen = b.intLen;
// Remainder starts as dividend with space for a leading zero /**
if (rem.value.length < intLen +1) * Internally used to calculate the quotient of this div v and places the
rem.value = new int[intLen+1]; * quotient in the provided MutableBigInteger object and the remainder is
* returned.
*
* @return the remainder of the division will be returned.
*/
long divide(long v, MutableBigInteger quotient) {
if (v == 0)
throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero
if (intLen == 0) {
quotient.intLen = quotient.offset = 0;
return 0;
}
if (v < 0)
v = -v;
int d = (int)(v >>> 32);
quotient.clear();
// Special case on word divisor
if (d == 0)
return divideOneWord((int)v, quotient) & LONG_MASK;
else {
int[] div = new int[]{ d, (int)(v & LONG_MASK) };
return divideMagnitude(div, quotient).toLong();
}
}
/**
* Divide this MutableBigInteger by the divisor represented by its magnitude
* array. The quotient will be placed into the provided quotient object &
* the remainder object is returned.
*/
private MutableBigInteger divideMagnitude(int[] divisor,
MutableBigInteger quotient) {
for (int i=0; i<intLen; i++) // Remainder starts as dividend with space for a leading zero
rem.value[i+1] = value[i+offset]; MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
System.arraycopy(value, offset, rem.value, 1, intLen);
rem.intLen = intLen; rem.intLen = intLen;
rem.offset = 1; rem.offset = 1;
int nlen = rem.intLen; int nlen = rem.intLen;
// Set the quotient size // Set the quotient size
int dlen = divisor.length;
int limit = nlen - dlen + 1; int limit = nlen - dlen + 1;
if (quotient.value.length < limit) { if (quotient.value.length < limit) {
quotient.value = new int[limit]; quotient.value = new int[limit];
...@@ -851,10 +972,10 @@ class MutableBigInteger { ...@@ -851,10 +972,10 @@ class MutableBigInteger {
int[] q = quotient.value; int[] q = quotient.value;
// D1 normalize the divisor // D1 normalize the divisor
int shift = 32 - BigInteger.bitLen(d[0]); int shift = Integer.numberOfLeadingZeros(divisor[0]);
if (shift > 0) { if (shift > 0) {
// First shift will not grow array // First shift will not grow array
BigInteger.primitiveLeftShift(d, dlen, shift); BigInteger.primitiveLeftShift(divisor, dlen, shift);
// But this one might // But this one might
rem.leftShift(shift); rem.leftShift(shift);
} }
...@@ -866,9 +987,9 @@ class MutableBigInteger { ...@@ -866,9 +987,9 @@ class MutableBigInteger {
rem.intLen++; rem.intLen++;
} }
int dh = d[0]; int dh = divisor[0];
long dhLong = dh & LONG_MASK; long dhLong = dh & LONG_MASK;
int dl = d[1]; int dl = divisor[1];
int[] qWord = new int[2]; int[] qWord = new int[2];
// D2 Initialize j // D2 Initialize j
...@@ -910,7 +1031,7 @@ class MutableBigInteger { ...@@ -910,7 +1031,7 @@ class MutableBigInteger {
qhat--; qhat--;
qrem = (int)((qrem & LONG_MASK) + dhLong); qrem = (int)((qrem & LONG_MASK) + dhLong);
if ((qrem & LONG_MASK) >= dhLong) { if ((qrem & LONG_MASK) >= dhLong) {
estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); estProduct -= (dl & LONG_MASK);
rs = ((qrem & LONG_MASK) << 32) | nl; rs = ((qrem & LONG_MASK) << 32) | nl;
if (unsignedLongCompare(estProduct, rs)) if (unsignedLongCompare(estProduct, rs))
qhat--; qhat--;
...@@ -920,12 +1041,12 @@ class MutableBigInteger { ...@@ -920,12 +1041,12 @@ class MutableBigInteger {
// D4 Multiply and subtract // D4 Multiply and subtract
rem.value[j+rem.offset] = 0; rem.value[j+rem.offset] = 0;
int borrow = mulsub(rem.value, d, qhat, dlen, j+rem.offset); int borrow = mulsub(rem.value, divisor, qhat, dlen, j+rem.offset);
// D5 Test remainder // D5 Test remainder
if (borrow + 0x80000000 > nh2) { if (borrow + 0x80000000 > nh2) {
// D6 Add back // D6 Add back
divadd(d, rem.value, j+1+rem.offset); divadd(divisor, rem.value, j+1+rem.offset);
qhat--; qhat--;
} }
...@@ -937,8 +1058,9 @@ class MutableBigInteger { ...@@ -937,8 +1058,9 @@ class MutableBigInteger {
if (shift > 0) if (shift > 0)
rem.rightShift(shift); rem.rightShift(shift);
rem.normalize();
quotient.normalize(); quotient.normalize();
rem.normalize();
return rem;
} }
/** /**
...@@ -989,16 +1111,15 @@ class MutableBigInteger { ...@@ -989,16 +1111,15 @@ class MutableBigInteger {
// Use Euclid's algorithm until the numbers are approximately the // Use Euclid's algorithm until the numbers are approximately the
// same length, then use the binary GCD algorithm to find the GCD. // same length, then use the binary GCD algorithm to find the GCD.
MutableBigInteger a = this; MutableBigInteger a = this;
MutableBigInteger q = new MutableBigInteger(), MutableBigInteger q = new MutableBigInteger();
r = new MutableBigInteger();
while (b.intLen != 0) { while (b.intLen != 0) {
if (Math.abs(a.intLen - b.intLen) < 2) if (Math.abs(a.intLen - b.intLen) < 2)
return a.binaryGCD(b); return a.binaryGCD(b);
a.divide(b, q, r); MutableBigInteger r = a.divide(b, q);
MutableBigInteger swapper = a; a = b;
a = b; b = r; r = swapper; b = r;
} }
return a; return a;
} }
...@@ -1069,40 +1190,21 @@ class MutableBigInteger { ...@@ -1069,40 +1190,21 @@ class MutableBigInteger {
if (a==0) if (a==0)
return b; return b;
int x; // Right shift a & b till their last bits equal to 1.
int aZeros = 0; int aZeros = Integer.numberOfTrailingZeros(a);
while ((x = a & 0xff) == 0) { int bZeros = Integer.numberOfTrailingZeros(b);
a >>>= 8; a >>>= aZeros;
aZeros += 8; b >>>= bZeros;
}
int y = BigInteger.trailingZeroTable[x];
aZeros += y;
a >>>= y;
int bZeros = 0;
while ((x = b & 0xff) == 0) {
b >>>= 8;
bZeros += 8;
}
y = BigInteger.trailingZeroTable[x];
bZeros += y;
b >>>= y;
int t = (aZeros < bZeros ? aZeros : bZeros); int t = (aZeros < bZeros ? aZeros : bZeros);
while (a != b) { while (a != b) {
if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned
a -= b; a -= b;
a >>>= Integer.numberOfTrailingZeros(a);
while ((x = a & 0xff) == 0)
a >>>= 8;
a >>>= BigInteger.trailingZeroTable[x];
} else { } else {
b -= a; b -= a;
b >>>= Integer.numberOfTrailingZeros(b);
while ((x = b & 0xff) == 0)
b >>>= 8;
b >>>= BigInteger.trailingZeroTable[x];
} }
} }
return a<<t; return a<<t;
...@@ -1152,8 +1254,7 @@ class MutableBigInteger { ...@@ -1152,8 +1254,7 @@ class MutableBigInteger {
temp1.multiply(y2, temp2); temp1.multiply(y2, temp2);
result.add(temp2); result.add(temp2);
result.divide(p, temp1, temp2); return result.divide(p, temp1);
return temp2;
} }
/* /*
...@@ -1321,40 +1422,45 @@ class MutableBigInteger { ...@@ -1321,40 +1422,45 @@ class MutableBigInteger {
MutableBigInteger a = new MutableBigInteger(this); MutableBigInteger a = new MutableBigInteger(this);
MutableBigInteger q = new MutableBigInteger(); MutableBigInteger q = new MutableBigInteger();
MutableBigInteger r = new MutableBigInteger(); MutableBigInteger r = b.divide(a, q);
b.divide(a, q, r); MutableBigInteger swapper = b;
MutableBigInteger swapper = b; b = r; r = swapper; // swap b & r
b = r;
r = swapper;
MutableBigInteger t1 = new MutableBigInteger(q); MutableBigInteger t1 = new MutableBigInteger(q);
MutableBigInteger t0 = new MutableBigInteger(1); MutableBigInteger t0 = new MutableBigInteger(1);
MutableBigInteger temp = new MutableBigInteger(); MutableBigInteger temp = new MutableBigInteger();
while (!b.isOne()) { while (!b.isOne()) {
a.divide(b, q, r); r = a.divide(b, q);
if (r.intLen == 0) if (r.intLen == 0)
throw new ArithmeticException("BigInteger not invertible."); throw new ArithmeticException("BigInteger not invertible.");
swapper = r; r = a; a = swapper; swapper = r;
a = swapper;
if (q.intLen == 1) if (q.intLen == 1)
t1.mul(q.value[q.offset], temp); t1.mul(q.value[q.offset], temp);
else else
q.multiply(t1, temp); q.multiply(t1, temp);
swapper = q; q = temp; temp = swapper; swapper = q;
q = temp;
temp = swapper;
t0.add(q); t0.add(q);
if (a.isOne()) if (a.isOne())
return t0; return t0;
b.divide(a, q, r); r = b.divide(a, q);
if (r.intLen == 0) if (r.intLen == 0)
throw new ArithmeticException("BigInteger not invertible."); throw new ArithmeticException("BigInteger not invertible.");
swapper = b; b = r; r = swapper; swapper = b;
b = r;
if (q.intLen == 1) if (q.intLen == 1)
t0.mul(q.value[q.offset], temp); t0.mul(q.value[q.offset], temp);
......
...@@ -129,9 +129,7 @@ class SignedMutableBigInteger extends MutableBigInteger { ...@@ -129,9 +129,7 @@ class SignedMutableBigInteger extends MutableBigInteger {
* array starting at offset. * array starting at offset.
*/ */
public String toString() { public String toString() {
BigInteger b = new BigInteger(this, sign); return this.toBigInteger(sign).toString();
return
b.toString();
} }
} }
...@@ -38,6 +38,31 @@ public class AddTests { ...@@ -38,6 +38,31 @@ public class AddTests {
private static Set<RoundingMode> nonExactRoundingModes = private static Set<RoundingMode> nonExactRoundingModes =
EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY)); EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
/**
* Test for some simple additions, particularly, it will test
* the overflow case.
*/
private static int simpleTests() {
int failures = 0;
BigDecimal[] bd1 = {
new BigDecimal(new BigInteger("7812404666936930160"), 11),
new BigDecimal(new BigInteger("7812404666936930160"), 12),
new BigDecimal(new BigInteger("7812404666936930160"), 13),
};
BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
BigDecimal[] expectedResult = {
new BigDecimal("78403046.66936930160"),
new BigDecimal("8091404.666936930160"),
new BigDecimal("1060240.4666936930160"),
};
for (int i = 0; i < bd1.length; i++) {
if (!bd1[i].add(bd2).equals(expectedResult[i]))
failures++;
}
return failures;
}
/** /**
* Test for extreme value of scale and rounding precision that * Test for extreme value of scale and rounding precision that
* could cause integer overflow in right-shift-into-sticky-bit * could cause integer overflow in right-shift-into-sticky-bit
......
...@@ -281,6 +281,10 @@ public class DivideTests { ...@@ -281,6 +281,10 @@ public class DivideTests {
BigDecimal c = new BigDecimal("31425"); BigDecimal c = new BigDecimal("31425");
BigDecimal c_minus = c.negate(); BigDecimal c_minus = c.negate();
// Ad hoc tests
BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
BigDecimal[][] testCases = { BigDecimal[][] testCases = {
{a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")}, {a, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("3.142")},
{a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")}, {a_minus, b, BigDecimal.valueOf(ROUND_UP, 3), new BigDecimal("-3.142")},
...@@ -305,6 +309,10 @@ public class DivideTests { ...@@ -305,6 +309,10 @@ public class DivideTests {
{c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")}, {c, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
{c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")}, {c_minus, b, BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
{d, e, BigDecimal.valueOf(ROUND_HALF_UP, -5), BigDecimal.valueOf(-1, -5)},
{d, e, BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
{d, e, BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
}; };
for(BigDecimal tc[] : testCases) { for(BigDecimal tc[] : testCases) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册