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 &times; 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 &times; 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 &times; * 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 &times; * 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 &times; * 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 &times; * 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 &gt; 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 &gt; 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; } }