提交 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; ...@@ -215,6 +215,7 @@ import static java.math.BigInteger.LONG_MASK;
* @author Josh Bloch * @author Josh Bloch
* @author Mike Cowlishaw * @author Mike Cowlishaw
* @author Joseph D. Darcy * @author Joseph D. Darcy
* @author Sergey V. Kuksenko
*/ */
public class BigDecimal extends Number implements Comparable<BigDecimal> { public class BigDecimal extends Number implements Comparable<BigDecimal> {
/** /**
...@@ -224,7 +225,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -224,7 +225,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @serial * @serial
* @see #unscaledValue * @see #unscaledValue
*/ */
private volatile BigInteger intVal; private final BigInteger intVal;
/** /**
* The scale of this BigDecimal, as returned by {@link #scale}. * The scale of this BigDecimal, as returned by {@link #scale}.
...@@ -232,8 +233,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -232,8 +233,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @serial * @serial
* @see #scale * @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 // calculations must be done in longs
/** /**
* The number of decimal digits in this BigDecimal, or 0 if the * The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If * number of digits are not known (lookaside information). If
...@@ -256,19 +258,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -256,19 +258,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
static final long INFLATED = Long.MIN_VALUE; 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 * If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be * less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations. * compactly stored in this field and used in computations.
*/ */
private transient long intCompact; private final transient long intCompact;
// All 18-digit base ten strings fit into a long; not all 19-digit // All 18-digit base ten strings fit into a long; not all 19-digit
// strings will // strings will
private static final int MAX_COMPACT_DIGITS = 18; private static final int MAX_COMPACT_DIGITS = 18;
private static final int MAX_BIGINT_BITS = 62;
/* Appease the serialization gods */ /* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L; private static final long serialVersionUID = 6108874887143696463L;
...@@ -282,17 +284,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -282,17 +284,17 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// Cache of common small BigDecimal values. // Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = { private static final BigDecimal zeroThroughTen[] = {
new BigDecimal(BigInteger.ZERO, 0, 0, 1), new BigDecimal(BigInteger.ZERO, 0, 0, 1),
new BigDecimal(BigInteger.ONE, 1, 0, 1), new BigDecimal(BigInteger.ONE, 1, 0, 1),
new BigDecimal(BigInteger.valueOf(2), 2, 0, 1), new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
new BigDecimal(BigInteger.valueOf(3), 3, 0, 1), new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
new BigDecimal(BigInteger.valueOf(4), 4, 0, 1), new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
new BigDecimal(BigInteger.valueOf(5), 5, 0, 1), new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
new BigDecimal(BigInteger.valueOf(6), 6, 0, 1), new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
new BigDecimal(BigInteger.valueOf(7), 7, 0, 1), new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
new BigDecimal(BigInteger.valueOf(8), 8, 0, 1), new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
new BigDecimal(BigInteger.valueOf(9), 9, 0, 1), new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
new BigDecimal(BigInteger.TEN, 10, 0, 2), new BigDecimal(BigInteger.TEN, 10, 0, 2),
}; };
// Cache of zero scaled by 0 - 15 // Cache of zero scaled by 0 - 15
...@@ -378,9 +380,36 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -378,9 +380,36 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(char[] in, int offset, int len) { public BigDecimal(char[] in, int offset, int len) {
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. // protect against huge length.
if (offset+len > in.length || offset < 0) if (offset + len > in.length || offset < 0)
throw new NumberFormatException(); throw new NumberFormatException("Bad offset or len arguments for char[] input.");
// This is the primary string to BigDecimal constructor; all // This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline) // incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate // parsing for speed and generates at most one intermediate
...@@ -391,7 +420,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -391,7 +420,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int scl = 0; // record scale value int scl = 0; // record scale value
long rs = 0; // the compact value in long long rs = 0; // the compact value in long
BigInteger rb = null; // the inflated value in BigInteger BigInteger rb = null; // the inflated value in BigInteger
// use array bounds checking to handle too-long, len == 0, // use array bounds checking to handle too-long, len == 0,
// bad offset, etc. // bad offset, etc.
try { try {
...@@ -408,23 +436,39 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -408,23 +436,39 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// should now be at numeric part of the significand // should now be at numeric part of the significand
boolean dot = false; // true when there is a '.' boolean dot = false; // true when there is a '.'
int cfirst = offset; // record start of integer
long exp = 0; // exponent long exp = 0; // exponent
char c; // current character char c; // current character
boolean isCompact = (len <= MAX_COMPACT_DIGITS); boolean isCompact = (len <= MAX_COMPACT_DIGITS);
// integer significand array & idx is the index to it. The array // integer significand array & idx is the index to it. The array
// is ONLY used when we can't use a compact representation. // is ONLY used when we can't use a compact representation.
char coeff[] = isCompact ? null : new char[len];
int idx = 0; int idx = 0;
if (isCompact) {
for (; len > 0; offset++, len--) { // First compact case, we need not to preserve the character
c = in[offset]; // and we can just compute the value in place.
// have digit for (; len > 0; offset++, len--) {
if ((c >= '0' && c <= '9') || Character.isDigit(c)) { c = in[offset];
// First compact case, we need not to preserve the character if ((c == '0')) { // have zero
// and we can just compute the value in place. if (prec == 0)
if (isCompact) { 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); int digit = Character.digit(c, 10);
if (digit == 0) { if (digit == 0) {
if (prec == 0) if (prec == 0)
...@@ -438,7 +482,44 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -438,7 +482,44 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
++prec; // prec unchanged if preceded by 0s ++prec; // prec unchanged if preceded by 0s
rs = rs * 10 + digit; 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 (c == '0' || Character.digit(c, 10) == 0) {
if (prec == 0) { if (prec == 0) {
coeff[idx] = c; coeff[idx] = c;
...@@ -452,94 +533,64 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -452,94 +533,64 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
++prec; // prec unchanged if preceded by 0s ++prec; // prec unchanged if preceded by 0s
coeff[idx++] = c; coeff[idx++] = c;
} }
if (dot)
++scl;
continue;
} }
if (dot)
++scl;
continue;
}
// have dot
if (c == '.') {
// have dot // have dot
if (dot) // two dots if (c == '.') {
throw new NumberFormatException(); // have dot
dot = true; if (dot) // two dots
continue;
}
// exponent expected
if ((c != 'e') && (c != 'E'))
throw new NumberFormatException();
offset++;
c = in[offset];
len--;
boolean negexp = (c == '-');
// optional sign
if (negexp || c == '+') {
offset++;
c = in[offset];
len--;
}
if (len <= 0) // no exponent digits
throw new NumberFormatException();
// skip leading zeros in the exponent
while (len > 10 && Character.digit(c, 10) == 0) {
offset++;
c = in[offset];
len--;
}
if (len > 10) // too many nonzero exponent digits
throw new NumberFormatException();
// c now holds first digit of exponent
for (;; len--) {
int v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else {
v = Character.digit(c, 10);
if (v < 0) // not a digit
throw new NumberFormatException(); throw new NumberFormatException();
dot = true;
continue;
} }
exp = exp * 10 + v; // exponent expected
if (len == 1) if ((c != 'e') && (c != 'E'))
break; // that was final character throw new NumberFormatException();
offset++; exp = parseExp(in, offset, len);
c = in[offset]; // Next test is required for backwards compatibility
if ((int) exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
} }
if (negexp) // apply sign // here when no characters left
exp = -exp; if (prec == 0) // no digits found
// Next test is required for backwards compatibility
if ((int)exp != exp) // overflow
throw new NumberFormatException(); throw new NumberFormatException();
break; // [saves a test] // Adjust scale if exp is not zero.
} if (exp != 0) { // had significant exponent
// here when no characters left scl = adjustScale(scl, exp);
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); // Remove leading zeros from precision (digits count)
rb = new BigInteger(coeff, isneg ? -1 : 1, prec);
rs = compactValFor(rb); 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) { } catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException(); throw new NumberFormatException();
...@@ -549,36 +600,61 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -549,36 +600,61 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
this.scale = scl; this.scale = scl;
this.precision = prec; this.precision = prec;
this.intCompact = rs; this.intCompact = rs;
this.intVal = (rs != INFLATED) ? null : rb; this.intVal = rb;
} }
/** private int adjustScale(int scl, long exp) {
* Translates a character array representation of a long adjustedScale = scl - exp;
* {@code BigDecimal} into a {@code BigDecimal}, accepting the if (adjustedScale > Integer.MAX_VALUE || adjustedScale < Integer.MIN_VALUE)
* same sequence of characters as the {@link #BigDecimal(String)} throw new NumberFormatException("Scale out of range.");
* constructor, while allowing a sub-array to be specified and scl = (int) adjustedScale;
* with rounding according to the context settings. return scl;
* }
* <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 * parse exponent
* {@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) { private static long parseExp(char[] in, int offset, int len){
this(in, offset, len); long exp = 0;
if (mc.precision > 0) offset++;
roundThis(mc); char c = in[offset];
len--;
boolean negexp = (c == '-');
// optional sign
if (negexp || c == '+') {
offset++;
c = in[offset];
len--;
}
if (len <= 0) // no exponent digits
throw new NumberFormatException();
// skip leading zeros in the exponent
while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) {
offset++;
c = in[offset];
len--;
}
if (len > 10) // too many nonzero exponent digits
throw new NumberFormatException();
// c now holds first digit of exponent
for (;; len--) {
int v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else {
v = Character.digit(c, 10);
if (v < 0) // not a digit
throw new NumberFormatException();
}
exp = exp * 10 + v;
if (len == 1)
break; // that was final character
offset++;
c = in[offset];
}
if (negexp) // apply sign
exp = -exp;
return exp;
} }
/** /**
...@@ -754,9 +830,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -754,9 +830,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(String val, MathContext mc) { public BigDecimal(String val, MathContext mc) {
this(val.toCharArray(), 0, val.length()); this(val.toCharArray(), 0, val.length(), mc);
if (mc.precision > 0)
roundThis(mc);
} }
/** /**
...@@ -804,49 +878,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -804,49 +878,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @throws NumberFormatException if {@code val} is infinite or NaN. * @throws NumberFormatException if {@code val} is infinite or NaN.
*/ */
public BigDecimal(double val) { public BigDecimal(double val) {
if (Double.isInfinite(val) || Double.isNaN(val)) this(val,MathContext.UNLIMITED);
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;
} }
/** /**
...@@ -868,9 +900,86 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -868,9 +900,86 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(double val, MathContext mc) { public BigDecimal(double val, MathContext mc) {
this(val); if (Double.isInfinite(val) || Double.isNaN(val))
if (mc.precision > 0) throw new NumberFormatException("Infinite or NaN");
roundThis(mc); // 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> { ...@@ -881,8 +990,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* {@code BigDecimal}. * {@code BigDecimal}.
*/ */
public BigDecimal(BigInteger val) { public BigDecimal(BigInteger val) {
scale = 0;
intVal = val;
intCompact = compactValFor(val); intCompact = compactValFor(val);
intVal = (intCompact != INFLATED) ? null : val;
} }
/** /**
...@@ -898,9 +1008,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -898,9 +1008,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(BigInteger val, MathContext mc) { public BigDecimal(BigInteger val, MathContext mc) {
this(val); this(val,0,mc);
if (mc.precision > 0)
roundThis(mc);
} }
/** /**
...@@ -914,7 +1022,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -914,7 +1022,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal(BigInteger unscaledVal, int scale) { public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed // Negative scales are now allowed
this(unscaledVal); this.intVal = unscaledVal;
this.intCompact = compactValFor(unscaledVal);
this.scale = scale; this.scale = scale;
} }
...@@ -934,10 +1043,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -934,10 +1043,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
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; this.scale = scale;
if (mc.precision > 0) this.precision = prec;
roundThis(mc);
} }
/** /**
...@@ -949,7 +1089,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -949,7 +1089,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(int val) { 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> { ...@@ -964,9 +1106,24 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(int val, MathContext mc) { public BigDecimal(int val, MathContext mc) {
intCompact = val; int mcp = mc.precision;
if (mc.precision > 0) long compactVal = val;
roundThis(mc); 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> { ...@@ -978,7 +1135,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal(long val) { public BigDecimal(long val) {
this.intCompact = val; this.intCompact = val;
this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null; this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
this.scale = 0;
} }
/** /**
...@@ -993,9 +1151,42 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -993,9 +1151,42 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal(long val, MathContext mc) { public BigDecimal(long val, MathContext mc) {
this(val); int mcp = mc.precision;
if (mc.precision > 0) int mode = mc.roundingMode.oldMode;
roundThis(mc); 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 // Static Factory Methods
...@@ -1016,13 +1207,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1016,13 +1207,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (scale == 0) if (scale == 0)
return valueOf(unscaledVal); return valueOf(unscaledVal);
else if (unscaledVal == 0) { else if (unscaledVal == 0) {
if (scale > 0 && scale < ZERO_SCALED_BY.length) return zeroValueOf(scale);
return ZERO_SCALED_BY[scale];
else
return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
} }
return new BigDecimal(unscaledVal == INFLATED ? return new BigDecimal(unscaledVal == INFLATED ?
BigInteger.valueOf(unscaledVal) : null, INFLATED_BIGINT : null,
unscaledVal, scale, 0); unscaledVal, scale, 0);
} }
...@@ -1041,7 +1229,34 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1041,7 +1229,34 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return zeroThroughTen[(int)val]; return zeroThroughTen[(int)val];
else if (val != INFLATED) else if (val != INFLATED)
return new BigDecimal(null, val, 0, 0); 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> { ...@@ -1079,42 +1294,19 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this + augend} * @return {@code this + augend}
*/ */
public BigDecimal add(BigDecimal augend) { public BigDecimal add(BigDecimal augend) {
long xs = this.intCompact; if (this.intCompact != INFLATED) {
long ys = augend.intCompact; if ((augend.intCompact != INFLATED)) {
BigInteger fst = (xs != INFLATED) ? null : this.intVal; return add(this.intCompact, this.scale, augend.intCompact, augend.scale);
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);
} else { } else {
int raise = augend.checkScale(sdiff); return add(this.intCompact, this.scale, augend.intVal, augend.scale);
if (ys == INFLATED || }
(ys = longMultiplyPowerTen(ys, raise)) == INFLATED) } else {
snd = augend.bigMultiplyPowerTen(raise); if ((augend.intCompact != INFLATED)) {
} return add(augend.intCompact, augend.scale, this.intVal, this.scale);
} } else {
if (xs != INFLATED && ys != INFLATED) { return add(this.intVal, this.scale, augend.intVal, augend.scale);
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> { ...@@ -1136,10 +1328,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return add(augend); return add(augend);
BigDecimal lhs = this; BigDecimal lhs = this;
// Could optimize if values are compact
this.inflate();
augend.inflate();
// If either number is zero then the other number, rounded and // If either number is zero then the other number, rounded and
// scaled if necessary, is used as the result. // scaled if necessary, is used as the result.
{ {
...@@ -1150,20 +1338,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1150,20 +1338,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
int preferredScale = Math.max(lhs.scale(), augend.scale()); int preferredScale = Math.max(lhs.scale(), augend.scale());
BigDecimal result; BigDecimal result;
// Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero) if (lhsIsZero && augendIsZero)
return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0); return zeroValueOf(preferredScale);
result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc); result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
if (result.scale() == preferredScale) if (result.scale() == preferredScale)
return result; return result;
else if (result.scale() > preferredScale) { else if (result.scale() > preferredScale) {
BigDecimal scaledResult = return stripZerosToMatchScale(result.intVal, result.intCompact, result.scale, preferredScale);
new BigDecimal(result.intVal, result.intCompact,
result.scale, 0);
scaledResult.stripZerosToMatchScale(preferredScale);
return scaledResult;
} else { // result.scale < preferredScale } else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision(); int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale(); int scaleDiff = preferredScale - result.scale();
...@@ -1176,17 +1358,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -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 if (padding != 0) { // scales differ; alignment needed
BigDecimal arg[] = preAlign(lhs, augend, padding, mc); BigDecimal arg[] = preAlign(lhs, augend, padding, mc);
matchScale(arg); matchScale(arg);
lhs = arg[0]; lhs = arg[0];
augend = arg[1]; augend = arg[1];
} }
return doRound(lhs.inflated().add(augend.inflated()), lhs.scale, mc);
BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
lhs.scale);
return doRound(d, mc);
} }
/** /**
...@@ -1211,27 +1390,26 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1211,27 +1390,26 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* that the number of digits of the smaller operand could be * that the number of digits of the smaller operand could be
* reduced even though the significands partially overlapped. * reduced even though the significands partially overlapped.
*/ */
private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, long padding, MathContext mc) {
long padding, MathContext mc) {
assert padding != 0; assert padding != 0;
BigDecimal big; BigDecimal big;
BigDecimal small; BigDecimal small;
if (padding < 0) { // lhs is big; augend is small if (padding < 0) { // lhs is big; augend is small
big = lhs; big = lhs;
small = augend; small = augend;
} else { // lhs is small; augend is big } else { // lhs is small; augend is big
big = augend; big = augend;
small = lhs; small = lhs;
} }
/* /*
* This is the estimated scale of an ulp of the result; it * This is the estimated scale of an ulp of the result; it assumes that
* assumes that the result doesn't have a carry-out on a true * the result doesn't have a carry-out on a true add (e.g. 999 + 1 =>
* add (e.g. 999 + 1 => 1000) or any subtractive cancellation * 1000) or any subtractive cancellation on borrowing (e.g. 100 - 1.2 =>
* on borrowing (e.g. 100 - 1.2 => 98.8) * 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 * The low-order digit position of big is big.scale(). This
...@@ -1242,11 +1420,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1242,11 +1420,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* disjoint *and* the digit positions of small should not be * disjoint *and* the digit positions of small should not be
* directly visible in the result. * 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 if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible
small = BigDecimal.valueOf(small.signum(), small = BigDecimal.valueOf(small.signum(), this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
} }
// Since addition is symmetric, preserving input order in // Since addition is symmetric, preserving input order in
...@@ -1264,7 +1441,22 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1264,7 +1441,22 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this - subtrahend} * @return {@code this - subtrahend}
*/ */
public BigDecimal subtract(BigDecimal subtrahend) { public BigDecimal subtract(BigDecimal subtrahend) {
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> { ...@@ -1282,11 +1474,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
BigDecimal nsubtrahend = subtrahend.negate();
if (mc.precision == 0) if (mc.precision == 0)
return add(nsubtrahend); return subtract(subtrahend);
// share the special rounding code in add() // 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> { ...@@ -1298,37 +1489,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code this * multiplicand} * @return {@code this * multiplicand}
*/ */
public BigDecimal multiply(BigDecimal multiplicand) { public BigDecimal multiply(BigDecimal multiplicand) {
long x = this.intCompact; int productScale = checkScale((long) scale + multiplicand.scale);
long y = multiplicand.intCompact; if (this.intCompact != INFLATED) {
int productScale = checkScale((long)scale + multiplicand.scale); if ((multiplicand.intCompact != INFLATED)) {
return multiply(this.intCompact, multiplicand.intCompact, productScale);
// Might be able to do a more clever check incorporating the } else {
// inflated check into the overflow computation. return multiply(this.intCompact, multiplicand.intVal, productScale);
if (x != INFLATED && y != INFLATED) { }
/* } else {
* If the product is not an overflowed value, continue if ((multiplicand.intCompact != INFLATED)) {
* to use the compact representation. if either of x or y return multiply(multiplicand.intCompact, this.intVal, productScale);
* is INFLATED, the product should also be regarded as } else {
* an overflow. Before using the overflow test suggested in return multiply(this.intVal, multiplicand.intVal, productScale);
* "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);
} }
/** /**
...@@ -1345,7 +1519,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1345,7 +1519,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0) if (mc.precision == 0)
return multiply(multiplicand); return multiply(multiplicand);
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,120 +1564,21 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1377,120 +1564,21 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #ROUND_UNNECESSARY * @see #ROUND_UNNECESSARY
*/ */
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
/*
* IMPLEMENTATION NOTE: This method *must* return a new object
* since divideAndRound uses divide to generate a value whose
* scale is then modified.
*/
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY) if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode"); throw new IllegalArgumentException("Invalid rounding mode");
/* if (this.intCompact != INFLATED) {
* Rescale dividend or divisor (whichever can be "upscaled" to if ((divisor.intCompact != INFLATED)) {
* produce correctly scaled quotient). return divide(this.intCompact, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
* Take care to detect out-of-range scales } else {
*/ return divide(this.intCompact, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
BigDecimal dividend = this; }
if (checkScale((long)scale + divisor.scale) > this.scale) } else {
dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY); if ((divisor.intCompact != INFLATED)) {
else return divide(this.intVal, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
divisor = divisor.setScale(checkScale((long)this.scale - scale), } else {
ROUND_UNNECESSARY); return divide(this.intVal, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
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;
} else {
mdivisor = new MutableBigInteger(bdivisor.mag);
mr = mdividend.divide(mdivisor, mq);
isRemainderZero = mr.isZero();
qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
}
}
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);
}
} else {
cmpFracHalf = mr.compareHalf(mdivisor);
}
if (cmpFracHalf < 0)
increment = false; // We're closer to higher digit
else if (cmpFracHalf > 0) // We're closer to lower digit
increment = true;
else if (roundingMode == ROUND_HALF_UP)
increment = true;
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;
} }
/** /**
...@@ -1541,7 +1629,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1541,7 +1629,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #ROUND_UNNECESSARY * @see #ROUND_UNNECESSARY
*/ */
public BigDecimal divide(BigDecimal divisor, int roundingMode) { public BigDecimal divide(BigDecimal divisor, int roundingMode) {
return this.divide(divisor, scale, roundingMode); return this.divide(divisor, scale, roundingMode);
} }
/** /**
...@@ -1588,15 +1676,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1588,15 +1676,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} }
// Calculate preferred scale // 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 && if (this.signum() == 0) // 0/y
preferredScale < ZERO_SCALED_BY.length) ? return zeroValueOf(preferredScale);
ZERO_SCALED_BY[preferredScale] :
BigDecimal.valueOf(0, preferredScale);
else { else {
this.inflate();
divisor.inflate();
/* /*
* If the quotient this/divisor has a terminating decimal * If the quotient this/divisor has a terminating decimal
* expansion, the expansion can have no more than * expansion, the expansion can have no more than
...@@ -1623,7 +1707,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1623,7 +1707,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// the desired one by removing trailing zeros; since the // the desired one by removing trailing zeros; since the
// exact divide method does not have an explicit digit // exact divide method does not have an explicit digit
// limit, we can add zeros too. // limit, we can add zeros too.
if (preferredScale > quotientScale) if (preferredScale > quotientScale)
return quotient.setScale(preferredScale, ROUND_UNNECESSARY); return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
...@@ -1668,38 +1751,23 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1668,38 +1751,23 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new ArithmeticException("Division undefined"); // NaN throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero"); throw new ArithmeticException("Division by zero");
} }
if (dividend.signum() == 0) // 0/y if (dividend.signum() == 0) // 0/y
return new BigDecimal(BigInteger.ZERO, 0, return zeroValueOf(saturateLong(preferredScale));
saturateLong(preferredScale), 1);
// Normalize dividend & divisor so that both fall into [0.1, 0.999...]
int xscale = dividend.precision(); int xscale = dividend.precision();
int yscale = divisor.precision(); int yscale = divisor.precision();
dividend = new BigDecimal(dividend.intVal, dividend.intCompact, if(dividend.intCompact!=INFLATED) {
xscale, xscale); if(divisor.intCompact!=INFLATED) {
divisor = new BigDecimal(divisor.intVal, divisor.intCompact, return divide(dividend.intCompact, xscale, divisor.intCompact, yscale, preferredScale, mc);
yscale, yscale); } else {
if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b) return divide(dividend.intCompact, xscale, divisor.intVal, yscale, preferredScale, mc);
yscale = divisor.scale -= 1; // [that is, divisor *= 10] }
} else {
// In order to find out whether the divide generates the exact result, if(divisor.intCompact!=INFLATED) {
// we avoid calling the above divide method. 'quotient' holds the return divide(dividend.intVal, xscale, divisor.intCompact, yscale, preferredScale, mc);
// return BigDecimal object whose scale will be set to 'scl'. } else {
BigDecimal quotient; return divide(dividend.intVal, xscale, divisor.intVal, yscale, preferredScale, mc);
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;
} }
/** /**
...@@ -1715,13 +1783,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1715,13 +1783,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigDecimal divideToIntegralValue(BigDecimal divisor) { public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale // Calculate preferred scale
int preferredScale = saturateLong((long)this.scale - divisor.scale); int preferredScale = saturateLong((long) this.scale - divisor.scale);
if (this.compareMagnitude(divisor) < 0) { if (this.compareMagnitude(divisor) < 0) {
// much faster when this << divisor // 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); return this.setScale(preferredScale, ROUND_UNNECESSARY);
// Perform a divide with enough digits to round to a correct // Perform a divide with enough digits to round to a correct
...@@ -1735,13 +1803,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1735,13 +1803,14 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
RoundingMode.DOWN)); RoundingMode.DOWN));
if (quotient.scale > 0) { if (quotient.scale > 0) {
quotient = quotient.setScale(0, RoundingMode.DOWN); quotient = quotient.setScale(0, RoundingMode.DOWN);
quotient.stripZerosToMatchScale(preferredScale); quotient = stripZerosToMatchScale(quotient.intVal, quotient.intCompact, quotient.scale, preferredScale);
} }
if (quotient.scale < preferredScale) { if (quotient.scale < preferredScale) {
// pad with zeros if necessary // pad with zeros if necessary
quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY); quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
} }
return quotient; return quotient;
} }
...@@ -1766,8 +1835,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1766,8 +1835,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @author Joseph D. Darcy * @author Joseph D. Darcy
*/ */
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0 || // exact result if (mc.precision == 0 || // exact result
(this.compareMagnitude(divisor) < 0) ) // zero result (this.compareMagnitude(divisor) < 0)) // zero result
return divideToIntegralValue(divisor); return divideToIntegralValue(divisor);
// Calculate preferred scale // Calculate preferred scale
...@@ -1780,8 +1849,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1780,8 +1849,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* digits. Next, remove any fractional digits from the * digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value. * quotient and adjust the scale to the preferred value.
*/ */
BigDecimal result = this. BigDecimal result = this.divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
if (result.scale() < 0) { if (result.scale() < 0) {
/* /*
...@@ -1811,8 +1879,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1811,8 +1879,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return result.setScale(result.scale() + return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) ); Math.min(precisionDiff, preferredScale - result.scale) );
} else { } else {
result.stripZerosToMatchScale(preferredScale); return stripZerosToMatchScale(result.intVal,result.intCompact,result.scale,preferredScale);
return result;
} }
} }
...@@ -1954,8 +2021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -1954,8 +2021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// No need to calculate pow(n) if result will over/underflow. // No need to calculate pow(n) if result will over/underflow.
// Don't attempt to support "supernormal" numbers. // Don't attempt to support "supernormal" numbers.
int newScale = checkScale((long)scale * n); int newScale = checkScale((long)scale * n);
this.inflate(); return new BigDecimal(this.inflated().pow(n), newScale);
return new BigDecimal(intVal.pow(n), newScale);
} }
...@@ -2016,12 +2082,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2016,12 +2082,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new ArithmeticException("Invalid operation"); throw new ArithmeticException("Invalid operation");
if (n == 0) if (n == 0)
return ONE; // x**0 == 1 in X3.274 return ONE; // x**0 == 1 in X3.274
this.inflate();
BigDecimal lhs = this; BigDecimal lhs = this;
MathContext workmc = mc; // working settings MathContext workmc = mc; // working settings
int mag = Math.abs(n); // magnitude of n int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) { if (mc.precision > 0) {
int elength = longDigitLength(mag); // length of n in digits int elength = longDigitLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation"); throw new ArithmeticException("Invalid operation");
...@@ -2044,7 +2108,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2044,7 +2108,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
// else (!seenbit) no point in squaring ONE // else (!seenbit) no point in squaring ONE
} }
// if negative n, calculate the reciprocal using working precision // 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); acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros // round to final precision and strip zeros
return doRound(acc, mc); return doRound(acc, mc);
...@@ -2083,14 +2147,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2083,14 +2147,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return {@code -this}. * @return {@code -this}.
*/ */
public BigDecimal negate() { public BigDecimal negate() {
BigDecimal result; if (intCompact == INFLATED) {
if (intCompact != INFLATED) return new BigDecimal(intVal.negate(), INFLATED, scale, precision);
result = BigDecimal.valueOf(-intCompact, scale); } else {
else { return valueOf(-intCompact, scale, precision);
result = new BigDecimal(intVal.negate(), scale);
result.precision = precision;
} }
return result;
} }
/** /**
...@@ -2186,7 +2247,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2186,7 +2247,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (s != INFLATED) if (s != INFLATED)
result = longDigitLength(s); result = longDigitLength(s);
else else
result = bigDigitLength(inflate()); result = bigDigitLength(intVal);
precision = result; precision = result;
} }
return result; return result;
...@@ -2202,7 +2263,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2202,7 +2263,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.2 * @since 1.2
*/ */
public BigInteger unscaledValue() { public BigInteger unscaledValue() {
return this.inflate(); return this.inflated();
} }
// Rounding Modes // Rounding Modes
...@@ -2383,29 +2444,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2383,29 +2444,41 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
if (newScale == oldScale) // easy case if (newScale == oldScale) // easy case
return this; return this;
if (this.signum() == 0) // zero can have any scale if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale); return zeroValueOf(newScale);
if(this.intCompact!=INFLATED) {
long rs = this.intCompact; long rs = this.intCompact;
if (newScale > oldScale) { if (newScale > oldScale) {
int raise = checkScale((long)newScale - oldScale); int raise = checkScale((long) newScale - oldScale);
BigInteger rb = null; if ((rs = longMultiplyPowerTen(rs, raise)) != INFLATED) {
if (rs == INFLATED || return valueOf(rs,newScale);
(rs = longMultiplyPowerTen(rs, raise)) == INFLATED) }
rb = bigMultiplyPowerTen(raise); BigInteger rb = bigMultiplyPowerTen(raise);
return new BigDecimal(rb, rs, newScale, return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0);
(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 { } else {
// newScale < oldScale -- drop some digits if (newScale > oldScale) {
// Can't predict the precision due to the effect of rounding. int raise = checkScale((long) newScale - oldScale);
int drop = checkScale((long)oldScale - newScale); BigInteger rb = bigMultiplyPowerTen(this.intVal,raise);
if (drop < LONG_TEN_POWERS_TABLE.length) return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0);
return divideAndRound(rs, this.intVal, } else {
LONG_TEN_POWERS_TABLE[drop], null, // newScale < oldScale -- drop some digits
newScale, roundingMode, newScale); // Can't predict the precision due to the effect of rounding.
else int drop = checkScale((long) oldScale - newScale);
return divideAndRound(rs, this.intVal, if (drop < LONG_TEN_POWERS_TABLE.length)
INFLATED, bigTenToThe(drop), return divideAndRound(this.intVal, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode,
newScale, roundingMode, newScale); newScale);
else
return divideAndRound(this.intVal, bigTenToThe(drop), newScale, roundingMode, newScale);
}
} }
} }
...@@ -2524,10 +2597,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2524,10 +2597,11 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal stripTrailingZeros() { public BigDecimal stripTrailingZeros() {
this.inflate(); if(intCompact!=INFLATED) {
BigDecimal result = new BigDecimal(intVal, scale); return createAndStripZerosToMatchScale(intCompact, scale, Long.MIN_VALUE);
result.stripZerosToMatchScale(Long.MIN_VALUE); } else {
return result; return createAndStripZerosToMatchScale(intVal, scale, Long.MIN_VALUE);
}
} }
// Comparison Operations // Comparison Operations
...@@ -2647,7 +2721,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2647,7 +2721,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} else if (xs != INFLATED) } else if (xs != INFLATED)
return xs == compactValFor(this.intVal); 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> { ...@@ -2872,13 +2946,38 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @see #toEngineeringString() * @see #toEngineeringString()
*/ */
public String toPlainString() { public String toPlainString() {
BigDecimal bd = this; if(scale==0) {
if (bd.scale < 0) if(intCompact!=INFLATED) {
bd = bd.setScale(0); return Long.toString(intCompact);
bd.inflate(); } else {
if (bd.scale == 0) // No decimal point return intVal.toString();
return bd.intVal.toString(); }
return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale); }
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 */ /* Returns a digit.digit string */
...@@ -2922,7 +3021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2922,7 +3021,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigInteger toBigInteger() { public BigInteger toBigInteger() {
// force to an integer, quietly // force to an integer, quietly
return this.setScale(0, ROUND_DOWN).inflate(); return this.setScale(0, ROUND_DOWN).inflated();
} }
/** /**
...@@ -2937,7 +3036,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2937,7 +3036,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
public BigInteger toBigIntegerExact() { public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0 // round to an integer, with Exception if decimal part non-0
return this.setScale(0, ROUND_UNNECESSARY).inflate(); return this.setScale(0, ROUND_UNNECESSARY).inflated();
} }
/** /**
...@@ -2990,7 +3089,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -2990,7 +3089,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
BigDecimal num = this.setScale(0, ROUND_UNNECESSARY); BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num); LongOverflow.check(num);
return num.inflate().longValue(); return num.inflated().longValue();
} }
private static class LongOverflow { private static class LongOverflow {
...@@ -3001,9 +3100,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3001,9 +3100,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE); private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
public static void check(BigDecimal num) { public static void check(BigDecimal num) {
num.inflate(); BigInteger intVal = num.inflated();
if ((num.intVal.compareTo(LONGMIN) < 0) || if (intVal.compareTo(LONGMIN) < 0 ||
(num.intVal.compareTo(LONGMAX) > 0)) intVal.compareTo(LONGMAX) > 0)
throw new java.lang.ArithmeticException("Overflow"); throw new java.lang.ArithmeticException("Overflow");
} }
} }
...@@ -3107,8 +3206,28 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3107,8 +3206,28 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return this {@code BigDecimal} converted to a {@code float}. * @return this {@code BigDecimal} converted to a {@code float}.
*/ */
public float floatValue(){ public float floatValue(){
if (scale == 0 && intCompact != INFLATED) if(intCompact != INFLATED) {
if (scale == 0) {
return (float)intCompact; 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. // Somewhat inefficient, but guaranteed to work.
return Float.parseFloat(this.toString()); return Float.parseFloat(this.toString());
} }
...@@ -3130,12 +3249,52 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3130,12 +3249,52 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @return this {@code BigDecimal} converted to a {@code double}. * @return this {@code BigDecimal} converted to a {@code double}.
*/ */
public double doubleValue(){ public double doubleValue(){
if (scale == 0 && intCompact != INFLATED) if(intCompact != INFLATED) {
return (double)intCompact; 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. // Somewhat inefficient, but guaranteed to work.
return Double.parseDouble(this.toString()); 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 * Returns the size of an ulp, a unit in the last place, of this
* {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal} * {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal}
...@@ -3151,10 +3310,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3151,10 +3310,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @since 1.5 * @since 1.5
*/ */
public BigDecimal ulp() { 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. // Private class to build a string representation for BigDecimal object.
// "StringBuilderHelper" is constructed as a thread local variable so it is // "StringBuilderHelper" is constructed as a thread local variable so it is
// thread safe. The StringBuilder field acts as a buffer to hold the temporary // 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> { ...@@ -3268,6 +3426,15 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return (intCompact != INFLATED) ? return (intCompact != INFLATED) ?
Long.toString(intCompact): Long.toString(intCompact):
intVal.toString(); 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(); StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
char[] coeff; char[] coeff;
...@@ -3377,7 +3544,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3377,7 +3544,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
tenpow[0] = '1'; tenpow[0] = '1';
for (int i = 1; i <= n; i++) for (int i = 1; i <= n; i++)
tenpow[i] = '0'; 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> { ...@@ -3433,11 +3600,16 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
1000000000000000000L // 18 / 10^18 1000000000000000000L // 18 / 10^18
}; };
private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE, private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {
BigInteger.valueOf(10), BigInteger.valueOf(100), BigInteger.ONE,
BigInteger.valueOf(1000), BigInteger.valueOf(10000), BigInteger.valueOf(10),
BigInteger.valueOf(100000), BigInteger.valueOf(1000000), BigInteger.valueOf(100),
BigInteger.valueOf(10000000), BigInteger.valueOf(100000000), BigInteger.valueOf(1000),
BigInteger.valueOf(10000),
BigInteger.valueOf(100000),
BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000),
BigInteger.valueOf(100000000),
BigInteger.valueOf(1000000000), BigInteger.valueOf(1000000000),
BigInteger.valueOf(10000000000L), BigInteger.valueOf(10000000000L),
BigInteger.valueOf(100000000000L), BigInteger.valueOf(100000000000L),
...@@ -3502,7 +3674,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3502,7 +3674,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
*/ */
private BigInteger bigMultiplyPowerTen(int n) { private BigInteger bigMultiplyPowerTen(int n) {
if (n <= 0) if (n <= 0)
return this.inflate(); return this.inflated();
if (intCompact != INFLATED) if (intCompact != INFLATED)
return bigTenToThe(n).multiply(intCompact); return bigTenToThe(n).multiply(intCompact);
...@@ -3511,12 +3683,13 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -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. * null, i.e. the compact representation is in use.
*/ */
private BigInteger inflate() { private BigInteger inflated() {
if (intVal == null) if (intVal == null) {
intVal = BigInteger.valueOf(intCompact); return BigInteger.valueOf(intCompact);
}
return intVal; return intVal;
} }
...@@ -3543,6 +3716,28 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -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, * Reconstitute the {@code BigDecimal} instance from a stream (that is,
* deserialize it). * deserialize it).
...@@ -3559,7 +3754,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3559,7 +3754,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed] // [all values of scale are now allowed]
} }
intCompact = compactValFor(intVal); setIntCompactVolatile(compactValFor(intVal));
} }
/** /**
...@@ -3570,13 +3765,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3570,13 +3765,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
private void writeObject(java.io.ObjectOutputStream s) private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException { throws java.io.IOException {
// Must inflate to maintain compatible serial form. // Must inflate to maintain compatible serial form.
this.inflate(); if (this.intVal == null)
this.setIntValVolatile(BigInteger.valueOf(this.intCompact));
// Write proper fields // Could reset intVal back to null if it has to be set.
s.defaultWriteObject(); s.defaultWriteObject();
} }
/** /**
* Returns the length of the absolute value of a {@code long}, in decimal * Returns the length of the absolute value of a {@code long}, in decimal
* digits. * digits.
...@@ -3584,36 +3778,29 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3584,36 +3778,29 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @param x the {@code long} * @param x the {@code long}
* @return the length of the unscaled value, in deciaml digits. * @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, * As described in "Bit Twiddling Hacks" by Sean Anderson,
* (http://graphics.stanford.edu/~seander/bithacks.html) * (http://graphics.stanford.edu/~seander/bithacks.html)
* integer log 10 of x is within 1 of * integer log 10 of x is within 1 of (1233/4096)* (1 +
* (1233/4096)* (1 + integer log 2 of x). * integer log 2 of x). The fraction 1233/4096 approximates
* The fraction 1233/4096 approximates log10(2). So we first * log10(2). So we first do a version of log2 (a variant of
* do a version of log2 (a variant of Long class with * Long class with pre-checks and opposite directionality) and
* pre-checks and opposite directionality) and then scale and * then scale and check against powers table. This is a little
* check against powers table. This is a little simpler in * simpler in present context than the version in Hacker's
* present context than the version in Hacker's Delight sec * Delight sec 11-4. Adding one to bit length allows comparing
* 11-4. Adding one to bit length allows comparing downward * downward from the LONG_TEN_POWERS_TABLE that we need
* from the LONG_TEN_POWERS_TABLE that we need anyway. * anyway.
*/ */
assert x != INFLATED; assert x != BigDecimal.INFLATED;
if (x < 0) if (x < 0)
x = -x; x = -x;
if (x < 10) // must screen for 0, might as well 10 if (x < 10) // must screen for 0, might as well 10
return 1; return 1;
int n = 64; // not 63, to avoid needing to add 1 later int r = ((64 - Long.numberOfLeadingZeros(x) + 1) * 1233) >>> 12;
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;
long[] tab = LONG_TEN_POWERS_TABLE; long[] tab = LONG_TEN_POWERS_TABLE;
// if r >= length, must have max possible digits for long // 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> { ...@@ -3635,41 +3822,6 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1; 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 * Check a scale for Underflow or Overflow. If this BigDecimal is
* nonzero, throw an exception if the scale is outof range. If this * nonzero, throw an exception if the scale is outof range. If this
...@@ -3693,74 +3845,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3693,74 +3845,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
return asInt; 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 * Returns the compact value for given {@code BigInteger}, or
* INFLATED if too big. Relies on internal representation of * INFLATED if too big. Relies on internal representation of
* {@code BigInteger}. * {@code BigInteger}.
...@@ -3852,4 +3937,1275 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> { ...@@ -3852,4 +3937,1275 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
} }
return this; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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> { ...@@ -353,27 +353,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
mag = trustedStripLeadingZeroInts(magnitude); 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 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 // 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++; cursor++;
}
if (cursor == len) { if (cursor == len) {
signum = 0; signum = 0;
mag = ZERO.mag; mag = ZERO.mag;
...@@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -382,7 +372,6 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
numDigits = len - cursor; numDigits = len - cursor;
signum = sign; signum = sign;
// Pre-allocate array of expected size // Pre-allocate array of expected size
int numWords; int numWords;
if (len < 10) { if (len < 10) {
...@@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1057,6 +1046,73 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return new BigInteger(resultMag, cmp == signum ? 1 : -1); 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 * 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 * 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> { ...@@ -1074,14 +1130,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int yIndex = y.length; int yIndex = y.length;
int result[] = new int[xIndex]; int result[] = new int[xIndex];
long sum = 0; long sum = 0;
if(yIndex==1) {
// Add common parts of both numbers sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ;
while(yIndex > 0) {
sum = (x[--xIndex] & LONG_MASK) +
(y[--yIndex] & LONG_MASK) + (sum >>> 32);
result[xIndex] = (int)sum; 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 // Copy remainder of longer number while carry propagation is required
boolean carry = (sum >>> 32 != 0); boolean carry = (sum >>> 32 != 0);
while (xIndex > 0 && carry) while (xIndex > 0 && carry)
...@@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1101,6 +1160,71 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return result; 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)}. * Returns a BigInteger whose value is {@code (this - val)}.
* *
...@@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -1165,11 +1289,39 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
public BigInteger multiply(BigInteger val) { public BigInteger multiply(BigInteger val) {
if (val.signum == 0 || signum == 0) if (val.signum == 0 || signum == 0)
return ZERO; 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, int[] result = multiplyToLen(mag, mag.length,
val.mag, val.mag.length, null); val.mag, val.mag.length, null);
result = trustedStripLeadingZeroInts(result); result = trustedStripLeadingZeroInts(result);
return new BigInteger(result, signum == val.signum ? 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> { ...@@ -1339,8 +1491,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
a = new MutableBigInteger(this.mag), a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag); b = new MutableBigInteger(val.mag);
a.divide(b, q); a.divide(b, q, false);
return q.toBigInteger(this.signum == val.signum ? 1 : -1); return q.toBigInteger(this.signum * val.signum);
} }
/** /**
...@@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2069,7 +2221,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return shiftRight(-n); 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 nInts = n >>> 5;
int nBits = n & 0x1f; int nBits = n & 0x1f;
int magLen = mag.length; int magLen = mag.length;
...@@ -2094,8 +2251,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -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 | mag[j] >>> nBits2;
newMag[i] = mag[j] << nBits; newMag[i] = mag[j] << nBits;
} }
return newMag;
return new BigInteger(newMag, signum);
} }
/** /**
...@@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> { ...@@ -2529,6 +2685,49 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return 0; 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. * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -160,7 +160,7 @@ class MutableBigInteger { ...@@ -160,7 +160,7 @@ class MutableBigInteger {
*/ */
BigDecimal toBigDecimal(int sign, int scale) { BigDecimal toBigDecimal(int sign, int scale) {
if (intLen == 0 || sign == 0) if (intLen == 0 || sign == 0)
return BigDecimal.valueOf(0, scale); return BigDecimal.zeroValueOf(scale);
int[] mag = getMagnitudeArray(); int[] mag = getMagnitudeArray();
int len = mag.length; int len = mag.length;
int d = mag[0]; int d = mag[0];
...@@ -171,7 +171,28 @@ class MutableBigInteger { ...@@ -171,7 +171,28 @@ class MutableBigInteger {
long v = (len == 2) ? long v = (len == 2) ?
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
d & LONG_MASK; 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 { ...@@ -543,6 +564,24 @@ class MutableBigInteger {
return (int)carry; 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 * Right shift this MutableBigInteger n bits, where n is
* less than 32. * less than 32.
...@@ -842,20 +881,20 @@ class MutableBigInteger { ...@@ -842,20 +881,20 @@ class MutableBigInteger {
rem = (int) (remLong - (quotient.value[0] * divisorLong)); rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
int xlen = intLen; int xlen = intLen;
int[] qWord = new int[2];
while (--xlen > 0) { while (--xlen > 0) {
long dividendEstimate = (remLong<<32) | long dividendEstimate = (remLong << 32) |
(value[offset + intLen - xlen] & LONG_MASK); (value[offset + intLen - xlen] & LONG_MASK);
int q;
if (dividendEstimate >= 0) { if (dividendEstimate >= 0) {
qWord[0] = (int) (dividendEstimate / divisorLong); q = (int) (dividendEstimate / divisorLong);
qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong); rem = (int) (dividendEstimate - q * divisorLong);
} else { } 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]; quotient.value[intLen - xlen] = q;
rem = qWord[1];
remLong = rem & LONG_MASK; remLong = rem & LONG_MASK;
} }
...@@ -879,40 +918,45 @@ class MutableBigInteger { ...@@ -879,40 +918,45 @@ class MutableBigInteger {
* *
*/ */
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) { MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
return divide(b,quotient,true);
}
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) {
if (b.intLen == 0) if (b.intLen == 0)
throw new ArithmeticException("BigInteger divide by zero"); throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero // Dividend is zero
if (intLen == 0) { if (intLen == 0) {
quotient.intLen = quotient.offset; quotient.intLen = quotient.offset;
return new MutableBigInteger(); return needReminder ? new MutableBigInteger() : null;
} }
int cmp = compare(b); int cmp = compare(b);
// Dividend less than divisor // Dividend less than divisor
if (cmp < 0) { if (cmp < 0) {
quotient.intLen = quotient.offset = 0; quotient.intLen = quotient.offset = 0;
return new MutableBigInteger(this); return needReminder ? new MutableBigInteger(this) : null;
} }
// Dividend equal to divisor // Dividend equal to divisor
if (cmp == 0) { if (cmp == 0) {
quotient.value[0] = quotient.intLen = 1; quotient.value[0] = quotient.intLen = 1;
quotient.offset = 0; quotient.offset = 0;
return new MutableBigInteger(); return needReminder ? new MutableBigInteger() : null;
} }
quotient.clear(); quotient.clear();
// Special case one word divisor // Special case one word divisor
if (b.intLen == 1) { if (b.intLen == 1) {
int r = divideOneWord(b.value[b.offset], quotient); int r = divideOneWord(b.value[b.offset], quotient);
if (r == 0) if(needReminder) {
return new MutableBigInteger(); if (r == 0)
return new MutableBigInteger(r); return new MutableBigInteger();
return new MutableBigInteger(r);
} else {
return null;
}
} }
return divideMagnitude(b, quotient, needReminder);
// Copy divisor value to protect divisor
int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
return divideMagnitude(div, quotient);
} }
/** /**
...@@ -940,30 +984,72 @@ class MutableBigInteger { ...@@ -940,30 +984,72 @@ class MutableBigInteger {
if (d == 0) if (d == 0)
return divideOneWord((int)v, quotient) & LONG_MASK; return divideOneWord((int)v, quotient) & LONG_MASK;
else { else {
int[] div = new int[]{ d, (int)(v & LONG_MASK) }; return divideLongMagnitude(v, quotient).toLong();
return divideMagnitude(div, 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 * Divide this MutableBigInteger by the divisor.
* array. The quotient will be placed into the provided quotient object & * The quotient will be placed into the provided quotient object &
* the remainder object is returned. * the remainder object is returned.
*/ */
private MutableBigInteger divideMagnitude(int[] divisor, private MutableBigInteger divideMagnitude(MutableBigInteger div,
MutableBigInteger quotient) { MutableBigInteger quotient,
boolean needReminder ) {
// Remainder starts as dividend with space for a leading zero // assert div.intLen > 1
MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]); // D1 normalize the divisor
System.arraycopy(value, offset, rem.value, 1, intLen); int shift = Integer.numberOfLeadingZeros(div.value[div.offset]);
rem.intLen = intLen; // Copy divisor value to protect divisor
rem.offset = 1; 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; int nlen = rem.intLen;
// Set the quotient size // Set the quotient size
int dlen = divisor.length; final int limit = nlen - dlen + 1;
int limit = nlen - dlen + 1;
if (quotient.value.length < limit) { if (quotient.value.length < limit) {
quotient.value = new int[limit]; quotient.value = new int[limit];
quotient.offset = 0; quotient.offset = 0;
...@@ -971,14 +1057,6 @@ class MutableBigInteger { ...@@ -971,14 +1057,6 @@ class MutableBigInteger {
quotient.intLen = limit; quotient.intLen = limit;
int[] q = quotient.value; 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 // Must insert leading 0 in rem if its length did not change
if (rem.intLen == nlen) { if (rem.intLen == nlen) {
...@@ -990,10 +1068,9 @@ class MutableBigInteger { ...@@ -990,10 +1068,9 @@ class MutableBigInteger {
int dh = divisor[0]; int dh = divisor[0];
long dhLong = dh & LONG_MASK; long dhLong = dh & LONG_MASK;
int dl = divisor[1]; int dl = divisor[1];
int[] qWord = new int[2];
// D2 Initialize j // D2 Initialize j
for(int j=0; j<limit; j++) { for(int j=0; j<limit-1; j++) {
// D3 Calculate qhat // D3 Calculate qhat
// estimate qhat // estimate qhat
int qhat = 0; int qhat = 0;
...@@ -1013,9 +1090,9 @@ class MutableBigInteger { ...@@ -1013,9 +1090,9 @@ class MutableBigInteger {
qhat = (int) (nChunk / dhLong); qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong)); qrem = (int) (nChunk - (qhat * dhLong));
} else { } else {
divWord(qWord, nChunk, dh); long tmp = divWord(nChunk, dh);
qhat = qWord[0]; qhat = (int) (tmp & LONG_MASK);
qrem = qWord[1]; qrem = (int) (tmp >>> 32);
} }
} }
...@@ -1053,6 +1130,181 @@ class MutableBigInteger { ...@@ -1053,6 +1130,181 @@ class MutableBigInteger {
// Store the quotient digit // Store the quotient digit
q[j] = qhat; q[j] = qhat;
} // D7 loop on j } // 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 // D8 Unnormalize
if (shift > 0) if (shift > 0)
...@@ -1063,6 +1315,46 @@ class MutableBigInteger { ...@@ -1063,6 +1315,46 @@ class MutableBigInteger {
return rem; 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. * Compare two longs as if they were unsigned.
* Returns true iff one is bigger than two. * Returns true iff one is bigger than two.
...@@ -1075,19 +1367,22 @@ class MutableBigInteger { ...@@ -1075,19 +1367,22 @@ class MutableBigInteger {
* This method divides a long quantity by an int to estimate * This method divides a long quantity by an int to estimate
* qhat for two multi precision numbers. It is used when * qhat for two multi precision numbers. It is used when
* the signed value of n is less than zero. * 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 dLong = d & LONG_MASK;
long r;
long q;
if (dLong == 1) { if (dLong == 1) {
result[0] = (int)n; q = (int)n;
result[1] = 0; r = 0;
return; return (r << 32) | (q & LONG_MASK);
} }
// Approximate the quotient and remainder // Approximate the quotient and remainder
long q = (n >>> 1) / (dLong >>> 1); q = (n >>> 1) / (dLong >>> 1);
long r = n - q*dLong; r = n - q*dLong;
// Correct the approximation // Correct the approximation
while (r < 0) { while (r < 0) {
...@@ -1098,10 +1393,8 @@ class MutableBigInteger { ...@@ -1098,10 +1393,8 @@ class MutableBigInteger {
r -= dLong; r -= dLong;
q++; q++;
} }
// n - q*dlong == r && 0 <= r <dLong, hence we're done. // n - q*dlong == r && 0 <= r <dLong, hence we're done.
result[0] = (int)q; return (r << 32) | (q & LONG_MASK);
result[1] = (int)r;
} }
/** /**
...@@ -1473,5 +1766,4 @@ class MutableBigInteger { ...@@ -1473,5 +1766,4 @@ class MutableBigInteger {
mod.subtract(t1); mod.subtract(t1);
return mod; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 6274390 * @bug 6274390 7082971
* @summary Verify {float, double}Value methods work with condensed representation * @summary Verify {float, double}Value methods work with condensed representation
* @run main FloatDoubleValueTests * @run main FloatDoubleValueTests
* @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests * @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests
...@@ -79,6 +79,7 @@ public class FloatDoubleValueTests { ...@@ -79,6 +79,7 @@ public class FloatDoubleValueTests {
// and double. // and double.
static void testFloatDoubleValue() { static void testFloatDoubleValue() {
long longValues[] = { long longValues[] = {
Long.MIN_VALUE, // -2^63
0, 0,
1, 1,
2, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.
先完成此消息的编辑!
想要评论请 注册