--- old/src/share/classes/java/math/BigDecimal.java 2011-08-24 16:25:06.000000000 -0700 +++ new/src/share/classes/java/math/BigDecimal.java 2011-08-24 16:25:06.000000000 -0700 @@ -224,7 +224,7 @@ * @serial * @see #unscaledValue */ - private volatile BigInteger intVal; + private final BigInteger intVal; /** * The scale of this BigDecimal, as returned by {@link #scale}. @@ -232,8 +232,9 @@ * @serial * @see #scale */ - private int scale; // Note: this may have any value, so - // calculations must be done in longs + private final int scale; // Note: this may have any value, so + // calculations must be done in longs + /** * The number of decimal digits in this BigDecimal, or 0 if the * number of digits are not known (lookaside information). If @@ -256,19 +257,19 @@ */ static final long INFLATED = Long.MIN_VALUE; + private static final BigInteger INFLATED_BIGINT = BigInteger.valueOf(INFLATED); + /** * If the absolute value of the significand of this BigDecimal is * less than or equal to {@code Long.MAX_VALUE}, the value can be * compactly stored in this field and used in computations. */ - private transient long intCompact; + private final transient long intCompact; // All 18-digit base ten strings fit into a long; not all 19-digit // strings will private static final int MAX_COMPACT_DIGITS = 18; - private static final int MAX_BIGINT_BITS = 62; - /* Appease the serialization gods */ private static final long serialVersionUID = 6108874887143696463L; @@ -282,17 +283,17 @@ // 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), + 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 @@ -378,8 +379,35 @@ * @since 1.5 */ public BigDecimal(char[] in, int offset, int len) { + this(in,offset,len,MathContext.UNLIMITED); + } + + /** + * Translates a character array representation of a + * {@code BigDecimal} into a {@code BigDecimal}, accepting the + * same sequence of characters as the {@link #BigDecimal(String)} + * constructor, while allowing a sub-array to be specified and + * with rounding according to the context settings. + * + *
Note that if the sequence of characters is already available + * within a character array, using this constructor is faster than + * converting the {@code char} array to string and using the + * {@code BigDecimal(String)} constructor . + * + * @param in {@code char} array that is the source of characters. + * @param offset first character in the array to inspect. + * @param len number of characters to consider.. + * @param mc the context to use. + * @throws ArithmeticException if the result is inexact but the + * rounding mode is {@code UNNECESSARY}. + * @throws NumberFormatException if {@code in} is not a valid + * representation of a {@code BigDecimal} or the defined subarray + * is not wholly within {@code in}. + * @since 1.5 + */ + public BigDecimal(char[] in, int offset, int len, MathContext mc) { // protect against huge length. - if (offset+len > in.length || offset < 0) + 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) @@ -391,7 +419,6 @@ 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 { @@ -407,24 +434,41 @@ } // should now be at numeric part of the significand - boolean dot = false; // true when there is a '.' - int cfirst = offset; // record start of integer + // int cfirst = offset; // record start of integer long exp = 0; // exponent char c; // current character - + boolean dot = false; // true when there is a '.' 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) { + if (isCompact) { + // First compact case, we need not to preserve the character + // and we can just compute the value in place. + for (; len > 0; offset++, len--) { + c = in[offset]; + if ((c == '0')) { // have zero + if (prec == 0) + prec = 1; + else if (rs != 0) { + rs *= 10; + ++prec; + } // else digit is a redundant leading zero + if (dot) + ++scl; + } else if ((c >= '1' && c <= '9')) { // have digit + int digit = c - '0'; + if (prec != 1 || rs != 0) + ++prec; // prec unchanged if preceded by 0s + rs = rs * 10 + digit; + if (dot) + ++scl; + } else if (c == '.') { // have dot + // have dot + if (dot) // two dots + throw new NumberFormatException(); + dot = true; + } else if (Character.isDigit(c)) { // slow path int digit = Character.digit(c, 10); if (digit == 0) { if (prec == 0) @@ -438,7 +482,43 @@ ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; } - } else { // the unscaled value is likely a BigInteger object. + if (dot) + ++scl; + } else if ((c == 'e') || (c == 'E')) { + exp = parseExp(in, offset, len); + // Next test is required for backwards compatibility + if ((int) exp != exp) // overflow + throw new NumberFormatException(); + break; // [saves a test] + } else { + throw new NumberFormatException(); + } + } + if (prec == 0) // no digits found + throw new NumberFormatException(); + // Adjust scale if exp is not zero. + if (exp != 0) { // had significant exponent + scl = adjustScale(scl, exp); + } + rs = isneg ? -rs : rs; + int mcp = mc.precision; + int drop; + if (mcp > 0 && (drop = prec - mcp) > 0) { // do rounding + while (drop > 0) { + scl = checkScaleNonZero((long) scl - drop); + rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(rs); + drop = prec - mcp; + } + } + } else { + char coeff[] = new char[len]; + for (; len > 0; offset++, len--) { + c = in[offset]; + // have digit + if ((c >= '0' && c <= '9') || Character.isDigit(c)) { + // First compact case, we need not to preserve the character + // and we can just compute the value in place. if (c == '0' || Character.digit(c, 10) == 0) { if (prec == 0) { coeff[idx] = c; @@ -452,94 +532,64 @@ ++prec; // prec unchanged if preceded by 0s coeff[idx++] = c; } + if (dot) + ++scl; + continue; } - 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 - throw new NumberFormatException(); - // skip leading zeros in the exponent - while (len > 10 && Character.digit(c, 10) == 0) { - offset++; - c = in[offset]; - len--; - } - if (len > 10) // too many nonzero exponent digits - throw new NumberFormatException(); - // c now holds first digit of exponent - for (;; len--) { - int v; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else { - v = Character.digit(c, 10); - if (v < 0) // not a digit + if (c == '.') { + // have dot + if (dot) // two dots throw new NumberFormatException(); + dot = true; + continue; } - exp = exp * 10 + v; - if (len == 1) - break; // that was final character - offset++; - c = in[offset]; + // exponent expected + if ((c != 'e') && (c != 'E')) + throw new NumberFormatException(); + exp = parseExp(in, offset, len); + // Next test is required for backwards compatibility + if ((int) exp != exp) // overflow + throw new NumberFormatException(); + break; // [saves a test] } - if (negexp) // apply sign - exp = -exp; - // Next test is required for backwards compatibility - if ((int)exp != exp) // overflow + // here when no characters left + if (prec == 0) // no digits found 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); + // Adjust scale if exp is not zero. + if (exp != 0) { // had significant exponent + scl = adjustScale(scl, exp); } - rb = new BigInteger(quick); + // Remove leading zeros from precision (digits count) + rb = new BigInteger(coeff, isneg ? -1 : 1, prec); rs = compactValFor(rb); + int mcp = mc.precision; + if (mcp > 0 && (prec > mcp)) { + if (rs == INFLATED) { + int drop = prec - mcp; + while (drop > 0) { + scl = checkScaleNonZero((long) scl - drop); + rb = divideAndRoundByTenPow(rb, drop, mc.roundingMode.oldMode); + rs = compactValFor(rb); + if (rs != INFLATED) { + prec = longDigitLength(rs); + break; + } + prec = bigDigitLength(rb); + drop = prec - mcp; + } + } + if (rs != INFLATED) { + int drop = prec - mcp; + while (drop > 0) { + scl = checkScaleNonZero((long) scl - drop); + rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(rs); + drop = prec - mcp; + } + rb = null; + } + } } } catch (ArrayIndexOutOfBoundsException e) { throw new NumberFormatException(); @@ -549,36 +599,61 @@ this.scale = scl; this.precision = prec; this.intCompact = rs; - this.intVal = (rs != INFLATED) ? null : rb; + this.intVal = rb; } - /** - * Translates a character array representation of a - * {@code BigDecimal} into a {@code BigDecimal}, accepting the - * same sequence of characters as the {@link #BigDecimal(String)} - * constructor, while allowing a sub-array to be specified and - * with rounding according to the context settings. - * - *
Note that if the sequence of characters is already available - * within a character array, using this constructor is faster than - * converting the {@code char} array to string and using the - * {@code BigDecimal(String)} constructor . - * - * @param in {@code char} array that is the source of characters. - * @param offset first character in the array to inspect. - * @param len number of characters to consider.. - * @param mc the context to use. - * @throws ArithmeticException if the result is inexact but the - * rounding mode is {@code UNNECESSARY}. - * @throws NumberFormatException if {@code in} is not a valid - * representation of a {@code BigDecimal} or the defined subarray - * is not wholly within {@code in}. - * @since 1.5 + private int adjustScale(int scl, long exp) { + long adjustedScale = scl - exp; + if (adjustedScale > Integer.MAX_VALUE || adjustedScale < Integer.MIN_VALUE) + throw new NumberFormatException("Scale out of range."); + scl = (int) adjustedScale; + return scl; + } + + /* + * parse exponent */ - public BigDecimal(char[] in, int offset, int len, MathContext mc) { - this(in, offset, len); - if (mc.precision > 0) - roundThis(mc); + private static long parseExp(char[] in, int offset, int len){ + long exp = 0; + offset++; + char c = in[offset]; + len--; + boolean negexp = (c == '-'); + // optional sign + if (negexp || c == '+') { + offset++; + c = in[offset]; + len--; + } + if (len <= 0) // no exponent digits + throw new NumberFormatException(); + // skip leading zeros in the exponent + while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) { + offset++; + c = in[offset]; + len--; + } + if (len > 10) // too many nonzero exponent digits + throw new NumberFormatException(); + // c now holds first digit of exponent + for (;; len--) { + int v; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else { + v = Character.digit(c, 10); + if (v < 0) // not a digit + throw new NumberFormatException(); + } + exp = exp * 10 + v; + if (len == 1) + break; // that was final character + offset++; + c = in[offset]; + } + if (negexp) // apply sign + exp = -exp; + return exp; } /** @@ -754,9 +829,7 @@ * @since 1.5 */ public BigDecimal(String val, MathContext mc) { - this(val.toCharArray(), 0, val.length()); - if (mc.precision > 0) - roundThis(mc); + this(val.toCharArray(), 0, val.length(), mc); } /** @@ -804,49 +877,7 @@ * @throws NumberFormatException if {@code val} is infinite or NaN. */ public BigDecimal(double val) { - if (Double.isInfinite(val) || Double.isNaN(val)) - throw new NumberFormatException("Infinite or NaN"); - - // Translate the double into sign, exponent and significand, according - // to the formulae in JLS, Section 20.10.22. - long valBits = Double.doubleToLongBits(val); - int sign = ((valBits >> 63)==0 ? 1 : -1); - int exponent = (int) ((valBits >> 52) & 0x7ffL); - long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1 - : (valBits & ((1L<<52) - 1)) | (1L<<52)); - exponent -= 1075; - // At this point, val == sign * significand * 2**exponent. - - /* - * Special case zero to supress nonterminating normalization - * and bogus scale calculation. - */ - if (significand == 0) { - intVal = BigInteger.ZERO; - intCompact = 0; - precision = 1; - return; - } - - // Normalize - while((significand & 1) == 0) { // i.e., significand is even - significand >>= 1; - exponent++; - } - - // Calculate intVal and scale - long s = sign * significand; - BigInteger b; - if (exponent < 0) { - b = BigInteger.valueOf(5).pow(-exponent).multiply(s); - scale = -exponent; - } else if (exponent > 0) { - b = BigInteger.valueOf(2).pow(exponent).multiply(s); - } else { - b = BigInteger.valueOf(s); - } - intCompact = compactValFor(b); - intVal = (intCompact != INFLATED) ? null : b; + this(val,MathContext.UNLIMITED); } /** @@ -868,9 +899,85 @@ * @since 1.5 */ public BigDecimal(double val, MathContext mc) { - this(val); - if (mc.precision > 0) - roundThis(mc); + if (Double.isInfinite(val) || Double.isNaN(val)) + throw new NumberFormatException("Infinite or NaN"); + // Translate the double into sign, exponent and significand, according + // to the formulae in JLS, Section 20.10.22. + long valBits = Double.doubleToLongBits(val); + int sign = ((valBits >> 63) == 0 ? 1 : -1); + int exponent = (int) ((valBits >> 52) & 0x7ffL); + long significand = (exponent == 0 + ? (valBits & ((1L << 52) - 1)) << 1 + : (valBits & ((1L << 52) - 1)) | (1L << 52)); + exponent -= 1075; + // At this point, val == sign * significand * 2**exponent. + + /* + * Special case zero to supress nonterminating normalization and bogus + * scale calculation. + */ + if (significand == 0) { + this.intVal = BigInteger.ZERO; + this.scale = 0; + this.intCompact = 0; + this.precision = 1; + return; + } + // Normalize + while ((significand & 1) == 0) { // i.e., significand is even + significand >>= 1; + exponent++; + } + int scale = 0; + // Calculate intVal and scale + BigInteger intVal; + long compactVal = sign * significand; + if (exponent == 0) { + intVal = (compactVal == INFLATED) ? INFLATED_BIGINT : null; + } else { + if (exponent < 0) { + intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal); + scale = -exponent; + } else { // (exponent > 0) + intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal); + } + compactVal = compactValFor(intVal); + } + int prec = 0; + int mcp = mc.precision; + if (mcp > 0) { // do rounding + int mode = mc.roundingMode.oldMode; + int drop; + if (compactVal == INFLATED) { + prec = bigDigitLength(intVal); + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + intVal = divideAndRoundByTenPow(intVal, drop, mode); + compactVal = compactValFor(intVal); + if (compactVal != INFLATED) { + break; + } + prec = bigDigitLength(intVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + intVal = null; + } + } + this.intVal = intVal; + this.intCompact = compactVal; + this.scale = scale; + this.precision = prec; } /** @@ -881,8 +988,9 @@ * {@code BigDecimal}. */ public BigDecimal(BigInteger val) { + scale = 0; + intVal = val; intCompact = compactValFor(val); - intVal = (intCompact != INFLATED) ? null : val; } /** @@ -898,9 +1006,7 @@ * @since 1.5 */ public BigDecimal(BigInteger val, MathContext mc) { - this(val); - if (mc.precision > 0) - roundThis(mc); + this(val,0,mc); } /** @@ -914,7 +1020,8 @@ */ public BigDecimal(BigInteger unscaledVal, int scale) { // Negative scales are now allowed - this(unscaledVal); + this.intVal = unscaledVal; + this.intCompact = compactValFor(unscaledVal); this.scale = scale; } @@ -934,10 +1041,41 @@ * @since 1.5 */ public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { - this(unscaledVal); + long compactVal = compactValFor(unscaledVal); + int mcp = mc.precision; + int prec = 0; + if (mcp > 0) { // do rounding + int mode = mc.roundingMode.oldMode; + if (compactVal == INFLATED) { + prec = bigDigitLength(unscaledVal); + int drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + unscaledVal = divideAndRoundByTenPow(unscaledVal, drop, mode); + compactVal = compactValFor(unscaledVal); + if (compactVal != INFLATED) { + break; + } + prec = bigDigitLength(unscaledVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + int drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + unscaledVal = null; + } + } + this.intVal = unscaledVal; + this.intCompact = compactVal; this.scale = scale; - if (mc.precision > 0) - roundThis(mc); + this.precision = prec; } /** @@ -949,7 +1087,9 @@ * @since 1.5 */ public BigDecimal(int val) { - intCompact = val; + this.intCompact = val; + this.scale = 0; + this.intVal = null; } /** @@ -964,9 +1104,24 @@ * @since 1.5 */ public BigDecimal(int val, MathContext mc) { - intCompact = val; - if (mc.precision > 0) - roundThis(mc); + int mcp = mc.precision; + long compactVal = val; + int scale = 0; + int prec = 0; + if (mcp > 0) { // do rounding + prec = longDigitLength(compactVal); + int drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + } + this.intVal = null; + this.intCompact = compactVal; + this.scale = scale; + this.precision = prec; } /** @@ -978,7 +1133,8 @@ */ public BigDecimal(long val) { this.intCompact = val; - this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null; + this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null; + this.scale = 0; } /** @@ -993,9 +1149,42 @@ * @since 1.5 */ public BigDecimal(long val, MathContext mc) { - this(val); - if (mc.precision > 0) - roundThis(mc); + int mcp = mc.precision; + int mode = mc.roundingMode.oldMode; + int prec = 0; + int scale = 0; + BigInteger intVal = (val == INFLATED) ? INFLATED_BIGINT : null; + if (mcp > 0) { // do rounding + if (val == INFLATED) { + prec = 19; + int drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + intVal = divideAndRoundByTenPow(intVal, drop, mode); + val = compactValFor(intVal); + if (val != INFLATED) { + break; + } + prec = bigDigitLength(intVal); + drop = prec - mcp; + } + } + if (val != INFLATED) { + prec = longDigitLength(val); + int drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + val = divideAndRound(val, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(val); + drop = prec - mcp; + } + intVal = null; + } + } + this.intVal = intVal; + this.intCompact = val; + this.scale = scale; + this.precision = prec; } // Static Factory Methods @@ -1016,13 +1205,10 @@ if (scale == 0) return valueOf(unscaledVal); else if (unscaledVal == 0) { - if (scale > 0 && scale < ZERO_SCALED_BY.length) - return ZERO_SCALED_BY[scale]; - else - return new BigDecimal(BigInteger.ZERO, 0, scale, 1); + return zeroValueOf(scale); } return new BigDecimal(unscaledVal == INFLATED ? - BigInteger.valueOf(unscaledVal) : null, + INFLATED_BIGINT : null, unscaledVal, scale, 0); } @@ -1041,7 +1227,34 @@ return zeroThroughTen[(int)val]; else if (val != INFLATED) return new BigDecimal(null, val, 0, 0); - return new BigDecimal(BigInteger.valueOf(val), val, 0, 0); + return new BigDecimal(INFLATED_BIGINT, val, 0, 0); + } + + static BigDecimal valueOf(long unscaledVal, int scale, int prec) { + if (scale == 0 && unscaledVal >= 0 && unscaledVal < zeroThroughTen.length) { + return zeroThroughTen[(int) unscaledVal]; + } else if (unscaledVal == 0) { + return zeroValueOf(scale); + } + return new BigDecimal(unscaledVal == INFLATED ? INFLATED_BIGINT : null, + unscaledVal, scale, prec); + } + + static BigDecimal valueOf(BigInteger intVal, int scale, int prec) { + long val = compactValFor(intVal); + if (val == 0) { + return zeroValueOf(scale); + } else if (scale == 0 && val >= 0 && val < zeroThroughTen.length) { + return zeroThroughTen[(int) val]; + } + return new BigDecimal(intVal, val, scale, prec); + } + + static BigDecimal zeroValueOf(int scale) { + if (scale >= 0 && scale < ZERO_SCALED_BY.length) + return ZERO_SCALED_BY[scale]; + else + return new BigDecimal(BigInteger.ZERO, 0, scale, 1); } /** @@ -1079,42 +1292,19 @@ * @return {@code this + augend} */ public BigDecimal add(BigDecimal augend) { - long xs = this.intCompact; - long ys = augend.intCompact; - BigInteger fst = (xs != INFLATED) ? null : this.intVal; - BigInteger snd = (ys != INFLATED) ? null : augend.intVal; - int rscale = this.scale; - - long sdiff = (long)rscale - augend.scale; - if (sdiff != 0) { - if (sdiff < 0) { - int raise = checkScale(-sdiff); - rscale = augend.scale; - if (xs == INFLATED || - (xs = longMultiplyPowerTen(xs, raise)) == INFLATED) - fst = bigMultiplyPowerTen(raise); - } 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 BigDecimal.valueOf(sum, rscale); - } - if (fst == null) - fst = BigInteger.valueOf(xs); - if (snd == null) - snd = BigInteger.valueOf(ys); - BigInteger sum = fst.add(snd); - return (fst.signum == snd.signum) ? - new BigDecimal(sum, INFLATED, rscale, 0) : - new BigDecimal(sum, rscale); + if (this.intCompact != INFLATED) { + if ((augend.intCompact != INFLATED)) { + return add(this.intCompact, this.scale, augend.intCompact, augend.scale); + } else { + return add(this.intCompact, this.scale, augend.intVal, augend.scale); + } + } else { + if ((augend.intCompact != INFLATED)) { + return add(augend.intCompact, augend.scale, this.intVal, this.scale); + } else { + return add(this.intVal, this.scale, augend.intVal, augend.scale); + } + } } /** @@ -1136,10 +1326,6 @@ return add(augend); BigDecimal lhs = this; - // Could optimize if values are compact - this.inflate(); - augend.inflate(); - // If either number is zero then the other number, rounded and // scaled if necessary, is used as the result. { @@ -1149,21 +1335,15 @@ if (lhsIsZero || augendIsZero) { int preferredScale = Math.max(lhs.scale(), augend.scale()); BigDecimal result; - // Could use a factory for zero instead of a new object if (lhsIsZero && augendIsZero) - return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0); - + return zeroValueOf(preferredScale); result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc); if (result.scale() == preferredScale) return result; else if (result.scale() > preferredScale) { - BigDecimal scaledResult = - new BigDecimal(result.intVal, result.intCompact, - result.scale, 0); - scaledResult.stripZerosToMatchScale(preferredScale); - return scaledResult; + return stripZerosToMatchScale(result.intVal, result.intCompact, result.scale, preferredScale); } else { // result.scale < preferredScale int precisionDiff = mc.precision - result.precision(); int scaleDiff = preferredScale - result.scale(); @@ -1176,19 +1356,16 @@ } } - long padding = (long)lhs.scale - augend.scale; - if (padding != 0) { // scales differ; alignment needed + long padding = (long) lhs.scale - augend.scale; + if (padding != 0) { // scales differ; alignment needed BigDecimal arg[] = preAlign(lhs, augend, padding, mc); matchScale(arg); - lhs = arg[0]; + lhs = arg[0]; augend = arg[1]; } - - BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()), - lhs.scale); - return doRound(d, mc); + return doRound(lhs.inflated().add(augend.inflated()), lhs.scale, mc); } - + /** * Returns an array of length two, the sum of whose entries is * equal to the rounded sum of the {@code BigDecimal} arguments. @@ -1211,27 +1388,26 @@ * that the number of digits of the smaller operand could be * reduced even though the significands partially overlapped. */ - private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, - long padding, MathContext mc) { + private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, long padding, MathContext mc) { assert padding != 0; BigDecimal big; BigDecimal small; - if (padding < 0) { // lhs is big; augend is small - big = lhs; + if (padding < 0) { // lhs is big; augend is small + big = lhs; small = augend; - } else { // lhs is small; augend is big - big = augend; + } else { // lhs is small; augend is big + big = augend; small = lhs; } /* - * This is the estimated scale of an ulp of the result; it - * assumes that the result doesn't have a carry-out on a true - * add (e.g. 999 + 1 => 1000) or any subtractive cancellation - * on borrowing (e.g. 100 - 1.2 => 98.8) + * This is the estimated scale of an ulp of the result; it assumes that + * the result doesn't have a carry-out on a true add (e.g. 999 + 1 => + * 1000) or any subtractive cancellation on borrowing (e.g. 100 - 1.2 => + * 98.8) */ - long estResultUlpScale = (long)big.scale - big.precision() + mc.precision; + long estResultUlpScale = (long) big.scale - big.precision() + mc.precision; /* * The low-order digit position of big is big.scale(). This @@ -1242,11 +1418,10 @@ * disjoint *and* the digit positions of small should not be * directly visible in the result. */ - long smallHighDigitPos = (long)small.scale - small.precision() + 1; - if (smallHighDigitPos > big.scale + 2 && // big and small disjoint + long smallHighDigitPos = (long) small.scale - small.precision() + 1; + if (smallHighDigitPos > big.scale + 2 && // big and small disjoint smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible - small = BigDecimal.valueOf(small.signum(), - this.checkScale(Math.max(big.scale, estResultUlpScale) + 3)); + small = BigDecimal.valueOf(small.signum(), this.checkScale(Math.max(big.scale, estResultUlpScale) + 3)); } // Since addition is symmetric, preserving input order in @@ -1264,7 +1439,22 @@ * @return {@code this - subtrahend} */ public BigDecimal subtract(BigDecimal subtrahend) { - return add(subtrahend.negate()); + if (this.intCompact != INFLATED) { + if ((subtrahend.intCompact != INFLATED)) { + return add(this.intCompact, this.scale, -subtrahend.intCompact, subtrahend.scale); + } else { + return add(this.intCompact, this.scale, subtrahend.intVal.negate(), subtrahend.scale); + } + } else { + if ((subtrahend.intCompact != INFLATED)) { + // Pair of subtrahend values given before pair of + // values from this BigDecimal to avoid need for + // method overloading on the specialized add method + return add(-subtrahend.intCompact, subtrahend.scale, this.intVal, this.scale); + } else { + return add(this.intVal, this.scale, subtrahend.intVal.negate(), subtrahend.scale); + } + } } /** @@ -1282,11 +1472,10 @@ * @since 1.5 */ public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { - BigDecimal nsubtrahend = subtrahend.negate(); if (mc.precision == 0) - return add(nsubtrahend); + return subtract(subtrahend); // share the special rounding code in add() - return add(nsubtrahend, mc); + return add(subtrahend.negate(), mc); } /** @@ -1298,37 +1487,20 @@ * @return {@code this * multiplicand} */ public BigDecimal multiply(BigDecimal multiplicand) { - long x = this.intCompact; - long y = multiplicand.intCompact; - int productScale = checkScale((long)scale + multiplicand.scale); - - // Might be able to do a more clever check incorporating the - // inflated check into the overflow computation. - if (x != INFLATED && y != INFLATED) { - /* - * If the product is not an overflowed value, continue - * to use the compact representation. if either of x or y - * is INFLATED, the product should also be regarded as - * an overflow. Before using the overflow test suggested in - * "Hacker's Delight" section 2-12, we perform quick checks - * using the precision information to see whether the overflow - * would occur since division is expensive on most CPUs. - */ - long product = x * y; - long prec = this.precision() + multiplicand.precision(); - if (prec < 19 || (prec < 21 && (y == 0 || product / y == x))) - return BigDecimal.valueOf(product, productScale); - return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED, - productScale, 0); - } - BigInteger rb; - if (x == INFLATED && y == INFLATED) - rb = this.intVal.multiply(multiplicand.intVal); - else if (x != INFLATED) - rb = multiplicand.intVal.multiply(x); - else - rb = this.intVal.multiply(y); - return new BigDecimal(rb, INFLATED, productScale, 0); + int productScale = checkScale((long) scale + multiplicand.scale); + if (this.intCompact != INFLATED) { + if ((multiplicand.intCompact != INFLATED)) { + return multiply(this.intCompact, multiplicand.intCompact, productScale); + } else { + return multiply(this.intCompact, multiplicand.intVal, productScale); + } + } else { + if ((multiplicand.intCompact != INFLATED)) { + return multiply(multiplicand.intCompact, this.intVal, productScale); + } else { + return multiply(this.intVal, multiplicand.intVal, productScale); + } + } } /** @@ -1345,7 +1517,20 @@ public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { if (mc.precision == 0) return multiply(multiplicand); - return doRound(this.multiply(multiplicand), mc); + int productScale = checkScale((long) scale + multiplicand.scale); + if (this.intCompact != INFLATED) { + if ((multiplicand.intCompact != INFLATED)) { + return multiplyAndRound(this.intCompact, multiplicand.intCompact, productScale, mc); + } else { + return multiplyAndRound(this.intCompact, multiplicand.intVal, productScale, mc); + } + } else { + if ((multiplicand.intCompact != INFLATED)) { + return multiplyAndRound(multiplicand.intCompact, this.intVal, productScale, mc); + } else { + return multiplyAndRound(this.intVal, multiplicand.intVal, productScale, mc); + } + } } /** @@ -1377,120 +1562,21 @@ * @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) { - if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) { - cmpFracHalf = 1; // 2 * r can't fit into long - } else { - cmpFracHalf = longCompareMagnitude(2 * r, ldivisor); - } - } else { - cmpFracHalf = mr.compareHalf(mdivisor); - } - if (cmpFracHalf < 0) - increment = false; // We're closer to higher digit - else if (cmpFracHalf > 0) // We're closer to lower digit - increment = true; - else if (roundingMode == ROUND_HALF_UP) - increment = true; - else if (roundingMode == ROUND_HALF_DOWN) - increment = false; - else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd - increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd(); - } - } - BigDecimal res; - if (isLongDivision) - res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0); - else { - if (increment) - mq.add(MutableBigInteger.ONE); - res = mq.toBigDecimal(qsign, scale); - } - if (isRemainderZero && preferredScale != scale) - res.stripZerosToMatchScale(preferredScale); - return res; + if (this.intCompact != INFLATED) { + if ((divisor.intCompact != INFLATED)) { + return divide(this.intCompact, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode); + } else { + return divide(this.intCompact, this.scale, divisor.intVal, divisor.scale, scale, roundingMode); + } + } else { + if ((divisor.intCompact != INFLATED)) { + return divide(this.intVal, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode); + } else { + return divide(this.intVal, this.scale, divisor.intVal, divisor.scale, scale, roundingMode); + } + } } /** @@ -1541,7 +1627,7 @@ * @see #ROUND_UNNECESSARY */ public BigDecimal divide(BigDecimal divisor, int roundingMode) { - return this.divide(divisor, scale, roundingMode); + return this.divide(divisor, scale, roundingMode); } /** @@ -1588,15 +1674,11 @@ } // 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] : - BigDecimal.valueOf(0, preferredScale); + int preferredScale = saturateLong((long) this.scale - divisor.scale); + + if (this.signum() == 0) // 0/y + return zeroValueOf(preferredScale); else { - this.inflate(); - divisor.inflate(); /* * If the quotient this/divisor has a terminating decimal * expansion, the expansion can have no more than @@ -1623,7 +1705,6 @@ // 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); @@ -1668,38 +1749,23 @@ 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...] + if (dividend.signum() == 0) // 0/y + return zeroValueOf(saturateLong(preferredScale)); int xscale = dividend.precision(); int yscale = divisor.precision(); - dividend = new BigDecimal(dividend.intVal, dividend.intCompact, - xscale, xscale); - divisor = new BigDecimal(divisor.intVal, divisor.intCompact, - yscale, yscale); - if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b) - yscale = divisor.scale -= 1; // [that is, divisor *= 10] - - // In order to find out whether the divide generates the exact result, - // we avoid calling the above divide method. 'quotient' holds the - // return BigDecimal object whose scale will be set to 'scl'. - BigDecimal quotient; - int scl = checkScale(preferredScale + yscale - xscale + mcp); - if (checkScale((long)mcp + yscale) > xscale) - dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY); - else - divisor = divisor.setScale(checkScale((long)xscale - mcp), - ROUND_UNNECESSARY); - quotient = divideAndRound(dividend.intCompact, dividend.intVal, - divisor.intCompact, divisor.intVal, - scl, mc.roundingMode.oldMode, - checkScale(preferredScale)); - // doRound, here, only affects 1000000000 case. - quotient = doRound(quotient, mc); - - return quotient; + if(dividend.intCompact!=INFLATED) { + if(divisor.intCompact!=INFLATED) { + return divide(dividend.intCompact, xscale, divisor.intCompact, yscale, preferredScale, mc); + } else { + return divide(dividend.intCompact, xscale, divisor.intVal, yscale, preferredScale, mc); + } + } else { + if(divisor.intCompact!=INFLATED) { + return divide(dividend.intVal, xscale, divisor.intCompact, yscale, preferredScale, mc); + } else { + return divide(dividend.intVal, xscale, divisor.intVal, yscale, preferredScale, mc); + } + } } /** @@ -1715,13 +1781,13 @@ */ public BigDecimal divideToIntegralValue(BigDecimal divisor) { // Calculate preferred scale - int preferredScale = saturateLong((long)this.scale - divisor.scale); + int preferredScale = saturateLong((long) this.scale - divisor.scale); if (this.compareMagnitude(divisor) < 0) { // much faster when this << divisor - return BigDecimal.valueOf(0, preferredScale); + return zeroValueOf(preferredScale); } - if(this.signum() == 0 && divisor.signum() != 0) + if (this.signum() == 0 && divisor.signum() != 0) return this.setScale(preferredScale, ROUND_UNNECESSARY); // Perform a divide with enough digits to round to a correct @@ -1735,13 +1801,14 @@ RoundingMode.DOWN)); if (quotient.scale > 0) { quotient = quotient.setScale(0, RoundingMode.DOWN); - quotient.stripZerosToMatchScale(preferredScale); + quotient = stripZerosToMatchScale(quotient.intVal, quotient.intCompact, quotient.scale, preferredScale); } if (quotient.scale < preferredScale) { // pad with zeros if necessary quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY); } + return quotient; } @@ -1766,8 +1833,8 @@ * @author Joseph D. Darcy */ public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { - if (mc.precision == 0 || // exact result - (this.compareMagnitude(divisor) < 0) ) // zero result + if (mc.precision == 0 || // exact result + (this.compareMagnitude(divisor) < 0)) // zero result return divideToIntegralValue(divisor); // Calculate preferred scale @@ -1780,8 +1847,7 @@ * digits. Next, remove any fractional digits from the * quotient and adjust the scale to the preferred value. */ - BigDecimal result = this. - divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN)); + BigDecimal result = this.divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN)); if (result.scale() < 0) { /* @@ -1811,8 +1877,7 @@ return result.setScale(result.scale() + Math.min(precisionDiff, preferredScale - result.scale) ); } else { - result.stripZerosToMatchScale(preferredScale); - return result; + return stripZerosToMatchScale(result.intVal,result.intCompact,result.scale,preferredScale); } } @@ -1954,8 +2019,7 @@ // No need to calculate pow(n) if result will over/underflow. // Don't attempt to support "supernormal" numbers. int newScale = checkScale((long)scale * n); - this.inflate(); - return new BigDecimal(intVal.pow(n), newScale); + return new BigDecimal(this.inflated().pow(n), newScale); } @@ -2016,12 +2080,10 @@ throw new ArithmeticException("Invalid operation"); if (n == 0) return ONE; // x**0 == 1 in X3.274 - this.inflate(); BigDecimal lhs = this; MathContext workmc = mc; // working settings int mag = Math.abs(n); // magnitude of n if (mc.precision > 0) { - int elength = longDigitLength(mag); // length of n in digits if (elength > mc.precision) // X3.274 rule throw new ArithmeticException("Invalid operation"); @@ -2044,7 +2106,7 @@ // else (!seenbit) no point in squaring ONE } // if negative n, calculate the reciprocal using working precision - if (n<0) // [hence mc.precision>0] + if (n < 0) // [hence mc.precision>0] acc=ONE.divide(acc, workmc); // round to final precision and strip zeros return doRound(acc, mc); @@ -2083,14 +2145,11 @@ * @return {@code -this}. */ public BigDecimal negate() { - BigDecimal result; - if (intCompact != INFLATED) - result = BigDecimal.valueOf(-intCompact, scale); - else { - result = new BigDecimal(intVal.negate(), scale); - result.precision = precision; + if (intCompact == INFLATED) { + return new BigDecimal(intVal.negate(), INFLATED, scale, precision); + } else { + return valueOf(-intCompact, scale, precision); } - return result; } /** @@ -2186,7 +2245,7 @@ if (s != INFLATED) result = longDigitLength(s); else - result = bigDigitLength(inflate()); + result = bigDigitLength(intVal); precision = result; } return result; @@ -2202,7 +2261,7 @@ * @since 1.2 */ public BigInteger unscaledValue() { - return this.inflate(); + return this.inflated(); } // Rounding Modes @@ -2383,29 +2442,41 @@ 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); + return zeroValueOf(newScale); + if(this.intCompact!=INFLATED) { + long rs = this.intCompact; + if (newScale > oldScale) { + int raise = checkScale((long) newScale - oldScale); + if ((rs = longMultiplyPowerTen(rs, raise)) != INFLATED) { + return valueOf(rs,newScale); + } + BigInteger rb = bigMultiplyPowerTen(raise); + return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0); + } else { + // newScale < oldScale -- drop some digits + // Can't predict the precision due to the effect of rounding. + int drop = checkScale((long) oldScale - newScale); + if (drop < LONG_TEN_POWERS_TABLE.length) { + return divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode, newScale); + } else { + return divideAndRound(this.inflated(), bigTenToThe(drop), newScale, roundingMode, newScale); + } + } + } else { + if (newScale > oldScale) { + int raise = checkScale((long) newScale - oldScale); + BigInteger rb = bigMultiplyPowerTen(this.intVal,raise); + return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0); + } else { + // newScale < oldScale -- drop some digits + // Can't predict the precision due to the effect of rounding. + int drop = checkScale((long) oldScale - newScale); + if (drop < LONG_TEN_POWERS_TABLE.length) + return divideAndRound(this.intVal, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode, + newScale); + else + return divideAndRound(this.intVal, bigTenToThe(drop), newScale, roundingMode, newScale); + } } } @@ -2524,10 +2595,11 @@ * @since 1.5 */ public BigDecimal stripTrailingZeros() { - this.inflate(); - BigDecimal result = new BigDecimal(intVal, scale); - result.stripZerosToMatchScale(Long.MIN_VALUE); - return result; + if(intCompact!=INFLATED) { + return createAndStripZerosToMatchScale(intCompact, scale, Long.MIN_VALUE); + } else { + return createAndStripZerosToMatchScale(intVal, scale, Long.MIN_VALUE); + } } // Comparison Operations @@ -2647,7 +2719,7 @@ } else if (xs != INFLATED) return xs == compactValFor(this.intVal); - return this.inflate().equals(xDec.inflate()); + return this.inflated().equals(xDec.inflated()); } /** @@ -2872,13 +2944,38 @@ * @see #toEngineeringString() */ public String toPlainString() { - BigDecimal bd = this; - if (bd.scale < 0) - bd = bd.setScale(0); - bd.inflate(); - if (bd.scale == 0) // No decimal point - return bd.intVal.toString(); - return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale); + if(scale==0) { + if(intCompact!=INFLATED) { + return Long.toString(intCompact); + } else { + return intVal.toString(); + } + } + if(this.scale<0) { // No decimal point + if(signum()==0) { + return "0"; + } + int tailingZeros = checkScaleNonZero((-(long)scale)); + StringBuilder buf; + if(intCompact!=INFLATED) { + buf = new StringBuilder(20+tailingZeros); + buf.append(intCompact); + } else { + String str = intVal.toString(); + buf = new StringBuilder(str.length()+tailingZeros); + buf.append(str); + } + for (int i = 0; i < tailingZeros; i++) + buf.append('0'); + return buf.toString(); + } + String str ; + if(intCompact!=INFLATED) { + str = Long.toString(Math.abs(intCompact)); + } else { + str = intVal.abs().toString(); + } + return getValueString(signum(), str, scale); } /* Returns a digit.digit string */ @@ -2922,7 +3019,7 @@ */ public BigInteger toBigInteger() { // force to an integer, quietly - return this.setScale(0, ROUND_DOWN).inflate(); + return this.setScale(0, ROUND_DOWN).inflated(); } /** @@ -2937,7 +3034,7 @@ */ public BigInteger toBigIntegerExact() { // round to an integer, with Exception if decimal part non-0 - return this.setScale(0, ROUND_UNNECESSARY).inflate(); + return this.setScale(0, ROUND_UNNECESSARY).inflated(); } /** @@ -2990,7 +3087,7 @@ BigDecimal num = this.setScale(0, ROUND_UNNECESSARY); if (num.precision() >= 19) // need to check carefully LongOverflow.check(num); - return num.inflate().longValue(); + return num.inflated().longValue(); } private static class LongOverflow { @@ -3001,9 +3098,9 @@ private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE); public static void check(BigDecimal num) { - num.inflate(); - if ((num.intVal.compareTo(LONGMIN) < 0) || - (num.intVal.compareTo(LONGMAX) > 0)) + BigInteger intVal = num.inflated(); + if (intVal.compareTo(LONGMIN) < 0 || + intVal.compareTo(LONGMAX) > 0) throw new java.lang.ArithmeticException("Overflow"); } } @@ -3107,8 +3204,25 @@ * @return this {@code BigDecimal} converted to a {@code float}. */ public float floatValue(){ - if (scale == 0 && intCompact != INFLATED) + if(intCompact != INFLATED) { + if (scale == 0) { return (float)intCompact; + } else { + /* + * If both intCompact and the scale can be exactly + * represented as float values, perform a single float + * multiply or divide to compute the (properly + * rounded) result. + */ + if (scale > 0 && scale < float10pow.length + && intCompact > -1L<<22 && intCompact < 1L<<22) { + return (float)intCompact / float10pow[scale]; + } else if (scale < 0 && scale > -float10pow.length + && intCompact > -1L<<22 && intCompact < 1L<<22) { + return (float)intCompact * float10pow[-scale]; + } + } + } // Somewhat inefficient, but guaranteed to work. return Float.parseFloat(this.toString()); } @@ -3130,13 +3244,50 @@ * @return this {@code BigDecimal} converted to a {@code double}. */ public double doubleValue(){ - if (scale == 0 && intCompact != INFLATED) - return (double)intCompact; + if(intCompact != INFLATED) { + if (scale == 0) { + return (double)intCompact; + } else { + /* + * If both intCompact and the scale can be exactly + * represented as double values, perform a single + * double multiply or divide to compute the (properly + * rounded) result. + */ + if (scale > 0 && scale < double10pow.length + && intCompact > -1L<<52 && intCompact < 1L<<52) { + return (double)intCompact / double10pow[scale]; + } else if (scale < 0 && scale > -double10pow.length + && intCompact > -1L<<52 && intCompact < 1L<<52) { + return (double)intCompact * double10pow[-scale]; + } + } + } // Somewhat inefficient, but guaranteed to work. return Double.parseDouble(this.toString()); } /** + * Powers of 10 which can be represented exactly in {@code + * double}. + */ + private static final double double10pow[] = { + 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, + 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, + 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, + 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22 + }; + + /** + * Powers of 10 which can be represented exactly in {@code + * float}. + */ + private static final float float10pow[] = { + 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, + 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f + }; + + /** * Returns the size of an ulp, a unit in the last place, of this * {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal} * value is the positive distance between this value and the @@ -3151,10 +3302,9 @@ * @since 1.5 */ public BigDecimal ulp() { - return BigDecimal.valueOf(1, this.scale()); + return BigDecimal.valueOf(1, this.scale(), 1); } - // Private class to build a string representation for BigDecimal object. // "StringBuilderHelper" is constructed as a thread local variable so it is // thread safe. The StringBuilder field acts as a buffer to hold the temporary @@ -3268,6 +3418,15 @@ return (intCompact != INFLATED) ? Long.toString(intCompact): intVal.toString(); + if (scale == 2 && + intCompact >= 0 && intCompact < Integer.MAX_VALUE) { + // currency fast path + int lowInt = (int)intCompact % 100; + int highInt = (int)intCompact / 100; + return (Integer.toString(highInt) + '.' + + StringBuilderHelper.DIGIT_TENS[lowInt] + + StringBuilderHelper.DIGIT_ONES[lowInt]) ; + } StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get(); char[] coeff; @@ -3377,7 +3536,7 @@ tenpow[0] = '1'; for (int i = 1; i <= n; i++) tenpow[i] = '0'; - return new BigInteger(tenpow); + return new BigInteger(tenpow,1, tenpow.length); } /** @@ -3433,11 +3592,16 @@ 1000000000000000000L // 18 / 10^18 }; - private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE, - BigInteger.valueOf(10), BigInteger.valueOf(100), - BigInteger.valueOf(1000), BigInteger.valueOf(10000), - BigInteger.valueOf(100000), BigInteger.valueOf(1000000), - BigInteger.valueOf(10000000), BigInteger.valueOf(100000000), + private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = { + BigInteger.ONE, + BigInteger.valueOf(10), + BigInteger.valueOf(100), + BigInteger.valueOf(1000), + BigInteger.valueOf(10000), + BigInteger.valueOf(100000), + BigInteger.valueOf(1000000), + BigInteger.valueOf(10000000), + BigInteger.valueOf(100000000), BigInteger.valueOf(1000000000), BigInteger.valueOf(10000000000L), BigInteger.valueOf(100000000000L), @@ -3502,7 +3666,7 @@ */ private BigInteger bigMultiplyPowerTen(int n) { if (n <= 0) - return this.inflate(); + return this.inflated(); if (intCompact != INFLATED) return bigTenToThe(n).multiply(intCompact); @@ -3511,12 +3675,13 @@ } /** - * Assign appropriate BigInteger to intVal field if intVal is + * Returns appropriate BigInteger from intVal field if intVal is * null, i.e. the compact representation is in use. */ - private BigInteger inflate() { - if (intVal == null) - intVal = BigInteger.valueOf(intCompact); + private BigInteger inflated() { + if (intVal == null) { + return BigInteger.valueOf(intCompact); + } return intVal; } @@ -3543,6 +3708,28 @@ } } + private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + private static final long intCompactOffset; + private static final long intValOffset; + static { + try { + intCompactOffset = unsafe.objectFieldOffset + (BigDecimal.class.getDeclaredField("intCompact")); + intValOffset = unsafe.objectFieldOffset + (BigDecimal.class.getDeclaredField("intVal")); + } catch (Exception ex) { + throw new Error(ex); + } + } + + private void setIntCompactVolatile(long val) { + unsafe.putLongVolatile(this, intCompactOffset, val); + } + + private void setIntValVolatile(BigInteger val) { + unsafe.putObjectVolatile(this, intValOffset, val); + } + /** * Reconstitute the {@code BigDecimal} instance from a stream (that is, * deserialize it). @@ -3559,7 +3746,7 @@ throw new java.io.StreamCorruptedException(message); // [all values of scale are now allowed] } - intCompact = compactValFor(intVal); + setIntCompactVolatile(compactValFor(intVal)); } /** @@ -3570,50 +3757,40 @@ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Must inflate to maintain compatible serial form. - this.inflate(); - - // Write proper fields + if (this.intVal == null) + this.setIntValVolatile(BigInteger.valueOf(this.intCompact)); s.defaultWriteObject(); } - /** * Returns the length of the absolute value of a {@code long}, in decimal * digits. * - * @param x the {@code long} + * @param x + * the {@code long} * @return the length of the unscaled value, in deciaml digits. */ - private static int longDigitLength(long x) { + static int longDigitLength(long x) { /* * As described in "Bit Twiddling Hacks" by Sean Anderson, - * (http://graphics.stanford.edu/~seander/bithacks.html) - * integer log 10 of x is within 1 of - * (1233/4096)* (1 + integer log 2 of x). - * The fraction 1233/4096 approximates log10(2). So we first - * do a version of log2 (a variant of Long class with - * pre-checks and opposite directionality) and then scale and - * check against powers table. This is a little simpler in - * present context than the version in Hacker's Delight sec - * 11-4. Adding one to bit length allows comparing downward + * (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; + assert x != BigDecimal.INFLATED; if (x < 0) x = -x; if (x < 10) // must screen for 0, might as well 10 return 1; - int n = 64; // not 63, to avoid needing to add 1 later - int y = (int)(x >>> 32); - if (y == 0) { n -= 32; y = (int)x; } - if (y >>> 16 == 0) { n -= 16; y <<= 16; } - if (y >>> 24 == 0) { n -= 8; y <<= 8; } - if (y >>> 28 == 0) { n -= 4; y <<= 4; } - if (y >>> 30 == 0) { n -= 2; y <<= 2; } - int r = (((y >>> 31) + n) * 1233) >>> 12; + int r = ((64 - Long.numberOfLeadingZeros(x) + 1) * 1233) >>> 12; long[] tab = LONG_TEN_POWERS_TABLE; // if r >= length, must have max possible digits for long - return (r >= tab.length || x < tab[r])? r : r+1; + return (r >= tab.length || x < tab[r]) ? r : r + 1; } /** @@ -3635,41 +3812,6 @@ return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1; } - - /** - * Remove insignificant trailing zeros from this - * {@code BigDecimal} until the preferred scale is reached or no - * more zeros can be removed. If the preferred scale is less than - * Integer.MIN_VALUE, all the trailing zeros will be removed. - * - * {@code BigInteger} assistance could help, here? - * - *
WARNING: This method should only be called on new objects as - * it mutates the value fields. - * - * @return this {@code BigDecimal} with a scale possibly reduced - * to be closed to the preferred scale. - */ - private BigDecimal stripZerosToMatchScale(long preferredScale) { - this.inflate(); - BigInteger qr[]; // quotient-remainder pair - while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 && - scale > preferredScale) { - if (intVal.testBit(0)) - break; // odd number cannot end in 0 - qr = intVal.divideAndRemainder(BigInteger.TEN); - if (qr[1].signum() != 0) - break; // non-0 remainder - intVal=qr[0]; - scale = checkScale((long)scale-1); // could Overflow - if (precision > 0) // adjust precision if known - precision--; - } - if (intVal != null) - intCompact = compactValFor(intVal); - return this; - } - /** * Check a scale for Underflow or Overflow. If this BigDecimal is * nonzero, throw an exception if the scale is outof range. If this @@ -3693,74 +3835,7 @@ return asInt; } - /** - * Round an operand; used only if digits > 0. Does not change - * {@code this}; if rounding is needed a new {@code BigDecimal} - * is created and returned. - * - * @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. - * - *
WARNING: This method should only be called on new objects as
- * it mutates the value fields.
- *
- * @param mc the context to use.
- * @throws ArithmeticException if the rounding mode is
- * {@code RoundingMode.UNNECESSARY} and the
- * {@code BigDecimal} operation would require rounding.
- */
- private void roundThis(MathContext mc) {
- BigDecimal rounded = doRound(this, mc);
- if (rounded == this) // wasn't rounded
- return;
- this.intVal = rounded.intVal;
- this.intCompact = rounded.intCompact;
- this.scale = rounded.scale;
- this.precision = rounded.precision;
- }
-
- /**
- * Returns a {@code BigDecimal} rounded according to the
- * MathContext settings; used only if {@code mc.precision > 0}.
- * Does not change {@code this}; if rounding is needed a new
- * {@code BigDecimal} is created and returned.
- *
- * @param mc the context to use.
- * @return a {@code BigDecimal} rounded according to the MathContext
- * settings. May return this, if no rounding needed.
- * @throws ArithmeticException if the rounding mode is
- * {@code RoundingMode.UNNECESSARY} and the
- * result is inexact.
- */
- private static BigDecimal doRound(BigDecimal d, MathContext mc) {
- int mcp = mc.precision;
- int drop;
- // This might (rarely) iterate to cover the 999=>1000 case
- while ((drop = d.precision() - mcp) > 0) {
- int newScale = d.checkScale((long)d.scale - drop);
- int mode = mc.roundingMode.oldMode;
- if (drop < LONG_TEN_POWERS_TABLE.length)
- d = divideAndRound(d.intCompact, d.intVal,
- LONG_TEN_POWERS_TABLE[drop], null,
- newScale, mode, newScale);
- else
- d = divideAndRound(d.intCompact, d.intVal,
- INFLATED, bigTenToThe(drop),
- newScale, mode, newScale);
- }
- return d;
- }
-
- /**
+ /**
* Returns the compact value for given {@code BigInteger}, or
* INFLATED if too big. Relies on internal representation of
* {@code BigInteger}.
@@ -3852,4 +3927,1307 @@
}
return this;
}
+
+ /* the same as checkScale where value!=0 */
+ private static int checkScaleNonZero(long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ private static int checkScale(long intCompact, long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ if (intCompact != 0)
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ private static int checkScale(BigInteger intVal, long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ if (intVal.signum() != 0)
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ /**
+ * Returns a {@code BigDecimal} rounded according to the MathContext
+ * settings;
+ * If rounding is needed a new {@code BigDecimal} is created and returned.
+ *
+ * @param val the value to be rounded
+ * @param mc the context to use.
+ * @return a {@code BigDecimal} rounded according to the MathContext
+ * settings. May return {@code value}, if no rounding needed.
+ * @throws ArithmeticException if the rounding mode is
+ * {@code RoundingMode.UNNECESSARY} and the
+ * result is inexact.
+ */
+ private static BigDecimal doRound(BigDecimal val, MathContext mc) {
+ int mcp = mc.precision;
+ boolean wasDivided = false;
+ if (mcp > 0) {
+ BigInteger intVal = val.intVal;
+ long compactVal = val.intCompact;
+ int scale = val.scale;
+ int prec = val.precision();
+ int mode = mc.roundingMode.oldMode;
+ int drop;
+ if (compactVal == INFLATED) {
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ wasDivided = true;
+ compactVal = compactValFor(intVal);
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ wasDivided = true;
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ intVal = null;
+ }
+ }
+ return wasDivided ? new BigDecimal(intVal,compactVal,scale,prec) : val;
+ }
+ return val;
+ }
+
+ /*
+ * Returns a {@code BigDecimal} created from {@code long} value with
+ * given scale rounded according to the MathContext settings
+ */
+ private static BigDecimal doRound(long compactVal, int scale, MathContext mc) {
+ int mcp = mc.precision;
+ if (mcp > 0 && mcp<19) {
+ int prec = longDigitLength(compactVal);
+ int drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ return valueOf(compactVal, scale, prec);
+ }
+ return valueOf(compactVal, scale);
+ }
+
+ /*
+ * Returns a {@code BigDecimal} created from {@code BigInteger} value with
+ * given scale rounded according to the MathContext settings
+ */
+ private static BigDecimal doRound(BigInteger intVal, int scale, MathContext mc) {
+ int mcp = mc.precision;
+ int prec = 0;
+ if (mcp > 0) {
+ long compactVal = compactValFor(intVal);
+ int mode = mc.roundingMode.oldMode;
+ int drop;
+ if (compactVal == INFLATED) {
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ compactVal = compactValFor(intVal);
+ if (compactVal != INFLATED) {
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ return valueOf(compactVal,scale,prec);
+ }
+ }
+ return new BigDecimal(intVal,INFLATED,scale,prec);
+ }
+
+ /*
+ * Divides {@code BigInteger} value by ten power.
+ */
+ private static BigInteger divideAndRoundByTenPow(BigInteger intVal, int tenPow, int roundingMode) {
+ if (tenPow < LONG_TEN_POWERS_TABLE.length)
+ intVal = divideAndRound(intVal, LONG_TEN_POWERS_TABLE[tenPow], roundingMode);
+ else
+ intVal = divideAndRound(intVal, bigTenToThe(tenPow), roundingMode);
+ return intVal;
+ }
+
+ /**
+ * Internally used for division operation for division {@code long} by
+ * {@code long}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(long ldividend, long ldivisor, int scale, int roundingMode,
+ int preferredScale) {
+
+ int qsign; // quotient sign
+ long q = ldividend / ldivisor; // store quotient in long
+ if (roundingMode == ROUND_DOWN && scale == preferredScale)
+ return valueOf(q, scale);
+ long r = ldividend % ldivisor; // store remainder in long
+ qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+ if (r != 0) {
+ boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
+ return valueOf((increment ? q + qsign : q), scale);
+ } else {
+ if (preferredScale != scale)
+ return createAndStripZerosToMatchScale(q, scale, preferredScale);
+ else
+ return valueOf(q, scale);
+ }
+ }
+
+ /**
+ * Divides {@code long} by {@code long} and do rounding based on the
+ * passed in roundingMode.
+ */
+ private static long divideAndRound(long ldividend, long ldivisor, int roundingMode) {
+ int qsign; // quotient sign
+ long q = ldividend / ldivisor; // store quotient in long
+ if (roundingMode == ROUND_DOWN)
+ return q;
+ long r = ldividend % ldivisor; // store remainder in long
+ qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+ if (r != 0) {
+ boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
+ return increment ? q + qsign : q;
+ } else {
+ return q;
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(long ldivisor, int roundingMode,
+ int qsign, long q, long r) {
+ boolean increment = false;
+ 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 (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
+ cmpFracHalf = 1; // 2 * r can't fit into long
+ } else {
+ cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+ }
+ if (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 = (q & 1L) != 0L ;
+ }
+ return increment;
+ }
+
+ /**
+ * Divides {@code BigInteger} value by {@code long} value and
+ * do rounding based on the passed in roundingMode.
+ */
+ private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ long r = 0; // store quotient & remainder in long
+ MutableBigInteger mq = null; // store quotient
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ mq = new MutableBigInteger();
+ r = mdividend.divide(ldivisor, mq);
+ isRemainderZero = (r == 0);
+ qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ if (!isRemainderZero) {
+ if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ }
+ return mq.toBigInteger(qsign);
+ }
+
+ /**
+ * Internally used for division operation for division {@code BigInteger}
+ * by {@code long}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(BigInteger bdividend,
+ long ldivisor, int scale, int roundingMode, int preferredScale) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ long r = 0; // store quotient & remainder in long
+ MutableBigInteger mq = null; // store quotient
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ mq = new MutableBigInteger();
+ r = mdividend.divide(ldivisor, mq);
+ isRemainderZero = (r == 0);
+ qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ if (!isRemainderZero) {
+ if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ return mq.toBigDecimal(qsign, scale);
+ } else {
+ if (preferredScale != scale) {
+ long compactVal = mq.toCompactValue(qsign);
+ if(compactVal!=INFLATED) {
+ return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
+ }
+ BigInteger intVal = mq.toBigInteger(qsign);
+ return createAndStripZerosToMatchScale(intVal,scale, preferredScale);
+ } else {
+ return mq.toBigDecimal(qsign, scale);
+ }
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(long ldivisor, int roundingMode,
+ int qsign, MutableBigInteger mq, long r) {
+ boolean increment = false;
+ /* 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 {
+ int cmpFracHalf;
+ if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
+ cmpFracHalf = 1; // 2 * r can't fit into long
+ } else {
+ cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+ }
+ 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 = mq.isOdd();
+ }
+ return increment;
+ }
+
+ /**
+ * Divides {@code BigInteger} value by {@code BigInteger} value and
+ * do rounding based on the passed in roundingMode.
+ */
+ private static BigInteger divideAndRound(BigInteger bdividend, BigInteger bdivisor, int roundingMode) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ MutableBigInteger mq = new MutableBigInteger();
+ MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
+ MutableBigInteger mr = mdividend.divide(mdivisor, mq);
+ isRemainderZero = mr.isZero();
+ qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
+ if (!isRemainderZero) {
+ if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ }
+ return mq.toBigInteger(qsign);
+ }
+
+ /**
+ * Internally used for division operation for division {@code BigInteger}
+ * by {@code BigInteger}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(BigInteger bdividend, BigInteger bdivisor, int scale, int roundingMode,
+ int preferredScale) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ MutableBigInteger mq = new MutableBigInteger();
+ MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
+ MutableBigInteger mr = mdividend.divide(mdivisor, mq);
+ isRemainderZero = mr.isZero();
+ qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
+ if (!isRemainderZero) {
+ if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ return mq.toBigDecimal(qsign, scale);
+ } else {
+ if (preferredScale != scale) {
+ long compactVal = mq.toCompactValue(qsign);
+ if (compactVal != INFLATED) {
+ return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
+ }
+ BigInteger intVal = mq.toBigInteger(qsign);
+ return createAndStripZerosToMatchScale(intVal, scale, preferredScale);
+ } else {
+ return mq.toBigDecimal(qsign, scale);
+ }
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMode, int qsign, MutableBigInteger mq,
+ MutableBigInteger mr) {
+ boolean increment = false;
+ /* 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 {
+ int 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 = mq.isOdd();
+ }
+ return increment;
+ }
+
+ /**
+ * Remove insignificant trailing zeros from this
+ * {@code BigInteger} value until the preferred scale is reached or no
+ * more zeros can be removed. If the preferred scale is less than
+ * Integer.MIN_VALUE, all the trailing zeros will be removed.
+ *
+ * @return new {@code BigDecimal} with a scale possibly reduced
+ * to be closed to the preferred scale.
+ */
+ private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) {
+ BigInteger qr[]; // quotient-remainder pair
+ while (intVal.compareMagnitude(BigInteger.TEN) >= 0
+ && scale > preferredScale) {
+ if (intVal.testBit(0))
+ break; // odd number cannot end in 0
+ qr = intVal.divideAndRemainder(BigInteger.TEN);
+ if (qr[1].signum() != 0)
+ break; // non-0 remainder
+ intVal = qr[0];
+ scale = checkScale(intVal,(long) scale - 1); // could Overflow
+ }
+ return valueOf(intVal, scale, 0);
+ }
+
+ /**
+ * Remove insignificant trailing zeros from this
+ * {@code long} value until the preferred scale is reached or no
+ * more zeros can be removed. If the preferred scale is less than
+ * Integer.MIN_VALUE, all the trailing zeros will be removed.
+ *
+ * @return new {@code BigDecimal} with a scale possibly reduced
+ * to be closed to the preferred scale.
+ */
+ private static BigDecimal createAndStripZerosToMatchScale(long compactVal, int scale, long preferredScale) {
+ while (Math.abs(compactVal) >= 10L && scale > preferredScale) {
+ if ((compactVal & 1L) != 0L)
+ break; // odd number cannot end in 0
+ long r = compactVal % 10L;
+ if (r != 0L)
+ break; // non-0 remainder
+ compactVal /= 10;
+ scale = checkScale(compactVal, (long) scale - 1); // could Overflow
+ }
+ return valueOf(compactVal, scale);
+ }
+
+ private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, int preferredScale) {
+ if(intCompact!=INFLATED) {
+ return createAndStripZerosToMatchScale(intCompact, scale, preferredScale);
+ } else {
+ return createAndStripZerosToMatchScale(intVal==null ? INFLATED_BIGINT : intVal,
+ scale, preferredScale);
+ }
+ }
+
+ /*
+ * returns INFLATED if oveflow
+ */
+ private static long add(long xs, long ys){
+ long sum = xs + ys;
+ // See "Hacker's Delight" section 2-12 for explanation of
+ // the overflow test.
+ if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) { // not overflowed
+ return sum;
+ }
+ return INFLATED;
+ }
+
+ private static BigDecimal add(long xs, long ys, int scale){
+ long sum = add(xs, ys);
+ if (sum!=INFLATED)
+ return BigDecimal.valueOf(sum, scale);
+ return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale);
+ }
+
+ private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) {
+ long sdiff = (long) scale1 - scale2;
+ if (sdiff == 0) {
+ return add(xs, ys, scale1);
+ } else if (sdiff < 0) {
+ int raise = checkScale(xs,-sdiff);
+ long scaledX = longMultiplyPowerTen(xs, raise);
+ if (scaledX != INFLATED) {
+ return add(scaledX, ys, scale2);
+ } else {
+ BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys);
+ return ((xs^ys)>=0) ? // same sign test
+ new BigDecimal(bigsum, INFLATED, scale2, 0)
+ : valueOf(bigsum, scale2, 0);
+ }
+ } else {
+ int raise = checkScale(ys,sdiff);
+ long scaledY = longMultiplyPowerTen(ys, raise);
+ if (scaledY != INFLATED) {
+ return add(xs, scaledY, scale1);
+ } else {
+ BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs);
+ return ((xs^ys)>=0) ?
+ new BigDecimal(bigsum, INFLATED, scale1, 0)
+ : valueOf(bigsum, scale1, 0);
+ }
+ }
+ }
+
+ private static BigDecimal add(final long xs, int scale1, BigInteger snd, int scale2) {
+ int rscale = scale1;
+ long sdiff = (long)rscale - scale2;
+ boolean sameSigns = (Long.signum(xs) == snd.signum);
+ BigInteger sum;
+ if (sdiff < 0) {
+ int raise = checkScale(xs,-sdiff);
+ rscale = scale2;
+ long scaledX = longMultiplyPowerTen(xs, raise);
+ if (scaledX == INFLATED) {
+ sum = snd.add(bigMultiplyPowerTen(xs,raise));
+ } else {
+ sum = snd.add(scaledX);
+ }
+ } else { //if (sdiff > 0) {
+ int raise = checkScale(snd,sdiff);
+ snd = bigMultiplyPowerTen(snd,raise);
+ sum = snd.add(xs);
+ }
+ return (sameSigns) ?
+ new BigDecimal(sum, INFLATED, rscale, 0) :
+ valueOf(sum, rscale, 0);
+ }
+
+ private static BigDecimal add(BigInteger fst, int scale1, BigInteger snd, int scale2) {
+ int rscale = scale1;
+ long sdiff = (long)rscale - scale2;
+ if (sdiff != 0) {
+ if (sdiff < 0) {
+ int raise = checkScale(fst,-sdiff);
+ rscale = scale2;
+ fst = bigMultiplyPowerTen(fst,raise);
+ } else {
+ int raise = checkScale(snd,sdiff);
+ snd = bigMultiplyPowerTen(snd,raise);
+ }
+ }
+ BigInteger sum = fst.add(snd);
+ return (fst.signum == snd.signum) ?
+ new BigDecimal(sum, INFLATED, rscale, 0) :
+ valueOf(sum, rscale, 0);
+ }
+
+ private static BigInteger bigMultiplyPowerTen(long value, int n) {
+ if (n <= 0)
+ return BigInteger.valueOf(value);
+ return bigTenToThe(n).multiply(value);
+ }
+
+ private static BigInteger bigMultiplyPowerTen(BigInteger value, int n) {
+ if (n <= 0)
+ return value;
+ if(n