提交 60839a4f 编写于 作者: D darcy

7082971: More performance tuning of BigDecimal and other java.math classes

Reviewed-by: darcy
Contributed-by: sergey.kuksenko@oracle.com
上级 509f241d
......@@ -215,6 +215,7 @@ import static java.math.BigInteger.LONG_MASK;
* @author Josh Bloch
* @author Mike Cowlishaw
* @author Joseph D. Darcy
* @author Sergey V. Kuksenko
*/
public class BigDecimal extends Number implements Comparable<BigDecimal> {
/**
......@@ -224,7 +225,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @serial
* @see #unscaledValue
*/
private volatile BigInteger intVal;
private final BigInteger intVal;
/**
* The scale of this BigDecimal, as returned by {@link #scale}.
......@@ -232,8 +233,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @serial
* @see #scale
*/
private int scale; // Note: this may have any value, so
private final int scale; // Note: this may have any value, so
// calculations must be done in longs
/**
* The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If
......@@ -256,19 +258,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
static final long INFLATED = Long.MIN_VALUE;
private static final BigInteger INFLATED_BIGINT = BigInteger.valueOf(INFLATED);
/**
* If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations.
*/
private transient long intCompact;
private final transient long intCompact;
// All 18-digit base ten strings fit into a long; not all 19-digit
// strings will
private static final int MAX_COMPACT_DIGITS = 18;
private static final int MAX_BIGINT_BITS = 62;
/* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L;
......@@ -378,9 +380,36 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len) {
this(in,offset,len,MathContext.UNLIMITED);
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor, while allowing a sub-array to be specified and
* with rounding according to the context settings.
*
* <p>Note that if the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
* @param len number of characters to consider..
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal} or the defined subarray
* is not wholly within {@code in}.
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
// protect against huge length.
if (offset+len > in.length || offset < 0)
throw new NumberFormatException();
if (offset + len > in.length || offset < 0)
throw new NumberFormatException("Bad offset or len arguments for char[] input.");
// This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate
......@@ -391,7 +420,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
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,
// bad offset, etc.
try {
......@@ -408,23 +436,39 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// should now be at numeric part of the significand
boolean dot = false; // true when there is a '.'
int cfirst = offset; // record start of integer
long exp = 0; // exponent
char c; // current character
boolean isCompact = (len <= MAX_COMPACT_DIGITS);
// 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--) {
c = in[offset];
// have digit
if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
if (isCompact) {
// First compact case, we need not to preserve the character
// and we can just compute the value in place.
if (isCompact) {
for (; len > 0; offset++, len--) {
c = in[offset];
if ((c == '0')) { // have zero
if (prec == 0)
prec = 1;
else if (rs != 0) {
rs *= 10;
++prec;
} // else digit is a redundant leading zero
if (dot)
++scl;
} else if ((c >= '1' && c <= '9')) { // have digit
int digit = c - '0';
if (prec != 1 || rs != 0)
++prec; // prec unchanged if preceded by 0s
rs = rs * 10 + digit;
if (dot)
++scl;
} else if (c == '.') { // have dot
// have dot
if (dot) // two dots
throw new NumberFormatException();
dot = true;
} else if (Character.isDigit(c)) { // slow path
int digit = Character.digit(c, 10);
if (digit == 0) {
if (prec == 0)
......@@ -438,7 +482,44 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
++prec; // prec unchanged if preceded by 0s
rs = rs * 10 + digit;
}
} else { // the unscaled value is likely a BigInteger object.
if (dot)
++scl;
} else if ((c == 'e') || (c == 'E')) {
exp = parseExp(in, offset, len);
// Next test is required for backwards compatibility
if ((int) exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
} else {
throw new NumberFormatException();
}
}
if (prec == 0) // no digits found
throw new NumberFormatException();
// Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
scl = adjustScale(scl, exp);
}
rs = isneg ? -rs : rs;
int mcp = mc.precision;
int drop = prec - mcp; // prec has range [1, MAX_INT], mcp has range [0, MAX_INT];
// therefore, this subtract cannot overflow
if (mcp > 0 && drop > 0) { // do rounding
while (drop > 0) {
scl = checkScaleNonZero((long) scl - drop);
rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(rs);
drop = prec - mcp;
}
}
} else {
char coeff[] = new char[len];
for (; len > 0; offset++, len--) {
c = in[offset];
// have digit
if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
// First compact case, we need not to preserve the character
// and we can just compute the value in place.
if (c == '0' || Character.digit(c, 10) == 0) {
if (prec == 0) {
coeff[idx] = c;
......@@ -452,7 +533,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
++prec; // prec unchanged if preceded by 0s
coeff[idx++] = c;
}
}
if (dot)
++scl;
continue;
......@@ -468,8 +548,76 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// exponent expected
if ((c != 'e') && (c != 'E'))
throw new NumberFormatException();
exp = parseExp(in, offset, len);
// Next test is required for backwards compatibility
if ((int) exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
}
// here when no characters left
if (prec == 0) // no digits found
throw new NumberFormatException();
// Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
scl = adjustScale(scl, exp);
}
// Remove leading zeros from precision (digits count)
rb = new BigInteger(coeff, isneg ? -1 : 1, prec);
rs = compactValFor(rb);
int mcp = mc.precision;
if (mcp > 0 && (prec > mcp)) {
if (rs == INFLATED) {
int drop = prec - mcp;
while (drop > 0) {
scl = checkScaleNonZero((long) scl - drop);
rb = divideAndRoundByTenPow(rb, drop, mc.roundingMode.oldMode);
rs = compactValFor(rb);
if (rs != INFLATED) {
prec = longDigitLength(rs);
break;
}
prec = bigDigitLength(rb);
drop = prec - mcp;
}
}
if (rs != INFLATED) {
int drop = prec - mcp;
while (drop > 0) {
scl = checkScaleNonZero((long) scl - drop);
rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(rs);
drop = prec - mcp;
}
rb = null;
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException();
} catch (NegativeArraySizeException e) {
throw new NumberFormatException();
}
this.scale = scl;
this.precision = prec;
this.intCompact = rs;
this.intVal = rb;
}
private int adjustScale(int scl, long exp) {
long adjustedScale = scl - exp;
if (adjustedScale > Integer.MAX_VALUE || adjustedScale < Integer.MIN_VALUE)
throw new NumberFormatException("Scale out of range.");
scl = (int) adjustedScale;
return scl;
}
/*
* parse exponent
*/
private static long parseExp(char[] in, int offset, int len){
long exp = 0;
offset++;
c = in[offset];
char c = in[offset];
len--;
boolean negexp = (c == '-');
// optional sign
......@@ -481,7 +629,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (len <= 0) // no exponent digits
throw new NumberFormatException();
// skip leading zeros in the exponent
while (len > 10 && Character.digit(c, 10) == 0) {
while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) {
offset++;
c = in[offset];
len--;
......@@ -506,79 +654,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
if (negexp) // apply sign
exp = -exp;
// Next test is required for backwards compatibility
if ((int)exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
}
// here when no characters left
if (prec == 0) // no digits found
throw new NumberFormatException();
// Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
// Can't call checkScale which relies on proper fields value
long adjustedScale = scl - exp;
if (adjustedScale > Integer.MAX_VALUE ||
adjustedScale < Integer.MIN_VALUE)
throw new NumberFormatException("Scale out of range.");
scl = (int)adjustedScale;
}
// Remove leading zeros from precision (digits count)
if (isCompact) {
rs = isneg ? -rs : rs;
} else {
char quick[];
if (!isneg) {
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);
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException();
} catch (NegativeArraySizeException e) {
throw new NumberFormatException();
}
this.scale = scl;
this.precision = prec;
this.intCompact = rs;
this.intVal = (rs != INFLATED) ? null : rb;
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor, while allowing a sub-array to be specified and
* with rounding according to the context settings.
*
* <p>Note that if the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
* @param len number of characters to consider..
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal} or the defined subarray
* is not wholly within {@code in}.
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
this(in, offset, len);
if (mc.precision > 0)
roundThis(mc);
return exp;
}
/**
......@@ -754,9 +830,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(String val, MathContext mc) {
this(val.toCharArray(), 0, val.length());
if (mc.precision > 0)
roundThis(mc);
this(val.toCharArray(), 0, val.length(), mc);
}
/**
......@@ -804,49 +878,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @throws NumberFormatException if {@code val} is infinite or NaN.
*/
public BigDecimal(double val) {
if (Double.isInfinite(val) || Double.isNaN(val))
throw new NumberFormatException("Infinite or NaN");
// Translate the double into sign, exponent and significand, according
// to the formulae in JLS, Section 20.10.22.
long valBits = Double.doubleToLongBits(val);
int sign = ((valBits >> 63)==0 ? 1 : -1);
int exponent = (int) ((valBits >> 52) & 0x7ffL);
long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
: (valBits & ((1L<<52) - 1)) | (1L<<52));
exponent -= 1075;
// At this point, val == sign * significand * 2**exponent.
/*
* Special case zero to supress nonterminating normalization
* and bogus scale calculation.
*/
if (significand == 0) {
intVal = BigInteger.ZERO;
intCompact = 0;
precision = 1;
return;
}
// Normalize
while((significand & 1) == 0) { // i.e., significand is even
significand >>= 1;
exponent++;
}
// Calculate intVal and scale
long s = sign * significand;
BigInteger b;
if (exponent < 0) {
b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
scale = -exponent;
} else if (exponent > 0) {
b = BigInteger.valueOf(2).pow(exponent).multiply(s);
} else {
b = BigInteger.valueOf(s);
}
intCompact = compactValFor(b);
intVal = (intCompact != INFLATED) ? null : b;
this(val,MathContext.UNLIMITED);
}
/**
......@@ -868,9 +900,86 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(double val, MathContext mc) {
this(val);
if (mc.precision > 0)
roundThis(mc);
if (Double.isInfinite(val) || Double.isNaN(val))
throw new NumberFormatException("Infinite or NaN");
// Translate the double into sign, exponent and significand, according
// to the formulae in JLS, Section 20.10.22.
int sign = (val >= 0.0 ? 1 : -1); // Preserving sign of zero doesn't matter
int exponent = Math.getExponent(val);
long valBits = Double.doubleToLongBits(val);
long significand = (exponent == (Double.MIN_EXPONENT-1)
? (valBits & ((1L << 52) - 1)) << 1
: (valBits & ((1L << 52) - 1)) | (1L << 52));
// At this point, val == sign * significand * 2**exponent.
/*
* Special case zero to supress nonterminating normalization and bogus
* scale calculation.
*/
if (significand == 0) {
this.intVal = BigInteger.ZERO;
this.scale = 0;
this.intCompact = 0;
this.precision = 1;
return;
}
// Normalize
while ((significand & 1) == 0) { // i.e., significand is even
significand >>= 1;
exponent++;
}
int scale = 0;
// Calculate intVal and scale
BigInteger intVal;
long compactVal = sign * significand;
if (exponent == 0) {
// If the exponent is zero, the significant fits in a long
assert compactVal != INFLATED;
intVal = null;
} else {
if (exponent < 0) {
intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
scale = -exponent;
} else { // (exponent > 0)
intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal);
}
compactVal = compactValFor(intVal);
}
int prec = 0;
int mcp = mc.precision;
if (mcp > 0) { // do rounding
int mode = mc.roundingMode.oldMode;
int drop;
if (compactVal == INFLATED) {
prec = bigDigitLength(intVal);
drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
intVal = divideAndRoundByTenPow(intVal, drop, mode);
compactVal = compactValFor(intVal);
if (compactVal != INFLATED) {
break;
}
prec = bigDigitLength(intVal);
drop = prec - mcp;
}
}
if (compactVal != INFLATED) {
prec = longDigitLength(compactVal);
drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
intVal = null;
}
}
this.intVal = intVal;
this.intCompact = compactVal;
this.scale = scale;
this.precision = prec;
}
/**
......@@ -881,8 +990,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code BigDecimal}.
*/
public BigDecimal(BigInteger val) {
scale = 0;
intVal = val;
intCompact = compactValFor(val);
intVal = (intCompact != INFLATED) ? null : val;
}
/**
......@@ -898,9 +1008,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(BigInteger val, MathContext mc) {
this(val);
if (mc.precision > 0)
roundThis(mc);
this(val,0,mc);
}
/**
......@@ -914,7 +1022,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed
this(unscaledVal);
this.intVal = unscaledVal;
this.intCompact = compactValFor(unscaledVal);
this.scale = scale;
}
......@@ -934,10 +1043,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
this(unscaledVal);
long compactVal = compactValFor(unscaledVal);
int mcp = mc.precision;
int prec = 0;
if (mcp > 0) { // do rounding
int mode = mc.roundingMode.oldMode;
if (compactVal == INFLATED) {
prec = bigDigitLength(unscaledVal);
int drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
unscaledVal = divideAndRoundByTenPow(unscaledVal, drop, mode);
compactVal = compactValFor(unscaledVal);
if (compactVal != INFLATED) {
break;
}
prec = bigDigitLength(unscaledVal);
drop = prec - mcp;
}
}
if (compactVal != INFLATED) {
prec = longDigitLength(compactVal);
int drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
unscaledVal = null;
}
}
this.intVal = unscaledVal;
this.intCompact = compactVal;
this.scale = scale;
if (mc.precision > 0)
roundThis(mc);
this.precision = prec;
}
/**
......@@ -949,7 +1089,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(int val) {
intCompact = val;
this.intCompact = val;
this.scale = 0;
this.intVal = null;
}
/**
......@@ -964,9 +1106,24 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(int val, MathContext mc) {
intCompact = val;
if (mc.precision > 0)
roundThis(mc);
int mcp = mc.precision;
long compactVal = val;
int scale = 0;
int prec = 0;
if (mcp > 0) { // do rounding
prec = longDigitLength(compactVal);
int drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
}
this.intVal = null;
this.intCompact = compactVal;
this.scale = scale;
this.precision = prec;
}
/**
......@@ -978,7 +1135,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigDecimal(long val) {
this.intCompact = val;
this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
this.scale = 0;
}
/**
......@@ -993,11 +1151,44 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal(long val, MathContext mc) {
this(val);
if (mc.precision > 0)
roundThis(mc);
}
int mcp = mc.precision;
int mode = mc.roundingMode.oldMode;
int prec = 0;
int scale = 0;
BigInteger intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
if (mcp > 0) { // do rounding
if (val == INFLATED) {
prec = 19;
int drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
intVal = divideAndRoundByTenPow(intVal, drop, mode);
val = compactValFor(intVal);
if (val != INFLATED) {
break;
}
prec = bigDigitLength(intVal);
drop = prec - mcp;
}
}
if (val != INFLATED) {
prec = longDigitLength(val);
int drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
val = divideAndRound(val, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(val);
drop = prec - mcp;
}
intVal = null;
}
}
this.intVal = intVal;
this.intCompact = val;
this.scale = scale;
this.precision = prec;
}
// Static Factory Methods
/**
......@@ -1016,13 +1207,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (scale == 0)
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);
return zeroValueOf(scale);
}
return new BigDecimal(unscaledVal == INFLATED ?
BigInteger.valueOf(unscaledVal) : null,
INFLATED_BIGINT : null,
unscaledVal, scale, 0);
}
......@@ -1041,7 +1229,34 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return zeroThroughTen[(int)val];
else if (val != INFLATED)
return new BigDecimal(null, val, 0, 0);
return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
}
static BigDecimal valueOf(long unscaledVal, int scale, int prec) {
if (scale == 0 && unscaledVal >= 0 && unscaledVal < zeroThroughTen.length) {
return zeroThroughTen[(int) unscaledVal];
} else if (unscaledVal == 0) {
return zeroValueOf(scale);
}
return new BigDecimal(unscaledVal == INFLATED ? INFLATED_BIGINT : null,
unscaledVal, scale, prec);
}
static BigDecimal valueOf(BigInteger intVal, int scale, int prec) {
long val = compactValFor(intVal);
if (val == 0) {
return zeroValueOf(scale);
} else if (scale == 0 && val >= 0 && val < zeroThroughTen.length) {
return zeroThroughTen[(int) val];
}
return new BigDecimal(intVal, val, scale, prec);
}
static BigDecimal zeroValueOf(int scale) {
if (scale >= 0 && scale < ZERO_SCALED_BY.length)
return ZERO_SCALED_BY[scale];
else
return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
}
/**
......@@ -1079,42 +1294,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this + augend}
*/
public BigDecimal add(BigDecimal augend) {
long xs = this.intCompact;
long ys = augend.intCompact;
BigInteger fst = (xs != INFLATED) ? null : this.intVal;
BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
int rscale = this.scale;
long sdiff = (long)rscale - augend.scale;
if (sdiff != 0) {
if (sdiff < 0) {
int raise = checkScale(-sdiff);
rscale = augend.scale;
if (xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
fst = bigMultiplyPowerTen(raise);
if (this.intCompact != INFLATED) {
if ((augend.intCompact != INFLATED)) {
return add(this.intCompact, this.scale, augend.intCompact, augend.scale);
} else {
int raise = augend.checkScale(sdiff);
if (ys == INFLATED ||
(ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
snd = augend.bigMultiplyPowerTen(raise);
return add(this.intCompact, this.scale, augend.intVal, augend.scale);
}
} else {
if ((augend.intCompact != INFLATED)) {
return add(augend.intCompact, augend.scale, this.intVal, this.scale);
} else {
return add(this.intVal, this.scale, augend.intVal, augend.scale);
}
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 BigDecimal.valueOf(sum, rscale);
}
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);
}
/**
......@@ -1136,10 +1328,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return add(augend);
BigDecimal lhs = this;
// Could optimize if values are compact
this.inflate();
augend.inflate();
// If either number is zero then the other number, rounded and
// scaled if necessary, is used as the result.
{
......@@ -1150,20 +1338,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int preferredScale = Math.max(lhs.scale(), augend.scale());
BigDecimal result;
// Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero)
return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
return zeroValueOf(preferredScale);
result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
if (result.scale() == preferredScale)
return result;
else if (result.scale() > preferredScale) {
BigDecimal scaledResult =
new BigDecimal(result.intVal, result.intCompact,
result.scale, 0);
scaledResult.stripZerosToMatchScale(preferredScale);
return scaledResult;
return stripZerosToMatchScale(result.intVal, result.intCompact, result.scale, preferredScale);
} else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale();
......@@ -1176,17 +1358,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
}
long padding = (long)lhs.scale - augend.scale;
long padding = (long) lhs.scale - augend.scale;
if (padding != 0) { // scales differ; alignment needed
BigDecimal arg[] = preAlign(lhs, augend, padding, mc);
matchScale(arg);
lhs = arg[0];
augend = arg[1];
}
BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
lhs.scale);
return doRound(d, mc);
return doRound(lhs.inflated().add(augend.inflated()), lhs.scale, mc);
}
/**
......@@ -1211,8 +1390,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* that the number of digits of the smaller operand could be
* reduced even though the significands partially overlapped.
*/
private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend,
long padding, MathContext mc) {
private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, long padding, MathContext mc) {
assert padding != 0;
BigDecimal big;
BigDecimal small;
......@@ -1226,12 +1404,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
/*
* This is the estimated scale of an ulp of the result; it
* assumes that the result doesn't have a carry-out on a true
* add (e.g. 999 + 1 => 1000) or any subtractive cancellation
* on borrowing (e.g. 100 - 1.2 => 98.8)
* This is the estimated scale of an ulp of the result; it assumes that
* the result doesn't have a carry-out on a true add (e.g. 999 + 1 =>
* 1000) or any subtractive cancellation on borrowing (e.g. 100 - 1.2 =>
* 98.8)
*/
long estResultUlpScale = (long)big.scale - big.precision() + mc.precision;
long estResultUlpScale = (long) big.scale - big.precision() + mc.precision;
/*
* The low-order digit position of big is big.scale(). This
......@@ -1242,11 +1420,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* disjoint *and* the digit positions of small should not be
* directly visible in the result.
*/
long smallHighDigitPos = (long)small.scale - small.precision() + 1;
long smallHighDigitPos = (long) small.scale - small.precision() + 1;
if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible
small = BigDecimal.valueOf(small.signum(),
this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
small = BigDecimal.valueOf(small.signum(), this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
}
// Since addition is symmetric, preserving input order in
......@@ -1264,7 +1441,22 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this - subtrahend}
*/
public BigDecimal subtract(BigDecimal subtrahend) {
return add(subtrahend.negate());
if (this.intCompact != INFLATED) {
if ((subtrahend.intCompact != INFLATED)) {
return add(this.intCompact, this.scale, -subtrahend.intCompact, subtrahend.scale);
} else {
return add(this.intCompact, this.scale, subtrahend.intVal.negate(), subtrahend.scale);
}
} else {
if ((subtrahend.intCompact != INFLATED)) {
// Pair of subtrahend values given before pair of
// values from this BigDecimal to avoid need for
// method overloading on the specialized add method
return add(-subtrahend.intCompact, subtrahend.scale, this.intVal, this.scale);
} else {
return add(this.intVal, this.scale, subtrahend.intVal.negate(), subtrahend.scale);
}
}
}
/**
......@@ -1282,11 +1474,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
BigDecimal nsubtrahend = subtrahend.negate();
if (mc.precision == 0)
return add(nsubtrahend);
return subtract(subtrahend);
// share the special rounding code in add()
return add(nsubtrahend, mc);
return add(subtrahend.negate(), mc);
}
/**
......@@ -1298,37 +1489,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this * multiplicand}
*/
public BigDecimal multiply(BigDecimal multiplicand) {
long x = this.intCompact;
long y = multiplicand.intCompact;
int productScale = checkScale((long)scale + multiplicand.scale);
// Might be able to do a more clever check incorporating the
// inflated check into the overflow computation.
if (x != INFLATED && y != INFLATED) {
/*
* If the product is not an overflowed value, continue
* to use the compact representation. if either of x or y
* is INFLATED, the product should also be regarded as
* an overflow. Before using the overflow test suggested in
* "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 prec = this.precision() + multiplicand.precision();
if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
return BigDecimal.valueOf(product, productScale);
return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
productScale, 0);
}
BigInteger rb;
if (x == INFLATED && y == INFLATED)
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);
int productScale = checkScale((long) scale + multiplicand.scale);
if (this.intCompact != INFLATED) {
if ((multiplicand.intCompact != INFLATED)) {
return multiply(this.intCompact, multiplicand.intCompact, productScale);
} else {
return multiply(this.intCompact, multiplicand.intVal, productScale);
}
} else {
if ((multiplicand.intCompact != INFLATED)) {
return multiply(multiplicand.intCompact, this.intVal, productScale);
} else {
return multiply(this.intVal, multiplicand.intVal, productScale);
}
}
}
/**
......@@ -1345,7 +1519,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0)
return multiply(multiplicand);
return doRound(this.multiply(multiplicand), mc);
int productScale = checkScale((long) scale + multiplicand.scale);
if (this.intCompact != INFLATED) {
if ((multiplicand.intCompact != INFLATED)) {
return multiplyAndRound(this.intCompact, multiplicand.intCompact, productScale, mc);
} else {
return multiplyAndRound(this.intCompact, multiplicand.intVal, productScale, mc);
}
} else {
if ((multiplicand.intCompact != INFLATED)) {
return multiplyAndRound(multiplicand.intCompact, this.intVal, productScale, mc);
} else {
return multiplyAndRound(this.intVal, multiplicand.intVal, productScale, mc);
}
}
}
/**
......@@ -1377,121 +1564,22 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #ROUND_UNNECESSARY
*/
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
/*
* IMPLEMENTATION NOTE: This method *must* return a new object
* since divideAndRound uses divide to generate a value whose
* scale is then modified.
*/
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
/*
* Rescale dividend or divisor (whichever can be "upscaled" to
* produce correctly scaled quotient).
* Take care to detect out-of-range scales
*/
BigDecimal dividend = this;
if (checkScale((long)scale + divisor.scale) > this.scale)
dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
else
divisor = divisor.setScale(checkScale((long)this.scale - scale),
ROUND_UNNECESSARY);
return divideAndRound(dividend.intCompact, dividend.intVal,
divisor.intCompact, divisor.intVal,
scale, roundingMode, scale);
}
/**
* Internally used for division operation. The dividend and divisor are
* passed both in {@code long} format and {@code BigInteger} format. The
* returned {@code BigDecimal} object is the quotient whose scale is set to
* the passed in scale. If the remainder is not zero, it will be rounded
* based on the passed in roundingMode. Also, if the remainder is zero and
* the last parameter, i.e. preferredScale is NOT equal to scale, the
* trailing zeros of the result is stripped to match the preferredScale.
*/
private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
long ldivisor, BigInteger bdivisor,
int scale, int roundingMode,
int preferredScale) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
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 {
if (bdividend == null)
bdividend = BigInteger.valueOf(ldividend);
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
mq = new MutableBigInteger();
if (ldivisor != INFLATED) {
r = mdividend.divide(ldivisor, mq);
isRemainderZero = (r == 0);
qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
if (this.intCompact != INFLATED) {
if ((divisor.intCompact != INFLATED)) {
return divide(this.intCompact, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
} else {
mdivisor = new MutableBigInteger(bdivisor.mag);
mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
return divide(this.intCompact, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
}
}
boolean increment = false;
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;
} else if (roundingMode == ROUND_DOWN) { // Towards zero
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) {
if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
cmpFracHalf = 1; // 2 * r can't fit into long
} else {
cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
}
if ((divisor.intCompact != INFLATED)) {
return divide(this.intVal, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
} else {
cmpFracHalf = mr.compareHalf(mdivisor);
return divide(this.intVal, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
}
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;
else if (roundingMode == ROUND_HALF_DOWN)
increment = false;
else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
}
}
BigDecimal res;
if (isLongDivision)
res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
else {
if (increment)
mq.add(MutableBigInteger.ONE);
res = mq.toBigDecimal(qsign, scale);
}
if (isRemainderZero && preferredScale != scale)
res.stripZerosToMatchScale(preferredScale);
return res;
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this /
......@@ -1588,15 +1676,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
// Calculate preferred scale
int preferredScale = saturateLong((long)this.scale - divisor.scale);
int preferredScale = saturateLong((long) this.scale - divisor.scale);
if (this.signum() == 0) // 0/y
return (preferredScale >= 0 &&
preferredScale < ZERO_SCALED_BY.length) ?
ZERO_SCALED_BY[preferredScale] :
BigDecimal.valueOf(0, preferredScale);
return zeroValueOf(preferredScale);
else {
this.inflate();
divisor.inflate();
/*
* If the quotient this/divisor has a terminating decimal
* expansion, the expansion can have no more than
......@@ -1623,7 +1707,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// the desired one by removing trailing zeros; since the
// exact divide method does not have an explicit digit
// limit, we can add zeros too.
if (preferredScale > quotientScale)
return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
......@@ -1669,37 +1752,22 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new ArithmeticException("Division by zero");
}
if (dividend.signum() == 0) // 0/y
return new BigDecimal(BigInteger.ZERO, 0,
saturateLong(preferredScale), 1);
// Normalize dividend & divisor so that both fall into [0.1, 0.999...]
return zeroValueOf(saturateLong(preferredScale));
int xscale = dividend.precision();
int yscale = divisor.precision();
dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
xscale, xscale);
divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
yscale, yscale);
if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
yscale = divisor.scale -= 1; // [that is, divisor *= 10]
// In order to find out whether the divide generates the exact result,
// we avoid calling the above divide method. 'quotient' holds the
// return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient;
int scl = checkScale(preferredScale + yscale - xscale + mcp);
if (checkScale((long)mcp + yscale) > xscale)
dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
else
divisor = divisor.setScale(checkScale((long)xscale - mcp),
ROUND_UNNECESSARY);
quotient = divideAndRound(dividend.intCompact, dividend.intVal,
divisor.intCompact, divisor.intVal,
scl, mc.roundingMode.oldMode,
checkScale(preferredScale));
// doRound, here, only affects 1000000000 case.
quotient = doRound(quotient, mc);
return quotient;
if(dividend.intCompact!=INFLATED) {
if(divisor.intCompact!=INFLATED) {
return divide(dividend.intCompact, xscale, divisor.intCompact, yscale, preferredScale, mc);
} else {
return divide(dividend.intCompact, xscale, divisor.intVal, yscale, preferredScale, mc);
}
} else {
if(divisor.intCompact!=INFLATED) {
return divide(dividend.intVal, xscale, divisor.intCompact, yscale, preferredScale, mc);
} else {
return divide(dividend.intVal, xscale, divisor.intVal, yscale, preferredScale, mc);
}
}
}
/**
......@@ -1715,13 +1783,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale
int preferredScale = saturateLong((long)this.scale - divisor.scale);
int preferredScale = saturateLong((long) this.scale - divisor.scale);
if (this.compareMagnitude(divisor) < 0) {
// much faster when this << divisor
return BigDecimal.valueOf(0, preferredScale);
return zeroValueOf(preferredScale);
}
if(this.signum() == 0 && divisor.signum() != 0)
if (this.signum() == 0 && divisor.signum() != 0)
return this.setScale(preferredScale, ROUND_UNNECESSARY);
// Perform a divide with enough digits to round to a correct
......@@ -1735,13 +1803,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
RoundingMode.DOWN));
if (quotient.scale > 0) {
quotient = quotient.setScale(0, RoundingMode.DOWN);
quotient.stripZerosToMatchScale(preferredScale);
quotient = stripZerosToMatchScale(quotient.intVal, quotient.intCompact, quotient.scale, preferredScale);
}
if (quotient.scale < preferredScale) {
// pad with zeros if necessary
quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
}
return quotient;
}
......@@ -1767,7 +1836,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0 || // exact result
(this.compareMagnitude(divisor) < 0) ) // zero result
(this.compareMagnitude(divisor) < 0)) // zero result
return divideToIntegralValue(divisor);
// Calculate preferred scale
......@@ -1780,8 +1849,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value.
*/
BigDecimal result = this.
divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
BigDecimal result = this.divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
if (result.scale() < 0) {
/*
......@@ -1811,8 +1879,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) );
} else {
result.stripZerosToMatchScale(preferredScale);
return result;
return stripZerosToMatchScale(result.intVal,result.intCompact,result.scale,preferredScale);
}
}
......@@ -1954,8 +2021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// No need to calculate pow(n) if result will over/underflow.
// Don't attempt to support "supernormal" numbers.
int newScale = checkScale((long)scale * n);
this.inflate();
return new BigDecimal(intVal.pow(n), newScale);
return new BigDecimal(this.inflated().pow(n), newScale);
}
......@@ -2016,12 +2082,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new ArithmeticException("Invalid operation");
if (n == 0)
return ONE; // x**0 == 1 in X3.274
this.inflate();
BigDecimal lhs = this;
MathContext workmc = mc; // working settings
int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) {
int elength = longDigitLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation");
......@@ -2044,7 +2108,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// else (!seenbit) no point in squaring ONE
}
// if negative n, calculate the reciprocal using working precision
if (n<0) // [hence mc.precision>0]
if (n < 0) // [hence mc.precision>0]
acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros
return doRound(acc, mc);
......@@ -2083,14 +2147,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code -this}.
*/
public BigDecimal negate() {
BigDecimal result;
if (intCompact != INFLATED)
result = BigDecimal.valueOf(-intCompact, scale);
else {
result = new BigDecimal(intVal.negate(), scale);
result.precision = precision;
if (intCompact == INFLATED) {
return new BigDecimal(intVal.negate(), INFLATED, scale, precision);
} else {
return valueOf(-intCompact, scale, precision);
}
return result;
}
/**
......@@ -2186,7 +2247,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (s != INFLATED)
result = longDigitLength(s);
else
result = bigDigitLength(inflate());
result = bigDigitLength(intVal);
precision = result;
}
return result;
......@@ -2202,7 +2263,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.2
*/
public BigInteger unscaledValue() {
return this.inflate();
return this.inflated();
}
// Rounding Modes
......@@ -2383,29 +2444,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (newScale == oldScale) // easy case
return this;
if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale);
return zeroValueOf(newScale);
if(this.intCompact!=INFLATED) {
long rs = this.intCompact;
if (newScale > oldScale) {
int raise = checkScale((long)newScale - oldScale);
BigInteger rb = null;
if (rs == INFLATED ||
(rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
rb = bigMultiplyPowerTen(raise);
return new BigDecimal(rb, rs, newScale,
(precision > 0) ? precision + raise : 0);
int raise = checkScale((long) newScale - oldScale);
if ((rs = longMultiplyPowerTen(rs, raise)) != INFLATED) {
return valueOf(rs,newScale);
}
BigInteger rb = bigMultiplyPowerTen(raise);
return new BigDecimal(rb, INFLATED, 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, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode, newScale);
} else {
return divideAndRound(this.inflated(), bigTenToThe(drop), newScale, roundingMode, newScale);
}
}
} else {
if (newScale > oldScale) {
int raise = checkScale((long) newScale - oldScale);
BigInteger rb = bigMultiplyPowerTen(this.intVal,raise);
return new BigDecimal(rb, INFLATED, 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);
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);
return divideAndRound(this.intVal, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode,
newScale);
else
return divideAndRound(rs, this.intVal,
INFLATED, bigTenToThe(drop),
newScale, roundingMode, newScale);
return divideAndRound(this.intVal, bigTenToThe(drop), newScale, roundingMode, newScale);
}
}
}
......@@ -2524,10 +2597,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal stripTrailingZeros() {
this.inflate();
BigDecimal result = new BigDecimal(intVal, scale);
result.stripZerosToMatchScale(Long.MIN_VALUE);
return result;
if(intCompact!=INFLATED) {
return createAndStripZerosToMatchScale(intCompact, scale, Long.MIN_VALUE);
} else {
return createAndStripZerosToMatchScale(intVal, scale, Long.MIN_VALUE);
}
}
// Comparison Operations
......@@ -2647,7 +2721,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflate().equals(xDec.inflate());
return this.inflated().equals(xDec.inflated());
}
/**
......@@ -2872,13 +2946,38 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #toEngineeringString()
*/
public String toPlainString() {
BigDecimal bd = this;
if (bd.scale < 0)
bd = bd.setScale(0);
bd.inflate();
if (bd.scale == 0) // No decimal point
return bd.intVal.toString();
return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale);
if(scale==0) {
if(intCompact!=INFLATED) {
return Long.toString(intCompact);
} else {
return intVal.toString();
}
}
if(this.scale<0) { // No decimal point
if(signum()==0) {
return "0";
}
int tailingZeros = checkScaleNonZero((-(long)scale));
StringBuilder buf;
if(intCompact!=INFLATED) {
buf = new StringBuilder(20+tailingZeros);
buf.append(intCompact);
} else {
String str = intVal.toString();
buf = new StringBuilder(str.length()+tailingZeros);
buf.append(str);
}
for (int i = 0; i < tailingZeros; i++)
buf.append('0');
return buf.toString();
}
String str ;
if(intCompact!=INFLATED) {
str = Long.toString(Math.abs(intCompact));
} else {
str = intVal.abs().toString();
}
return getValueString(signum(), str, scale);
}
/* Returns a digit.digit string */
......@@ -2922,7 +3021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigInteger toBigInteger() {
// force to an integer, quietly
return this.setScale(0, ROUND_DOWN).inflate();
return this.setScale(0, ROUND_DOWN).inflated();
}
/**
......@@ -2937,7 +3036,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0
return this.setScale(0, ROUND_UNNECESSARY).inflate();
return this.setScale(0, ROUND_UNNECESSARY).inflated();
}
/**
......@@ -2990,7 +3089,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num);
return num.inflate().longValue();
return num.inflated().longValue();
}
private static class LongOverflow {
......@@ -3001,9 +3100,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
public static void check(BigDecimal num) {
num.inflate();
if ((num.intVal.compareTo(LONGMIN) < 0) ||
(num.intVal.compareTo(LONGMAX) > 0))
BigInteger intVal = num.inflated();
if (intVal.compareTo(LONGMIN) < 0 ||
intVal.compareTo(LONGMAX) > 0)
throw new java.lang.ArithmeticException("Overflow");
}
}
......@@ -3107,8 +3206,28 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return this {@code BigDecimal} converted to a {@code float}.
*/
public float floatValue(){
if (scale == 0 && intCompact != INFLATED)
if(intCompact != INFLATED) {
if (scale == 0) {
return (float)intCompact;
} else {
/*
* If both intCompact and the scale can be exactly
* represented as float values, perform a single float
* multiply or divide to compute the (properly
* rounded) result.
*/
if (Math.abs(intCompact) < 1L<<22 ) {
// Don't have too guard against
// Math.abs(MIN_VALUE) because of outer check
// against INFLATED.
if (scale > 0 && scale < float10pow.length) {
return (float)intCompact / float10pow[scale];
} else if (scale < 0 && scale > -float10pow.length) {
return (float)intCompact * float10pow[-scale];
}
}
}
}
// Somewhat inefficient, but guaranteed to work.
return Float.parseFloat(this.toString());
}
......@@ -3130,12 +3249,52 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return this {@code BigDecimal} converted to a {@code double}.
*/
public double doubleValue(){
if (scale == 0 && intCompact != INFLATED)
if(intCompact != INFLATED) {
if (scale == 0) {
return (double)intCompact;
} else {
/*
* If both intCompact and the scale can be exactly
* represented as double values, perform a single
* double multiply or divide to compute the (properly
* rounded) result.
*/
if (Math.abs(intCompact) < 1L<<52 ) {
// Don't have too guard against
// Math.abs(MIN_VALUE) because of outer check
// against INFLATED.
if (scale > 0 && scale < double10pow.length) {
return (double)intCompact / double10pow[scale];
} else if (scale < 0 && scale > -double10pow.length) {
return (double)intCompact * double10pow[-scale];
}
}
}
}
// Somewhat inefficient, but guaranteed to work.
return Double.parseDouble(this.toString());
}
/**
* Powers of 10 which can be represented exactly in {@code
* double}.
*/
private static final double double10pow[] = {
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11,
1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17,
1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22
};
/**
* Powers of 10 which can be represented exactly in {@code
* float}.
*/
private static final float float10pow[] = {
1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
};
/**
* Returns the size of an ulp, a unit in the last place, of this
* {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal}
......@@ -3151,10 +3310,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5
*/
public BigDecimal ulp() {
return BigDecimal.valueOf(1, this.scale());
return BigDecimal.valueOf(1, this.scale(), 1);
}
// 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
......@@ -3268,6 +3426,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return (intCompact != INFLATED) ?
Long.toString(intCompact):
intVal.toString();
if (scale == 2 &&
intCompact >= 0 && intCompact < Integer.MAX_VALUE) {
// currency fast path
int lowInt = (int)intCompact % 100;
int highInt = (int)intCompact / 100;
return (Integer.toString(highInt) + '.' +
StringBuilderHelper.DIGIT_TENS[lowInt] +
StringBuilderHelper.DIGIT_ONES[lowInt]) ;
}
StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
char[] coeff;
......@@ -3377,7 +3544,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
tenpow[0] = '1';
for (int i = 1; i <= n; i++)
tenpow[i] = '0';
return new BigInteger(tenpow);
return new BigInteger(tenpow,1, tenpow.length);
}
/**
......@@ -3433,11 +3600,16 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
1000000000000000000L // 18 / 10^18
};
private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
BigInteger.valueOf(10), BigInteger.valueOf(100),
BigInteger.valueOf(1000), BigInteger.valueOf(10000),
BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {
BigInteger.ONE,
BigInteger.valueOf(10),
BigInteger.valueOf(100),
BigInteger.valueOf(1000),
BigInteger.valueOf(10000),
BigInteger.valueOf(100000),
BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000),
BigInteger.valueOf(100000000),
BigInteger.valueOf(1000000000),
BigInteger.valueOf(10000000000L),
BigInteger.valueOf(100000000000L),
......@@ -3502,7 +3674,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/
private BigInteger bigMultiplyPowerTen(int n) {
if (n <= 0)
return this.inflate();
return this.inflated();
if (intCompact != INFLATED)
return bigTenToThe(n).multiply(intCompact);
......@@ -3511,12 +3683,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
/**
* Assign appropriate BigInteger to intVal field if intVal is
* Returns appropriate BigInteger from intVal field if intVal is
* null, i.e. the compact representation is in use.
*/
private BigInteger inflate() {
if (intVal == null)
intVal = BigInteger.valueOf(intCompact);
private BigInteger inflated() {
if (intVal == null) {
return BigInteger.valueOf(intCompact);
}
return intVal;
}
......@@ -3543,6 +3716,28 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
}
private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
private static final long intCompactOffset;
private static final long intValOffset;
static {
try {
intCompactOffset = unsafe.objectFieldOffset
(BigDecimal.class.getDeclaredField("intCompact"));
intValOffset = unsafe.objectFieldOffset
(BigDecimal.class.getDeclaredField("intVal"));
} catch (Exception ex) {
throw new Error(ex);
}
}
private void setIntCompactVolatile(long val) {
unsafe.putLongVolatile(this, intCompactOffset, val);
}
private void setIntValVolatile(BigInteger val) {
unsafe.putObjectVolatile(this, intValOffset, val);
}
/**
* Reconstitute the {@code BigDecimal} instance from a stream (that is,
* deserialize it).
......@@ -3559,7 +3754,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed]
}
intCompact = compactValFor(intVal);
setIntCompactVolatile(compactValFor(intVal));
}
/**
......@@ -3570,13 +3765,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Must inflate to maintain compatible serial form.
this.inflate();
// Write proper fields
if (this.intVal == null)
this.setIntValVolatile(BigInteger.valueOf(this.intCompact));
// Could reset intVal back to null if it has to be set.
s.defaultWriteObject();
}
/**
* Returns the length of the absolute value of a {@code long}, in decimal
* digits.
......@@ -3584,36 +3778,29 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @param x the {@code long}
* @return the length of the unscaled value, in deciaml digits.
*/
private static int longDigitLength(long x) {
static int longDigitLength(long x) {
/*
* As described in "Bit Twiddling Hacks" by Sean Anderson,
* (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;
* 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 != BigDecimal.INFLATED;
if (x < 0)
x = -x;
if (x < 10) // must screen for 0, might as well 10
return 1;
int n = 64; // not 63, to avoid needing to add 1 later
int y = (int)(x >>> 32);
if (y == 0) { n -= 32; y = (int)x; }
if (y >>> 16 == 0) { n -= 16; y <<= 16; }
if (y >>> 24 == 0) { n -= 8; y <<= 8; }
if (y >>> 28 == 0) { n -= 4; y <<= 4; }
if (y >>> 30 == 0) { n -= 2; y <<= 2; }
int r = (((y >>> 31) + n) * 1233) >>> 12;
int r = ((64 - Long.numberOfLeadingZeros(x) + 1) * 1233) >>> 12;
long[] tab = LONG_TEN_POWERS_TABLE;
// if r >= length, must have max possible digits for long
return (r >= tab.length || x < tab[r])? r : r+1;
return (r >= tab.length || x < tab[r]) ? r : r + 1;
}
/**
......@@ -3635,41 +3822,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
}
/**
* Remove insignificant trailing zeros from this
* {@code BigDecimal} until the preferred scale is reached or no
* more zeros can be removed. If the preferred scale is less than
* Integer.MIN_VALUE, all the trailing zeros will be removed.
*
* {@code BigInteger} assistance could help, here?
*
* <p>WARNING: This method should only be called on new objects as
* it mutates the value fields.
*
* @return this {@code BigDecimal} with a scale possibly reduced
* to be closed to the preferred scale.
*/
private BigDecimal stripZerosToMatchScale(long preferredScale) {
this.inflate();
BigInteger qr[]; // quotient-remainder pair
while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
scale > preferredScale) {
if (intVal.testBit(0))
break; // odd number cannot end in 0
qr = intVal.divideAndRemainder(BigInteger.TEN);
if (qr[1].signum() != 0)
break; // non-0 remainder
intVal=qr[0];
scale = checkScale((long)scale-1); // could Overflow
if (precision > 0) // adjust precision if known
precision--;
}
if (intVal != null)
intCompact = compactValFor(intVal);
return this;
}
/**
* Check a scale for Underflow or Overflow. If this BigDecimal is
* nonzero, throw an exception if the scale is outof range. If this
......@@ -3693,73 +3845,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return asInt;
}
/**
* Round an operand; used only if digits &gt; 0. Does not change
* {@code this}; if rounding is needed a new {@code BigDecimal}
* is created and returned.
*
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
*/
private BigDecimal roundOp(MathContext mc) {
BigDecimal rounded = doRound(this, mc);
return rounded;
}
/** Round this BigDecimal according to the MathContext settings;
* used only if precision {@literal >} 0.
*
* <p>WARNING: This method should only be called on new objects as
* it mutates the value fields.
*
* @param mc the context to use.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* {@code BigDecimal} operation would require rounding.
*/
private void roundThis(MathContext mc) {
BigDecimal rounded = doRound(this, mc);
if (rounded == this) // wasn't rounded
return;
this.intVal = rounded.intVal;
this.intCompact = rounded.intCompact;
this.scale = rounded.scale;
this.precision = rounded.precision;
}
/**
* Returns a {@code BigDecimal} rounded according to the
* MathContext settings; used only if {@code mc.precision > 0}.
* Does not change {@code this}; if rounding is needed a new
* {@code BigDecimal} is created and returned.
*
* @param mc the context to use.
* @return a {@code BigDecimal} rounded according to the MathContext
* settings. May return this, if no rounding needed.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* result is inexact.
*/
private static BigDecimal doRound(BigDecimal d, MathContext mc) {
int mcp = mc.precision;
int drop;
// This might (rarely) iterate to cover the 999=>1000 case
while ((drop = d.precision() - mcp) > 0) {
int newScale = d.checkScale((long)d.scale - drop);
int mode = mc.roundingMode.oldMode;
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);
}
return d;
}
/**
* Returns the compact value for given {@code BigInteger}, or
* INFLATED if too big. Relies on internal representation of
......@@ -3852,4 +3937,1275 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
}
return this;
}
/* the same as checkScale where value!=0 */
private static int checkScaleNonZero(long val) {
int asInt = (int)val;
if (asInt != val) {
throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
}
return asInt;
}
private static int checkScale(long intCompact, long val) {
int asInt = (int)val;
if (asInt != val) {
asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
if (intCompact != 0)
throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
}
return asInt;
}
private static int checkScale(BigInteger intVal, long val) {
int asInt = (int)val;
if (asInt != val) {
asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
if (intVal.signum() != 0)
throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
}
return asInt;
}
/**
* Returns a {@code BigDecimal} rounded according to the MathContext
* settings;
* If rounding is needed a new {@code BigDecimal} is created and returned.
*
* @param val the value to be rounded
* @param mc the context to use.
* @return a {@code BigDecimal} rounded according to the MathContext
* settings. May return {@code value}, if no rounding needed.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* result is inexact.
*/
private static BigDecimal doRound(BigDecimal val, MathContext mc) {
int mcp = mc.precision;
boolean wasDivided = false;
if (mcp > 0) {
BigInteger intVal = val.intVal;
long compactVal = val.intCompact;
int scale = val.scale;
int prec = val.precision();
int mode = mc.roundingMode.oldMode;
int drop;
if (compactVal == INFLATED) {
drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
intVal = divideAndRoundByTenPow(intVal, drop, mode);
wasDivided = true;
compactVal = compactValFor(intVal);
if (compactVal != INFLATED) {
prec = longDigitLength(compactVal);
break;
}
prec = bigDigitLength(intVal);
drop = prec - mcp;
}
}
if (compactVal != INFLATED) {
drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
wasDivided = true;
prec = longDigitLength(compactVal);
drop = prec - mcp;
intVal = null;
}
}
return wasDivided ? new BigDecimal(intVal,compactVal,scale,prec) : val;
}
return val;
}
/*
* Returns a {@code BigDecimal} created from {@code long} value with
* given scale rounded according to the MathContext settings
*/
private static BigDecimal doRound(long compactVal, int scale, MathContext mc) {
int mcp = mc.precision;
if (mcp > 0 && mcp < 19) {
int prec = longDigitLength(compactVal);
int drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
return valueOf(compactVal, scale, prec);
}
return valueOf(compactVal, scale);
}
/*
* Returns a {@code BigDecimal} created from {@code BigInteger} value with
* given scale rounded according to the MathContext settings
*/
private static BigDecimal doRound(BigInteger intVal, int scale, MathContext mc) {
int mcp = mc.precision;
int prec = 0;
if (mcp > 0) {
long compactVal = compactValFor(intVal);
int mode = mc.roundingMode.oldMode;
int drop;
if (compactVal == INFLATED) {
prec = bigDigitLength(intVal);
drop = prec - mcp;
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
intVal = divideAndRoundByTenPow(intVal, drop, mode);
compactVal = compactValFor(intVal);
if (compactVal != INFLATED) {
break;
}
prec = bigDigitLength(intVal);
drop = prec - mcp;
}
}
if (compactVal != INFLATED) {
prec = longDigitLength(compactVal);
drop = prec - mcp; // drop can't be more than 18
while (drop > 0) {
scale = checkScaleNonZero((long) scale - drop);
compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
prec = longDigitLength(compactVal);
drop = prec - mcp;
}
return valueOf(compactVal,scale,prec);
}
}
return new BigDecimal(intVal,INFLATED,scale,prec);
}
/*
* Divides {@code BigInteger} value by ten power.
*/
private static BigInteger divideAndRoundByTenPow(BigInteger intVal, int tenPow, int roundingMode) {
if (tenPow < LONG_TEN_POWERS_TABLE.length)
intVal = divideAndRound(intVal, LONG_TEN_POWERS_TABLE[tenPow], roundingMode);
else
intVal = divideAndRound(intVal, bigTenToThe(tenPow), roundingMode);
return intVal;
}
/**
* Internally used for division operation for division {@code long} by
* {@code long}.
* The returned {@code BigDecimal} object is the quotient whose scale is set
* to the passed in scale. If the remainder is not zero, it will be rounded
* based on the passed in roundingMode. Also, if the remainder is zero and
* the last parameter, i.e. preferredScale is NOT equal to scale, the
* trailing zeros of the result is stripped to match the preferredScale.
*/
private static BigDecimal divideAndRound(long ldividend, long ldivisor, int scale, int roundingMode,
int preferredScale) {
int qsign; // quotient sign
long q = ldividend / ldivisor; // store quotient in long
if (roundingMode == ROUND_DOWN && scale == preferredScale)
return valueOf(q, scale);
long r = ldividend % ldivisor; // store remainder in long
qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
if (r != 0) {
boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
return valueOf((increment ? q + qsign : q), scale);
} else {
if (preferredScale != scale)
return createAndStripZerosToMatchScale(q, scale, preferredScale);
else
return valueOf(q, scale);
}
}
/**
* Divides {@code long} by {@code long} and do rounding based on the
* passed in roundingMode.
*/
private static long divideAndRound(long ldividend, long ldivisor, int roundingMode) {
int qsign; // quotient sign
long q = ldividend / ldivisor; // store quotient in long
if (roundingMode == ROUND_DOWN)
return q;
long r = ldividend % ldivisor; // store remainder in long
qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
if (r != 0) {
boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
return increment ? q + qsign : q;
} else {
return q;
}
}
/**
* Shared logic of need increment computation.
*/
private static boolean commonNeedIncrement(int roundingMode, int qsign,
int cmpFracHalf, boolean oddQuot) {
switch(roundingMode) {
case ROUND_UNNECESSARY:
throw new ArithmeticException("Rounding necessary");
case ROUND_UP: // Away from zero
return true;
case ROUND_DOWN: // Towards zero
return false;
case ROUND_CEILING: // Towards +infinity
return qsign > 0;
case ROUND_FLOOR: // Towards -infinity
return qsign < 0;
default: // Some kind of half-way rounding
if (roundingMode == ROUND_HALF_DOWN ||
cmpFracHalf < 0 ) // We're closer to higher digit
return false;
else if (roundingMode == ROUND_HALF_UP ||
cmpFracHalf > 0 ) // We're closer to lower digit
return true;
else
// roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
return oddQuot;
}
}
/**
* Tests if quotient has to be incremented according the roundingMode
*/
private static boolean needIncrement(long ldivisor, int roundingMode,
int qsign, long q, long r) {
assert r != 0L;
int cmpFracHalf;
if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
cmpFracHalf = 1; // 2 * r can't fit into long
} else {
cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
}
return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, (q & 1L) != 0L);
}
/**
* Divides {@code BigInteger} value by {@code long} value and
* do rounding based on the passed in roundingMode.
*/
private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
long r = 0; // store quotient & remainder in long
MutableBigInteger mq = null; // store quotient
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
mq = new MutableBigInteger();
r = mdividend.divide(ldivisor, mq);
isRemainderZero = (r == 0);
qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
if (!isRemainderZero) {
if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
mq.add(MutableBigInteger.ONE);
}
}
return mq.toBigInteger(qsign);
}
/**
* Internally used for division operation for division {@code BigInteger}
* by {@code long}.
* The returned {@code BigDecimal} object is the quotient whose scale is set
* to the passed in scale. If the remainder is not zero, it will be rounded
* based on the passed in roundingMode. Also, if the remainder is zero and
* the last parameter, i.e. preferredScale is NOT equal to scale, the
* trailing zeros of the result is stripped to match the preferredScale.
*/
private static BigDecimal divideAndRound(BigInteger bdividend,
long ldivisor, int scale, int roundingMode, int preferredScale) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
long r = 0; // store quotient & remainder in long
MutableBigInteger mq = null; // store quotient
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
mq = new MutableBigInteger();
r = mdividend.divide(ldivisor, mq);
isRemainderZero = (r == 0);
qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
if (!isRemainderZero) {
if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
mq.add(MutableBigInteger.ONE);
}
return mq.toBigDecimal(qsign, scale);
} else {
if (preferredScale != scale) {
long compactVal = mq.toCompactValue(qsign);
if(compactVal!=INFLATED) {
return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
}
BigInteger intVal = mq.toBigInteger(qsign);
return createAndStripZerosToMatchScale(intVal,scale, preferredScale);
} else {
return mq.toBigDecimal(qsign, scale);
}
}
}
/**
* Tests if quotient has to be incremented according the roundingMode
*/
private static boolean needIncrement(long ldivisor, int roundingMode,
int qsign, MutableBigInteger mq, long r) {
assert r != 0L;
int cmpFracHalf;
if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
cmpFracHalf = 1; // 2 * r can't fit into long
} else {
cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
}
return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd());
}
/**
* Divides {@code BigInteger} value by {@code BigInteger} value and
* do rounding based on the passed in roundingMode.
*/
private static BigInteger divideAndRound(BigInteger bdividend, BigInteger bdivisor, int roundingMode) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
MutableBigInteger mq = new MutableBigInteger();
MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
MutableBigInteger mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
if (!isRemainderZero) {
if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
mq.add(MutableBigInteger.ONE);
}
}
return mq.toBigInteger(qsign);
}
/**
* Internally used for division operation for division {@code BigInteger}
* by {@code BigInteger}.
* The returned {@code BigDecimal} object is the quotient whose scale is set
* to the passed in scale. If the remainder is not zero, it will be rounded
* based on the passed in roundingMode. Also, if the remainder is zero and
* the last parameter, i.e. preferredScale is NOT equal to scale, the
* trailing zeros of the result is stripped to match the preferredScale.
*/
private static BigDecimal divideAndRound(BigInteger bdividend, BigInteger bdivisor, int scale, int roundingMode,
int preferredScale) {
boolean isRemainderZero; // record remainder is zero or not
int qsign; // quotient sign
// Descend into mutables for faster remainder checks
MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
MutableBigInteger mq = new MutableBigInteger();
MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
MutableBigInteger mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
if (!isRemainderZero) {
if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
mq.add(MutableBigInteger.ONE);
}
return mq.toBigDecimal(qsign, scale);
} else {
if (preferredScale != scale) {
long compactVal = mq.toCompactValue(qsign);
if (compactVal != INFLATED) {
return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
}
BigInteger intVal = mq.toBigInteger(qsign);
return createAndStripZerosToMatchScale(intVal, scale, preferredScale);
} else {
return mq.toBigDecimal(qsign, scale);
}
}
}
/**
* Tests if quotient has to be incremented according the roundingMode
*/
private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMode,
int qsign, MutableBigInteger mq, MutableBigInteger mr) {
assert !mr.isZero();
int cmpFracHalf = mr.compareHalf(mdivisor);
return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd());
}
/**
* Remove insignificant trailing zeros from this
* {@code BigInteger} value until the preferred scale is reached or no
* more zeros can be removed. If the preferred scale is less than
* Integer.MIN_VALUE, all the trailing zeros will be removed.
*
* @return new {@code BigDecimal} with a scale possibly reduced
* to be closed to the preferred scale.
*/
private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) {
BigInteger qr[]; // quotient-remainder pair
while (intVal.compareMagnitude(BigInteger.TEN) >= 0
&& scale > preferredScale) {
if (intVal.testBit(0))
break; // odd number cannot end in 0
qr = intVal.divideAndRemainder(BigInteger.TEN);
if (qr[1].signum() != 0)
break; // non-0 remainder
intVal = qr[0];
scale = checkScale(intVal,(long) scale - 1); // could Overflow
}
return valueOf(intVal, scale, 0);
}
/**
* Remove insignificant trailing zeros from this
* {@code long} value until the preferred scale is reached or no
* more zeros can be removed. If the preferred scale is less than
* Integer.MIN_VALUE, all the trailing zeros will be removed.
*
* @return new {@code BigDecimal} with a scale possibly reduced
* to be closed to the preferred scale.
*/
private static BigDecimal createAndStripZerosToMatchScale(long compactVal, int scale, long preferredScale) {
while (Math.abs(compactVal) >= 10L && scale > preferredScale) {
if ((compactVal & 1L) != 0L)
break; // odd number cannot end in 0
long r = compactVal % 10L;
if (r != 0L)
break; // non-0 remainder
compactVal /= 10;
scale = checkScale(compactVal, (long) scale - 1); // could Overflow
}
return valueOf(compactVal, scale);
}
private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, int preferredScale) {
if(intCompact!=INFLATED) {
return createAndStripZerosToMatchScale(intCompact, scale, preferredScale);
} else {
return createAndStripZerosToMatchScale(intVal==null ? INFLATED_BIGINT : intVal,
scale, preferredScale);
}
}
/*
* returns INFLATED if oveflow
*/
private static long add(long xs, long ys){
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 sum;
}
return INFLATED;
}
private static BigDecimal add(long xs, long ys, int scale){
long sum = add(xs, ys);
if (sum!=INFLATED)
return BigDecimal.valueOf(sum, scale);
return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale);
}
private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) {
long sdiff = (long) scale1 - scale2;
if (sdiff == 0) {
return add(xs, ys, scale1);
} else if (sdiff < 0) {
int raise = checkScale(xs,-sdiff);
long scaledX = longMultiplyPowerTen(xs, raise);
if (scaledX != INFLATED) {
return add(scaledX, ys, scale2);
} else {
BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys);
return ((xs^ys)>=0) ? // same sign test
new BigDecimal(bigsum, INFLATED, scale2, 0)
: valueOf(bigsum, scale2, 0);
}
} else {
int raise = checkScale(ys,sdiff);
long scaledY = longMultiplyPowerTen(ys, raise);
if (scaledY != INFLATED) {
return add(xs, scaledY, scale1);
} else {
BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs);
return ((xs^ys)>=0) ?
new BigDecimal(bigsum, INFLATED, scale1, 0)
: valueOf(bigsum, scale1, 0);
}
}
}
private static BigDecimal add(final long xs, int scale1, BigInteger snd, int scale2) {
int rscale = scale1;
long sdiff = (long)rscale - scale2;
boolean sameSigns = (Long.signum(xs) == snd.signum);
BigInteger sum;
if (sdiff < 0) {
int raise = checkScale(xs,-sdiff);
rscale = scale2;
long scaledX = longMultiplyPowerTen(xs, raise);
if (scaledX == INFLATED) {
sum = snd.add(bigMultiplyPowerTen(xs,raise));
} else {
sum = snd.add(scaledX);
}
} else { //if (sdiff > 0) {
int raise = checkScale(snd,sdiff);
snd = bigMultiplyPowerTen(snd,raise);
sum = snd.add(xs);
}
return (sameSigns) ?
new BigDecimal(sum, INFLATED, rscale, 0) :
valueOf(sum, rscale, 0);
}
private static BigDecimal add(BigInteger fst, int scale1, BigInteger snd, int scale2) {
int rscale = scale1;
long sdiff = (long)rscale - scale2;
if (sdiff != 0) {
if (sdiff < 0) {
int raise = checkScale(fst,-sdiff);
rscale = scale2;
fst = bigMultiplyPowerTen(fst,raise);
} else {
int raise = checkScale(snd,sdiff);
snd = bigMultiplyPowerTen(snd,raise);
}
}
BigInteger sum = fst.add(snd);
return (fst.signum == snd.signum) ?
new BigDecimal(sum, INFLATED, rscale, 0) :
valueOf(sum, rscale, 0);
}
private static BigInteger bigMultiplyPowerTen(long value, int n) {
if (n <= 0)
return BigInteger.valueOf(value);
return bigTenToThe(n).multiply(value);
}
private static BigInteger bigMultiplyPowerTen(BigInteger value, int n) {
if (n <= 0)
return value;
if(n<LONG_TEN_POWERS_TABLE.length) {
return value.multiply(LONG_TEN_POWERS_TABLE[n]);
}
return value.multiply(bigTenToThe(n));
}
/**
* Returns a {@code BigDecimal} whose value is {@code (xs /
* ys)}, with rounding according to the context settings.
*
* Fast path - used only when (xscale <= yscale && yscale < 18
* && mc.presision<18) {
*/
private static BigDecimal divideSmallFastPath(final long xs, int xscale,
final long ys, int yscale,
long preferredScale, MathContext mc) {
int mcp = mc.precision;
int roundingMode = mc.roundingMode.oldMode;
assert (xscale <= yscale) && (yscale < 18) && (mcp < 18);
int xraise = yscale - xscale; // xraise >=0
long scaledX = (xraise==0) ? xs :
longMultiplyPowerTen(xs, xraise); // can't overflow here!
BigDecimal quotient;
int cmp = longCompareMagnitude(scaledX, ys);
if(cmp > 0) { // satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10]
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
// assert newScale >= xscale
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
long scaledXs;
if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
quotient = null;
if((mcp-1) >=0 && (mcp-1)<LONG_TEN_POWERS_TABLE.length) {
quotient = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[mcp-1], scaledX, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
}
if(quotient==null) {
BigInteger rb = bigMultiplyPowerTen(scaledX,mcp-1);
quotient = divideAndRound(rb, ys,
scl, roundingMode, checkScaleNonZero(preferredScale));
}
} else {
quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
}
} else {
int newScale = checkScaleNonZero((long) xscale - mcp);
// assert newScale >= yscale
if (newScale == yscale) { // easy case
quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
int raise = checkScaleNonZero((long) newScale - yscale);
long scaledYs;
if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
BigInteger rb = bigMultiplyPowerTen(ys,raise);
quotient = divideAndRound(BigInteger.valueOf(xs),
rb, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
}
}
}
} else {
// abs(scaledX) <= abs(ys)
// result is "scaledX * 10^msp / ys"
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if(cmp==0) {
// abs(scaleX)== abs(ys) => result will be scaled 10^mcp + correct sign
quotient = roundedTenPower(((scaledX < 0) == (ys < 0)) ? 1 : -1, mcp, scl, checkScaleNonZero(preferredScale));
} else {
// abs(scaledX) < abs(ys)
long scaledXs;
if ((scaledXs = longMultiplyPowerTen(scaledX, mcp)) == INFLATED) {
quotient = null;
if(mcp<LONG_TEN_POWERS_TABLE.length) {
quotient = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[mcp], scaledX, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
}
if(quotient==null) {
BigInteger rb = bigMultiplyPowerTen(scaledX,mcp);
quotient = divideAndRound(rb, ys,
scl, roundingMode, checkScaleNonZero(preferredScale));
}
} else {
quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
}
}
}
// doRound, here, only affects 1000000000 case.
return doRound(quotient,mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (xs /
* ys)}, with rounding according to the context settings.
*/
private static BigDecimal divide(final long xs, int xscale, final long ys, int yscale, long preferredScale, MathContext mc) {
int mcp = mc.precision;
if(xscale <= yscale && yscale < 18 && mcp<18) {
return divideSmallFastPath(xs, xscale, ys, yscale, preferredScale, mc);
}
if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10]
}
int roundingMode = mc.roundingMode.oldMode;
// In order to find out whether the divide generates the exact result,
// we avoid calling the above divide method. 'quotient' holds the
// return BigDecimal object whose scale will be set to 'scl'.
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
BigDecimal quotient;
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
long scaledXs;
if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
} else {
quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
}
} else {
int newScale = checkScaleNonZero((long) xscale - mcp);
// assert newScale >= yscale
if (newScale == yscale) { // easy case
quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
int raise = checkScaleNonZero((long) newScale - yscale);
long scaledYs;
if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
BigInteger rb = bigMultiplyPowerTen(ys,raise);
quotient = divideAndRound(BigInteger.valueOf(xs),
rb, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
}
}
}
// doRound, here, only affects 1000000000 case.
return doRound(quotient,mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (xs /
* ys)}, with rounding according to the context settings.
*/
private static BigDecimal divide(BigInteger xs, int xscale, long ys, int yscale, long preferredScale, MathContext mc) {
// Normalize dividend & divisor so that both fall into [0.1, 0.999...]
if ((-compareMagnitudeNormalized(ys, yscale, xs, xscale)) > 0) {// satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10]
}
int mcp = mc.precision;
int roundingMode = mc.roundingMode.oldMode;
// In order to find out whether the divide generates the exact result,
// we avoid calling the above divide method. 'quotient' holds the
// return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
} else {
int newScale = checkScaleNonZero((long) xscale - mcp);
// assert newScale >= yscale
if (newScale == yscale) { // easy case
quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
int raise = checkScaleNonZero((long) newScale - yscale);
long scaledYs;
if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
BigInteger rb = bigMultiplyPowerTen(ys,raise);
quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale));
} else {
quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
}
}
}
// doRound, here, only affects 1000000000 case.
return doRound(quotient, mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (xs /
* ys)}, with rounding according to the context settings.
*/
private static BigDecimal divide(long xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) {
// Normalize dividend & divisor so that both fall into [0.1, 0.999...]
if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10]
}
int mcp = mc.precision;
int roundingMode = mc.roundingMode.oldMode;
// In order to find out whether the divide generates the exact result,
// we avoid calling the above divide method. 'quotient' holds the
// return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
} else {
int newScale = checkScaleNonZero((long) xscale - mcp);
int raise = checkScaleNonZero((long) newScale - yscale);
BigInteger rb = bigMultiplyPowerTen(ys,raise);
quotient = divideAndRound(BigInteger.valueOf(xs), rb, scl, roundingMode,checkScaleNonZero(preferredScale));
}
// doRound, here, only affects 1000000000 case.
return doRound(quotient, mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (xs /
* ys)}, with rounding according to the context settings.
*/
private static BigDecimal divide(BigInteger xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) {
// Normalize dividend & divisor so that both fall into [0.1, 0.999...]
if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
yscale -= 1; // [that is, divisor *= 10]
}
int mcp = mc.precision;
int roundingMode = mc.roundingMode.oldMode;
// In order to find out whether the divide generates the exact result,
// we avoid calling the above divide method. 'quotient' holds the
// return BigDecimal object whose scale will be set to 'scl'.
BigDecimal quotient;
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
BigInteger rb = bigMultiplyPowerTen(xs,raise);
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
} else {
int newScale = checkScaleNonZero((long) xscale - mcp);
int raise = checkScaleNonZero((long) newScale - yscale);
BigInteger rb = bigMultiplyPowerTen(ys,raise);
quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale));
}
// doRound, here, only affects 1000000000 case.
return doRound(quotient, mc);
}
/*
* performs divideAndRound for (dividend0*dividend1, divisor)
* returns null if quotient can't fit into long value;
*/
private static BigDecimal multiplyDivideAndRound(long dividend0, long dividend1, long divisor, int scale, int roundingMode,
int preferredScale) {
int qsign = Long.signum(dividend0)*Long.signum(dividend1)*Long.signum(divisor);
dividend0 = Math.abs(dividend0);
dividend1 = Math.abs(dividend1);
divisor = Math.abs(divisor);
// multiply dividend0 * dividend1
long d0_hi = dividend0 >>> 32;
long d0_lo = dividend0 & LONG_MASK;
long d1_hi = dividend1 >>> 32;
long d1_lo = dividend1 & LONG_MASK;
long product = d0_lo * d1_lo;
long d0 = product & LONG_MASK;
long d1 = product >>> 32;
product = d0_hi * d1_lo + d1;
d1 = product & LONG_MASK;
long d2 = product >>> 32;
product = d0_lo * d1_hi + d1;
d1 = product & LONG_MASK;
d2 += product >>> 32;
long d3 = d2>>>32;
d2 &= LONG_MASK;
product = d0_hi*d1_hi + d2;
d2 = product & LONG_MASK;
d3 = ((product>>>32) + d3) & LONG_MASK;
final long dividendHi = make64(d3,d2);
final long dividendLo = make64(d1,d0);
// divide
return divideAndRound128(dividendHi, dividendLo, divisor, qsign, scale, roundingMode, preferredScale);
}
private static final long DIV_NUM_BASE = (1L<<32); // Number base (32 bits).
/*
* divideAndRound 128-bit value by long divisor.
* returns null if quotient can't fit into long value;
* Specialized version of Knuth's division
*/
private static BigDecimal divideAndRound128(final long dividendHi, final long dividendLo, long divisor, int sign,
int scale, int roundingMode, int preferredScale) {
if (dividendHi >= divisor) {
return null;
}
final int shift = Long.numberOfLeadingZeros(divisor);
divisor <<= shift;
final long v1 = divisor >>> 32;
final long v0 = divisor & LONG_MASK;
long q1, q0;
long r_tmp;
long tmp = dividendLo << shift;
long u1 = tmp >>> 32;
long u0 = tmp & LONG_MASK;
tmp = (dividendHi << shift) | (dividendLo >>> 64 - shift);
long u2 = tmp & LONG_MASK;
tmp = divWord(tmp,v1);
q1 = tmp & LONG_MASK;
r_tmp = tmp >>> 32;
while(q1 >= DIV_NUM_BASE || unsignedLongCompare(q1*v0, make64(r_tmp, u1))) {
q1--;
r_tmp += v1;
if (r_tmp >= DIV_NUM_BASE)
break;
}
tmp = mulsub(u2,u1,v1,v0,q1);
u1 = tmp & LONG_MASK;
tmp = divWord(tmp,v1);
q0 = tmp & LONG_MASK;
r_tmp = tmp >>> 32;
while(q0 >= DIV_NUM_BASE || unsignedLongCompare(q0*v0,make64(r_tmp,u0))) {
q0--;
r_tmp += v1;
if (r_tmp >= DIV_NUM_BASE)
break;
}
if((int)q1 < 0) {
// result (which is positive and unsigned here)
// can't fit into long due to sign bit is used for value
MutableBigInteger mq = new MutableBigInteger(new int[]{(int)q1, (int)q0});
if (roundingMode == ROUND_DOWN && scale == preferredScale) {
return mq.toBigDecimal(sign, scale);
}
long r = mulsub(u1, u0, v1, v0, q0) >>> shift;
if (r != 0) {
if(needIncrement(divisor >>> shift, roundingMode, sign, mq, r)){
mq.add(MutableBigInteger.ONE);
}
return mq.toBigDecimal(sign, scale);
} else {
if (preferredScale != scale) {
BigInteger intVal = mq.toBigInteger(sign);
return createAndStripZerosToMatchScale(intVal,scale, preferredScale);
} else {
return mq.toBigDecimal(sign, scale);
}
}
}
long q = make64(q1,q0);
q*=sign;
if (roundingMode == ROUND_DOWN && scale == preferredScale)
return valueOf(q, scale);
long r = mulsub(u1, u0, v1, v0, q0) >>> shift;
if (r != 0) {
boolean increment = needIncrement(divisor >>> shift, roundingMode, sign, q, r);
return valueOf((increment ? q + sign : q), scale);
} else {
if (preferredScale != scale) {
return createAndStripZerosToMatchScale(q, scale, preferredScale);
} else {
return valueOf(q, scale);
}
}
}
/*
* calculate divideAndRound for ldividend*10^raise / divisor
* when abs(dividend)==abs(divisor);
*/
private static BigDecimal roundedTenPower(int qsign, int raise, int scale, int preferredScale) {
if (scale > preferredScale) {
int diff = scale - preferredScale;
if(diff < raise) {
return scaledTenPow(raise - diff, qsign, preferredScale);
} else {
return valueOf(qsign,scale-raise);
}
} else {
return scaledTenPow(raise, qsign, scale);
}
}
static BigDecimal scaledTenPow(int n, int sign, int scale) {
if (n < LONG_TEN_POWERS_TABLE.length)
return valueOf(sign*LONG_TEN_POWERS_TABLE[n],scale);
else {
BigInteger unscaledVal = bigTenToThe(n);
if(sign==-1) {
unscaledVal = unscaledVal.negate();
}
return new BigDecimal(unscaledVal, INFLATED, scale, n+1);
}
}
private static long divWord(long n, long dLong) {
long r;
long q;
if (dLong == 1) {
q = (int)n;
return (q & LONG_MASK);
}
// Approximate the quotient and remainder
q = (n >>> 1) / (dLong >>> 1);
r = n - q*dLong;
// Correct the approximation
while (r < 0) {
r += dLong;
q--;
}
while (r >= dLong) {
r -= dLong;
q++;
}
// n - q*dlong == r && 0 <= r <dLong, hence we're done.
return (r << 32) | (q & LONG_MASK);
}
private static long make64(long hi, long lo) {
return hi<<32 | lo;
}
private static long mulsub(long u1, long u0, final long v1, final long v0, long q0) {
long tmp = u0 - q0*v0;
return make64(u1 + (tmp>>>32) - q0*v1,tmp & LONG_MASK);
}
private static boolean unsignedLongCompare(long one, long two) {
return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
}
private static boolean unsignedLongCompareEq(long one, long two) {
return (one+Long.MIN_VALUE) >= (two+Long.MIN_VALUE);
}
// Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
private static int compareMagnitudeNormalized(long xs, int xscale, long ys, int yscale) {
// assert xs!=0 && ys!=0
int sdiff = xscale - yscale;
if (sdiff != 0) {
if (sdiff < 0) {
xs = longMultiplyPowerTen(xs, -sdiff);
} else { // sdiff > 0
ys = longMultiplyPowerTen(ys, sdiff);
}
}
if (xs != INFLATED)
return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
else
return 1;
}
// Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
private static int compareMagnitudeNormalized(long xs, int xscale, BigInteger ys, int yscale) {
// assert "ys can't be represented as long"
if (xs == 0)
return -1;
int sdiff = xscale - yscale;
if (sdiff < 0) {
if (longMultiplyPowerTen(xs, -sdiff) == INFLATED ) {
return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys);
}
}
return -1;
}
// Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
private static int compareMagnitudeNormalized(BigInteger xs, int xscale, BigInteger ys, int yscale) {
int sdiff = xscale - yscale;
if (sdiff < 0) {
return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys);
} else { // sdiff >= 0
return xs.compareMagnitude(bigMultiplyPowerTen(ys, sdiff));
}
}
private static long multiply(long x, long y){
long product = x * y;
long ax = Math.abs(x);
long ay = Math.abs(y);
if (((ax | ay) >>> 31 == 0) || (y == 0) || (product / y == x)){
return product;
}
return INFLATED;
}
private static BigDecimal multiply(long x, long y, int scale) {
long product = multiply(x, y);
if(product!=INFLATED) {
return valueOf(product,scale);
}
return new BigDecimal(BigInteger.valueOf(x).multiply(y),INFLATED,scale,0);
}
private static BigDecimal multiply(long x, BigInteger y, int scale) {
if(x==0) {
return zeroValueOf(scale);
}
return new BigDecimal(y.multiply(x),INFLATED,scale,0);
}
private static BigDecimal multiply(BigInteger x, BigInteger y, int scale) {
return new BigDecimal(x.multiply(y),INFLATED,scale,0);
}
/**
* Multiplies two long values and rounds according {@code MathContext}
*/
private static BigDecimal multiplyAndRound(long x, long y, int scale, MathContext mc) {
long product = multiply(x, y);
if(product!=INFLATED) {
return doRound(product, scale, mc);
}
// attempt to do it in 128 bits
int rsign = 1;
if(x < 0) {
x = -x;
rsign = -1;
}
if(y < 0) {
y = -y;
rsign *= -1;
}
// multiply dividend0 * dividend1
long m0_hi = x >>> 32;
long m0_lo = x & LONG_MASK;
long m1_hi = y >>> 32;
long m1_lo = y & LONG_MASK;
product = m0_lo * m1_lo;
long m0 = product & LONG_MASK;
long m1 = product >>> 32;
product = m0_hi * m1_lo + m1;
m1 = product & LONG_MASK;
long m2 = product >>> 32;
product = m0_lo * m1_hi + m1;
m1 = product & LONG_MASK;
m2 += product >>> 32;
long m3 = m2>>>32;
m2 &= LONG_MASK;
product = m0_hi*m1_hi + m2;
m2 = product & LONG_MASK;
m3 = ((product>>>32) + m3) & LONG_MASK;
final long mHi = make64(m3,m2);
final long mLo = make64(m1,m0);
BigDecimal res = doRound128(mHi, mLo, rsign, scale, mc);
if(res!=null) {
return res;
}
res = new BigDecimal(BigInteger.valueOf(x).multiply(y*rsign), INFLATED, scale, 0);
return doRound(res,mc);
}
private static BigDecimal multiplyAndRound(long x, BigInteger y, int scale, MathContext mc) {
if(x==0) {
return zeroValueOf(scale);
}
return doRound(y.multiply(x), scale, mc);
}
private static BigDecimal multiplyAndRound(BigInteger x, BigInteger y, int scale, MathContext mc) {
return doRound(x.multiply(y), scale, mc);
}
/**
* rounds 128-bit value according {@code MathContext}
* returns null if result can't be repsented as compact BigDecimal.
*/
private static BigDecimal doRound128(long hi, long lo, int sign, int scale, MathContext mc) {
int mcp = mc.precision;
int drop;
BigDecimal res = null;
if(((drop = precision(hi, lo) - mcp) > 0)&&(drop<LONG_TEN_POWERS_TABLE.length)) {
scale = checkScaleNonZero((long)scale - drop);
res = divideAndRound128(hi, lo, LONG_TEN_POWERS_TABLE[drop], sign, scale, mc.roundingMode.oldMode, scale);
}
if(res!=null) {
return doRound(res,mc);
}
return null;
}
private static final long[][] LONGLONG_TEN_POWERS_TABLE = {
{ 0L, 0x8AC7230489E80000L }, //10^19
{ 0x5L, 0x6bc75e2d63100000L }, //10^20
{ 0x36L, 0x35c9adc5dea00000L }, //10^21
{ 0x21eL, 0x19e0c9bab2400000L }, //10^22
{ 0x152dL, 0x02c7e14af6800000L }, //10^23
{ 0xd3c2L, 0x1bcecceda1000000L }, //10^24
{ 0x84595L, 0x161401484a000000L }, //10^25
{ 0x52b7d2L, 0xdcc80cd2e4000000L }, //10^26
{ 0x33b2e3cL, 0x9fd0803ce8000000L }, //10^27
{ 0x204fce5eL, 0x3e25026110000000L }, //10^28
{ 0x1431e0faeL, 0x6d7217caa0000000L }, //10^29
{ 0xc9f2c9cd0L, 0x4674edea40000000L }, //10^30
{ 0x7e37be2022L, 0xc0914b2680000000L }, //10^31
{ 0x4ee2d6d415bL, 0x85acef8100000000L }, //10^32
{ 0x314dc6448d93L, 0x38c15b0a00000000L }, //10^33
{ 0x1ed09bead87c0L, 0x378d8e6400000000L }, //10^34
{ 0x13426172c74d82L, 0x2b878fe800000000L }, //10^35
{ 0xc097ce7bc90715L, 0xb34b9f1000000000L }, //10^36
{ 0x785ee10d5da46d9L, 0x00f436a000000000L }, //10^37
{ 0x4b3b4ca85a86c47aL, 0x098a224000000000L }, //10^38
};
/*
* returns precision of 128-bit value
*/
private static int precision(long hi, long lo){
if(hi==0) {
if(lo>=0) {
return longDigitLength(lo);
}
return (unsignedLongCompareEq(lo, LONGLONG_TEN_POWERS_TABLE[0][1])) ? 20 : 19;
// 0x8AC7230489E80000L = unsigned 2^19
}
int r = ((128 - Long.numberOfLeadingZeros(hi) + 1) * 1233) >>> 12;
int idx = r-19;
return (idx >= LONGLONG_TEN_POWERS_TABLE.length || longLongCompareMagnitude(hi, lo,
LONGLONG_TEN_POWERS_TABLE[idx][0], LONGLONG_TEN_POWERS_TABLE[idx][1])) ? r : r + 1;
}
/*
* returns true if 128 bit number <hi0,lo0> is less then <hi1,lo1>
* hi0 & hi1 should be non-negative
*/
private static boolean longLongCompareMagnitude(long hi0, long lo0, long hi1, long lo1) {
if(hi0!=hi1) {
return hi0<hi1;
}
return (lo0+Long.MIN_VALUE) <(lo1+Long.MIN_VALUE);
}
private static BigDecimal divide(long dividend, int dividendScale, long divisor, int divisorScale, int scale, int roundingMode) {
if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
int newScale = scale + divisorScale;
int raise = newScale - dividendScale;
if(raise<LONG_TEN_POWERS_TABLE.length) {
long xs = dividend;
if ((xs = longMultiplyPowerTen(xs, raise)) != INFLATED) {
return divideAndRound(xs, divisor, scale, roundingMode, scale);
}
BigDecimal q = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[raise], dividend, divisor, scale, roundingMode, scale);
if(q!=null) {
return q;
}
}
BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
} else {
int newScale = checkScale(divisor,(long)dividendScale - scale);
int raise = newScale - divisorScale;
if(raise<LONG_TEN_POWERS_TABLE.length) {
long ys = divisor;
if ((ys = longMultiplyPowerTen(ys, raise)) != INFLATED) {
return divideAndRound(dividend, ys, scale, roundingMode, scale);
}
}
BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
return divideAndRound(BigInteger.valueOf(dividend), scaledDivisor, scale, roundingMode, scale);
}
}
private static BigDecimal divide(BigInteger dividend, int dividendScale, long divisor, int divisorScale, int scale, int roundingMode) {
if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
int newScale = scale + divisorScale;
int raise = newScale - dividendScale;
BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
} else {
int newScale = checkScale(divisor,(long)dividendScale - scale);
int raise = newScale - divisorScale;
if(raise<LONG_TEN_POWERS_TABLE.length) {
long ys = divisor;
if ((ys = longMultiplyPowerTen(ys, raise)) != INFLATED) {
return divideAndRound(dividend, ys, scale, roundingMode, scale);
}
}
BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
return divideAndRound(dividend, scaledDivisor, scale, roundingMode, scale);
}
}
private static BigDecimal divide(long dividend, int dividendScale, BigInteger divisor, int divisorScale, int scale, int roundingMode) {
if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
int newScale = scale + divisorScale;
int raise = newScale - dividendScale;
BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
} else {
int newScale = checkScale(divisor,(long)dividendScale - scale);
int raise = newScale - divisorScale;
BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
return divideAndRound(BigInteger.valueOf(dividend), scaledDivisor, scale, roundingMode, scale);
}
}
private static BigDecimal divide(BigInteger dividend, int dividendScale, BigInteger divisor, int divisorScale, int scale, int roundingMode) {
if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
int newScale = scale + divisorScale;
int raise = newScale - dividendScale;
BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
} else {
int newScale = checkScale(divisor,(long)dividendScale - scale);
int raise = newScale - divisorScale;
BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
return divideAndRound(dividend, scaledDivisor, scale, roundingMode, scale);
}
}
}
/*
* Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -353,27 +353,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
mag = trustedStripLeadingZeroInts(magnitude);
}
// Constructs a new BigInteger using a char array with radix=10
BigInteger(char[] val) {
/*
* Constructs a new BigInteger using a char array with radix=10.
* Sign is precalculated outside and not allowed in the val.
*/
BigInteger(char[] val, int sign, int len) {
int cursor = 0, numDigits;
int len = val.length;
// Check for leading minus sign
int sign = 1;
if (val[0] == '-') {
if (len == 1)
throw new NumberFormatException("Zero length BigInteger");
sign = -1;
cursor = 1;
} else if (val[0] == '+') {
if (len == 1)
throw new NumberFormatException("Zero length BigInteger");
cursor = 1;
}
// Skip leading zeros and compute number of digits in magnitude
while (cursor < len && Character.digit(val[cursor], 10) == 0)
while (cursor < len && Character.digit(val[cursor], 10) == 0) {
cursor++;
}
if (cursor == len) {
signum = 0;
mag = ZERO.mag;
......@@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
numDigits = len - cursor;
signum = sign;
// Pre-allocate array of expected size
int numWords;
if (len < 10) {
......@@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return new BigInteger(resultMag, cmp == signum ? 1 : -1);
}
/**
* Package private methods used by BigDecimal code to add a BigInteger
* with a long. Assumes val is not equal to INFLATED.
*/
BigInteger add(long val) {
if (val == 0)
return this;
if (signum == 0)
return valueOf(val);
if (Long.signum(val) == signum)
return new BigInteger(add(mag, Math.abs(val)), signum);
int cmp = compareMagnitude(val);
if (cmp == 0)
return ZERO;
int[] resultMag = (cmp > 0 ? subtract(mag, Math.abs(val)) : subtract(Math.abs(val), mag));
resultMag = trustedStripLeadingZeroInts(resultMag);
return new BigInteger(resultMag, cmp == signum ? 1 : -1);
}
/**
* Adds the contents of the int array x and long value val. This
* method allocates a new int array to hold the answer and returns
* a reference to that array. Assumes x.length &gt; 0 and val is
* non-negative
*/
private static int[] add(int[] x, long val) {
int[] y;
long sum = 0;
int xIndex = x.length;
int[] result;
int highWord = (int)(val >>> 32);
if (highWord==0) {
result = new int[xIndex];
sum = (x[--xIndex] & LONG_MASK) + val;
result[xIndex] = (int)sum;
} else {
if (xIndex == 1) {
result = new int[2];
sum = val + (x[0] & LONG_MASK);
result[1] = (int)sum;
result[0] = (int)(sum >>> 32);
return result;
} else {
result = new int[xIndex];
sum = (x[--xIndex] & LONG_MASK) + (val & LONG_MASK);
result[xIndex] = (int)sum;
sum = (x[--xIndex] & LONG_MASK) + (highWord & LONG_MASK) + (sum >>> 32);
result[xIndex] = (int)sum;
}
}
// Copy remainder of longer number while carry propagation is required
boolean carry = (sum >>> 32 != 0);
while (xIndex > 0 && carry)
carry = ((result[--xIndex] = x[xIndex] + 1) == 0);
// Copy remainder of longer number
while (xIndex > 0)
result[--xIndex] = x[xIndex];
// Grow result if necessary
if (carry) {
int bigger[] = new int[result.length + 1];
System.arraycopy(result, 0, bigger, 1, result.length);
bigger[0] = 0x01;
return bigger;
}
return result;
}
/**
* Adds the contents of the int arrays x and y. This method allocates
* a new int array to hold the answer and returns a reference to that
......@@ -1074,14 +1130,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int yIndex = y.length;
int result[] = new int[xIndex];
long sum = 0;
if(yIndex==1) {
sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ;
result[xIndex] = (int)sum;
} else {
// Add common parts of both numbers
while(yIndex > 0) {
sum = (x[--xIndex] & LONG_MASK) +
(y[--yIndex] & LONG_MASK) + (sum >>> 32);
result[xIndex] = (int)sum;
}
}
// Copy remainder of longer number while carry propagation is required
boolean carry = (sum >>> 32 != 0);
while (xIndex > 0 && carry)
......@@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return result;
}
private static int[] subtract(long val, int[] little) {
int highWord = (int)(val >>> 32);
if (highWord==0) {
int result[] = new int[1];
result[0] = (int)(val - (little[0] & LONG_MASK));
return result;
} else {
int result[] = new int[2];
if(little.length==1) {
long difference = ((int)val & LONG_MASK) - (little[0] & LONG_MASK);
result[1] = (int)difference;
// Subtract remainder of longer number while borrow propagates
boolean borrow = (difference >> 32 != 0);
if(borrow) {
result[0] = highWord - 1;
} else { // Copy remainder of longer number
result[0] = highWord;
}
return result;
} else { // little.length==2
long difference = ((int)val & LONG_MASK) - (little[1] & LONG_MASK);
result[1] = (int)difference;
difference = (highWord & LONG_MASK) - (little[0] & LONG_MASK) + (difference >> 32);
result[0] = (int)difference;
return result;
}
}
}
/**
* Subtracts the contents of the second argument (val) from the
* first (big). The first int array (big) must represent a larger number
* than the second. This method allocates the space necessary to hold the
* answer.
* assumes val &gt;= 0
*/
private static int[] subtract(int[] big, long val) {
int highWord = (int)(val >>> 32);
int bigIndex = big.length;
int result[] = new int[bigIndex];
long difference = 0;
if (highWord==0) {
difference = (big[--bigIndex] & LONG_MASK) - val;
result[bigIndex] = (int)difference;
} else {
difference = (big[--bigIndex] & LONG_MASK) - (val & LONG_MASK);
result[bigIndex] = (int)difference;
difference = (big[--bigIndex] & LONG_MASK) - (highWord & LONG_MASK) + (difference >> 32);
result[bigIndex] = (int)difference;
}
// Subtract remainder of longer number while borrow propagates
boolean borrow = (difference >> 32 != 0);
while (bigIndex > 0 && borrow)
borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
// Copy remainder of longer number
while (bigIndex > 0)
result[--bigIndex] = big[bigIndex];
return result;
}
/**
* Returns a BigInteger whose value is {@code (this - val)}.
*
......@@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
public BigInteger multiply(BigInteger val) {
if (val.signum == 0 || signum == 0)
return ZERO;
int resultSign = signum == val.signum ? 1 : -1;
if (val.mag.length == 1) {
return multiplyByInt(mag,val.mag[0], resultSign);
}
if(mag.length == 1) {
return multiplyByInt(val.mag,mag[0], resultSign);
}
int[] result = multiplyToLen(mag, mag.length,
val.mag, val.mag.length, null);
result = trustedStripLeadingZeroInts(result);
return new BigInteger(result, signum == val.signum ? 1 : -1);
return new BigInteger(result, resultSign);
}
private static BigInteger multiplyByInt(int[] x, int y, int sign) {
if(Integer.bitCount(y)==1) {
return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign);
}
int xlen = x.length;
int[] rmag = new int[xlen + 1];
long carry = 0;
long yl = y & LONG_MASK;
int rstart = rmag.length - 1;
for (int i = xlen - 1; i >= 0; i--) {
long product = (x[i] & LONG_MASK) * yl + carry;
rmag[rstart--] = (int)product;
carry = product >>> 32;
}
if (carry == 0L) {
rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
} else {
rmag[rstart] = (int)carry;
}
return new BigInteger(rmag, sign);
}
/**
......@@ -1339,8 +1491,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag);
a.divide(b, q);
return q.toBigInteger(this.signum == val.signum ? 1 : -1);
a.divide(b, q, false);
return q.toBigInteger(this.signum * val.signum);
}
/**
......@@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return shiftRight(-n);
}
}
int[] newMag = shiftLeft(mag,n);
return new BigInteger(newMag, signum);
}
private static int[] shiftLeft(int[] mag, int n) {
int nInts = n >>> 5;
int nBits = n & 0x1f;
int magLen = mag.length;
......@@ -2094,8 +2251,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2;
newMag[i] = mag[j] << nBits;
}
return new BigInteger(newMag, signum);
return newMag;
}
/**
......@@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return 0;
}
/**
* Version of compareMagnitude that compares magnitude with long value.
* val can't be Long.MIN_VALUE.
*/
final int compareMagnitude(long val) {
assert val != Long.MIN_VALUE;
int[] m1 = mag;
int len = m1.length;
if(len > 2) {
return 1;
}
if (val < 0) {
val = -val;
}
int highWord = (int)(val >>> 32);
if (highWord==0) {
if (len < 1)
return -1;
if (len > 1)
return 1;
int a = m1[0];
int b = (int)val;
if (a != b) {
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
}
return 0;
} else {
if (len < 2)
return -1;
int a = m1[0];
int b = highWord;
if (a != b) {
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
}
a = m1[1];
b = (int)val;
if (a != b) {
return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
}
return 0;
}
}
/**
* Compares this BigInteger with the specified Object for equality.
*
......
/*
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -160,7 +160,7 @@ class MutableBigInteger {
*/
BigDecimal toBigDecimal(int sign, int scale) {
if (intLen == 0 || sign == 0)
return BigDecimal.valueOf(0, scale);
return BigDecimal.zeroValueOf(scale);
int[] mag = getMagnitudeArray();
int len = mag.length;
int d = mag[0];
......@@ -171,7 +171,28 @@ class MutableBigInteger {
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);
return BigDecimal.valueOf(sign == -1 ? -v : v, scale);
}
/**
* This is for internal use in converting from a MutableBigInteger
* object into a long value given a specified sign.
* returns INFLATED if value is not fit into long
*/
long toCompactValue(int sign) {
if (intLen == 0 || sign == 0)
return 0L;
int[] mag = getMagnitudeArray();
int len = mag.length;
int d = mag[0];
// If this MutableBigInteger can not be fitted into long, we need to
// make a BigInteger object for the resultant BigDecimal object.
if (len > 2 || (d < 0 && len == 2))
return INFLATED;
long v = (len == 2) ?
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
d & LONG_MASK;
return sign == -1 ? -v : v;
}
/**
......@@ -543,6 +564,24 @@ class MutableBigInteger {
return (int)carry;
}
/**
* The method is the same as mulsun, except the fact that q array is not
* updated, the only result of the method is borrow flag.
*/
private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset) {
long xLong = x & LONG_MASK;
long carry = 0;
offset += len;
for (int j=len-1; j >= 0; j--) {
long product = (a[j] & LONG_MASK) * xLong + carry;
long difference = q[offset--] - product;
carry = (product >>> 32)
+ (((difference & LONG_MASK) >
(((~(int)product) & LONG_MASK))) ? 1:0);
}
return (int)carry;
}
/**
* Right shift this MutableBigInteger n bits, where n is
* less than 32.
......@@ -842,20 +881,20 @@ class MutableBigInteger {
rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK;
}
int xlen = intLen;
int[] qWord = new int[2];
while (--xlen > 0) {
long dividendEstimate = (remLong<<32) |
long dividendEstimate = (remLong << 32) |
(value[offset + intLen - xlen] & LONG_MASK);
int q;
if (dividendEstimate >= 0) {
qWord[0] = (int) (dividendEstimate / divisorLong);
qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
q = (int) (dividendEstimate / divisorLong);
rem = (int) (dividendEstimate - q * divisorLong);
} else {
divWord(qWord, dividendEstimate, divisor);
long tmp = divWord(dividendEstimate, divisor);
q = (int) (tmp & LONG_MASK);
rem = (int) (tmp >>> 32);
}
quotient.value[intLen - xlen] = qWord[0];
rem = qWord[1];
quotient.value[intLen - xlen] = q;
remLong = rem & LONG_MASK;
}
......@@ -879,40 +918,45 @@ class MutableBigInteger {
*
*/
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
return divide(b,quotient,true);
}
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) {
if (b.intLen == 0)
throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero
if (intLen == 0) {
quotient.intLen = quotient.offset;
return new MutableBigInteger();
return needReminder ? new MutableBigInteger() : null;
}
int cmp = compare(b);
// Dividend less than divisor
if (cmp < 0) {
quotient.intLen = quotient.offset = 0;
return new MutableBigInteger(this);
return needReminder ? new MutableBigInteger(this) : null;
}
// Dividend equal to divisor
if (cmp == 0) {
quotient.value[0] = quotient.intLen = 1;
quotient.offset = 0;
return new MutableBigInteger();
return needReminder ? new MutableBigInteger() : null;
}
quotient.clear();
// Special case one word divisor
if (b.intLen == 1) {
int r = divideOneWord(b.value[b.offset], quotient);
if(needReminder) {
if (r == 0)
return new MutableBigInteger();
return new MutableBigInteger(r);
} else {
return null;
}
// Copy divisor value to protect divisor
int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
return divideMagnitude(div, quotient);
}
return divideMagnitude(b, quotient, needReminder);
}
/**
......@@ -940,30 +984,72 @@ class MutableBigInteger {
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();
return divideLongMagnitude(v, quotient).toLong();
}
}
private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift) {
int n2 = 32 - shift;
int c=src[srcFrom];
for (int i=0; i < srcLen-1; i++) {
int b = c;
c = src[++srcFrom];
dst[dstFrom+i] = (b << shift) | (c >>> n2);
}
dst[dstFrom+srcLen-1] = c << shift;
}
/**
* Divide this MutableBigInteger by the divisor represented by its magnitude
* array. The quotient will be placed into the provided quotient object &
* Divide this MutableBigInteger by the divisor.
* The quotient will be placed into the provided quotient object &
* the remainder object is returned.
*/
private MutableBigInteger divideMagnitude(int[] divisor,
MutableBigInteger quotient) {
// Remainder starts as dividend with space for a leading zero
MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
private MutableBigInteger divideMagnitude(MutableBigInteger div,
MutableBigInteger quotient,
boolean needReminder ) {
// assert div.intLen > 1
// D1 normalize the divisor
int shift = Integer.numberOfLeadingZeros(div.value[div.offset]);
// Copy divisor value to protect divisor
final int dlen = div.intLen;
int[] divisor;
MutableBigInteger rem; // Remainder starts as dividend with space for a leading zero
if (shift > 0) {
divisor = new int[dlen];
copyAndShift(div.value,div.offset,dlen,divisor,0,shift);
if(Integer.numberOfLeadingZeros(value[offset])>=shift) {
int[] remarr = new int[intLen + 1];
rem = new MutableBigInteger(remarr);
rem.intLen = intLen;
rem.offset = 1;
copyAndShift(value,offset,intLen,remarr,1,shift);
} else {
int[] remarr = new int[intLen + 2];
rem = new MutableBigInteger(remarr);
rem.intLen = intLen+1;
rem.offset = 1;
int rFrom = offset;
int c=0;
int n2 = 32 - shift;
for (int i=1; i < intLen+1; i++,rFrom++) {
int b = c;
c = value[rFrom];
remarr[i] = (b << shift) | (c >>> n2);
}
remarr[intLen+1] = c << shift;
}
} else {
divisor = Arrays.copyOfRange(div.value, div.offset, div.offset + div.intLen);
rem = new MutableBigInteger(new int[intLen + 1]);
System.arraycopy(value, offset, rem.value, 1, intLen);
rem.intLen = intLen;
rem.offset = 1;
}
int nlen = rem.intLen;
// Set the quotient size
int dlen = divisor.length;
int limit = nlen - dlen + 1;
final int limit = nlen - dlen + 1;
if (quotient.value.length < limit) {
quotient.value = new int[limit];
quotient.offset = 0;
......@@ -971,14 +1057,6 @@ class MutableBigInteger {
quotient.intLen = limit;
int[] q = quotient.value;
// D1 normalize the divisor
int shift = Integer.numberOfLeadingZeros(divisor[0]);
if (shift > 0) {
// First shift will not grow array
BigInteger.primitiveLeftShift(divisor, dlen, shift);
// But this one might
rem.leftShift(shift);
}
// Must insert leading 0 in rem if its length did not change
if (rem.intLen == nlen) {
......@@ -990,10 +1068,9 @@ class MutableBigInteger {
int dh = divisor[0];
long dhLong = dh & LONG_MASK;
int dl = divisor[1];
int[] qWord = new int[2];
// D2 Initialize j
for(int j=0; j<limit; j++) {
for(int j=0; j<limit-1; j++) {
// D3 Calculate qhat
// estimate qhat
int qhat = 0;
......@@ -1013,9 +1090,9 @@ class MutableBigInteger {
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
} else {
divWord(qWord, nChunk, dh);
qhat = qWord[0];
qrem = qWord[1];
long tmp = divWord(nChunk, dh);
qhat = (int) (tmp & LONG_MASK);
qrem = (int) (tmp >>> 32);
}
}
......@@ -1053,6 +1130,181 @@ class MutableBigInteger {
// Store the quotient digit
q[j] = qhat;
} // D7 loop on j
// D3 Calculate qhat
// estimate qhat
int qhat = 0;
int qrem = 0;
boolean skipCorrection = false;
int nh = rem.value[limit - 1 + rem.offset];
int nh2 = nh + 0x80000000;
int nm = rem.value[limit + rem.offset];
if (nh == dh) {
qhat = ~0;
qrem = nh + nm;
skipCorrection = qrem + 0x80000000 < nh2;
} else {
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
if (nChunk >= 0) {
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
} else {
long tmp = divWord(nChunk, dh);
qhat = (int) (tmp & LONG_MASK);
qrem = (int) (tmp >>> 32);
}
}
if (qhat != 0) {
if (!skipCorrection) { // Correct qhat
long nl = rem.value[limit + 1 + rem.offset] & LONG_MASK;
long rs = ((qrem & LONG_MASK) << 32) | nl;
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
if (unsignedLongCompare(estProduct, rs)) {
qhat--;
qrem = (int) ((qrem & LONG_MASK) + dhLong);
if ((qrem & LONG_MASK) >= dhLong) {
estProduct -= (dl & LONG_MASK);
rs = ((qrem & LONG_MASK) << 32) | nl;
if (unsignedLongCompare(estProduct, rs))
qhat--;
}
}
}
// D4 Multiply and subtract
int borrow;
rem.value[limit - 1 + rem.offset] = 0;
if(needReminder)
borrow = mulsub(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
else
borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
// D5 Test remainder
if (borrow + 0x80000000 > nh2) {
// D6 Add back
if(needReminder)
divadd(divisor, rem.value, limit - 1 + 1 + rem.offset);
qhat--;
}
// Store the quotient digit
q[(limit - 1)] = qhat;
}
if(needReminder) {
// D8 Unnormalize
if (shift > 0)
rem.rightShift(shift);
rem.normalize();
}
quotient.normalize();
return needReminder ? rem : null;
}
/**
* Divide this MutableBigInteger by the divisor represented by positive long
* value. The quotient will be placed into the provided quotient object &
* the remainder object is returned.
*/
private MutableBigInteger divideLongMagnitude(long ldivisor, MutableBigInteger quotient) {
// Remainder starts as dividend with space for a leading zero
MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
System.arraycopy(value, offset, rem.value, 1, intLen);
rem.intLen = intLen;
rem.offset = 1;
int nlen = rem.intLen;
int limit = nlen - 2 + 1;
if (quotient.value.length < limit) {
quotient.value = new int[limit];
quotient.offset = 0;
}
quotient.intLen = limit;
int[] q = quotient.value;
// D1 normalize the divisor
int shift = Long.numberOfLeadingZeros(ldivisor);
if (shift > 0) {
ldivisor<<=shift;
rem.leftShift(shift);
}
// Must insert leading 0 in rem if its length did not change
if (rem.intLen == nlen) {
rem.offset = 0;
rem.value[0] = 0;
rem.intLen++;
}
int dh = (int)(ldivisor >>> 32);
long dhLong = dh & LONG_MASK;
int dl = (int)(ldivisor & LONG_MASK);
// D2 Initialize j
for (int j = 0; j < limit; j++) {
// D3 Calculate qhat
// estimate qhat
int qhat = 0;
int qrem = 0;
boolean skipCorrection = false;
int nh = rem.value[j + rem.offset];
int nh2 = nh + 0x80000000;
int nm = rem.value[j + 1 + rem.offset];
if (nh == dh) {
qhat = ~0;
qrem = nh + nm;
skipCorrection = qrem + 0x80000000 < nh2;
} else {
long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
if (nChunk >= 0) {
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
} else {
long tmp = divWord(nChunk, dh);
qhat =(int)(tmp & LONG_MASK);
qrem = (int)(tmp>>>32);
}
}
if (qhat == 0)
continue;
if (!skipCorrection) { // Correct qhat
long nl = rem.value[j + 2 + rem.offset] & LONG_MASK;
long rs = ((qrem & LONG_MASK) << 32) | nl;
long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
if (unsignedLongCompare(estProduct, rs)) {
qhat--;
qrem = (int) ((qrem & LONG_MASK) + dhLong);
if ((qrem & LONG_MASK) >= dhLong) {
estProduct -= (dl & LONG_MASK);
rs = ((qrem & LONG_MASK) << 32) | nl;
if (unsignedLongCompare(estProduct, rs))
qhat--;
}
}
}
// D4 Multiply and subtract
rem.value[j + rem.offset] = 0;
int borrow = mulsubLong(rem.value, dh, dl, qhat, j + rem.offset);
// D5 Test remainder
if (borrow + 0x80000000 > nh2) {
// D6 Add back
divaddLong(dh,dl, rem.value, j + 1 + rem.offset);
qhat--;
}
// Store the quotient digit
q[j] = qhat;
} // D7 loop on j
// D8 Unnormalize
if (shift > 0)
......@@ -1063,6 +1315,46 @@ class MutableBigInteger {
return rem;
}
/**
* A primitive used for division by long.
* Specialized version of the method divadd.
* dh is a high part of the divisor, dl is a low part
*/
private int divaddLong(int dh, int dl, int[] result, int offset) {
long carry = 0;
long sum = (dl & LONG_MASK) + (result[1+offset] & LONG_MASK);
result[1+offset] = (int)sum;
sum = (dh & LONG_MASK) + (result[offset] & LONG_MASK) + carry;
result[offset] = (int)sum;
carry = sum >>> 32;
return (int)carry;
}
/**
* This method is used for division by long.
* Specialized version of the method sulsub.
* dh is a high part of the divisor, dl is a low part
*/
private int mulsubLong(int[] q, int dh, int dl, int x, int offset) {
long xLong = x & LONG_MASK;
offset += 2;
long product = (dl & LONG_MASK) * xLong;
long difference = q[offset] - product;
q[offset--] = (int)difference;
long carry = (product >>> 32)
+ (((difference & LONG_MASK) >
(((~(int)product) & LONG_MASK))) ? 1:0);
product = (dh & LONG_MASK) * xLong + carry;
difference = q[offset] - product;
q[offset--] = (int)difference;
carry = (product >>> 32)
+ (((difference & LONG_MASK) >
(((~(int)product) & LONG_MASK))) ? 1:0);
return (int)carry;
}
/**
* Compare two longs as if they were unsigned.
* Returns true iff one is bigger than two.
......@@ -1075,19 +1367,22 @@ class MutableBigInteger {
* This method divides a long quantity by an int to estimate
* qhat for two multi precision numbers. It is used when
* the signed value of n is less than zero.
* Returns long value where high 32 bits contain reminder value and
* low 32 bits contain quotient value.
*/
private void divWord(int[] result, long n, int d) {
static long divWord(long n, int d) {
long dLong = d & LONG_MASK;
long r;
long q;
if (dLong == 1) {
result[0] = (int)n;
result[1] = 0;
return;
q = (int)n;
r = 0;
return (r << 32) | (q & LONG_MASK);
}
// Approximate the quotient and remainder
long q = (n >>> 1) / (dLong >>> 1);
long r = n - q*dLong;
q = (n >>> 1) / (dLong >>> 1);
r = n - q*dLong;
// Correct the approximation
while (r < 0) {
......@@ -1098,10 +1393,8 @@ class MutableBigInteger {
r -= dLong;
q++;
}
// n - q*dlong == r && 0 <= r <dLong, hence we're done.
result[0] = (int)q;
result[1] = (int)r;
return (r << 32) | (q & LONG_MASK);
}
/**
......@@ -1473,5 +1766,4 @@ class MutableBigInteger {
mod.subtract(t1);
return mod;
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2011 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -23,7 +23,7 @@
/*
* @test
* @bug 6274390
* @bug 6274390 7082971
* @summary Verify {float, double}Value methods work with condensed representation
* @run main FloatDoubleValueTests
* @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests
......@@ -79,6 +79,7 @@ public class FloatDoubleValueTests {
// and double.
static void testFloatDoubleValue() {
long longValues[] = {
Long.MIN_VALUE, // -2^63
0,
1,
2,
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2011 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册