src/share/classes/java/math/BigDecimal.java
Print this page
*** 27,36 ****
--- 27,39 ----
* Portions Copyright IBM Corporation, 2001. All Rights Reserved.
*/
package java.math;
+ import java.util.Arrays;
+ import static java.math.BigInteger.LONG_MASK;
+
/**
* Immutable, arbitrary-precision signed decimal numbers. A
* {@code BigDecimal} consists of an arbitrary precision integer
* <i>unscaled value</i> and a 32-bit integer <i>scale</i>. If zero
* or positive, the scale is the number of digits to the right of the
*** 227,237 ****
* The scale of this BigDecimal, as returned by {@link #scale}.
*
* @serial
* @see #scale
*/
! private int scale = 0; // Note: this may have any value, so
// calculations must be done in longs
/**
* The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If
* nonzero, the value is guaranteed correct. Use the precision()
--- 230,240 ----
* The scale of this BigDecimal, as returned by {@link #scale}.
*
* @serial
* @see #scale
*/
! private int scale; // Note: this may have any value, so
// calculations must be done in longs
/**
* The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If
* nonzero, the value is guaranteed correct. Use the precision()
*** 238,266 ****
* method to obtain and set the value if it might be 0. This
* field is mutable until set nonzero.
*
* @since 1.5
*/
! private volatile transient int precision = 0;
/**
* Used to store the canonical string representation, if computed.
*/
! private volatile transient String stringCache = null;
/**
* Sentinel value for {@link #intCompact} indicating the
* significand information is only available from {@code intVal}.
*/
! private static final long INFLATED = Long.MIN_VALUE;
/**
* If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations.
*/
! private transient long intCompact = INFLATED;
// All 18-digit base ten strings fit into a long; not all 19-digit
// strings will
private static final int MAX_COMPACT_DIGITS = 18;
--- 241,269 ----
* method to obtain and set the value if it might be 0. This
* field is mutable until set nonzero.
*
* @since 1.5
*/
! private transient int precision;
/**
* Used to store the canonical string representation, if computed.
*/
! private transient String stringCache;
/**
* Sentinel value for {@link #intCompact} indicating the
* significand information is only available from {@code intVal}.
*/
! static final long INFLATED = Long.MIN_VALUE;
/**
* If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations.
*/
! private transient long intCompact;
// All 18-digit base ten strings fit into a long; not all 19-digit
// strings will
private static final int MAX_COMPACT_DIGITS = 18;
*** 267,291 ****
private static final int MAX_BIGINT_BITS = 62;
/* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L;
// Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = {
! new BigDecimal(BigInteger.ZERO, 0, 0),
! new BigDecimal(BigInteger.ONE, 1, 0),
! new BigDecimal(BigInteger.valueOf(2), 2, 0),
! new BigDecimal(BigInteger.valueOf(3), 3, 0),
! new BigDecimal(BigInteger.valueOf(4), 4, 0),
! new BigDecimal(BigInteger.valueOf(5), 5, 0),
! new BigDecimal(BigInteger.valueOf(6), 6, 0),
! new BigDecimal(BigInteger.valueOf(7), 7, 0),
! new BigDecimal(BigInteger.valueOf(8), 8, 0),
! new BigDecimal(BigInteger.valueOf(9), 9, 0),
! new BigDecimal(BigInteger.TEN, 10, 0),
};
// Constants
/**
* The value 0, with a scale of 0.
*
* @since 1.5
--- 270,322 ----
private static final int MAX_BIGINT_BITS = 62;
/* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L;
+ private static final ThreadLocal<StringBuilderHelper>
+ threadLocalStringBuilderHelper = new ThreadLocal<StringBuilderHelper>() {
+ @Override
+ protected StringBuilderHelper initialValue() {
+ return new StringBuilderHelper();
+ }
+ };
+
// Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = {
! new BigDecimal(BigInteger.ZERO, 0, 0, 1),
! new BigDecimal(BigInteger.ONE, 1, 0, 1),
! new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
! new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
! new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
! new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
! new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
! new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
! new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
! new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
! new BigDecimal(BigInteger.TEN, 10, 0, 2),
};
+ // Cache of zero scaled by 0 - 15
+ private static final BigDecimal[] ZERO_SCALED_BY = {
+ zeroThroughTen[0],
+ new BigDecimal(BigInteger.ZERO, 0, 1, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 2, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 3, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 4, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 5, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 6, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 7, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 8, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 9, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 10, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 11, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 12, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 13, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 14, 1),
+ new BigDecimal(BigInteger.ZERO, 0, 15, 1),
+ };
+
// Constants
/**
* The value 0, with a scale of 0.
*
* @since 1.5
*** 310,319 ****
--- 341,362 ----
zeroThroughTen[10];
// Constructors
/**
+ * Trusted package private constructor.
+ * Trusted simply means if val is INFLATED, intVal could not be null and
+ * if intVal is null, val could not be INFLATED.
+ */
+ BigDecimal(BigInteger intVal, long val, int scale, int prec) {
+ this.scale = scale;
+ this.precision = prec;
+ this.intCompact = val;
+ this.intVal = intVal;
+ }
+
+ /**
* Translates a character array representation of a
* {@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.
*
*** 329,343 ****
* 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) {
// This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate
! // (temporary) object (a char[] array).
// use array bounds checking to handle too-long, len == 0,
// bad offset, etc.
try {
// handle the sign
boolean isneg = false; // assume positive
--- 372,395 ----
* 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) {
+ // protect against huge length.
+ if (offset+len > in.length || offset < 0)
+ throw new NumberFormatException();
// This is the primary string to BigDecimal constructor; all
// incoming strings end up here; it uses explicit (inline)
// parsing for speed and generates at most one intermediate
! // (temporary) object (a char[] array) for non-compact case.
+ // Use locals for all fields values until completion
+ int prec = 0; // record precision value
+ int scl = 0; // record scale value
+ long rs = 0; // the compact value in long
+ BigInteger rb = null; // the inflated value in BigInteger
+
// use array bounds checking to handle too-long, len == 0,
// bad offset, etc.
try {
// handle the sign
boolean isneg = false; // assume positive
*** 349,391 ****
offset++;
len--;
}
// should now be at numeric part of the significand
! int dotoff = -1; // '.' offset, -1 if none
int cfirst = offset; // record start of integer
long exp = 0; // exponent
! if (len > in.length) // protect against huge length
! throw new NumberFormatException();
! char coeff[] = new char[len]; // integer significand array
! char c; // work
for (; len > 0; offset++, len--) {
c = in[offset];
- if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
// have digit
! coeff[precision] = c;
! precision++; // count of digits
continue;
}
if (c == '.') {
// have dot
! if (dotoff >= 0) // two dots
throw new NumberFormatException();
! dotoff = offset;
continue;
}
// exponent expected
if ((c != 'e') && (c != 'E'))
throw new NumberFormatException();
offset++;
c = in[offset];
len--;
! boolean negexp = false;
// optional sign
! if (c == '-' || c == '+') {
! negexp = (c == '-');
offset++;
c = in[offset];
len--;
}
if (len <= 0) // no exponent digits
--- 401,477 ----
offset++;
len--;
}
// should now be at numeric part of the significand
! boolean dot = false; // true when there is a '.'
int cfirst = offset; // record start of integer
long exp = 0; // exponent
! char c; // current character
+ boolean isCompact = (len <= MAX_COMPACT_DIGITS);
+ // integer significand array & idx is the index to it. The array
+ // is ONLY used when we can't use a compact representation.
+ char coeff[] = isCompact ? null : new char[len];
+ int idx = 0;
+
for (; len > 0; offset++, len--) {
c = in[offset];
// have digit
! if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
! // First compact case, we need not to preserve the character
! // and we can just compute the value in place.
! if (isCompact) {
! int digit = Character.digit(c, 10);
! if (digit == 0) {
! if (prec == 0)
! prec = 1;
! else if (rs != 0) {
! rs *= 10;
! ++prec;
! } // else digit is a redundant leading zero
! } else {
! if (prec != 1 || rs != 0)
! ++prec; // prec unchanged if preceded by 0s
! rs = rs * 10 + digit;
! }
! } else { // the unscaled value is likely a BigInteger object.
! if (c == '0' || Character.digit(c, 10) == 0) {
! if (prec == 0) {
! coeff[idx] = c;
! prec = 1;
! } else if (idx != 0) {
! coeff[idx++] = c;
! ++prec;
! } // else c must be a redundant leading zero
! } else {
! if (prec != 1 || idx != 0)
! ++prec; // prec unchanged if preceded by 0s
! coeff[idx++] = c;
! }
! }
! if (dot)
! ++scl;
continue;
}
+ // have dot
if (c == '.') {
// have dot
! if (dot) // two dots
throw new NumberFormatException();
! dot = true;
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
*** 420,476 ****
if ((int)exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
}
// here when no characters left
! if (precision == 0) // no digits found
throw new NumberFormatException();
! if (dotoff >= 0) { // had dot; set scale
! scale = precision - (dotoff - cfirst);
! // [cannot overflow]
! }
if (exp != 0) { // had significant exponent
! try {
! scale = checkScale(-exp + scale); // adjust
! } catch (ArithmeticException e) {
throw new NumberFormatException("Scale out of range.");
}
- }
// Remove leading zeros from precision (digits count)
! int first = 0;
! for (; (coeff[first] == '0' || Character.digit(coeff[first], 10) == 0) &&
! precision > 1;
! first++)
! precision--;
!
! // Set the significand ..
! // Copy significand to exact-sized array, with sign if
! // negative
! // Later use: BigInteger(coeff, first, precision) for
! // both cases, by allowing an extra char at the front of
! // coeff.
char quick[];
if (!isneg) {
! quick = new char[precision];
! System.arraycopy(coeff, first, quick, 0, precision);
} else {
! quick = new char[precision+1];
quick[0] = '-';
! System.arraycopy(coeff, first, quick, 1, precision);
}
! if (precision <= MAX_COMPACT_DIGITS)
! intCompact = Long.parseLong(new String(quick));
! else
! intVal = new BigInteger(quick);
! // System.out.println(" new: " +intVal+" ["+scale+"] "+precision);
} catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException();
} catch (NegativeArraySizeException e) {
throw new NumberFormatException();
}
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
--- 506,553 ----
if ((int)exp != exp) // overflow
throw new NumberFormatException();
break; // [saves a test]
}
// here when no characters left
! if (prec == 0) // no digits found
throw new NumberFormatException();
! // Adjust scale if exp is not zero.
if (exp != 0) { // had significant exponent
! // Can't call checkScale which relies on proper fields value
! long adjustedScale = scl - exp;
! if (adjustedScale > Integer.MAX_VALUE ||
! adjustedScale < Integer.MIN_VALUE)
throw new NumberFormatException("Scale out of range.");
+ scl = (int)adjustedScale;
}
// Remove leading zeros from precision (digits count)
! if (isCompact) {
! rs = isneg ? -rs : rs;
! } else {
char quick[];
if (!isneg) {
! quick = (coeff.length != prec) ?
! Arrays.copyOf(coeff, prec) : coeff;
} else {
! quick = new char[prec + 1];
quick[0] = '-';
! System.arraycopy(coeff, 0, quick, 1, prec);
}
! rb = new BigInteger(quick);
! rs = compactValFor(rb);
! }
} catch (ArrayIndexOutOfBoundsException e) {
throw new NumberFormatException();
} catch (NegativeArraySizeException e) {
throw new NumberFormatException();
}
+ this.scale = scl;
+ this.precision = prec;
+ this.intCompact = rs;
+ this.intVal = rb;
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
*** 759,772 ****
intVal = intVal.multiply(BigInteger.valueOf(5).pow(-exponent));
scale = -exponent;
} else if (exponent > 0) {
intVal = intVal.multiply(BigInteger.valueOf(2).pow(exponent));
}
! if (intVal.bitLength() <= MAX_BIGINT_BITS) {
! intCompact = intVal.longValue();
}
- }
/**
* Translates a {@code double} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is the smallest value such that
--- 836,847 ----
intVal = intVal.multiply(BigInteger.valueOf(5).pow(-exponent));
scale = -exponent;
} else if (exponent > 0) {
intVal = intVal.multiply(BigInteger.valueOf(2).pow(exponent));
}
! intCompact = compactValFor(intVal);
}
/**
* Translates a {@code double} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is the smallest value such that
*** 797,810 ****
* @param val {@code BigInteger} value to be converted to
* {@code BigDecimal}.
*/
public BigDecimal(BigInteger val) {
intVal = val;
! if (val.bitLength() <= MAX_BIGINT_BITS) {
! intCompact = val.longValue();
}
- }
/**
* Translates a {@code BigInteger} into a {@code BigDecimal}
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is zero.
--- 872,883 ----
* @param val {@code BigInteger} value to be converted to
* {@code BigDecimal}.
*/
public BigDecimal(BigInteger val) {
intVal = val;
! intCompact = compactValFor(val);
}
/**
* Translates a {@code BigInteger} into a {@code BigDecimal}
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is zero.
*** 815,825 ****
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger val, MathContext mc) {
! intVal = val;
if (mc.precision > 0)
roundThis(mc);
}
/**
--- 888,898 ----
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger val, MathContext mc) {
! this(val);
if (mc.precision > 0)
roundThis(mc);
}
/**
*** 831,846 ****
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
*/
public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed
! intVal = unscaledVal;
this.scale = scale;
- if (unscaledVal.bitLength() <= MAX_BIGINT_BITS) {
- intCompact = unscaledVal.longValue();
}
- }
/**
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}, with rounding
* according to the context settings. The value of the
--- 904,916 ----
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
*/
public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed
! this(unscaledVal);
this.scale = scale;
}
/**
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}, with rounding
* according to the context settings. The value of the
*** 854,864 ****
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
! intVal = unscaledVal;
this.scale = scale;
if (mc.precision > 0)
roundThis(mc);
}
--- 924,934 ----
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
! this(unscaledVal);
this.scale = scale;
if (mc.precision > 0)
roundThis(mc);
}
*** 897,910 ****
*
* @param val {@code long} value to be converted to {@code BigDecimal}.
* @since 1.5
*/
public BigDecimal(long val) {
! if (compactLong(val))
! intCompact = val;
! else
! intVal = BigInteger.valueOf(val);
}
/**
* Translates a {@code long} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
--- 967,978 ----
*
* @param val {@code long} value to be converted to {@code BigDecimal}.
* @since 1.5
*/
public BigDecimal(long val) {
! this.intCompact = val;
! this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
}
/**
* Translates a {@code long} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
*** 915,949 ****
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(long val, MathContext mc) {
! if (compactLong(val))
! intCompact = val;
! else
! intVal = BigInteger.valueOf(val);
if (mc.precision > 0)
roundThis(mc);
}
- /**
- * Trusted internal constructor
- */
- private BigDecimal(long val, int scale) {
- this.intCompact = val;
- this.scale = scale;
- }
-
- /**
- * Trusted internal constructor
- */
- private BigDecimal(BigInteger intVal, long val, int scale) {
- this.intVal = intVal;
- this.intCompact = val;
- this.scale = scale;
- }
-
// Static Factory Methods
/**
* Translates a {@code long} unscaled value and an
* {@code int} scale into a {@code BigDecimal}. This
--- 983,997 ----
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(long val, MathContext mc) {
! this(val);
if (mc.precision > 0)
roundThis(mc);
}
// Static Factory Methods
/**
* Translates a {@code long} unscaled value and an
* {@code int} scale into a {@code BigDecimal}. This
*** 955,970 ****
* @param scale scale of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is
* <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
*/
public static BigDecimal valueOf(long unscaledVal, int scale) {
! if (scale == 0 && unscaledVal >= 0 && unscaledVal <= 10) {
! return zeroThroughTen[(int)unscaledVal];
}
! if (compactLong(unscaledVal))
! return new BigDecimal(unscaledVal, scale);
! return new BigDecimal(BigInteger.valueOf(unscaledVal), scale);
}
/**
* Translates a {@code long} value into a {@code BigDecimal}
* with a scale of zero. This {@literal "static factory method"}
--- 1003,1023 ----
* @param scale scale of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is
* <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
*/
public static BigDecimal valueOf(long unscaledVal, int scale) {
! if (scale == 0)
! return valueOf(unscaledVal);
! else if (unscaledVal == 0) {
! if (scale > 0 && scale < ZERO_SCALED_BY.length)
! return ZERO_SCALED_BY[scale];
! else
! return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
}
! return new BigDecimal(unscaledVal == INFLATED ?
! BigInteger.valueOf(unscaledVal) : null,
! unscaledVal, scale, 0);
}
/**
* Translates a {@code long} value into a {@code BigDecimal}
* with a scale of zero. This {@literal "static factory method"}
*** 974,984 ****
*
* @param val value of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is {@code val}.
*/
public static BigDecimal valueOf(long val) {
! return valueOf(val, 0);
}
/**
* Translates a {@code double} into a {@code BigDecimal}, using
* the {@code double}'s canonical string representation provided
--- 1027,1041 ----
*
* @param val value of the {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is {@code val}.
*/
public static BigDecimal valueOf(long val) {
! if (val >= 0 && val < zeroThroughTen.length)
! return zeroThroughTen[(int)val];
! else if (val != INFLATED)
! return new BigDecimal(null, val, 0, 0);
! return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
}
/**
* Translates a {@code double} into a {@code BigDecimal}, using
* the {@code double}'s canonical string representation provided
*** 1012,1043 ****
*
* @param augend value to be added to this {@code BigDecimal}.
* @return {@code this + augend}
*/
public BigDecimal add(BigDecimal augend) {
! BigDecimal arg[] = {this, augend};
! matchScale(arg);
! long x = arg[0].intCompact;
! long y = arg[1].intCompact;
!
! // Might be able to do a more clever check incorporating the
! // inflated check into the overflow computation.
! if (x != INFLATED && y != INFLATED) {
! long sum = x + y;
! /*
! * If the sum is not an overflowed value, continue to use
! * the compact representation. if either of x or y is
! * INFLATED, the sum should also be regarded as an
! * overflow. See "Hacker's Delight" section 2-12 for
! * explanation of the overflow test.
! */
! if ( (((sum ^ x) & (sum ^ y)) >> 63) == 0L ) // not overflowed
! return BigDecimal.valueOf(sum, arg[0].scale);
}
- return new BigDecimal(arg[0].inflate().intVal.add(arg[1].inflate().intVal), arg[0].scale);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this + augend)},
* with rounding according to the context settings.
*
--- 1069,1115 ----
*
* @param augend value to be added to this {@code BigDecimal}.
* @return {@code this + augend}
*/
public BigDecimal add(BigDecimal augend) {
! long xs = this.intCompact;
! long ys = augend.intCompact;
! BigInteger fst = this.intVal;
! BigInteger snd = 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 {
! int raise = augend.checkScale(sdiff);
! if (ys == INFLATED ||
! (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
! snd = augend.bigMultiplyPowerTen(raise);
}
}
+ if (xs != INFLATED && ys != INFLATED) {
+ long sum = xs + ys;
+ // See "Hacker's Delight" section 2-12 for explanation of
+ // the overflow test.
+ if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
+ return new BigDecimal(null, sum, rscale, 0);
+ }
+ 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, compactValFor(sum), rscale, 0);
+ }
/**
* Returns a {@code BigDecimal} whose value is {@code (this + augend)},
* with rounding according to the context settings.
*
*** 1070,1090 ****
int preferredScale = Math.max(lhs.scale(), augend.scale());
BigDecimal result;
// Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero)
! return new BigDecimal(BigInteger.ZERO, 0, preferredScale);
- result = lhsIsZero ? augend.doRound(mc) : lhs.doRound(mc);
-
if (result.scale() == preferredScale)
return result;
! else if (result.scale() > preferredScale)
! return new BigDecimal(result.intVal, result.intCompact, result.scale).
! stripZerosToMatchScale(preferredScale);
! else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale();
if (precisionDiff >= scaleDiff)
return result.setScale(preferredScale); // can achieve target scale
--- 1142,1164 ----
int preferredScale = Math.max(lhs.scale(), augend.scale());
BigDecimal result;
// Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero)
! return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
+ result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
if (result.scale() == preferredScale)
return result;
! else if (result.scale() > preferredScale) {
! BigDecimal scaledResult =
! new BigDecimal(result.intVal, result.intCompact,
! result.scale, 0);
! scaledResult.stripZerosToMatchScale(preferredScale);
! return scaledResult;
! } else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale();
if (precisionDiff >= scaleDiff)
return result.setScale(preferredScale); // can achieve target scale
*** 1100,1111 ****
matchScale(arg);
lhs = arg[0];
augend = arg[1];
}
! return new BigDecimal(lhs.inflate().intVal.add(augend.inflate().intVal),
! lhs.scale).doRound(mc);
}
/**
* Returns an array of length two, the sum of whose entries is
* equal to the rounded sum of the {@code BigDecimal} arguments.
--- 1174,1186 ----
matchScale(arg);
lhs = arg[0];
augend = arg[1];
}
! BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
! lhs.scale);
! return doRound(d, mc);
}
/**
* Returns an array of length two, the sum of whose entries is
* equal to the rounded sum of the {@code BigDecimal} arguments.
*** 1179,1211 ****
*
* @param subtrahend value to be subtracted from this {@code BigDecimal}.
* @return {@code this - subtrahend}
*/
public BigDecimal subtract(BigDecimal subtrahend) {
! BigDecimal arg[] = {this, subtrahend};
! matchScale(arg);
!
! long x = arg[0].intCompact;
! long y = arg[1].intCompact;
!
! // Might be able to do a more clever check incorporating the
! // inflated check into the overflow computation.
! if (x != INFLATED && y != INFLATED) {
! long difference = x - y;
! /*
! * If the difference is not an overflowed value, continue
! * to use the compact representation. if either of x or y
! * is INFLATED, the difference should also be regarded as
! * an overflow. See "Hacker's Delight" section 2-12 for
! * explanation of the overflow test.
! */
! if ( ((x ^ y) & (difference ^ x) ) >> 63 == 0L ) // not overflowed
! return BigDecimal.valueOf(difference, arg[0].scale);
}
- return new BigDecimal(arg[0].inflate().intVal.subtract(arg[1].inflate().intVal),
- arg[0].scale);
- }
/**
* Returns a {@code BigDecimal} whose value is {@code (this - subtrahend)},
* with rounding according to the context settings.
*
--- 1254,1265 ----
*
* @param subtrahend value to be subtracted from this {@code BigDecimal}.
* @return {@code this - subtrahend}
*/
public BigDecimal subtract(BigDecimal subtrahend) {
! return add(subtrahend.negate());
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this - subtrahend)},
* with rounding according to the context settings.
*
*** 1218,1235 ****
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
if (mc.precision == 0)
! return subtract(subtrahend);
// share the special rounding code in add()
! this.inflate();
! subtrahend.inflate();
! BigDecimal rhs = new BigDecimal(subtrahend.intVal.negate(), subtrahend.scale);
! rhs.precision = subtrahend.precision;
! return add(rhs, mc);
}
/**
* Returns a {@code BigDecimal} whose value is <tt>(this ×
* multiplicand)</tt>, and whose scale is {@code (this.scale() +
--- 1272,1286 ----
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
+ BigDecimal nsubtrahend = subtrahend.negate();
if (mc.precision == 0)
! return add(nsubtrahend);
// share the special rounding code in add()
! return add(nsubtrahend, mc);
}
/**
* Returns a {@code BigDecimal} whose value is <tt>(this ×
* multiplicand)</tt>, and whose scale is {@code (this.scale() +
*** 1239,1267 ****
* @return {@code this * multiplicand}
*/
public BigDecimal multiply(BigDecimal multiplicand) {
long x = this.intCompact;
long y = multiplicand.intCompact;
! int productScale = checkScale((long)scale+multiplicand.scale);
// Might be able to do a more clever check incorporating the
// inflated check into the overflow computation.
if (x != INFLATED && y != INFLATED) {
/*
* If the product is not an overflowed value, continue
* to use the compact representation. if either of x or y
* is INFLATED, the product should also be regarded as
! * an overflow. See "Hacker's Delight" section 2-12 for
! * explanation of the overflow test.
*/
long product = x * y;
! if ( !(y != 0L && product/y != x) ) // not overflowed
! return BigDecimal.valueOf(product, productScale);
}
!
! BigDecimal result = new BigDecimal(this.inflate().intVal.multiply(multiplicand.inflate().intVal), productScale);
! return result;
}
/**
* Returns a {@code BigDecimal} whose value is <tt>(this ×
* multiplicand)</tt>, with rounding according to the context settings.
--- 1290,1328 ----
* @return {@code this * multiplicand}
*/
public BigDecimal multiply(BigDecimal multiplicand) {
long x = this.intCompact;
long y = multiplicand.intCompact;
! int productScale = checkScale((long)scale + multiplicand.scale);
// Might be able to do a more clever check incorporating the
// inflated check into the overflow computation.
if (x != INFLATED && y != INFLATED) {
/*
* If the product is not an overflowed value, continue
* to use the compact representation. if either of x or y
* is INFLATED, the product should also be regarded as
! * an overflow. Before using the overflow test suggested in
! * "Hacker's Delight" section 2-12, we perform quick checks
! * using the precision information to see whether the overflow
! * would occur since division is expensive on most CPUs.
*/
long product = x * y;
! int prec = this.precision() + multiplicand.precision();
! if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
! return new BigDecimal(null, product, productScale, 0);
! return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
! productScale, 0);
}
! BigInteger rb;
! 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);
}
/**
* Returns a {@code BigDecimal} whose value is <tt>(this ×
* multiplicand)</tt>, with rounding according to the context settings.
*** 1274,1285 ****
* @since 1.5
*/
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0)
return multiply(multiplicand);
! BigDecimal lhs = this;
! return lhs.inflate().multiply(multiplicand.inflate()).doRound(mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this /
* divisor)}, and whose scale is as specified. If rounding must
--- 1335,1345 ----
* @since 1.5
*/
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0)
return multiply(multiplicand);
! return doRound(this.multiply(multiplicand), mc);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this /
* divisor)}, and whose scale is as specified. If rounding must
*** 1309,1409 ****
* @see #ROUND_UNNECESSARY
*/
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
/*
* IMPLEMENTATION NOTE: This method *must* return a new object
! * since dropDigits uses divide to generate a value whose
* scale is then modified.
*/
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
/*
* Rescale dividend or divisor (whichever can be "upscaled" to
* produce correctly scaled quotient).
* Take care to detect out-of-range scales
*/
! BigDecimal dividend;
! if (checkScale((long)scale + divisor.scale) >= this.scale) {
! dividend = this.setScale(scale + divisor.scale);
! } else {
! dividend = this;
! divisor = divisor.setScale(checkScale((long)this.scale - scale));
}
! boolean compact = dividend.intCompact != INFLATED && divisor.intCompact != INFLATED;
! long div = INFLATED;
! long rem = INFLATED;;
! BigInteger q=null, r=null;
!
! if (compact) {
! div = dividend.intCompact / divisor.intCompact;
! rem = dividend.intCompact % divisor.intCompact;
} else {
! // Do the division and return result if it's exact.
! BigInteger i[] = dividend.inflate().intVal.divideAndRemainder(divisor.inflate().intVal);
! q = i[0];
! r = i[1];
! }
!
! // Check for exact result
! if (compact) {
! if (rem == 0)
! return new BigDecimal(div, scale);
} else {
! if (r.signum() == 0)
! return new BigDecimal(q, scale);
}
!
! if (roundingMode == ROUND_UNNECESSARY) // Rounding prohibited
! throw new ArithmeticException("Rounding necessary");
!
/* Round as appropriate */
! int signum = dividend.signum() * divisor.signum(); // Sign of result
! boolean increment;
! if (roundingMode == ROUND_UP) { // Away from zero
increment = true;
} else if (roundingMode == ROUND_DOWN) { // Towards zero
increment = false;
} else if (roundingMode == ROUND_CEILING) { // Towards +infinity
! increment = (signum > 0);
} else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
! increment = (signum < 0);
! } else { // Remaining modes based on nearest-neighbor determination
! int cmpFracHalf;
! if (compact) {
! cmpFracHalf = longCompareTo(Math.abs(2*rem), Math.abs(divisor.intCompact));
} else {
! // add(r) here is faster than multiply(2) or shiftLeft(1)
! cmpFracHalf= r.add(r).abs().compareTo(divisor.intVal.abs());
! }
! if (cmpFracHalf < 0) { // We're closer to higher digit
! increment = false;
! } else if (cmpFracHalf > 0) { // We're closer to lower digit
increment = true;
! } else { // We're dead-center
! if (roundingMode == ROUND_HALF_UP)
increment = true;
else if (roundingMode == ROUND_HALF_DOWN)
increment = false;
! else { // roundingMode == ROUND_HALF_EVEN
! if (compact)
! increment = (div & 1L) != 0L;
! else
! increment = q.testBit(0); // true iff q is odd
}
}
! }
!
! if (compact) {
if (increment)
! div += signum; // guaranteed not to overflow
! return new BigDecimal(div, scale);
! } else {
! return (increment
! ? new BigDecimal(q.add(BigInteger.valueOf(signum)), scale)
! : new BigDecimal(q, scale));
}
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this /
* divisor)}, and whose scale is as specified. If rounding must
--- 1369,1485 ----
* @see #ROUND_UNNECESSARY
*/
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
/*
* IMPLEMENTATION NOTE: This method *must* return a new object
! * since divideAndRound uses divide to generate a value whose
* scale is then modified.
*/
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
/*
* Rescale dividend or divisor (whichever can be "upscaled" to
* produce correctly scaled quotient).
* Take care to detect out-of-range scales
*/
! BigDecimal dividend = this;
! if (checkScale((long)scale + divisor.scale) > this.scale)
! dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
! else
! divisor = divisor.setScale(checkScale((long)this.scale - scale),
! ROUND_UNNECESSARY);
! return divideAndRound(dividend.intCompact, dividend.intVal,
! divisor.intCompact, divisor.intVal,
! scale, roundingMode, scale);
}
! /**
! * Internally used for division operation. The dividend and divisor are
! * passed both in {@code long} format and {@code BigInteger} format. The
! * returned {@code BigDecimal} object is the quotient whose scale is set to
! * the passed in scale. If the remainder is not zero, it will be rounded
! * based on the passed in roundingMode. Also, if the remainder is zero and
! * the last parameter, i.e. preferredScale is NOT equal to scale, the
! * trailing zeros of the result is stripped to match the preferredScale.
! */
! private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
! long ldivisor, BigInteger bdivisor,
! int scale, int roundingMode,
! int preferredScale) {
! boolean isRemainderZero; // record remainder is zero or not
! int qsign; // quotient sign
! long q = 0, r = 0; // store quotient & remainder in long
! MutableBigInteger mq = null; // store quotient
! MutableBigInteger mr = null; // store remainder
! MutableBigInteger mdivisor = null;
! boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
! if (isLongDivision) {
! q = ldividend / ldivisor;
! if (roundingMode == ROUND_DOWN && scale == preferredScale)
! return new BigDecimal(null, q, scale, 0);
! r = ldividend % ldivisor;
! isRemainderZero = (r == 0);
! qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
} else {
! if (bdividend == null)
! bdividend = BigInteger.valueOf(ldividend);
! // Descend into mutables for faster remainder checks
! MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
! mq = new MutableBigInteger();
! if (ldivisor != INFLATED) {
! r = mdividend.divide(ldivisor, mq);
! isRemainderZero = (r == 0);
! qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
} 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)
! 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;
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this /
* divisor)}, and whose scale is as specified. If rounding must
*** 1497,1510 ****
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
// Calculate preferred scale
! int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
! Integer.MAX_VALUE), Integer.MIN_VALUE);
if (this.signum() == 0) // 0/y
! return new BigDecimal(0, preferredScale);
else {
this.inflate();
divisor.inflate();
/*
* If the quotient this/divisor has a terminating decimal
--- 1573,1588 ----
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
// Calculate preferred scale
! int preferredScale = saturateLong((long)this.scale - divisor.scale);
if (this.signum() == 0) // 0/y
! return (preferredScale >= 0 &&
! preferredScale < ZERO_SCALED_BY.length) ?
! ZERO_SCALED_BY[preferredScale] :
! new BigDecimal(null, 0, preferredScale, 1);
else {
this.inflate();
divisor.inflate();
/*
* If the quotient this/divisor has a terminating decimal
*** 1532,1542 ****
// the desired one by removing trailing zeros; since the
// exact divide method does not have an explicit digit
// limit, we can add zeros too.
if (preferredScale > quotientScale)
! return quotient.setScale(preferredScale);
return quotient;
}
}
--- 1610,1620 ----
// the desired one by removing trailing zeros; since the
// exact divide method does not have an explicit digit
// limit, we can add zeros too.
if (preferredScale > quotientScale)
! return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
return quotient;
}
}
*** 1552,1569 ****
* {@code mc.precision == 0} and the quotient has a
* non-terminating decimal expansion.
* @since 1.5
*/
public BigDecimal divide(BigDecimal divisor, MathContext mc) {
! if (mc.precision == 0)
return divide(divisor);
- BigDecimal lhs = this.inflate(); // left-hand-side
- BigDecimal rhs = divisor.inflate(); // right-hand-side
- BigDecimal result; // work
! long preferredScale = (long)lhs.scale() - rhs.scale();
!
// Now calculate the answer. We use the existing
// divide-and-round method, but as this rounds to scale we have
// to normalize the values here to achieve the desired result.
// For x/y we first handle y=0 and x=0, and then normalize x and
// y to give x' and y' with the following constraints:
--- 1630,1645 ----
* {@code mc.precision == 0} and the quotient has a
* non-terminating decimal expansion.
* @since 1.5
*/
public BigDecimal divide(BigDecimal divisor, MathContext mc) {
! int mcp = mc.precision;
! if (mcp == 0)
return divide(divisor);
! BigDecimal dividend = this;
! long preferredScale = (long)dividend.scale - divisor.scale;
// Now calculate the answer. We use the existing
// divide-and-round method, but as this rounds to scale we have
// to normalize the values here to achieve the desired result.
// For x/y we first handle y=0 and x=0, and then normalize x and
// y to give x' and y' with the following constraints:
*** 1572,1630 ****
// Dividing x'/y' with the required scale set to mc.precision then
// will give a result in the range 0.1 to 1 rounded to exactly
// the right number of digits (except in the case of a result of
// 1.000... which can arise when x=y, or when rounding overflows
// The 1.000... case will reduce properly to 1.
! if (rhs.signum() == 0) { // x/0
! if (lhs.signum() == 0) // 0/0
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
! if (lhs.signum() == 0) // 0/y
! return new BigDecimal(BigInteger.ZERO,
! (int)Math.max(Math.min(preferredScale,
! Integer.MAX_VALUE),
! Integer.MIN_VALUE));
! BigDecimal xprime = new BigDecimal(lhs.intVal.abs(), lhs.precision());
! BigDecimal yprime = new BigDecimal(rhs.intVal.abs(), rhs.precision());
! // xprime and yprime are now both in range 0.1 through 0.999...
! if (mc.roundingMode == RoundingMode.CEILING ||
! mc.roundingMode == RoundingMode.FLOOR) {
! // The floor (round toward negative infinity) and ceil
! // (round toward positive infinity) rounding modes are not
! // invariant under a sign flip. If xprime/yprime has a
! // different sign than lhs/rhs, the rounding mode must be
! // changed.
! if ((xprime.signum() != lhs.signum()) ^
! (yprime.signum() != rhs.signum())) {
! mc = new MathContext(mc.precision,
! (mc.roundingMode==RoundingMode.CEILING)?
! RoundingMode.FLOOR:RoundingMode.CEILING);
! }
! }
! if (xprime.compareTo(yprime) > 0) // satisfy constraint (b)
! yprime.scale -= 1; // [that is, yprime *= 10]
! result = xprime.divide(yprime, mc.precision, mc.roundingMode.oldMode);
! // correct the scale of the result...
! result.scale = checkScale((long)yprime.scale - xprime.scale
! - (rhs.scale - lhs.scale) + mc.precision);
! // apply the sign
! if (lhs.signum() != rhs.signum())
! result = result.negate();
// doRound, here, only affects 1000000000 case.
! result = result.doRound(mc);
! if (result.multiply(divisor).compareTo(this) == 0) {
! // Apply preferred scale rules for exact quotients
! return result.stripZerosToMatchScale(preferredScale);
}
- else {
- return result;
- }
- }
/**
* Returns a {@code BigDecimal} whose value is the integer part
* of the quotient {@code (this / divisor)} rounded down. The
* preferred scale of the result is {@code (this.scale() -
--- 1648,1695 ----
// Dividing x'/y' with the required scale set to mc.precision then
// will give a result in the range 0.1 to 1 rounded to exactly
// the right number of digits (except in the case of a result of
// 1.000... which can arise when x=y, or when rounding overflows
// The 1.000... case will reduce properly to 1.
! if (divisor.signum() == 0) { // x/0
! if (dividend.signum() == 0) // 0/0
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
! if (dividend.signum() == 0) // 0/y
! return new BigDecimal(BigInteger.ZERO, 0,
! saturateLong(preferredScale), 1);
! // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
! int xscale = dividend.precision();
! int yscale = divisor.precision();
! dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
! xscale, xscale);
! divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
! yscale, yscale);
! if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
! yscale = divisor.scale -= 1; // [that is, divisor *= 10]
! // In order to find out whether the divide generates the exact result,
! // we avoid calling the above divide method. 'quotient' holds the
! // return BigDecimal object whose scale will be set to 'scl'.
! BigDecimal quotient;
! int scl = checkScale(preferredScale + yscale - xscale + mcp);
! if (checkScale((long)mcp + yscale) > xscale)
! dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
! else
! divisor = divisor.setScale(checkScale((long)xscale - mcp),
! ROUND_UNNECESSARY);
! quotient = divideAndRound(dividend.intCompact, dividend.intVal,
! divisor.intCompact, divisor.intVal,
! scl, mc.roundingMode.oldMode,
! checkScale(preferredScale));
// doRound, here, only affects 1000000000 case.
! quotient = doRound(quotient, mc);
! return quotient;
}
/**
* Returns a {@code BigDecimal} whose value is the integer part
* of the quotient {@code (this / divisor)} rounded down. The
* preferred scale of the result is {@code (this.scale() -
*** 1635,1676 ****
* @throws ArithmeticException if {@code divisor==0}
* @since 1.5
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale
! int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
! Integer.MAX_VALUE), Integer.MIN_VALUE);
! this.inflate();
! divisor.inflate();
! if (this.abs().compareTo(divisor.abs()) < 0) {
// much faster when this << divisor
return BigDecimal.valueOf(0, preferredScale);
}
if(this.signum() == 0 && divisor.signum() != 0)
! return this.setScale(preferredScale);
// Perform a divide with enough digits to round to a correct
// integer value; then remove any fractional digits
int maxDigits = (int)Math.min(this.precision() +
(long)Math.ceil(10.0*divisor.precision()/3.0) +
Math.abs((long)this.scale() - divisor.scale()) + 2,
Integer.MAX_VALUE);
-
BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
RoundingMode.DOWN));
if (quotient.scale > 0) {
! quotient = quotient.setScale(0, RoundingMode.DOWN).
! stripZerosToMatchScale(preferredScale);
}
if (quotient.scale < preferredScale) {
// pad with zeros if necessary
! quotient = quotient.setScale(preferredScale);
}
-
return quotient;
}
/**
* Returns a {@code BigDecimal} whose value is the integer part
--- 1700,1736 ----
* @throws ArithmeticException if {@code divisor==0}
* @since 1.5
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale
! int preferredScale = saturateLong((long)this.scale - divisor.scale);
! if (this.compareMagnitude(divisor) < 0) {
// much faster when this << divisor
return BigDecimal.valueOf(0, preferredScale);
}
if(this.signum() == 0 && divisor.signum() != 0)
! return this.setScale(preferredScale, ROUND_UNNECESSARY);
// Perform a divide with enough digits to round to a correct
// integer value; then remove any fractional digits
int maxDigits = (int)Math.min(this.precision() +
(long)Math.ceil(10.0*divisor.precision()/3.0) +
Math.abs((long)this.scale() - divisor.scale()) + 2,
Integer.MAX_VALUE);
BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
RoundingMode.DOWN));
if (quotient.scale > 0) {
! quotient = quotient.setScale(0, RoundingMode.DOWN);
! quotient.stripZerosToMatchScale(preferredScale);
}
if (quotient.scale < preferredScale) {
// pad with zeros if necessary
! quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
}
return quotient;
}
/**
* Returns a {@code BigDecimal} whose value is the integer part
*** 1692,1718 ****
* @since 1.5
* @author Joseph D. Darcy
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0 || // exact result
! (this.abs().compareTo(divisor.abs()) < 0) ) // zero result
return divideToIntegralValue(divisor);
// Calculate preferred scale
! int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
! Integer.MAX_VALUE), Integer.MIN_VALUE);
/*
* Perform a normal divide to mc.precision digits. If the
* remainder has absolute value less than the divisor, the
* integer portion of the quotient fits into mc.precision
* digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value.
*/
! BigDecimal result = this.divide(divisor, new MathContext(mc.precision,
! RoundingMode.DOWN));
! int resultScale = result.scale();
if (result.scale() < 0) {
/*
* Result is an integer. See if quotient represents the
* full integer portion of the exact quotient; if it does,
--- 1752,1776 ----
* @since 1.5
* @author Joseph D. Darcy
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
if (mc.precision == 0 || // exact result
! (this.compareMagnitude(divisor) < 0) ) // zero result
return divideToIntegralValue(divisor);
// Calculate preferred scale
! int preferredScale = saturateLong((long)this.scale - divisor.scale);
/*
* Perform a normal divide to mc.precision digits. If the
* remainder has absolute value less than the divisor, the
* integer portion of the quotient fits into mc.precision
* digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value.
*/
! BigDecimal result = this.
! divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
if (result.scale() < 0) {
/*
* Result is an integer. See if quotient represents the
* full integer portion of the exact quotient; if it does,
*** 1719,1729 ****
* the computed remainder will be less than the divisor.
*/
BigDecimal product = result.multiply(divisor);
// If the quotient is the full integer value,
// |dividend-product| < |divisor|.
! if (this.subtract(product).abs().compareTo(divisor.abs()) >= 0) {
throw new ArithmeticException("Division impossible");
}
} else if (result.scale() > 0) {
/*
* Integer portion of quotient will fit into precision
--- 1777,1787 ----
* the computed remainder will be less than the divisor.
*/
BigDecimal product = result.multiply(divisor);
// If the quotient is the full integer value,
// |dividend-product| < |divisor|.
! if (this.subtract(product).compareMagnitude(divisor) >= 0) {
throw new ArithmeticException("Division impossible");
}
} else if (result.scale() > 0) {
/*
* Integer portion of quotient will fit into precision
*** 1734,1749 ****
}
// else result.scale() == 0;
int precisionDiff;
if ((preferredScale > result.scale()) &&
! (precisionDiff = mc.precision - result.precision()) > 0 ) {
return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) );
! } else
! return result.stripZerosToMatchScale(preferredScale);
}
/**
* Returns a {@code BigDecimal} whose value is {@code (this % divisor)}.
*
* <p>The remainder is given by
--- 1792,1809 ----
}
// else result.scale() == 0;
int precisionDiff;
if ((preferredScale > result.scale()) &&
! (precisionDiff = mc.precision - result.precision()) > 0) {
return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) );
! } else {
! result.stripZerosToMatchScale(preferredScale);
! return result;
}
+ }
/**
* Returns a {@code BigDecimal} whose value is {@code (this % divisor)}.
*
* <p>The remainder is given by
*** 1947,1957 ****
BigDecimal lhs = this;
MathContext workmc = mc; // working settings
int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) {
! int elength = intLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation");
workmc = new MathContext(mc.precision + elength + 1,
mc.roundingMode);
}
--- 2007,2017 ----
BigDecimal lhs = this;
MathContext workmc = mc; // working settings
int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) {
! int elength = longDigitLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation");
workmc = new MathContext(mc.precision + elength + 1,
mc.roundingMode);
}
*** 1972,1982 ****
}
// if negative n, calculate the reciprocal using working precision
if (n<0) // [hence mc.precision>0]
acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros
! return acc.doRound(mc);
}
/**
* Returns a {@code BigDecimal} whose value is the absolute value
* of this {@code BigDecimal}, and whose scale is
--- 2032,2042 ----
}
// if negative n, calculate the reciprocal using working precision
if (n<0) // [hence mc.precision>0]
acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros
! return doRound(acc, mc);
}
/**
* Returns a {@code BigDecimal} whose value is the absolute value
* of this {@code BigDecimal}, and whose scale is
*** 2066,2076 ****
* @since 1.5
*/
public BigDecimal plus(MathContext mc) {
if (mc.precision == 0) // no rounding please
return this;
! return this.doRound(mc);
}
/**
* Returns the signum function of this {@code BigDecimal}.
*
--- 2126,2136 ----
* @since 1.5
*/
public BigDecimal plus(MathContext mc) {
if (mc.precision == 0) // no rounding please
return this;
! return doRound(this, mc);
}
/**
* Returns the signum function of this {@code BigDecimal}.
*
*** 2107,2117 ****
* @since 1.5
*/
public int precision() {
int result = precision;
if (result == 0) {
! result = digitLength();
precision = result;
}
return result;
}
--- 2167,2181 ----
* @since 1.5
*/
public int precision() {
int result = precision;
if (result == 0) {
! long s = intCompact;
! if (s != INFLATED)
! result = longDigitLength(s);
! else
! result = bigDigitLength(inflate());
precision = result;
}
return result;
}
*** 2123,2133 ****
*
* @return the unscaled value of this {@code BigDecimal}.
* @since 1.2
*/
public BigInteger unscaledValue() {
! return this.inflate().intVal;
}
// Rounding Modes
/**
--- 2187,2197 ----
*
* @return the unscaled value of this {@code BigDecimal}.
* @since 1.2
*/
public BigInteger unscaledValue() {
! return this.inflate();
}
// Rounding Modes
/**
*** 2300,2334 ****
*/
public BigDecimal setScale(int newScale, int roundingMode) {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
! if (newScale == this.scale) // easy case
return this;
if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale);
- if (newScale > this.scale) {
- // [we can use checkScale to assure multiplier is valid]
- int raise = checkScale((long)newScale - this.scale);
! if (intCompact != INFLATED) {
! long scaledResult = longTenToThe(intCompact, raise);
! if (scaledResult != INFLATED)
! return BigDecimal.valueOf(scaledResult, newScale);
! this.inflate();
}
-
- BigDecimal result = new BigDecimal(intVal.multiply(tenToThe(raise)),
- newScale);
- if (this.precision > 0)
- result.precision = this.precision + newScale - this.scale;
- return result;
}
- // scale < this.scale
- // we cannot perfectly predict the precision after rounding
- return divide(ONE, newScale, roundingMode);
- }
/**
* Returns a {@code BigDecimal} whose scale is the specified
* value, and whose value is numerically equal to this
* {@code BigDecimal}'s. Throws an {@code ArithmeticException}
--- 2364,2402 ----
*/
public BigDecimal setScale(int newScale, int roundingMode) {
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
! int oldScale = this.scale;
! if (newScale == oldScale) // easy case
return this;
if (this.signum() == 0) // zero can have any scale
return BigDecimal.valueOf(0, newScale);
! long rs = this.intCompact;
! if (newScale > oldScale) {
! int raise = checkScale((long)newScale - oldScale);
! BigInteger rb = null;
! if (rs == INFLATED ||
! (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
! rb = bigMultiplyPowerTen(raise);
! return new BigDecimal(rb, rs, newScale,
! (precision > 0) ? precision + raise : 0);
! } else {
! // newScale < oldScale -- drop some digits
! // Can't predict the precision due to the effect of rounding.
! int drop = checkScale((long)oldScale - newScale);
! if (drop < LONG_TEN_POWERS_TABLE.length)
! return divideAndRound(rs, this.intVal,
! LONG_TEN_POWERS_TABLE[drop], null,
! newScale, roundingMode, newScale);
! else
! return divideAndRound(rs, this.intVal,
! INFLATED, bigTenToThe(drop),
! newScale, roundingMode, newScale);
}
}
/**
* Returns a {@code BigDecimal} whose scale is the specified
* value, and whose value is numerically equal to this
* {@code BigDecimal}'s. Throws an {@code ArithmeticException}
*** 2386,2401 ****
* @throws ArithmeticException if scale overflows.
*/
public BigDecimal movePointLeft(int n) {
// Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale + n);
! BigDecimal num;
! if (intCompact != INFLATED)
! num = BigDecimal.valueOf(intCompact, newScale);
! else
! num = new BigDecimal(intVal, newScale);
! return (num.scale<0 ? num.setScale(0) : num);
}
/**
* Returns a {@code BigDecimal} which is equivalent to this one
* with the decimal point moved {@code n} places to the right.
--- 2454,2465 ----
* @throws ArithmeticException if scale overflows.
*/
public BigDecimal movePointLeft(int n) {
// Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale + n);
! BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
! return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
}
/**
* Returns a {@code BigDecimal} which is equivalent to this one
* with the decimal point moved {@code n} places to the right.
*** 2412,2427 ****
* @throws ArithmeticException if scale overflows.
*/
public BigDecimal movePointRight(int n) {
// Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale - n);
! BigDecimal num;
! if (intCompact != INFLATED)
! num = BigDecimal.valueOf(intCompact, newScale);
! else
! num = new BigDecimal(intVal, newScale);
! return (num.scale<0 ? num.setScale(0) : num);
}
/**
* Returns a BigDecimal whose numerical value is equal to
* ({@code this} * 10<sup>n</sup>). The scale of
--- 2476,2487 ----
* @throws ArithmeticException if scale overflows.
*/
public BigDecimal movePointRight(int n) {
// Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
int newScale = checkScale((long)scale - n);
! BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
! return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
}
/**
* Returns a BigDecimal whose numerical value is equal to
* ({@code this} * 10<sup>n</sup>). The scale of
*** 2431,2444 ****
* outside the range of a 32-bit integer.
*
* @since 1.5
*/
public BigDecimal scaleByPowerOfTen(int n) {
! this.inflate();
! BigDecimal num = new BigDecimal(intVal, checkScale((long)scale - n));
! num.precision = precision;
! return num;
}
/**
* Returns a {@code BigDecimal} which is numerically equal to
* this one but with any trailing zeros removed from the
--- 2491,2502 ----
* outside the range of a 32-bit integer.
*
* @since 1.5
*/
public BigDecimal scaleByPowerOfTen(int n) {
! return new BigDecimal(intVal, intCompact,
! checkScale((long)scale - n), precision);
}
/**
* Returns a {@code BigDecimal} which is numerically equal to
* this one but with any trailing zeros removed from the
*** 2452,2462 ****
* trailing zeros removed.
* @since 1.5
*/
public BigDecimal stripTrailingZeros() {
this.inflate();
! return (new BigDecimal(intVal, scale)).stripZerosToMatchScale(Long.MIN_VALUE);
}
// Comparison Operations
/**
--- 2510,2522 ----
* trailing zeros removed.
* @since 1.5
*/
public BigDecimal stripTrailingZeros() {
this.inflate();
! BigDecimal result = new BigDecimal(intVal, scale);
! result.stripZerosToMatchScale(Long.MIN_VALUE);
! return result;
}
// Comparison Operations
/**
*** 2475,2511 ****
* to be compared.
* @return -1, 0, or 1 as this {@code BigDecimal} is numerically
* less than, equal to, or greater than {@code val}.
*/
public int compareTo(BigDecimal val) {
! if (this.scale == val.scale &&
! this.intCompact != INFLATED &&
! val.intCompact != INFLATED)
! return longCompareTo(this.intCompact, val.intCompact);
! // Optimization: would run fine without the next three lines
! int sigDiff = signum() - val.signum();
! if (sigDiff != 0)
! return (sigDiff > 0 ? 1 : -1);
! // If the (adjusted) exponents are different we do not need to
! // expensively match scales and compare the significands
! int aethis = this.precision() - this.scale; // [-1]
! int aeval = val.precision() - val.scale; // [-1]
! if (aethis < aeval)
! return -this.signum();
! else if (aethis > aeval)
! return this.signum();
!
! // Scale and compare intVals
! BigDecimal arg[] = {this, val};
! matchScale(arg);
! if (arg[0].intCompact != INFLATED &&
! arg[1].intCompact != INFLATED)
! return longCompareTo(arg[0].intCompact, arg[1].intCompact);
! return arg[0].inflate().intVal.compareTo(arg[1].inflate().intVal);
}
/**
* Compares this {@code BigDecimal} with the specified
* {@code Object} for equality. Unlike {@link
* #compareTo(BigDecimal) compareTo}, this method considers two
--- 2535,2606 ----
* to be compared.
* @return -1, 0, or 1 as this {@code BigDecimal} is numerically
* less than, equal to, or greater than {@code val}.
*/
public int compareTo(BigDecimal val) {
! // Quick path for equal scale and non-inflated case.
! if (scale == val.scale) {
! long xs = intCompact;
! long ys = val.intCompact;
! if (xs != INFLATED && ys != INFLATED)
! return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
! }
! int xsign = this.signum();
! int ysign = val.signum();
! if (xsign != ysign)
! return (xsign > ysign) ? 1 : -1;
! if (xsign == 0)
! return 0;
! int cmp = compareMagnitude(val);
! return (xsign > 0) ? cmp : -cmp;
! }
! /**
! * Version of compareTo that ignores sign.
! */
! private int compareMagnitude(BigDecimal val) {
! // Match scales, avoid unnecessary inflation
! long ys = val.intCompact;
! long xs = this.intCompact;
! if (xs == 0)
! return (ys == 0) ? 0 : -1;
! if (ys == 0)
! return 1;
! int sdiff = this.scale - val.scale;
! if (sdiff != 0) {
! // Avoid matching scales if the (adjusted) exponents differ
! int xae = this.precision() - this.scale; // [-1]
! int yae = val.precision() - val.scale; // [-1]
! if (xae < yae)
! return -1;
! if (xae > yae)
! return 1;
! BigInteger rb = null;
! if (sdiff < 0) {
! if ( (xs == INFLATED ||
! (xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
! ys == INFLATED) {
! rb = bigMultiplyPowerTen(-sdiff);
! return rb.compareMagnitude(val.intVal);
}
+ } else { // sdiff > 0
+ if ( (ys == INFLATED ||
+ (ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
+ xs == INFLATED) {
+ rb = val.bigMultiplyPowerTen(sdiff);
+ return this.intVal.compareMagnitude(rb);
+ }
+ }
+ }
+ if (xs != INFLATED)
+ return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
+ else if (ys != INFLATED)
+ return 1;
+ else
+ return this.intVal.compareMagnitude(val.intVal);
+ }
/**
* Compares this {@code BigDecimal} with the specified
* {@code Object} for equality. Unlike {@link
* #compareTo(BigDecimal) compareTo}, this method considers two
*** 2519,2537 ****
* {@code BigDecimal} whose value and scale are equal to this
* {@code BigDecimal}'s.
* @see #compareTo(java.math.BigDecimal)
* @see #hashCode
*/
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (scale != xDec.scale)
return false;
! if (this.intCompact != INFLATED && xDec.intCompact != INFLATED)
! return this.intCompact == xDec.intCompact;
! return this.inflate().intVal.equals(xDec.inflate().intVal);
}
/**
* Returns the minimum of this {@code BigDecimal} and
* {@code val}.
--- 2614,2642 ----
* {@code BigDecimal} whose value and scale are equal to this
* {@code BigDecimal}'s.
* @see #compareTo(java.math.BigDecimal)
* @see #hashCode
*/
+ @Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
+ if (x == this)
+ return true;
if (scale != xDec.scale)
return false;
! long s = this.intCompact;
! long xs = xDec.intCompact;
! if (s != INFLATED) {
! if (xs == INFLATED)
! xs = compactValFor(xDec.intVal);
! return xs == s;
! } else if (xs != INFLATED)
! return xs == compactValFor(this.intVal);
!
! return this.inflate().equals(xDec.inflate());
}
/**
* Returns the minimum of this {@code BigDecimal} and
* {@code val}.
*** 2570,2584 ****
* have the same hash code.
*
* @return hash code for this {@code BigDecimal}.
* @see #equals(Object)
*/
public int hashCode() {
if (intCompact != INFLATED) {
! long val2 = (intCompact < 0)?-intCompact:intCompact;
int temp = (int)( ((int)(val2 >>> 32)) * 31 +
! (val2 & 0xffffffffL));
return 31*((intCompact < 0) ?-temp:temp) + scale;
} else
return 31*intVal.hashCode() + scale;
}
--- 2675,2690 ----
* have the same hash code.
*
* @return hash code for this {@code BigDecimal}.
* @see #equals(Object)
*/
+ @Override
public int hashCode() {
if (intCompact != INFLATED) {
! long val2 = (intCompact < 0)? -intCompact : intCompact;
int temp = (int)( ((int)(val2 >>> 32)) * 31 +
! (val2 & LONG_MASK));
return 31*((intCompact < 0) ?-temp:temp) + scale;
} else
return 31*intVal.hashCode() + scale;
}
*** 2681,2694 ****
*
* @return string representation of this {@code BigDecimal}.
* @see Character#forDigit
* @see #BigDecimal(java.lang.String)
*/
public String toString() {
! if (stringCache == null)
! stringCache = layoutChars(true);
! return stringCache;
}
/**
* Returns a string representation of this {@code BigDecimal},
* using engineering notation if an exponent is needed.
--- 2787,2802 ----
*
* @return string representation of this {@code BigDecimal}.
* @see Character#forDigit
* @see #BigDecimal(java.lang.String)
*/
+ @Override
public String toString() {
! String sc = stringCache;
! if (sc == null)
! stringCache = sc = layoutChars(true);
! return sc;
}
/**
* Returns a string representation of this {@code BigDecimal},
* using engineering notation if an exponent is needed.
*** 2800,2810 ****
*
* @return this {@code BigDecimal} converted to a {@code BigInteger}.
*/
public BigInteger toBigInteger() {
// force to an integer, quietly
! return this.setScale(0, ROUND_DOWN).inflate().intVal;
}
/**
* Converts this {@code BigDecimal} to a {@code BigInteger},
* checking for lost information. An exception is thrown if this
--- 2908,2918 ----
*
* @return this {@code BigDecimal} converted to a {@code BigInteger}.
*/
public BigInteger toBigInteger() {
// force to an integer, quietly
! return this.setScale(0, ROUND_DOWN).inflate();
}
/**
* Converts this {@code BigDecimal} to a {@code BigInteger},
* checking for lost information. An exception is thrown if this
*** 2815,2825 ****
* fractional part.
* @since 1.5
*/
public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0
! return this.setScale(0, ROUND_UNNECESSARY).inflate().intVal;
}
/**
* Converts this {@code BigDecimal} to a {@code long}. This
* conversion is analogous to a <a
--- 2923,2933 ----
* fractional part.
* @since 1.5
*/
public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0
! return this.setScale(0, ROUND_UNNECESSARY).inflate();
}
/**
* Converts this {@code BigDecimal} to a {@code long}. This
* conversion is analogous to a <a
*** 2866,2879 ****
if (this.signum() == 0)
return 0;
if ((this.precision() - this.scale) <= 0)
throw new ArithmeticException("Rounding necessary");
// round to an integer, with Exception if decimal part non-0
! BigDecimal num = this.setScale(0, ROUND_UNNECESSARY).inflate();
if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num);
! return num.intVal.longValue();
}
private static class LongOverflow {
/** BigInteger equal to Long.MIN_VALUE. */
private static final BigInteger LONGMIN = BigInteger.valueOf(Long.MIN_VALUE);
--- 2974,2987 ----
if (this.signum() == 0)
return 0;
if ((this.precision() - this.scale) <= 0)
throw new ArithmeticException("Rounding necessary");
// round to an integer, with Exception if decimal part non-0
! BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num);
! return num.inflate().longValue();
}
private static class LongOverflow {
/** BigInteger equal to Long.MIN_VALUE. */
private static final BigInteger LONGMIN = BigInteger.valueOf(Long.MIN_VALUE);
*** 2880,2889 ****
--- 2988,2998 ----
/** BigInteger equal to Long.MAX_VALUE. */
private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
public static void check(BigDecimal num) {
+ num.inflate();
if ((num.intVal.compareTo(LONGMIN) < 0) ||
(num.intVal.compareTo(LONGMAX) > 0))
throw new java.lang.ArithmeticException("Overflow");
}
}
*** 3035,3047 ****
*/
public BigDecimal ulp() {
return BigDecimal.valueOf(1, this.scale());
}
- // Private "Helper" Methods
/**
* Lay out this {@code BigDecimal} into a {@code char[]} array.
* The Java 1.2 equivalent to this was called {@code getValueString}.
*
* @param sci {@code true} for Scientific exponential notation;
* {@code false} for Engineering
--- 3144,3254 ----
*/
public BigDecimal ulp() {
return BigDecimal.valueOf(1, this.scale());
}
+ // Private class to build a string representation for BigDecimal object.
+ // "StringBuilderHelper" is constructed as a thread local variable so it is
+ // thread safe. The StringBuilder field acts as a buffer to hold the temporary
+ // representation of BigDecimal. The cmpCharArray holds all the characters for
+ // the compact representation of BigDecimal (except for '-' sign' if it is
+ // negative) if its intCompact field is not INFLATED. It is shared by all
+ // calls to toString() and its variants in that particular thread.
+ static class StringBuilderHelper {
+ final StringBuilder sb; // Placeholder for BigDecimal string
+ final char[] cmpCharArray; // character array to place the intCompact
+
+ StringBuilderHelper() {
+ sb = new StringBuilder();
+ // All non negative longs can be made to fit into 19 character array.
+ cmpCharArray = new char[19];
+ }
+
+ // Accessors.
+ StringBuilder getStringBuilder() {
+ sb.setLength(0);
+ return sb;
+ }
+
+ char[] getCompactCharArray() {
+ return cmpCharArray;
+ }
+
/**
+ * Places characters representing the intCompact in {@code long} into
+ * cmpCharArray and returns the offset to the array where the
+ * representation starts.
+ *
+ * @param intCompact the number to put into the cmpCharArray.
+ * @return offset to the array where the representation starts.
+ * Note: intCompact must be greater or equal to zero.
+ */
+ int putIntCompact(long intCompact) {
+ assert intCompact >= 0;
+
+ long q;
+ int r;
+ // since we start from the least significant digit, charPos points to
+ // the last character in cmpCharArray.
+ int charPos = cmpCharArray.length;
+
+ // Get 2 digits/iteration using longs until quotient fits into an int
+ while (intCompact > Integer.MAX_VALUE) {
+ q = intCompact / 100;
+ r = (int)(intCompact - q * 100);
+ intCompact = q;
+ cmpCharArray[--charPos] = DIGIT_ONES[r];
+ cmpCharArray[--charPos] = DIGIT_TENS[r];
+ }
+
+ // Get 2 digits/iteration using ints when i2 >= 100
+ int q2;
+ int i2 = (int)intCompact;
+ while (i2 >= 100) {
+ q2 = i2 / 100;
+ r = i2 - q2 * 100;
+ i2 = q2;
+ cmpCharArray[--charPos] = DIGIT_ONES[r];
+ cmpCharArray[--charPos] = DIGIT_TENS[r];
+ }
+
+ cmpCharArray[--charPos] = DIGIT_ONES[i2];
+ if (i2 >= 10)
+ cmpCharArray[--charPos] = DIGIT_TENS[i2];
+
+ return charPos;
+ }
+
+ final static char[] DIGIT_TENS = {
+ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
+ '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
+ '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
+ '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
+ '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
+ '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
+ '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
+ '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
+ '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
+ '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
+ };
+
+ final static char[] DIGIT_ONES = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ };
+ }
+
+ /**
* Lay out this {@code BigDecimal} into a {@code char[]} array.
* The Java 1.2 equivalent to this was called {@code getValueString}.
*
* @param sci {@code true} for Scientific exponential notation;
* {@code false} for Engineering
*** 3052,3096 ****
if (scale == 0) // zero scale is trivial
return (intCompact != INFLATED) ?
Long.toString(intCompact):
intVal.toString();
// Get the significand as an absolute value
! char coeff[];
! if (intCompact != INFLATED)
! coeff = Long.toString(Math.abs(intCompact)).toCharArray();
! else
coeff = intVal.abs().toString().toCharArray();
// Construct a buffer, with sufficient capacity for all cases.
// If E-notation is needed, length will be: +1 if negative, +1
// if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
// Otherwise it could have +1 if negative, plus leading "0.00000"
! StringBuilder buf=new StringBuilder(coeff.length+14);
if (signum() < 0) // prefix '-' if negative
buf.append('-');
! long adjusted = -(long)scale + (coeff.length-1);
if ((scale >= 0) && (adjusted >= -6)) { // plain number
! int pad = scale - coeff.length; // count of padding zeros
if (pad >= 0) { // 0.xxx form
buf.append('0');
buf.append('.');
for (; pad>0; pad--) {
buf.append('0');
}
! buf.append(coeff);
} else { // xx.xx form
! buf.append(coeff, 0, -pad);
buf.append('.');
! buf.append(coeff, -pad, scale);
}
} else { // E-notation is needed
if (sci) { // Scientific notation
! buf.append(coeff[0]); // first character
! if (coeff.length > 1) { // more to come
buf.append('.');
! buf.append(coeff, 1, coeff.length-1);
}
} else { // Engineering notation
int sig = (int)(adjusted % 3);
if (sig < 0)
sig += 3; // [adjusted was negative]
--- 3259,3309 ----
if (scale == 0) // zero scale is trivial
return (intCompact != INFLATED) ?
Long.toString(intCompact):
intVal.toString();
+ StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
+ char[] coeff;
+ int offset; // offset is the starting index for coeff array
// Get the significand as an absolute value
! if (intCompact != INFLATED) {
! offset = sbHelper.putIntCompact(Math.abs(intCompact));
! coeff = sbHelper.getCompactCharArray();
! } else {
! offset = 0;
coeff = intVal.abs().toString().toCharArray();
+ }
// Construct a buffer, with sufficient capacity for all cases.
// If E-notation is needed, length will be: +1 if negative, +1
// if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
// Otherwise it could have +1 if negative, plus leading "0.00000"
! StringBuilder buf = sbHelper.getStringBuilder();
if (signum() < 0) // prefix '-' if negative
buf.append('-');
! int coeffLen = coeff.length - offset;
! long adjusted = -(long)scale + (coeffLen -1);
if ((scale >= 0) && (adjusted >= -6)) { // plain number
! int pad = scale - coeffLen; // count of padding zeros
if (pad >= 0) { // 0.xxx form
buf.append('0');
buf.append('.');
for (; pad>0; pad--) {
buf.append('0');
}
! buf.append(coeff, offset, coeffLen);
} else { // xx.xx form
! buf.append(coeff, offset, -pad);
buf.append('.');
! buf.append(coeff, -pad + offset, scale);
}
} else { // E-notation is needed
if (sci) { // Scientific notation
! buf.append(coeff[offset]); // first character
! if (coeffLen > 1) { // more to come
buf.append('.');
! buf.append(coeff, offset + 1, coeffLen - 1);
}
} else { // Engineering notation
int sig = (int)(adjusted % 3);
if (sig < 0)
sig += 3; // [adjusted was negative]
*** 3110,3128 ****
adjusted += 3;
break;
default:
throw new AssertionError("Unexpected sig value " + sig);
}
! } else if (sig >= coeff.length) { // significand all in integer
! buf.append(coeff, 0, coeff.length);
// may need some zeros, too
! for (int i = sig - coeff.length; i > 0; i--)
buf.append('0');
} else { // xx.xxE form
! buf.append(coeff, 0, sig);
buf.append('.');
! buf.append(coeff, sig, coeff.length-sig);
}
}
if (adjusted != 0) { // [!sci could have made 0]
buf.append('E');
if (adjusted > 0) // force sign for positive
--- 3323,3341 ----
adjusted += 3;
break;
default:
throw new AssertionError("Unexpected sig value " + sig);
}
! } else if (sig >= coeffLen) { // significand all in integer
! buf.append(coeff, offset, coeffLen);
// may need some zeros, too
! for (int i = sig - coeffLen; i > 0; i--)
buf.append('0');
} else { // xx.xxE form
! buf.append(coeff, offset, sig);
buf.append('.');
! buf.append(coeff, offset + sig, coeffLen - sig);
}
}
if (adjusted != 0) { // [!sci could have made 0]
buf.append('E');
if (adjusted > 0) // force sign for positive
*** 3137,3209 ****
* Return 10 to the power n, as a {@code BigInteger}.
*
* @param n the power of ten to be returned (>=0)
* @return a {@code BigInteger} with the value (10<sup>n</sup>)
*/
! private static BigInteger tenToThe(int n) {
! if (n < TENPOWERS.length) // use value from constant array
! return TENPOWERS[n];
// BigInteger.pow is slow, so make 10**n by constructing a
// BigInteger from a character string (still not very fast)
char tenpow[] = new char[n + 1];
tenpow[0] = '1';
for (int i = 1; i <= n; i++)
tenpow[i] = '0';
return new BigInteger(tenpow);
}
! private static BigInteger TENPOWERS[] = {BigInteger.ONE,
BigInteger.valueOf(10), BigInteger.valueOf(100),
BigInteger.valueOf(1000), BigInteger.valueOf(10000),
BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
! BigInteger.valueOf(1000000000)};
/**
* Compute val * 10 ^ n; return this product if it is
* representable as a long, INFLATED otherwise.
*/
! private static long longTenToThe(long val, int n) {
! // System.err.print("\tval " + val + "\t power " + n + "\tresult ");
! if (n >= 0 && n < thresholds.length) {
! if (Math.abs(val) <= thresholds[n][0] ) {
! // System.err.println(val * thresholds[n][1]);
! return val * thresholds[n][1];
}
- }
- // System.err.println(INFLATED);
return INFLATED;
}
! private static long thresholds[][] = {
! {Long.MAX_VALUE, 1L}, // 0
! {Long.MAX_VALUE/10L, 10L}, // 1
! {Long.MAX_VALUE/100L, 100L}, // 2
! {Long.MAX_VALUE/1000L, 1000L}, // 3
! {Long.MAX_VALUE/10000L, 10000L}, // 4
! {Long.MAX_VALUE/100000L, 100000L}, // 5
! {Long.MAX_VALUE/1000000L, 1000000L}, // 6
! {Long.MAX_VALUE/10000000L, 10000000L}, // 7
! {Long.MAX_VALUE/100000000L, 100000000L}, // 8
! {Long.MAX_VALUE/1000000000L, 1000000000L}, // 9
! {Long.MAX_VALUE/10000000000L, 10000000000L}, // 10
! {Long.MAX_VALUE/100000000000L, 100000000000L}, // 11
! {Long.MAX_VALUE/1000000000000L, 1000000000000L},// 12
! {Long.MAX_VALUE/100000000000000L, 10000000000000L},// 13
! };
! private static boolean compactLong(long val) {
! return (val != Long.MIN_VALUE);
}
/**
* Assign appropriate BigInteger to intVal field if intVal is
* null, i.e. the compact representation is in use.
*/
! private BigDecimal inflate() {
if (intVal == null)
intVal = BigInteger.valueOf(intCompact);
! return this;
}
/**
* Match the scales of two {@code BigDecimal}s to align their
* least significant digits.
--- 3350,3517 ----
* Return 10 to the power n, as a {@code BigInteger}.
*
* @param n the power of ten to be returned (>=0)
* @return a {@code BigInteger} with the value (10<sup>n</sup>)
*/
! private static BigInteger bigTenToThe(int n) {
! if (n < 0)
! return BigInteger.ZERO;
!
! if (n < BIG_TEN_POWERS_TABLE_MAX) {
! BigInteger[] pows = BIG_TEN_POWERS_TABLE;
! if (n < pows.length)
! return pows[n];
! else
! return expandBigIntegerTenPowers(n);
! }
// BigInteger.pow is slow, so make 10**n by constructing a
// BigInteger from a character string (still not very fast)
char tenpow[] = new char[n + 1];
tenpow[0] = '1';
for (int i = 1; i <= n; i++)
tenpow[i] = '0';
return new BigInteger(tenpow);
}
!
! /**
! * Expand the BIG_TEN_POWERS_TABLE array to contain at least 10**n.
! *
! * @param n the power of ten to be returned (>=0)
! * @return a {@code BigDecimal} with the value (10<sup>n</sup>) and
! * in the meantime, the BIG_TEN_POWERS_TABLE array gets
! * expanded to the size greater than n.
! */
! private static BigInteger expandBigIntegerTenPowers(int n) {
! synchronized(BigDecimal.class) {
! BigInteger[] pows = BIG_TEN_POWERS_TABLE;
! int curLen = pows.length;
! // The following comparison and the above synchronized statement is
! // to prevent multiple threads from expanding the same array.
! if (curLen <= n) {
! int newLen = curLen << 1;
! while (newLen <= n)
! newLen <<= 1;
! pows = Arrays.copyOf(pows, newLen);
! for (int i = curLen; i < newLen; i++)
! pows[i] = pows[i - 1].multiply(BigInteger.TEN);
! // Based on the following facts:
! // 1. pows is a private local varible;
! // 2. the following store is a volatile store.
! // the newly created array elements can be safely published.
! BIG_TEN_POWERS_TABLE = pows;
! }
! return pows[n];
! }
! }
!
! private static final long[] LONG_TEN_POWERS_TABLE = {
! 1, // 0 / 10^0
! 10, // 1 / 10^1
! 100, // 2 / 10^2
! 1000, // 3 / 10^3
! 10000, // 4 / 10^4
! 100000, // 5 / 10^5
! 1000000, // 6 / 10^6
! 10000000, // 7 / 10^7
! 100000000, // 8 / 10^8
! 1000000000, // 9 / 10^9
! 10000000000L, // 10 / 10^10
! 100000000000L, // 11 / 10^11
! 1000000000000L, // 12 / 10^12
! 10000000000000L, // 13 / 10^13
! 100000000000000L, // 14 / 10^14
! 1000000000000000L, // 15 / 10^15
! 10000000000000000L, // 16 / 10^16
! 100000000000000000L, // 17 / 10^17
! 1000000000000000000L // 18 / 10^18
! };
!
! private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
BigInteger.valueOf(10), BigInteger.valueOf(100),
BigInteger.valueOf(1000), BigInteger.valueOf(10000),
BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
! BigInteger.valueOf(1000000000),
! BigInteger.valueOf(10000000000L),
! BigInteger.valueOf(100000000000L),
! BigInteger.valueOf(1000000000000L),
! BigInteger.valueOf(10000000000000L),
! BigInteger.valueOf(100000000000000L),
! BigInteger.valueOf(1000000000000000L),
! BigInteger.valueOf(10000000000000000L),
! BigInteger.valueOf(100000000000000000L),
! BigInteger.valueOf(1000000000000000000L)
! };
+ private static final int BIG_TEN_POWERS_TABLE_INITLEN =
+ BIG_TEN_POWERS_TABLE.length;
+ private static final int BIG_TEN_POWERS_TABLE_MAX =
+ 16 * BIG_TEN_POWERS_TABLE_INITLEN;
+
+ private static final long THRESHOLDS_TABLE[] = {
+ Long.MAX_VALUE, // 0
+ Long.MAX_VALUE/10L, // 1
+ Long.MAX_VALUE/100L, // 2
+ Long.MAX_VALUE/1000L, // 3
+ Long.MAX_VALUE/10000L, // 4
+ Long.MAX_VALUE/100000L, // 5
+ Long.MAX_VALUE/1000000L, // 6
+ Long.MAX_VALUE/10000000L, // 7
+ Long.MAX_VALUE/100000000L, // 8
+ Long.MAX_VALUE/1000000000L, // 9
+ Long.MAX_VALUE/10000000000L, // 10
+ Long.MAX_VALUE/100000000000L, // 11
+ Long.MAX_VALUE/1000000000000L, // 12
+ Long.MAX_VALUE/10000000000000L, // 13
+ Long.MAX_VALUE/100000000000000L, // 14
+ Long.MAX_VALUE/1000000000000000L, // 15
+ Long.MAX_VALUE/10000000000000000L, // 16
+ Long.MAX_VALUE/100000000000000000L, // 17
+ Long.MAX_VALUE/1000000000000000000L // 18
+ };
+
/**
* Compute val * 10 ^ n; return this product if it is
* representable as a long, INFLATED otherwise.
*/
! private static long longMultiplyPowerTen(long val, int n) {
! if (val == 0 || n <= 0)
! return val;
! long[] tab = LONG_TEN_POWERS_TABLE;
! long[] bounds = THRESHOLDS_TABLE;
! if (n < tab.length && n < bounds.length) {
! long tenpower = tab[n];
! if (val == 1)
! return tenpower;
! if (Math.abs(val) <= bounds[n])
! return val * tenpower;
}
return INFLATED;
}
! /**
! * Compute this * 10 ^ n.
! * Needed mainly to allow special casing to trap zero value
! */
! private BigInteger bigMultiplyPowerTen(int n) {
! if (n <= 0)
! return this.inflate();
! if (intCompact != INFLATED)
! return bigTenToThe(n).multiply(intCompact);
! else
! return intVal.multiply(bigTenToThe(n));
}
/**
* Assign appropriate BigInteger to intVal field if intVal is
* null, i.e. the compact representation is in use.
*/
! private BigInteger inflate() {
if (intVal == null)
intVal = BigInteger.valueOf(intCompact);
! return intVal;
}
/**
* Match the scales of two {@code BigDecimal}s to align their
* least significant digits.
*** 3216,3230 ****
*
* @param val array of two elements referring to the two
* {@code BigDecimal}s to be aligned.
*/
private static void matchScale(BigDecimal[] val) {
! if (val[0].scale < val[1].scale)
! val[0] = val[0].setScale(val[1].scale);
! else if (val[1].scale < val[0].scale)
! val[1] = val[1].setScale(val[0].scale);
}
/**
* Reconstitute the {@code BigDecimal} instance from a stream (that is,
* deserialize it).
*
--- 3524,3541 ----
*
* @param val array of two elements referring to the two
* {@code BigDecimal}s to be aligned.
*/
private static void matchScale(BigDecimal[] val) {
! if (val[0].scale == val[1].scale) {
! return;
! } else if (val[0].scale < val[1].scale) {
! val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
! } else if (val[1].scale < val[0].scale) {
! val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
}
+ }
/**
* Reconstitute the {@code BigDecimal} instance from a stream (that is,
* deserialize it).
*
*** 3238,3250 ****
if (intVal == null) {
String message = "BigDecimal: null intVal in stream";
throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed]
}
! // Set intCompact to uninitialized value; could also see if the
! // intVal was small enough to fit as a compact value.
! intCompact = INFLATED;
}
/**
* Serialize this {@code BigDecimal} to the stream in question
*
--- 3549,3559 ----
if (intVal == null) {
String message = "BigDecimal: null intVal in stream";
throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed]
}
! intCompact = compactValFor(intVal);
}
/**
* Serialize this {@code BigDecimal} to the stream in question
*
*** 3257,3344 ****
// Write proper fields
s.defaultWriteObject();
}
/**
! * Returns the length of this {@code BigDecimal}, in decimal digits.
*
! * Notes:
! *<ul>
! * <li> This is performance-critical; most operations where a
! * context is supplied will need at least one call to this
! * method.
! *
! * <li> This should be a method on BigInteger; the call to this
! * method in precision() can then be replaced with the
! * term: intVal.digitLength(). It could also be called
! * precision() in BigInteger.
! *
! * Better still -- the precision lookaside could be moved to
! * BigInteger, too.
! *
! * <li> This could/should use MutableBigIntegers directly for the
! * reduction loop.
! *<ul>
! * @return the length of the unscaled value, in decimal digits
*/
! private int digitLength() {
! if (intCompact != INFLATED && Math.abs(intCompact) <= Integer.MAX_VALUE)
! return intLength(Math.abs((int)intCompact));
! if (signum() == 0) // 0 is one decimal digit
return 1;
! this.inflate();
! // we have a nonzero magnitude
! BigInteger work = intVal;
! int digits = 0; // counter
! for (;work.mag.length>1;) {
! // here when more than one integer in the magnitude; divide
! // by a billion (reduce by 9 digits) and try again
! work = work.divide(TENPOWERS[9]);
! digits += 9;
! if (work.signum() == 0) // the division was exact
! return digits; // (a power of a billion)
}
- // down to a simple nonzero integer
- digits += intLength(work.mag[0]);
- // System.out.println("digitLength... "+this+" -> "+digits);
- return digits;
- }
- private static int[] ilogTable = {
- 0,
- 9,
- 99,
- 999,
- 9999,
- 99999,
- 999999,
- 9999999,
- 99999999,
- 999999999,
- Integer.MAX_VALUE};
-
/**
! * Returns the length of an unsigned {@code int}, in decimal digits.
! * @param i the {@code int} (treated as unsigned)
* @return the length of the unscaled value, in decimal digits
*/
! private int intLength(int x) {
! int digits;
! if (x < 0) { // 'negative' is 10 digits unsigned
! return 10;
! } else { // positive integer
! if (x <= 9)
return 1;
! // "Hacker's Delight" section 11-4
! for(int i = -1; ; i++) {
! if (x <= ilogTable[i+1])
! return i +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.
--- 3566,3635 ----
// Write proper fields
s.defaultWriteObject();
}
+
/**
! * Returns the length of the absolute value of a {@code long}, in decimal
! * digits.
*
! * @param x the {@code long}
! * @return the length of the unscaled value, in deciaml digits.
*/
! private static int longDigitLength(long x) {
! /*
! * As described in "Bit Twiddling Hacks" by Sean Anderson,
! * (http://graphics.stanford.edu/~seander/bithacks.html)
! * integer log 10 of x is within 1 of
! * (1233/4096)* (1 + integer log 2 of x).
! * The fraction 1233/4096 approximates log10(2). So we first
! * do a version of log2 (a variant of Long class with
! * pre-checks and opposite directionality) and then scale and
! * check against powers table. This is a little simpler in
! * present context than the version in Hacker's Delight sec
! * 11-4. Adding one to bit length allows comparing downward
! * from the LONG_TEN_POWERS_TABLE that we need anyway.
! */
! assert x != INFLATED;
! if (x < 0)
! x = -x;
! if (x < 10) // must screen for 0, might as well 10
return 1;
! int n = 64; // not 63, to avoid needing to add 1 later
! int y = (int)(x >>> 32);
! if (y == 0) { n -= 32; y = (int)x; }
! if (y >>> 16 == 0) { n -= 16; y <<= 16; }
! if (y >>> 24 == 0) { n -= 8; y <<= 8; }
! if (y >>> 28 == 0) { n -= 4; y <<= 4; }
! if (y >>> 30 == 0) { n -= 2; y <<= 2; }
! int r = (((y >>> 31) + n) * 1233) >>> 12;
! long[] tab = LONG_TEN_POWERS_TABLE;
! // if r >= length, must have max possible digits for long
! return (r >= tab.length || x < tab[r])? r : r+1;
}
/**
! * Returns the length of the absolute value of a BigInteger, in
! * decimal digits.
! *
! * @param b the BigInteger
* @return the length of the unscaled value, in decimal digits
*/
! private static int bigDigitLength(BigInteger b) {
! /*
! * Same idea as the long version, but we need a better
! * approximation of log10(2). Using 646456993/2^31
! * is accurate up to max possible reported bitLength.
! */
! if (b.signum == 0)
return 1;
! int r = (int)((((long)b.bitLength() + 1) * 646456993) >>> 31);
! 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.
*** 3353,3363 ****
*/
private BigDecimal stripZerosToMatchScale(long preferredScale) {
boolean compact = (intCompact != INFLATED);
this.inflate();
BigInteger qr[]; // quotient-remainder pair
! while ( intVal.abs().compareTo(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)
--- 3644,3654 ----
*/
private BigDecimal stripZerosToMatchScale(long preferredScale) {
boolean compact = (intCompact != INFLATED);
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)
*** 3365,3406 ****
intVal=qr[0];
scale = checkScale((long)scale-1); // could Overflow
if (precision > 0) // adjust precision if known
precision--;
}
! if (compact)
! intCompact = intVal.longValue();
return this;
}
/**
* Check a scale for Underflow or Overflow. If this BigDecimal is
! * uninitialized or initialized and nonzero, throw an exception if
! * the scale is out of range. If this is zero, saturate the scale
! * to the extreme value of the right sign if the scale is out of
! * range.
*
* @param val The new scale.
* @throws ArithmeticException (overflow or underflow) if the new
* scale is out of range.
* @return validated scale as an int.
*/
private int checkScale(long val) {
! if ((int)val != val) {
! if ((this.intCompact != INFLATED && this.intCompact != 0) ||
! (this.intVal != null && this.signum() != 0) ||
! (this.intVal == null && this.intCompact == INFLATED) ) {
! if (val > Integer.MAX_VALUE)
! throw new ArithmeticException("Underflow");
! if (val < Integer.MIN_VALUE)
! throw new ArithmeticException("Overflow");
! } else {
! return (val > Integer.MAX_VALUE)?Integer.MAX_VALUE:Integer.MIN_VALUE;
}
}
- return (int)val;
- }
/**
* Round an operand; used only if digits > 0. Does not change
* {@code this}; if rounding is needed a new {@code BigDecimal}
* is created and returned.
--- 3656,3692 ----
intVal=qr[0];
scale = checkScale((long)scale-1); // could Overflow
if (precision > 0) // adjust precision if known
precision--;
}
! if (intVal != null)
! intCompact = compactValFor(intVal);
return this;
}
/**
* Check a scale for Underflow or Overflow. If this BigDecimal is
! * nonzero, throw an exception if the scale is outof range. If this
! * is zero, saturate the scale to the extreme value of the right
! * sign if the scale is out of range.
*
* @param val The new scale.
* @throws ArithmeticException (overflow or underflow) if the new
* scale is out of range.
* @return validated scale as an int.
*/
private int checkScale(long val) {
! int asInt = (int)val;
! if (asInt != val) {
! asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
! BigInteger b;
! if (intCompact != 0 &&
! ((b = intVal) == null || b.signum() != 0))
! throw new ArithmeticException(asInt>0 ? "Undeflow":"Overflow");
}
+ return asInt;
}
/**
* Round an operand; used only if digits > 0. Does not change
* {@code this}; if rounding is needed a new {@code BigDecimal}
* is created and returned.
*** 3408,3418 ****
* @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(mc);
return rounded;
}
/** Round this BigDecimal according to the MathContext settings;
* used only if precision {@literal >} 0.
--- 3694,3704 ----
* @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.
*** 3424,3434 ****
* @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(mc);
if (rounded == this) // wasn't rounded
return;
this.intVal = rounded.intVal;
this.intCompact = rounded.intCompact;
this.scale = rounded.scale;
--- 3710,3720 ----
* @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;
*** 3446,3507 ****
* settings. May return this, if no rounding needed.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* result is inexact.
*/
! private BigDecimal doRound(MathContext mc) {
! this.inflate();
! if (precision == 0) {
! if (mc.roundingMax != null
! && intVal.compareTo(mc.roundingMax) < 0
! && intVal.compareTo(mc.roundingMin) > 0)
! return this; // no rounding needed
! precision(); // find it
}
! int drop = precision - mc.precision; // digits to discard
! if (drop <= 0) // we fit
! return this;
! BigDecimal rounded = dropDigits(mc, drop);
! // we need to double-check, in case of the 999=>1000 case
! return rounded.doRound(mc);
}
/**
! * Removes digits from the significand of a {@code BigDecimal},
! * rounding according to the MathContext settings. Does not
! * change {@code this}; a new {@code BigDecimal} is always
! * created and returned.
! *
! * <p>Actual rounding is carried out, as before, by the divide
! * method, as this minimized code changes. It might be more
! * efficient in most cases to move rounding to here, so we can do
! * a round-to-length rather than round-to-scale.
! *
! * @param mc the context to use.
! * @param drop the number of digits to drop, must be {@literal >} 0
! * @return a {@code BigDecimal} rounded according to the MathContext
! * settings. May return {@code this}, if no rounding needed.
! * @throws ArithmeticException if the rounding mode is
! * {@code RoundingMode.UNNECESSARY} and the
! * result is inexact.
*/
! private BigDecimal dropDigits(MathContext mc, int drop) {
! // here if we need to round; make the divisor = 10**drop)
! // [calculating the BigInteger here saves setScale later]
! BigDecimal divisor = new BigDecimal(tenToThe(drop), 0);
! // divide to same scale to force round to length
! BigDecimal rounded = this.divide(divisor, scale,
! mc.roundingMode.oldMode);
! rounded.scale = checkScale((long)rounded.scale - drop ); // adjust the scale
! return rounded;
}
! private static int longCompareTo(long x, long y) {
! return (x < y) ? -1 : (x == y) ? 0 : 1;
}
/*
* Internal printing routine
*/
private static void print(String name, BigDecimal bd) {
System.err.format("%s:\tintCompact %d\tintVal %d\tscale %d\tprecision %d%n",
--- 3732,3793 ----
* settings. May return this, if no rounding needed.
* @throws ArithmeticException if the rounding mode is
* {@code RoundingMode.UNNECESSARY} and the
* result is inexact.
*/
! private static BigDecimal doRound(BigDecimal d, MathContext mc) {
! int mcp = mc.precision;
! int drop;
! // This might (rarely) iterate to cover the 999=>1000 case
! while ((drop = d.precision() - mcp) > 0) {
! int newScale = d.checkScale((long)d.scale - drop);
! int mode = mc.roundingMode.oldMode;
! if (drop < LONG_TEN_POWERS_TABLE.length)
! d = divideAndRound(d.intCompact, d.intVal,
! LONG_TEN_POWERS_TABLE[drop], null,
! newScale, mode, newScale);
! else
! d = divideAndRound(d.intCompact, d.intVal,
! INFLATED, bigTenToThe(drop),
! newScale, mode, newScale);
}
! return d;
}
/**
! * Returns the compact value for given {@code BigInteger}, or
! * INFLATED if too big. Relies on internal representation of
! * {@code BigInteger}.
*/
! private static long compactValFor(BigInteger b) {
! int[] m = b.mag;
! int len = m.length;
! if (len == 0)
! return 0;
! int d = m[0];
! if (len > 2 || (len == 2 && d < 0))
! return INFLATED;
! long u = (len == 2)?
! (((long) m[1] & LONG_MASK) + (((long)d) << 32)) :
! (((long)d) & LONG_MASK);
! return (b.signum < 0)? -u : u;
}
! private static int longCompareMagnitude(long x, long y) {
! if (x < 0)
! x = -x;
! if (y < 0)
! y = -y;
! return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
+ private static int saturateLong(long s) {
+ int i = (int)s;
+ return (s == i) ? i : (s < 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE);
+ }
+
/*
* Internal printing routine
*/
private static void print(String name, BigDecimal bd) {
System.err.format("%s:\tintCompact %d\tintVal %d\tscale %d\tprecision %d%n",
*** 3525,3557 ****
* <li>If both intCompact and intVal and set, their values must be
* consistent.
*
* <li>If precision is nonzero, it must have the right value.
* </ul>
*/
private BigDecimal audit() {
- // Check precision
- if (precision > 0) {
- if (precision != digitLength()) {
- print("audit", this);
- throw new AssertionError("precision mismatch");
- }
- }
-
if (intCompact == INFLATED) {
if (intVal == null) {
print("audit", this);
throw new AssertionError("null intVal");
}
} else {
if (intVal != null) {
long val = intVal.longValue();
if (val != intCompact) {
print("audit", this);
throw new AssertionError("Inconsistent state, intCompact=" +
intCompact + "\t intVal=" + val);
}
}
}
return this;
}
}
--- 3811,3848 ----
* <li>If both intCompact and intVal and set, their values must be
* consistent.
*
* <li>If precision is nonzero, it must have the right value.
* </ul>
+ *
+ * Note: Since this is an audit method, we are not supposed to change the
+ * state of this BigDecimal object.
*/
private BigDecimal audit() {
if (intCompact == INFLATED) {
if (intVal == null) {
print("audit", this);
throw new AssertionError("null intVal");
}
+ // Check precision
+ if (precision > 0 && precision != bigDigitLength(intVal)) {
+ print("audit", this);
+ throw new AssertionError("precision mismatch");
+ }
} else {
if (intVal != null) {
long val = intVal.longValue();
if (val != intCompact) {
print("audit", this);
throw new AssertionError("Inconsistent state, intCompact=" +
intCompact + "\t intVal=" + val);
}
}
+ // Check precision
+ if (precision > 0 && precision != longDigitLength(intCompact)) {
+ print("audit", this);
+ throw new AssertionError("precision mismatch");
}
+ }
return this;
}
}