--- old/src/share/classes/java/math/BigDecimal.java 2011-09-01 22:59:25.000000000 -0700 +++ new/src/share/classes/java/math/BigDecimal.java 2011-09-01 22:59:24.000000000 -0700 @@ -215,6 +215,7 @@ * @author Josh Bloch * @author Mike Cowlishaw * @author Joseph D. Darcy + * @author Sergey V. Kuksenko */ public class BigDecimal extends Number implements Comparable { /** @@ -224,7 +225,7 @@ * @serial * @see #unscaledValue */ - private volatile BigInteger intVal; + private final BigInteger intVal; /** * The scale of this BigDecimal, as returned by {@link #scale}. @@ -232,8 +233,9 @@ * @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 +258,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 +284,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,9 +380,36 @@ * @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) - throw new NumberFormatException(); + if (offset + len > in.length || offset < 0) + throw new NumberFormatException("Bad offset or len arguments for char[] input."); // This is the primary string to BigDecimal constructor; all // incoming strings end up here; it uses explicit (inline) // parsing for speed and generates at most one intermediate @@ -391,7 +420,6 @@ int scl = 0; // record scale value long rs = 0; // the compact value in long BigInteger rb = null; // the inflated value in BigInteger - // use array bounds checking to handle too-long, len == 0, // bad offset, etc. try { @@ -408,23 +436,39 @@ // 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) { + 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,44 @@ ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; } - } else { // the unscaled value is likely a BigInteger object. + if (dot) + ++scl; + } else if ((c == 'e') || (c == 'E')) { + exp = parseExp(in, offset, len); + // Next test is required for backwards compatibility + if ((int) exp != exp) // overflow + throw new NumberFormatException(); + break; // [saves a test] + } else { + throw new NumberFormatException(); + } + } + if (prec == 0) // no digits found + throw new NumberFormatException(); + // Adjust scale if exp is not zero. + if (exp != 0) { // had significant exponent + scl = adjustScale(scl, exp); + } + rs = isneg ? -rs : rs; + int mcp = mc.precision; + int drop = prec - mcp; // prec has range [1, MAX_INT], mcp has range [0, MAX_INT]; + // therefore, this subtract cannot overflow + if (mcp > 0 && drop > 0) { // do rounding + while (drop > 0) { + scl = checkScaleNonZero((long) scl - drop); + rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(rs); + drop = prec - mcp; + } + } + } else { + char coeff[] = new char[len]; + for (; len > 0; offset++, len--) { + c = in[offset]; + // have digit + if ((c >= '0' && c <= '9') || Character.isDigit(c)) { + // First compact case, we need not to preserve the character + // and we can just compute the value in place. if (c == '0' || Character.digit(c, 10) == 0) { if (prec == 0) { coeff[idx] = c; @@ -452,94 +533,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 +600,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 +830,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 +878,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 +900,86 @@ * @since 1.5 */ public BigDecimal(double val, MathContext mc) { - this(val); - if (mc.precision > 0) - roundThis(mc); + if (Double.isInfinite(val) || Double.isNaN(val)) + throw new NumberFormatException("Infinite or NaN"); + // Translate the double into sign, exponent and significand, according + // to the formulae in JLS, Section 20.10.22. + int sign = (val >= 0.0 ? 1 : -1); // Preserving sign of zero doesn't matter + int exponent = Math.getExponent(val); + long valBits = Double.doubleToLongBits(val); + long significand = (exponent == (Double.MIN_EXPONENT-1) + ? (valBits & ((1L << 52) - 1)) << 1 + : (valBits & ((1L << 52) - 1)) | (1L << 52)); + // At this point, val == sign * significand * 2**exponent. + + /* + * Special case zero to supress nonterminating normalization and bogus + * scale calculation. + */ + if (significand == 0) { + this.intVal = BigInteger.ZERO; + this.scale = 0; + this.intCompact = 0; + this.precision = 1; + return; + } + // Normalize + while ((significand & 1) == 0) { // i.e., significand is even + significand >>= 1; + exponent++; + } + int scale = 0; + // Calculate intVal and scale + BigInteger intVal; + long compactVal = sign * significand; + if (exponent == 0) { + // If the exponent is zero, the significant fits in a long + assert compactVal != INFLATED; + intVal = null; + } else { + if (exponent < 0) { + intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal); + scale = -exponent; + } else { // (exponent > 0) + intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal); + } + compactVal = compactValFor(intVal); + } + int prec = 0; + int mcp = mc.precision; + if (mcp > 0) { // do rounding + int mode = mc.roundingMode.oldMode; + int drop; + if (compactVal == INFLATED) { + prec = bigDigitLength(intVal); + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + intVal = divideAndRoundByTenPow(intVal, drop, mode); + compactVal = compactValFor(intVal); + if (compactVal != INFLATED) { + break; + } + prec = bigDigitLength(intVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + intVal = null; + } + } + this.intVal = intVal; + this.intCompact = compactVal; + this.scale = scale; + this.precision = prec; } /** @@ -881,8 +990,9 @@ * {@code BigDecimal}. */ public BigDecimal(BigInteger val) { + scale = 0; + intVal = val; intCompact = compactValFor(val); - intVal = (intCompact != INFLATED) ? null : val; } /** @@ -898,9 +1008,7 @@ * @since 1.5 */ public BigDecimal(BigInteger val, MathContext mc) { - this(val); - if (mc.precision > 0) - roundThis(mc); + this(val,0,mc); } /** @@ -914,7 +1022,8 @@ */ public BigDecimal(BigInteger unscaledVal, int scale) { // Negative scales are now allowed - this(unscaledVal); + this.intVal = unscaledVal; + this.intCompact = compactValFor(unscaledVal); this.scale = scale; } @@ -934,10 +1043,41 @@ * @since 1.5 */ public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { - this(unscaledVal); + long compactVal = compactValFor(unscaledVal); + int mcp = mc.precision; + int prec = 0; + if (mcp > 0) { // do rounding + int mode = mc.roundingMode.oldMode; + if (compactVal == INFLATED) { + prec = bigDigitLength(unscaledVal); + int drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + unscaledVal = divideAndRoundByTenPow(unscaledVal, drop, mode); + compactVal = compactValFor(unscaledVal); + if (compactVal != INFLATED) { + break; + } + prec = bigDigitLength(unscaledVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + int drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + unscaledVal = null; + } + } + this.intVal = unscaledVal; + this.intCompact = compactVal; this.scale = scale; - if (mc.precision > 0) - roundThis(mc); + this.precision = prec; } /** @@ -949,7 +1089,9 @@ * @since 1.5 */ public BigDecimal(int val) { - intCompact = val; + this.intCompact = val; + this.scale = 0; + this.intVal = null; } /** @@ -964,9 +1106,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 +1135,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 +1151,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 +1207,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 +1229,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 +1294,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 +1328,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. { @@ -1150,20 +1338,14 @@ int preferredScale = Math.max(lhs.scale(), augend.scale()); BigDecimal result; - // Could use a factory for zero instead of a new object if (lhsIsZero && augendIsZero) - return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0); - + return zeroValueOf(preferredScale); result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc); if (result.scale() == preferredScale) return result; else if (result.scale() > preferredScale) { - BigDecimal scaledResult = - new BigDecimal(result.intVal, result.intCompact, - result.scale, 0); - scaledResult.stripZerosToMatchScale(preferredScale); - return scaledResult; + return stripZerosToMatchScale(result.intVal, result.intCompact, result.scale, preferredScale); } else { // result.scale < preferredScale int precisionDiff = mc.precision - result.precision(); int scaleDiff = preferredScale - result.scale(); @@ -1176,17 +1358,14 @@ } } - 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); } /** @@ -1211,27 +1390,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 +1420,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 +1441,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 +1474,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 +1489,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 +1519,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 +1564,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 +1629,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 +1676,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 +1707,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 +1751,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 +1783,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 +1803,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 +1835,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 +1849,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 +1879,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 +2021,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 +2082,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 +2108,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 +2147,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 +2247,7 @@ if (s != INFLATED) result = longDigitLength(s); else - result = bigDigitLength(inflate()); + result = bigDigitLength(intVal); precision = result; } return result; @@ -2202,7 +2263,7 @@ * @since 1.2 */ public BigInteger unscaledValue() { - return this.inflate(); + return this.inflated(); } // Rounding Modes @@ -2383,29 +2444,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 +2597,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 +2721,7 @@ } else if (xs != INFLATED) return xs == compactValFor(this.intVal); - return this.inflate().equals(xDec.inflate()); + return this.inflated().equals(xDec.inflated()); } /** @@ -2872,13 +2946,38 @@ * @see #toEngineeringString() */ public String toPlainString() { - BigDecimal bd = this; - if (bd.scale < 0) - bd = bd.setScale(0); - bd.inflate(); - if (bd.scale == 0) // No decimal point - return bd.intVal.toString(); - return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale); + if(scale==0) { + if(intCompact!=INFLATED) { + return Long.toString(intCompact); + } else { + return intVal.toString(); + } + } + if(this.scale<0) { // No decimal point + if(signum()==0) { + return "0"; + } + int tailingZeros = checkScaleNonZero((-(long)scale)); + StringBuilder buf; + if(intCompact!=INFLATED) { + buf = new StringBuilder(20+tailingZeros); + buf.append(intCompact); + } else { + String str = intVal.toString(); + buf = new StringBuilder(str.length()+tailingZeros); + buf.append(str); + } + for (int i = 0; i < tailingZeros; i++) + buf.append('0'); + return buf.toString(); + } + String str ; + if(intCompact!=INFLATED) { + str = Long.toString(Math.abs(intCompact)); + } else { + str = intVal.abs().toString(); + } + return getValueString(signum(), str, scale); } /* Returns a digit.digit string */ @@ -2922,7 +3021,7 @@ */ public BigInteger toBigInteger() { // force to an integer, quietly - return this.setScale(0, ROUND_DOWN).inflate(); + return this.setScale(0, ROUND_DOWN).inflated(); } /** @@ -2937,7 +3036,7 @@ */ public BigInteger toBigIntegerExact() { // round to an integer, with Exception if decimal part non-0 - return this.setScale(0, ROUND_UNNECESSARY).inflate(); + return this.setScale(0, ROUND_UNNECESSARY).inflated(); } /** @@ -2990,7 +3089,7 @@ BigDecimal num = this.setScale(0, ROUND_UNNECESSARY); if (num.precision() >= 19) // need to check carefully LongOverflow.check(num); - return num.inflate().longValue(); + return num.inflated().longValue(); } private static class LongOverflow { @@ -3001,9 +3100,9 @@ private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE); public static void check(BigDecimal num) { - num.inflate(); - if ((num.intVal.compareTo(LONGMIN) < 0) || - (num.intVal.compareTo(LONGMAX) > 0)) + BigInteger intVal = num.inflated(); + if (intVal.compareTo(LONGMIN) < 0 || + intVal.compareTo(LONGMAX) > 0) throw new java.lang.ArithmeticException("Overflow"); } } @@ -3107,8 +3206,28 @@ * @return this {@code BigDecimal} converted to a {@code float}. */ public float floatValue(){ - if (scale == 0 && intCompact != INFLATED) + if(intCompact != INFLATED) { + if (scale == 0) { return (float)intCompact; + } else { + /* + * If both intCompact and the scale can be exactly + * represented as float values, perform a single float + * multiply or divide to compute the (properly + * rounded) result. + */ + if (Math.abs(intCompact) < 1L<<22 ) { + // Don't have too guard against + // Math.abs(MIN_VALUE) because of outer check + // against INFLATED. + if (scale > 0 && scale < float10pow.length) { + return (float)intCompact / float10pow[scale]; + } else if (scale < 0 && scale > -float10pow.length) { + return (float)intCompact * float10pow[-scale]; + } + } + } + } // Somewhat inefficient, but guaranteed to work. return Float.parseFloat(this.toString()); } @@ -3130,13 +3249,53 @@ * @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 (Math.abs(intCompact) < 1L<<52 ) { + // Don't have too guard against + // Math.abs(MIN_VALUE) because of outer check + // against INFLATED. + if (scale > 0 && scale < double10pow.length) { + return (double)intCompact / double10pow[scale]; + } else if (scale < 0 && scale > -double10pow.length) { + return (double)intCompact * double10pow[-scale]; + } + } + } + } // Somewhat inefficient, but guaranteed to work. return Double.parseDouble(this.toString()); } /** + * Powers of 10 which can be represented exactly in {@code + * double}. + */ + private static final double double10pow[] = { + 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, + 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, + 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, + 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22 + }; + + /** + * Powers of 10 which can be represented exactly in {@code + * float}. + */ + private static final float float10pow[] = { + 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, + 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f + }; + + /** * Returns the size of an ulp, a unit in the last place, of this * {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal} * value is the positive distance between this value and the @@ -3151,10 +3310,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 +3426,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 +3544,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 +3600,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 +3674,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 +3683,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 +3716,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 +3754,7 @@ throw new java.io.StreamCorruptedException(message); // [all values of scale are now allowed] } - intCompact = compactValFor(intVal); + setIntCompactVolatile(compactValFor(intVal)); } /** @@ -3570,13 +3765,12 @@ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Must inflate to maintain compatible serial form. - this.inflate(); - - // Write proper fields + if (this.intVal == null) + this.setIntValVolatile(BigInteger.valueOf(this.intCompact)); + // Could reset intVal back to null if it has to be set. s.defaultWriteObject(); } - /** * Returns the length of the absolute value of a {@code long}, in decimal * digits. @@ -3584,36 +3778,29 @@ * @param x the {@code long} * @return the length of the unscaled value, in deciaml digits. */ - private static int longDigitLength(long x) { + static int longDigitLength(long x) { /* * As described in "Bit Twiddling Hacks" by Sean Anderson, * (http://graphics.stanford.edu/~seander/bithacks.html) - * integer log 10 of x is within 1 of - * (1233/4096)* (1 + integer log 2 of x). - * The fraction 1233/4096 approximates log10(2). So we first - * do a version of log2 (a variant of Long class with - * pre-checks and opposite directionality) and then scale and - * check against powers table. This is a little simpler in - * present context than the version in Hacker's Delight sec - * 11-4. Adding one to bit length allows comparing downward - * from the LONG_TEN_POWERS_TABLE that we need anyway. + * 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 +3822,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 +3845,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 +3937,1275 @@ } return this; } + + /* the same as checkScale where value!=0 */ + private static int checkScaleNonZero(long val) { + int asInt = (int)val; + if (asInt != val) { + throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow"); + } + return asInt; + } + + private static int checkScale(long intCompact, long val) { + int asInt = (int)val; + if (asInt != val) { + asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE; + if (intCompact != 0) + throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow"); + } + return asInt; + } + + private static int checkScale(BigInteger intVal, long val) { + int asInt = (int)val; + if (asInt != val) { + asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE; + if (intVal.signum() != 0) + throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow"); + } + return asInt; + } + + /** + * Returns a {@code BigDecimal} rounded according to the MathContext + * settings; + * If rounding is needed a new {@code BigDecimal} is created and returned. + * + * @param val the value to be rounded + * @param mc the context to use. + * @return a {@code BigDecimal} rounded according to the MathContext + * settings. May return {@code value}, if no rounding needed. + * @throws ArithmeticException if the rounding mode is + * {@code RoundingMode.UNNECESSARY} and the + * result is inexact. + */ + private static BigDecimal doRound(BigDecimal val, MathContext mc) { + int mcp = mc.precision; + boolean wasDivided = false; + if (mcp > 0) { + BigInteger intVal = val.intVal; + long compactVal = val.intCompact; + int scale = val.scale; + int prec = val.precision(); + int mode = mc.roundingMode.oldMode; + int drop; + if (compactVal == INFLATED) { + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + intVal = divideAndRoundByTenPow(intVal, drop, mode); + wasDivided = true; + compactVal = compactValFor(intVal); + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + break; + } + prec = bigDigitLength(intVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + wasDivided = true; + prec = longDigitLength(compactVal); + drop = prec - mcp; + intVal = null; + } + } + return wasDivided ? new BigDecimal(intVal,compactVal,scale,prec) : val; + } + return val; + } + + /* + * Returns a {@code BigDecimal} created from {@code long} value with + * given scale rounded according to the MathContext settings + */ + private static BigDecimal doRound(long compactVal, int scale, MathContext mc) { + int mcp = mc.precision; + if (mcp > 0 && mcp < 19) { + int prec = longDigitLength(compactVal); + int drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + return valueOf(compactVal, scale, prec); + } + return valueOf(compactVal, scale); + } + + /* + * Returns a {@code BigDecimal} created from {@code BigInteger} value with + * given scale rounded according to the MathContext settings + */ + private static BigDecimal doRound(BigInteger intVal, int scale, MathContext mc) { + int mcp = mc.precision; + int prec = 0; + if (mcp > 0) { + long compactVal = compactValFor(intVal); + int mode = mc.roundingMode.oldMode; + int drop; + if (compactVal == INFLATED) { + prec = bigDigitLength(intVal); + drop = prec - mcp; + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + intVal = divideAndRoundByTenPow(intVal, drop, mode); + compactVal = compactValFor(intVal); + if (compactVal != INFLATED) { + break; + } + prec = bigDigitLength(intVal); + drop = prec - mcp; + } + } + if (compactVal != INFLATED) { + prec = longDigitLength(compactVal); + drop = prec - mcp; // drop can't be more than 18 + while (drop > 0) { + scale = checkScaleNonZero((long) scale - drop); + compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); + prec = longDigitLength(compactVal); + drop = prec - mcp; + } + return valueOf(compactVal,scale,prec); + } + } + return new BigDecimal(intVal,INFLATED,scale,prec); + } + + /* + * Divides {@code BigInteger} value by ten power. + */ + private static BigInteger divideAndRoundByTenPow(BigInteger intVal, int tenPow, int roundingMode) { + if (tenPow < LONG_TEN_POWERS_TABLE.length) + intVal = divideAndRound(intVal, LONG_TEN_POWERS_TABLE[tenPow], roundingMode); + else + intVal = divideAndRound(intVal, bigTenToThe(tenPow), roundingMode); + return intVal; + } + + /** + * Internally used for division operation for division {@code long} by + * {@code long}. + * The returned {@code BigDecimal} object is the quotient whose scale is set + * to the passed in scale. If the remainder is not zero, it will be rounded + * based on the passed in roundingMode. Also, if the remainder is zero and + * the last parameter, i.e. preferredScale is NOT equal to scale, the + * trailing zeros of the result is stripped to match the preferredScale. + */ + private static BigDecimal divideAndRound(long ldividend, long ldivisor, int scale, int roundingMode, + int preferredScale) { + + int qsign; // quotient sign + long q = ldividend / ldivisor; // store quotient in long + if (roundingMode == ROUND_DOWN && scale == preferredScale) + return valueOf(q, scale); + long r = ldividend % ldivisor; // store remainder in long + qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1; + if (r != 0) { + boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r); + return valueOf((increment ? q + qsign : q), scale); + } else { + if (preferredScale != scale) + return createAndStripZerosToMatchScale(q, scale, preferredScale); + else + return valueOf(q, scale); + } + } + + /** + * Divides {@code long} by {@code long} and do rounding based on the + * passed in roundingMode. + */ + private static long divideAndRound(long ldividend, long ldivisor, int roundingMode) { + int qsign; // quotient sign + long q = ldividend / ldivisor; // store quotient in long + if (roundingMode == ROUND_DOWN) + return q; + long r = ldividend % ldivisor; // store remainder in long + qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1; + if (r != 0) { + boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r); + return increment ? q + qsign : q; + } else { + return q; + } + } + + /** + * Shared logic of need increment computation. + */ + private static boolean commonNeedIncrement(int roundingMode, int qsign, + int cmpFracHalf, boolean oddQuot) { + switch(roundingMode) { + case ROUND_UNNECESSARY: + throw new ArithmeticException("Rounding necessary"); + + case ROUND_UP: // Away from zero + return true; + + case ROUND_DOWN: // Towards zero + return false; + + case ROUND_CEILING: // Towards +infinity + return qsign > 0; + + case ROUND_FLOOR: // Towards -infinity + return qsign < 0; + + default: // Some kind of half-way rounding + if (roundingMode == ROUND_HALF_DOWN || + cmpFracHalf < 0 ) // We're closer to higher digit + return false; + else if (roundingMode == ROUND_HALF_UP || + cmpFracHalf > 0 ) // We're closer to lower digit + return true; + else + // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd + return oddQuot; + } + } + + /** + * Tests if quotient has to be incremented according the roundingMode + */ + private static boolean needIncrement(long ldivisor, int roundingMode, + int qsign, long q, long r) { + assert r != 0L; + + int cmpFracHalf; + if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) { + cmpFracHalf = 1; // 2 * r can't fit into long + } else { + cmpFracHalf = longCompareMagnitude(2 * r, ldivisor); + } + + return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, (q & 1L) != 0L); + } + + /** + * Divides {@code BigInteger} value by {@code long} value and + * do rounding based on the passed in roundingMode. + */ + private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) { + boolean isRemainderZero; // record remainder is zero or not + int qsign; // quotient sign + long r = 0; // store quotient & remainder in long + MutableBigInteger mq = null; // store quotient + // Descend into mutables for faster remainder checks + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag); + mq = new MutableBigInteger(); + r = mdividend.divide(ldivisor, mq); + isRemainderZero = (r == 0); + qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum; + if (!isRemainderZero) { + if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) { + mq.add(MutableBigInteger.ONE); + } + } + return mq.toBigInteger(qsign); + } + + /** + * Internally used for division operation for division {@code BigInteger} + * by {@code long}. + * The returned {@code BigDecimal} object is the quotient whose scale is set + * to the passed in scale. If the remainder is not zero, it will be rounded + * based on the passed in roundingMode. Also, if the remainder is zero and + * the last parameter, i.e. preferredScale is NOT equal to scale, the + * trailing zeros of the result is stripped to match the preferredScale. + */ + private static BigDecimal divideAndRound(BigInteger bdividend, + long ldivisor, int scale, int roundingMode, int preferredScale) { + boolean isRemainderZero; // record remainder is zero or not + int qsign; // quotient sign + long r = 0; // store quotient & remainder in long + MutableBigInteger mq = null; // store quotient + // Descend into mutables for faster remainder checks + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag); + mq = new MutableBigInteger(); + r = mdividend.divide(ldivisor, mq); + isRemainderZero = (r == 0); + qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum; + if (!isRemainderZero) { + if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) { + mq.add(MutableBigInteger.ONE); + } + return mq.toBigDecimal(qsign, scale); + } else { + if (preferredScale != scale) { + long compactVal = mq.toCompactValue(qsign); + if(compactVal!=INFLATED) { + return createAndStripZerosToMatchScale(compactVal, scale, preferredScale); + } + BigInteger intVal = mq.toBigInteger(qsign); + return createAndStripZerosToMatchScale(intVal,scale, preferredScale); + } else { + return mq.toBigDecimal(qsign, scale); + } + } + } + + /** + * Tests if quotient has to be incremented according the roundingMode + */ + private static boolean needIncrement(long ldivisor, int roundingMode, + int qsign, MutableBigInteger mq, long r) { + assert r != 0L; + + int cmpFracHalf; + if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) { + cmpFracHalf = 1; // 2 * r can't fit into long + } else { + cmpFracHalf = longCompareMagnitude(2 * r, ldivisor); + } + + return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd()); + } + + /** + * Divides {@code BigInteger} value by {@code BigInteger} value and + * do rounding based on the passed in roundingMode. + */ + private static BigInteger divideAndRound(BigInteger bdividend, BigInteger bdivisor, int roundingMode) { + boolean isRemainderZero; // record remainder is zero or not + int qsign; // quotient sign + // Descend into mutables for faster remainder checks + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag); + MutableBigInteger mq = new MutableBigInteger(); + MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag); + MutableBigInteger mr = mdividend.divide(mdivisor, mq); + isRemainderZero = mr.isZero(); + qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1; + if (!isRemainderZero) { + if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) { + mq.add(MutableBigInteger.ONE); + } + } + return mq.toBigInteger(qsign); + } + + /** + * Internally used for division operation for division {@code BigInteger} + * by {@code BigInteger}. + * The returned {@code BigDecimal} object is the quotient whose scale is set + * to the passed in scale. If the remainder is not zero, it will be rounded + * based on the passed in roundingMode. Also, if the remainder is zero and + * the last parameter, i.e. preferredScale is NOT equal to scale, the + * trailing zeros of the result is stripped to match the preferredScale. + */ + private static BigDecimal divideAndRound(BigInteger bdividend, BigInteger bdivisor, int scale, int roundingMode, + int preferredScale) { + boolean isRemainderZero; // record remainder is zero or not + int qsign; // quotient sign + // Descend into mutables for faster remainder checks + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag); + MutableBigInteger mq = new MutableBigInteger(); + MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag); + MutableBigInteger mr = mdividend.divide(mdivisor, mq); + isRemainderZero = mr.isZero(); + qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1; + if (!isRemainderZero) { + if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) { + mq.add(MutableBigInteger.ONE); + } + return mq.toBigDecimal(qsign, scale); + } else { + if (preferredScale != scale) { + long compactVal = mq.toCompactValue(qsign); + if (compactVal != INFLATED) { + return createAndStripZerosToMatchScale(compactVal, scale, preferredScale); + } + BigInteger intVal = mq.toBigInteger(qsign); + return createAndStripZerosToMatchScale(intVal, scale, preferredScale); + } else { + return mq.toBigDecimal(qsign, scale); + } + } + } + + /** + * Tests if quotient has to be incremented according the roundingMode + */ + private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMode, + int qsign, MutableBigInteger mq, MutableBigInteger mr) { + assert !mr.isZero(); + int cmpFracHalf = mr.compareHalf(mdivisor); + return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd()); + } + + /** + * Remove insignificant trailing zeros from this + * {@code BigInteger} value until the preferred scale is reached or no + * more zeros can be removed. If the preferred scale is less than + * Integer.MIN_VALUE, all the trailing zeros will be removed. + * + * @return new {@code BigDecimal} with a scale possibly reduced + * to be closed to the preferred scale. + */ + private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) { + BigInteger qr[]; // quotient-remainder pair + while (intVal.compareMagnitude(BigInteger.TEN) >= 0 + && scale > preferredScale) { + if (intVal.testBit(0)) + break; // odd number cannot end in 0 + qr = intVal.divideAndRemainder(BigInteger.TEN); + if (qr[1].signum() != 0) + break; // non-0 remainder + intVal = qr[0]; + scale = checkScale(intVal,(long) scale - 1); // could Overflow + } + return valueOf(intVal, scale, 0); + } + + /** + * Remove insignificant trailing zeros from this + * {@code long} value until the preferred scale is reached or no + * more zeros can be removed. If the preferred scale is less than + * Integer.MIN_VALUE, all the trailing zeros will be removed. + * + * @return new {@code BigDecimal} with a scale possibly reduced + * to be closed to the preferred scale. + */ + private static BigDecimal createAndStripZerosToMatchScale(long compactVal, int scale, long preferredScale) { + while (Math.abs(compactVal) >= 10L && scale > preferredScale) { + if ((compactVal & 1L) != 0L) + break; // odd number cannot end in 0 + long r = compactVal % 10L; + if (r != 0L) + break; // non-0 remainder + compactVal /= 10; + scale = checkScale(compactVal, (long) scale - 1); // could Overflow + } + return valueOf(compactVal, scale); + } + + private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, int preferredScale) { + if(intCompact!=INFLATED) { + return createAndStripZerosToMatchScale(intCompact, scale, preferredScale); + } else { + return createAndStripZerosToMatchScale(intVal==null ? INFLATED_BIGINT : intVal, + scale, preferredScale); + } + } + + /* + * returns INFLATED if oveflow + */ + private static long add(long xs, long ys){ + long sum = xs + ys; + // See "Hacker's Delight" section 2-12 for explanation of + // the overflow test. + if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) { // not overflowed + return sum; + } + return INFLATED; + } + + private static BigDecimal add(long xs, long ys, int scale){ + long sum = add(xs, ys); + if (sum!=INFLATED) + return BigDecimal.valueOf(sum, scale); + return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale); + } + + private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) { + long sdiff = (long) scale1 - scale2; + if (sdiff == 0) { + return add(xs, ys, scale1); + } else if (sdiff < 0) { + int raise = checkScale(xs,-sdiff); + long scaledX = longMultiplyPowerTen(xs, raise); + if (scaledX != INFLATED) { + return add(scaledX, ys, scale2); + } else { + BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys); + return ((xs^ys)>=0) ? // same sign test + new BigDecimal(bigsum, INFLATED, scale2, 0) + : valueOf(bigsum, scale2, 0); + } + } else { + int raise = checkScale(ys,sdiff); + long scaledY = longMultiplyPowerTen(ys, raise); + if (scaledY != INFLATED) { + return add(xs, scaledY, scale1); + } else { + BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs); + return ((xs^ys)>=0) ? + new BigDecimal(bigsum, INFLATED, scale1, 0) + : valueOf(bigsum, scale1, 0); + } + } + } + + private static BigDecimal add(final long xs, int scale1, BigInteger snd, int scale2) { + int rscale = scale1; + long sdiff = (long)rscale - scale2; + boolean sameSigns = (Long.signum(xs) == snd.signum); + BigInteger sum; + if (sdiff < 0) { + int raise = checkScale(xs,-sdiff); + rscale = scale2; + long scaledX = longMultiplyPowerTen(xs, raise); + if (scaledX == INFLATED) { + sum = snd.add(bigMultiplyPowerTen(xs,raise)); + } else { + sum = snd.add(scaledX); + } + } else { //if (sdiff > 0) { + int raise = checkScale(snd,sdiff); + snd = bigMultiplyPowerTen(snd,raise); + sum = snd.add(xs); + } + return (sameSigns) ? + new BigDecimal(sum, INFLATED, rscale, 0) : + valueOf(sum, rscale, 0); + } + + private static BigDecimal add(BigInteger fst, int scale1, BigInteger snd, int scale2) { + int rscale = scale1; + long sdiff = (long)rscale - scale2; + if (sdiff != 0) { + if (sdiff < 0) { + int raise = checkScale(fst,-sdiff); + rscale = scale2; + fst = bigMultiplyPowerTen(fst,raise); + } else { + int raise = checkScale(snd,sdiff); + snd = bigMultiplyPowerTen(snd,raise); + } + } + BigInteger sum = fst.add(snd); + return (fst.signum == snd.signum) ? + new BigDecimal(sum, INFLATED, rscale, 0) : + valueOf(sum, rscale, 0); + } + + private static BigInteger bigMultiplyPowerTen(long value, int n) { + if (n <= 0) + return BigInteger.valueOf(value); + return bigTenToThe(n).multiply(value); + } + + private static BigInteger bigMultiplyPowerTen(BigInteger value, int n) { + if (n <= 0) + return value; + if(n=0 + long scaledX = (xraise==0) ? xs : + longMultiplyPowerTen(xs, xraise); // can't overflow here! + BigDecimal quotient; + + int cmp = longCompareMagnitude(scaledX, ys); + if(cmp > 0) { // satisfy constraint (b) + yscale -= 1; // [that is, divisor *= 10] + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + if (checkScaleNonZero((long) mcp + yscale) > xscale) { + // assert newScale >= xscale + int raise = checkScaleNonZero((long) mcp + yscale - xscale); + long scaledXs; + if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) { + quotient = null; + if((mcp-1) >=0 && (mcp-1)= yscale + if (newScale == yscale) { // easy case + quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + int raise = checkScaleNonZero((long) newScale - yscale); + long scaledYs; + if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) { + BigInteger rb = bigMultiplyPowerTen(ys,raise); + quotient = divideAndRound(BigInteger.valueOf(xs), + rb, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale)); + } + } + } + } else { + // abs(scaledX) <= abs(ys) + // result is "scaledX * 10^msp / ys" + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + if(cmp==0) { + // abs(scaleX)== abs(ys) => result will be scaled 10^mcp + correct sign + quotient = roundedTenPower(((scaledX < 0) == (ys < 0)) ? 1 : -1, mcp, scl, checkScaleNonZero(preferredScale)); + } else { + // abs(scaledX) < abs(ys) + long scaledXs; + if ((scaledXs = longMultiplyPowerTen(scaledX, mcp)) == INFLATED) { + quotient = null; + if(mcp 0) {// satisfy constraint (b) + yscale -= 1; // [that is, divisor *= 10] + } + int roundingMode = mc.roundingMode.oldMode; + // In order to find out whether the divide generates the exact result, + // we avoid calling the above divide method. 'quotient' holds the + // return BigDecimal object whose scale will be set to 'scl'. + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + BigDecimal quotient; + if (checkScaleNonZero((long) mcp + yscale) > xscale) { + int raise = checkScaleNonZero((long) mcp + yscale - xscale); + long scaledXs; + if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) { + BigInteger rb = bigMultiplyPowerTen(xs,raise); + quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); + } else { + quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); + } + } else { + int newScale = checkScaleNonZero((long) xscale - mcp); + // assert newScale >= yscale + if (newScale == yscale) { // easy case + quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + int raise = checkScaleNonZero((long) newScale - yscale); + long scaledYs; + if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) { + BigInteger rb = bigMultiplyPowerTen(ys,raise); + quotient = divideAndRound(BigInteger.valueOf(xs), + rb, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale)); + } + } + } + // doRound, here, only affects 1000000000 case. + return doRound(quotient,mc); + } + + /** + * Returns a {@code BigDecimal} whose value is {@code (xs / + * ys)}, with rounding according to the context settings. + */ + private static BigDecimal divide(BigInteger xs, int xscale, long ys, int yscale, long preferredScale, MathContext mc) { + // Normalize dividend & divisor so that both fall into [0.1, 0.999...] + if ((-compareMagnitudeNormalized(ys, yscale, xs, xscale)) > 0) {// satisfy constraint (b) + yscale -= 1; // [that is, divisor *= 10] + } + int mcp = mc.precision; + int roundingMode = mc.roundingMode.oldMode; + + // In order to find out whether the divide generates the exact result, + // we avoid calling the above divide method. 'quotient' holds the + // return BigDecimal object whose scale will be set to 'scl'. + BigDecimal quotient; + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + if (checkScaleNonZero((long) mcp + yscale) > xscale) { + int raise = checkScaleNonZero((long) mcp + yscale - xscale); + BigInteger rb = bigMultiplyPowerTen(xs,raise); + quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); + } else { + int newScale = checkScaleNonZero((long) xscale - mcp); + // assert newScale >= yscale + if (newScale == yscale) { // easy case + quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + int raise = checkScaleNonZero((long) newScale - yscale); + long scaledYs; + if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) { + BigInteger rb = bigMultiplyPowerTen(ys,raise); + quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale)); + } else { + quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale)); + } + } + } + // doRound, here, only affects 1000000000 case. + return doRound(quotient, mc); + } + + /** + * Returns a {@code BigDecimal} whose value is {@code (xs / + * ys)}, with rounding according to the context settings. + */ + private static BigDecimal divide(long xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) { + // Normalize dividend & divisor so that both fall into [0.1, 0.999...] + if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b) + yscale -= 1; // [that is, divisor *= 10] + } + int mcp = mc.precision; + int roundingMode = mc.roundingMode.oldMode; + + // In order to find out whether the divide generates the exact result, + // we avoid calling the above divide method. 'quotient' holds the + // return BigDecimal object whose scale will be set to 'scl'. + BigDecimal quotient; + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + if (checkScaleNonZero((long) mcp + yscale) > xscale) { + int raise = checkScaleNonZero((long) mcp + yscale - xscale); + BigInteger rb = bigMultiplyPowerTen(xs,raise); + quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); + } else { + int newScale = checkScaleNonZero((long) xscale - mcp); + int raise = checkScaleNonZero((long) newScale - yscale); + BigInteger rb = bigMultiplyPowerTen(ys,raise); + quotient = divideAndRound(BigInteger.valueOf(xs), rb, scl, roundingMode,checkScaleNonZero(preferredScale)); + } + // doRound, here, only affects 1000000000 case. + return doRound(quotient, mc); + } + + /** + * Returns a {@code BigDecimal} whose value is {@code (xs / + * ys)}, with rounding according to the context settings. + */ + private static BigDecimal divide(BigInteger xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) { + // Normalize dividend & divisor so that both fall into [0.1, 0.999...] + if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b) + yscale -= 1; // [that is, divisor *= 10] + } + int mcp = mc.precision; + int roundingMode = mc.roundingMode.oldMode; + + // In order to find out whether the divide generates the exact result, + // we avoid calling the above divide method. 'quotient' holds the + // return BigDecimal object whose scale will be set to 'scl'. + BigDecimal quotient; + int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp); + if (checkScaleNonZero((long) mcp + yscale) > xscale) { + int raise = checkScaleNonZero((long) mcp + yscale - xscale); + BigInteger rb = bigMultiplyPowerTen(xs,raise); + quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale)); + } else { + int newScale = checkScaleNonZero((long) xscale - mcp); + int raise = checkScaleNonZero((long) newScale - yscale); + BigInteger rb = bigMultiplyPowerTen(ys,raise); + quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale)); + } + // doRound, here, only affects 1000000000 case. + return doRound(quotient, mc); + } + + /* + * performs divideAndRound for (dividend0*dividend1, divisor) + * returns null if quotient can't fit into long value; + */ + private static BigDecimal multiplyDivideAndRound(long dividend0, long dividend1, long divisor, int scale, int roundingMode, + int preferredScale) { + int qsign = Long.signum(dividend0)*Long.signum(dividend1)*Long.signum(divisor); + dividend0 = Math.abs(dividend0); + dividend1 = Math.abs(dividend1); + divisor = Math.abs(divisor); + // multiply dividend0 * dividend1 + long d0_hi = dividend0 >>> 32; + long d0_lo = dividend0 & LONG_MASK; + long d1_hi = dividend1 >>> 32; + long d1_lo = dividend1 & LONG_MASK; + long product = d0_lo * d1_lo; + long d0 = product & LONG_MASK; + long d1 = product >>> 32; + product = d0_hi * d1_lo + d1; + d1 = product & LONG_MASK; + long d2 = product >>> 32; + product = d0_lo * d1_hi + d1; + d1 = product & LONG_MASK; + d2 += product >>> 32; + long d3 = d2>>>32; + d2 &= LONG_MASK; + product = d0_hi*d1_hi + d2; + d2 = product & LONG_MASK; + d3 = ((product>>>32) + d3) & LONG_MASK; + final long dividendHi = make64(d3,d2); + final long dividendLo = make64(d1,d0); + // divide + return divideAndRound128(dividendHi, dividendLo, divisor, qsign, scale, roundingMode, preferredScale); + } + + private static final long DIV_NUM_BASE = (1L<<32); // Number base (32 bits). + + /* + * divideAndRound 128-bit value by long divisor. + * returns null if quotient can't fit into long value; + * Specialized version of Knuth's division + */ + private static BigDecimal divideAndRound128(final long dividendHi, final long dividendLo, long divisor, int sign, + int scale, int roundingMode, int preferredScale) { + if (dividendHi >= divisor) { + return null; + } + final int shift = Long.numberOfLeadingZeros(divisor); + divisor <<= shift; + + final long v1 = divisor >>> 32; + final long v0 = divisor & LONG_MASK; + + long q1, q0; + long r_tmp; + + long tmp = dividendLo << shift; + long u1 = tmp >>> 32; + long u0 = tmp & LONG_MASK; + + tmp = (dividendHi << shift) | (dividendLo >>> 64 - shift); + long u2 = tmp & LONG_MASK; + tmp = divWord(tmp,v1); + q1 = tmp & LONG_MASK; + r_tmp = tmp >>> 32; + while(q1 >= DIV_NUM_BASE || unsignedLongCompare(q1*v0, make64(r_tmp, u1))) { + q1--; + r_tmp += v1; + if (r_tmp >= DIV_NUM_BASE) + break; + } + tmp = mulsub(u2,u1,v1,v0,q1); + u1 = tmp & LONG_MASK; + tmp = divWord(tmp,v1); + q0 = tmp & LONG_MASK; + r_tmp = tmp >>> 32; + while(q0 >= DIV_NUM_BASE || unsignedLongCompare(q0*v0,make64(r_tmp,u0))) { + q0--; + r_tmp += v1; + if (r_tmp >= DIV_NUM_BASE) + break; + } + if((int)q1 < 0) { + // result (which is positive and unsigned here) + // can't fit into long due to sign bit is used for value + MutableBigInteger mq = new MutableBigInteger(new int[]{(int)q1, (int)q0}); + if (roundingMode == ROUND_DOWN && scale == preferredScale) { + return mq.toBigDecimal(sign, scale); + } + long r = mulsub(u1, u0, v1, v0, q0) >>> shift; + if (r != 0) { + if(needIncrement(divisor >>> shift, roundingMode, sign, mq, r)){ + mq.add(MutableBigInteger.ONE); + } + return mq.toBigDecimal(sign, scale); + } else { + if (preferredScale != scale) { + BigInteger intVal = mq.toBigInteger(sign); + return createAndStripZerosToMatchScale(intVal,scale, preferredScale); + } else { + return mq.toBigDecimal(sign, scale); + } + } + } + long q = make64(q1,q0); + q*=sign; + if (roundingMode == ROUND_DOWN && scale == preferredScale) + return valueOf(q, scale); + long r = mulsub(u1, u0, v1, v0, q0) >>> shift; + if (r != 0) { + boolean increment = needIncrement(divisor >>> shift, roundingMode, sign, q, r); + return valueOf((increment ? q + sign : q), scale); + } else { + if (preferredScale != scale) { + return createAndStripZerosToMatchScale(q, scale, preferredScale); + } else { + return valueOf(q, scale); + } + } + } + + /* + * calculate divideAndRound for ldividend*10^raise / divisor + * when abs(dividend)==abs(divisor); + */ + private static BigDecimal roundedTenPower(int qsign, int raise, int scale, int preferredScale) { + if (scale > preferredScale) { + int diff = scale - preferredScale; + if(diff < raise) { + return scaledTenPow(raise - diff, qsign, preferredScale); + } else { + return valueOf(qsign,scale-raise); + } + } else { + return scaledTenPow(raise, qsign, scale); + } + } + + static BigDecimal scaledTenPow(int n, int sign, int scale) { + if (n < LONG_TEN_POWERS_TABLE.length) + return valueOf(sign*LONG_TEN_POWERS_TABLE[n],scale); + else { + BigInteger unscaledVal = bigTenToThe(n); + if(sign==-1) { + unscaledVal = unscaledVal.negate(); + } + return new BigDecimal(unscaledVal, INFLATED, scale, n+1); + } + } + + private static long divWord(long n, long dLong) { + long r; + long q; + if (dLong == 1) { + q = (int)n; + return (q & LONG_MASK); + } + // Approximate the quotient and remainder + q = (n >>> 1) / (dLong >>> 1); + r = n - q*dLong; + + // Correct the approximation + while (r < 0) { + r += dLong; + q--; + } + while (r >= dLong) { + r -= dLong; + q++; + } + // n - q*dlong == r && 0 <= r >>32) - q0*v1,tmp & LONG_MASK); + } + + private static boolean unsignedLongCompare(long one, long two) { + return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE); + } + + private static boolean unsignedLongCompareEq(long one, long two) { + return (one+Long.MIN_VALUE) >= (two+Long.MIN_VALUE); + } + + + // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...] + private static int compareMagnitudeNormalized(long xs, int xscale, long ys, int yscale) { + // assert xs!=0 && ys!=0 + int sdiff = xscale - yscale; + if (sdiff != 0) { + if (sdiff < 0) { + xs = longMultiplyPowerTen(xs, -sdiff); + } else { // sdiff > 0 + ys = longMultiplyPowerTen(ys, sdiff); + } + } + if (xs != INFLATED) + return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1; + else + return 1; + } + + // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...] + private static int compareMagnitudeNormalized(long xs, int xscale, BigInteger ys, int yscale) { + // assert "ys can't be represented as long" + if (xs == 0) + return -1; + int sdiff = xscale - yscale; + if (sdiff < 0) { + if (longMultiplyPowerTen(xs, -sdiff) == INFLATED ) { + return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys); + } + } + return -1; + } + + // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...] + private static int compareMagnitudeNormalized(BigInteger xs, int xscale, BigInteger ys, int yscale) { + int sdiff = xscale - yscale; + if (sdiff < 0) { + return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys); + } else { // sdiff >= 0 + return xs.compareMagnitude(bigMultiplyPowerTen(ys, sdiff)); + } + } + + private static long multiply(long x, long y){ + long product = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 == 0) || (y == 0) || (product / y == x)){ + return product; + } + return INFLATED; + } + + private static BigDecimal multiply(long x, long y, int scale) { + long product = multiply(x, y); + if(product!=INFLATED) { + return valueOf(product,scale); + } + return new BigDecimal(BigInteger.valueOf(x).multiply(y),INFLATED,scale,0); + } + + private static BigDecimal multiply(long x, BigInteger y, int scale) { + if(x==0) { + return zeroValueOf(scale); + } + return new BigDecimal(y.multiply(x),INFLATED,scale,0); + } + + private static BigDecimal multiply(BigInteger x, BigInteger y, int scale) { + return new BigDecimal(x.multiply(y),INFLATED,scale,0); + } + + /** + * Multiplies two long values and rounds according {@code MathContext} + */ + private static BigDecimal multiplyAndRound(long x, long y, int scale, MathContext mc) { + long product = multiply(x, y); + if(product!=INFLATED) { + return doRound(product, scale, mc); + } + // attempt to do it in 128 bits + int rsign = 1; + if(x < 0) { + x = -x; + rsign = -1; + } + if(y < 0) { + y = -y; + rsign *= -1; + } + // multiply dividend0 * dividend1 + long m0_hi = x >>> 32; + long m0_lo = x & LONG_MASK; + long m1_hi = y >>> 32; + long m1_lo = y & LONG_MASK; + product = m0_lo * m1_lo; + long m0 = product & LONG_MASK; + long m1 = product >>> 32; + product = m0_hi * m1_lo + m1; + m1 = product & LONG_MASK; + long m2 = product >>> 32; + product = m0_lo * m1_hi + m1; + m1 = product & LONG_MASK; + m2 += product >>> 32; + long m3 = m2>>>32; + m2 &= LONG_MASK; + product = m0_hi*m1_hi + m2; + m2 = product & LONG_MASK; + m3 = ((product>>>32) + m3) & LONG_MASK; + final long mHi = make64(m3,m2); + final long mLo = make64(m1,m0); + BigDecimal res = doRound128(mHi, mLo, rsign, scale, mc); + if(res!=null) { + return res; + } + res = new BigDecimal(BigInteger.valueOf(x).multiply(y*rsign), INFLATED, scale, 0); + return doRound(res,mc); + } + + private static BigDecimal multiplyAndRound(long x, BigInteger y, int scale, MathContext mc) { + if(x==0) { + return zeroValueOf(scale); + } + return doRound(y.multiply(x), scale, mc); + } + + private static BigDecimal multiplyAndRound(BigInteger x, BigInteger y, int scale, MathContext mc) { + return doRound(x.multiply(y), scale, mc); + } + + /** + * rounds 128-bit value according {@code MathContext} + * returns null if result can't be repsented as compact BigDecimal. + */ + private static BigDecimal doRound128(long hi, long lo, int sign, int scale, MathContext mc) { + int mcp = mc.precision; + int drop; + BigDecimal res = null; + if(((drop = precision(hi, lo) - mcp) > 0)&&(drop=0) { + return longDigitLength(lo); + } + return (unsignedLongCompareEq(lo, LONGLONG_TEN_POWERS_TABLE[0][1])) ? 20 : 19; + // 0x8AC7230489E80000L = unsigned 2^19 + } + int r = ((128 - Long.numberOfLeadingZeros(hi) + 1) * 1233) >>> 12; + int idx = r-19; + return (idx >= LONGLONG_TEN_POWERS_TABLE.length || longLongCompareMagnitude(hi, lo, + LONGLONG_TEN_POWERS_TABLE[idx][0], LONGLONG_TEN_POWERS_TABLE[idx][1])) ? r : r + 1; + } + + /* + * returns true if 128 bit number is less then + * hi0 & hi1 should be non-negative + */ + private static boolean longLongCompareMagnitude(long hi0, long lo0, long hi1, long lo1) { + if(hi0!=hi1) { + return hi0 dividendScale) { + int newScale = scale + divisorScale; + int raise = newScale - dividendScale; + if(raise dividendScale) { + int newScale = scale + divisorScale; + int raise = newScale - dividendScale; + BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise); + return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale); + } else { + int newScale = checkScale(divisor,(long)dividendScale - scale); + int raise = newScale - divisorScale; + if(raise dividendScale) { + int newScale = scale + divisorScale; + int raise = newScale - dividendScale; + BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise); + return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale); + } else { + int newScale = checkScale(divisor,(long)dividendScale - scale); + int raise = newScale - divisorScale; + BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise); + return divideAndRound(BigInteger.valueOf(dividend), scaledDivisor, scale, roundingMode, scale); + } + } + + private static BigDecimal divide(BigInteger dividend, int dividendScale, BigInteger divisor, int divisorScale, int scale, int roundingMode) { + if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) { + int newScale = scale + divisorScale; + int raise = newScale - dividendScale; + BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise); + return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale); + } else { + int newScale = checkScale(divisor,(long)dividendScale - scale); + int raise = newScale - divisorScale; + BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise); + return divideAndRound(dividend, scaledDivisor, scale, roundingMode, scale); + } + } + } --- old/src/share/classes/java/math/BigInteger.java 2011-09-01 22:59:26.000000000 -0700 +++ new/src/share/classes/java/math/BigInteger.java 2011-09-01 22:59:25.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -353,27 +353,17 @@ mag = trustedStripLeadingZeroInts(magnitude); } - // Constructs a new BigInteger using a char array with radix=10 - BigInteger(char[] val) { + /* + * Constructs a new BigInteger using a char array with radix=10. + * Sign is precalculated outside and not allowed in the val. + */ + BigInteger(char[] val, int sign, int len) { int cursor = 0, numDigits; - int len = val.length; - - // Check for leading minus sign - int sign = 1; - if (val[0] == '-') { - if (len == 1) - throw new NumberFormatException("Zero length BigInteger"); - sign = -1; - cursor = 1; - } else if (val[0] == '+') { - if (len == 1) - throw new NumberFormatException("Zero length BigInteger"); - cursor = 1; - } // Skip leading zeros and compute number of digits in magnitude - while (cursor < len && Character.digit(val[cursor], 10) == 0) + while (cursor < len && Character.digit(val[cursor], 10) == 0) { cursor++; + } if (cursor == len) { signum = 0; mag = ZERO.mag; @@ -382,7 +372,6 @@ numDigits = len - cursor; signum = sign; - // Pre-allocate array of expected size int numWords; if (len < 10) { @@ -1058,6 +1047,73 @@ } /** + * Package private methods used by BigDecimal code to add a BigInteger + * with a long. Assumes val is not equal to INFLATED. + */ + BigInteger add(long val) { + if (val == 0) + return this; + if (signum == 0) + return valueOf(val); + if (Long.signum(val) == signum) + return new BigInteger(add(mag, Math.abs(val)), signum); + int cmp = compareMagnitude(val); + if (cmp == 0) + return ZERO; + int[] resultMag = (cmp > 0 ? subtract(mag, Math.abs(val)) : subtract(Math.abs(val), mag)); + resultMag = trustedStripLeadingZeroInts(resultMag); + return new BigInteger(resultMag, cmp == signum ? 1 : -1); + } + + /** + * Adds the contents of the int array x and long value val. This + * method allocates a new int array to hold the answer and returns + * a reference to that array. Assumes x.length > 0 and val is + * non-negative + */ + private static int[] add(int[] x, long val) { + int[] y; + long sum = 0; + int xIndex = x.length; + int[] result; + int highWord = (int)(val >>> 32); + if (highWord==0) { + result = new int[xIndex]; + sum = (x[--xIndex] & LONG_MASK) + val; + result[xIndex] = (int)sum; + } else { + if (xIndex == 1) { + result = new int[2]; + sum = val + (x[0] & LONG_MASK); + result[1] = (int)sum; + result[0] = (int)(sum >>> 32); + return result; + } else { + result = new int[xIndex]; + sum = (x[--xIndex] & LONG_MASK) + (val & LONG_MASK); + result[xIndex] = (int)sum; + sum = (x[--xIndex] & LONG_MASK) + (highWord & LONG_MASK) + (sum >>> 32); + result[xIndex] = (int)sum; + } + } + // Copy remainder of longer number while carry propagation is required + boolean carry = (sum >>> 32 != 0); + while (xIndex > 0 && carry) + carry = ((result[--xIndex] = x[xIndex] + 1) == 0); + // Copy remainder of longer number + while (xIndex > 0) + result[--xIndex] = x[xIndex]; + // Grow result if necessary + if (carry) { + int bigger[] = new int[result.length + 1]; + System.arraycopy(result, 0, bigger, 1, result.length); + bigger[0] = 0x01; + return bigger; + } + return result; + } + + /** * Adds the contents of the int arrays x and y. This method allocates * a new int array to hold the answer and returns a reference to that * array. @@ -1074,14 +1130,17 @@ int yIndex = y.length; int result[] = new int[xIndex]; long sum = 0; - - // Add common parts of both numbers - while(yIndex > 0) { - sum = (x[--xIndex] & LONG_MASK) + - (y[--yIndex] & LONG_MASK) + (sum >>> 32); + if(yIndex==1) { + sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ; result[xIndex] = (int)sum; + } else { + // Add common parts of both numbers + while(yIndex > 0) { + sum = (x[--xIndex] & LONG_MASK) + + (y[--yIndex] & LONG_MASK) + (sum >>> 32); + result[xIndex] = (int)sum; + } } - // Copy remainder of longer number while carry propagation is required boolean carry = (sum >>> 32 != 0); while (xIndex > 0 && carry) @@ -1101,6 +1160,71 @@ return result; } + private static int[] subtract(long val, int[] little) { + int highWord = (int)(val >>> 32); + if (highWord==0) { + int result[] = new int[1]; + result[0] = (int)(val - (little[0] & LONG_MASK)); + return result; + } else { + int result[] = new int[2]; + if(little.length==1) { + long difference = ((int)val & LONG_MASK) - (little[0] & LONG_MASK); + result[1] = (int)difference; + // Subtract remainder of longer number while borrow propagates + boolean borrow = (difference >> 32 != 0); + if(borrow) { + result[0] = highWord - 1; + } else { // Copy remainder of longer number + result[0] = highWord; + } + return result; + } else { // little.length==2 + long difference = ((int)val & LONG_MASK) - (little[1] & LONG_MASK); + result[1] = (int)difference; + difference = (highWord & LONG_MASK) - (little[0] & LONG_MASK) + (difference >> 32); + result[0] = (int)difference; + return result; + } + } + } + + /** + * Subtracts the contents of the second argument (val) from the + * first (big). The first int array (big) must represent a larger number + * than the second. This method allocates the space necessary to hold the + * answer. + * assumes val >= 0 + */ + private static int[] subtract(int[] big, long val) { + int highWord = (int)(val >>> 32); + int bigIndex = big.length; + int result[] = new int[bigIndex]; + long difference = 0; + + if (highWord==0) { + difference = (big[--bigIndex] & LONG_MASK) - val; + result[bigIndex] = (int)difference; + } else { + difference = (big[--bigIndex] & LONG_MASK) - (val & LONG_MASK); + result[bigIndex] = (int)difference; + difference = (big[--bigIndex] & LONG_MASK) - (highWord & LONG_MASK) + (difference >> 32); + result[bigIndex] = (int)difference; + } + + + // Subtract remainder of longer number while borrow propagates + boolean borrow = (difference >> 32 != 0); + while (bigIndex > 0 && borrow) + borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1); + + // Copy remainder of longer number + while (bigIndex > 0) + result[--bigIndex] = big[bigIndex]; + + return result; + } + /** * Returns a BigInteger whose value is {@code (this - val)}. * @@ -1165,11 +1289,39 @@ public BigInteger multiply(BigInteger val) { if (val.signum == 0 || signum == 0) return ZERO; - + int resultSign = signum == val.signum ? 1 : -1; + if (val.mag.length == 1) { + return multiplyByInt(mag,val.mag[0], resultSign); + } + if(mag.length == 1) { + return multiplyByInt(val.mag,mag[0], resultSign); + } int[] result = multiplyToLen(mag, mag.length, val.mag, val.mag.length, null); result = trustedStripLeadingZeroInts(result); - return new BigInteger(result, signum == val.signum ? 1 : -1); + return new BigInteger(result, resultSign); + } + + private static BigInteger multiplyByInt(int[] x, int y, int sign) { + if(Integer.bitCount(y)==1) { + return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign); + } + int xlen = x.length; + int[] rmag = new int[xlen + 1]; + long carry = 0; + long yl = y & LONG_MASK; + int rstart = rmag.length - 1; + for (int i = xlen - 1; i >= 0; i--) { + long product = (x[i] & LONG_MASK) * yl + carry; + rmag[rstart--] = (int)product; + carry = product >>> 32; + } + if (carry == 0L) { + rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length); + } else { + rmag[rstart] = (int)carry; + } + return new BigInteger(rmag, sign); } /** @@ -1339,8 +1491,8 @@ a = new MutableBigInteger(this.mag), b = new MutableBigInteger(val.mag); - a.divide(b, q); - return q.toBigInteger(this.signum == val.signum ? 1 : -1); + a.divide(b, q, false); + return q.toBigInteger(this.signum * val.signum); } /** @@ -2069,7 +2221,12 @@ return shiftRight(-n); } } + int[] newMag = shiftLeft(mag,n); + return new BigInteger(newMag, signum); + } + + private static int[] shiftLeft(int[] mag, int n) { int nInts = n >>> 5; int nBits = n & 0x1f; int magLen = mag.length; @@ -2094,8 +2251,7 @@ newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2; newMag[i] = mag[j] << nBits; } - - return new BigInteger(newMag, signum); + return newMag; } /** @@ -2530,6 +2686,49 @@ } /** + * Version of compareMagnitude that compares magnitude with long value. + * val can't be Long.MIN_VALUE. + */ + final int compareMagnitude(long val) { + assert val != Long.MIN_VALUE; + int[] m1 = mag; + int len = m1.length; + if(len > 2) { + return 1; + } + if (val < 0) { + val = -val; + } + int highWord = (int)(val >>> 32); + if (highWord==0) { + if (len < 1) + return -1; + if (len > 1) + return 1; + int a = m1[0]; + int b = (int)val; + if (a != b) { + return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + } + return 0; + } else { + if (len < 2) + return -1; + int a = m1[0]; + int b = highWord; + if (a != b) { + return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + } + a = m1[1]; + b = (int)val; + if (a != b) { + return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1; + } + return 0; + } + } + + /** * Compares this BigInteger with the specified Object for equality. * * @param x Object to which this BigInteger is to be compared. --- old/src/share/classes/java/math/MutableBigInteger.java 2011-09-01 22:59:26.000000000 -0700 +++ new/src/share/classes/java/math/MutableBigInteger.java 2011-09-01 22:59:26.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,7 +160,7 @@ */ BigDecimal toBigDecimal(int sign, int scale) { if (intLen == 0 || sign == 0) - return BigDecimal.valueOf(0, scale); + return BigDecimal.zeroValueOf(scale); int[] mag = getMagnitudeArray(); int len = mag.length; int d = mag[0]; @@ -171,7 +171,28 @@ long v = (len == 2) ? ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : d & LONG_MASK; - return new BigDecimal(null, sign == -1 ? -v : v, scale, 0); + return BigDecimal.valueOf(sign == -1 ? -v : v, scale); + } + + /** + * This is for internal use in converting from a MutableBigInteger + * object into a long value given a specified sign. + * returns INFLATED if value is not fit into long + */ + long toCompactValue(int sign) { + if (intLen == 0 || sign == 0) + return 0L; + int[] mag = getMagnitudeArray(); + int len = mag.length; + int d = mag[0]; + // If this MutableBigInteger can not be fitted into long, we need to + // make a BigInteger object for the resultant BigDecimal object. + if (len > 2 || (d < 0 && len == 2)) + return INFLATED; + long v = (len == 2) ? + ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) : + d & LONG_MASK; + return sign == -1 ? -v : v; } /** @@ -544,6 +565,24 @@ } /** + * The method is the same as mulsun, except the fact that q array is not + * updated, the only result of the method is borrow flag. + */ + private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset) { + long xLong = x & LONG_MASK; + long carry = 0; + offset += len; + for (int j=len-1; j >= 0; j--) { + long product = (a[j] & LONG_MASK) * xLong + carry; + long difference = q[offset--] - product; + carry = (product >>> 32) + + (((difference & LONG_MASK) > + (((~(int)product) & LONG_MASK))) ? 1:0); + } + return (int)carry; + } + + /** * Right shift this MutableBigInteger n bits, where n is * less than 32. * Assumes that intLen > 0, n > 0 for speed @@ -842,20 +881,20 @@ rem = (int) (remLong - (quotient.value[0] * divisorLong)); remLong = rem & LONG_MASK; } - int xlen = intLen; - int[] qWord = new int[2]; while (--xlen > 0) { - long dividendEstimate = (remLong<<32) | - (value[offset + intLen - xlen] & LONG_MASK); + long dividendEstimate = (remLong << 32) | + (value[offset + intLen - xlen] & LONG_MASK); + int q; if (dividendEstimate >= 0) { - qWord[0] = (int) (dividendEstimate / divisorLong); - qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong); + q = (int) (dividendEstimate / divisorLong); + rem = (int) (dividendEstimate - q * divisorLong); } else { - divWord(qWord, dividendEstimate, divisor); + long tmp = divWord(dividendEstimate, divisor); + q = (int) (tmp & LONG_MASK); + rem = (int) (tmp >>> 32); } - quotient.value[intLen - xlen] = qWord[0]; - rem = qWord[1]; + quotient.value[intLen - xlen] = q; remLong = rem & LONG_MASK; } @@ -879,40 +918,45 @@ * */ MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) { + return divide(b,quotient,true); + } + + MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) { if (b.intLen == 0) throw new ArithmeticException("BigInteger divide by zero"); // Dividend is zero if (intLen == 0) { quotient.intLen = quotient.offset; - return new MutableBigInteger(); + return needReminder ? new MutableBigInteger() : null; } int cmp = compare(b); // Dividend less than divisor if (cmp < 0) { quotient.intLen = quotient.offset = 0; - return new MutableBigInteger(this); + return needReminder ? new MutableBigInteger(this) : null; } // Dividend equal to divisor if (cmp == 0) { quotient.value[0] = quotient.intLen = 1; quotient.offset = 0; - return new MutableBigInteger(); + return needReminder ? new MutableBigInteger() : null; } quotient.clear(); // Special case one word divisor if (b.intLen == 1) { int r = divideOneWord(b.value[b.offset], quotient); - if (r == 0) - return new MutableBigInteger(); - return new MutableBigInteger(r); + if(needReminder) { + if (r == 0) + return new MutableBigInteger(); + return new MutableBigInteger(r); + } else { + return null; + } } - - // Copy divisor value to protect divisor - int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen); - return divideMagnitude(div, quotient); + return divideMagnitude(b, quotient, needReminder); } /** @@ -940,30 +984,72 @@ if (d == 0) return divideOneWord((int)v, quotient) & LONG_MASK; else { - int[] div = new int[]{ d, (int)(v & LONG_MASK) }; - return divideMagnitude(div, quotient).toLong(); + return divideLongMagnitude(v, quotient).toLong(); + } + } + + private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift) { + int n2 = 32 - shift; + int c=src[srcFrom]; + for (int i=0; i < srcLen-1; i++) { + int b = c; + c = src[++srcFrom]; + dst[dstFrom+i] = (b << shift) | (c >>> n2); } + dst[dstFrom+srcLen-1] = c << shift; } /** - * Divide this MutableBigInteger by the divisor represented by its magnitude - * array. The quotient will be placed into the provided quotient object & + * Divide this MutableBigInteger by the divisor. + * The quotient will be placed into the provided quotient object & * the remainder object is returned. */ - private MutableBigInteger divideMagnitude(int[] divisor, - MutableBigInteger quotient) { - - // Remainder starts as dividend with space for a leading zero - MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]); - System.arraycopy(value, offset, rem.value, 1, intLen); - rem.intLen = intLen; - rem.offset = 1; + private MutableBigInteger divideMagnitude(MutableBigInteger div, + MutableBigInteger quotient, + boolean needReminder ) { + // assert div.intLen > 1 + // D1 normalize the divisor + int shift = Integer.numberOfLeadingZeros(div.value[div.offset]); + // Copy divisor value to protect divisor + final int dlen = div.intLen; + int[] divisor; + MutableBigInteger rem; // Remainder starts as dividend with space for a leading zero + if (shift > 0) { + divisor = new int[dlen]; + copyAndShift(div.value,div.offset,dlen,divisor,0,shift); + if(Integer.numberOfLeadingZeros(value[offset])>=shift) { + int[] remarr = new int[intLen + 1]; + rem = new MutableBigInteger(remarr); + rem.intLen = intLen; + rem.offset = 1; + copyAndShift(value,offset,intLen,remarr,1,shift); + } else { + int[] remarr = new int[intLen + 2]; + rem = new MutableBigInteger(remarr); + rem.intLen = intLen+1; + rem.offset = 1; + int rFrom = offset; + int c=0; + int n2 = 32 - shift; + for (int i=1; i < intLen+1; i++,rFrom++) { + int b = c; + c = value[rFrom]; + remarr[i] = (b << shift) | (c >>> n2); + } + remarr[intLen+1] = c << shift; + } + } else { + divisor = Arrays.copyOfRange(div.value, div.offset, div.offset + div.intLen); + rem = new MutableBigInteger(new int[intLen + 1]); + System.arraycopy(value, offset, rem.value, 1, intLen); + rem.intLen = intLen; + rem.offset = 1; + } int nlen = rem.intLen; // Set the quotient size - int dlen = divisor.length; - int limit = nlen - dlen + 1; + final int limit = nlen - dlen + 1; if (quotient.value.length < limit) { quotient.value = new int[limit]; quotient.offset = 0; @@ -971,14 +1057,6 @@ quotient.intLen = limit; int[] q = quotient.value; - // D1 normalize the divisor - int shift = Integer.numberOfLeadingZeros(divisor[0]); - if (shift > 0) { - // First shift will not grow array - BigInteger.primitiveLeftShift(divisor, dlen, shift); - // But this one might - rem.leftShift(shift); - } // Must insert leading 0 in rem if its length did not change if (rem.intLen == nlen) { @@ -990,10 +1068,9 @@ int dh = divisor[0]; long dhLong = dh & LONG_MASK; int dl = divisor[1]; - int[] qWord = new int[2]; // D2 Initialize j - for(int j=0; j>> 32); } } @@ -1053,6 +1130,181 @@ // Store the quotient digit q[j] = qhat; } // D7 loop on j + // D3 Calculate qhat + // estimate qhat + int qhat = 0; + int qrem = 0; + boolean skipCorrection = false; + int nh = rem.value[limit - 1 + rem.offset]; + int nh2 = nh + 0x80000000; + int nm = rem.value[limit + rem.offset]; + + if (nh == dh) { + qhat = ~0; + qrem = nh + nm; + skipCorrection = qrem + 0x80000000 < nh2; + } else { + long nChunk = (((long) nh) << 32) | (nm & LONG_MASK); + if (nChunk >= 0) { + qhat = (int) (nChunk / dhLong); + qrem = (int) (nChunk - (qhat * dhLong)); + } else { + long tmp = divWord(nChunk, dh); + qhat = (int) (tmp & LONG_MASK); + qrem = (int) (tmp >>> 32); + } + } + if (qhat != 0) { + if (!skipCorrection) { // Correct qhat + long nl = rem.value[limit + 1 + rem.offset] & LONG_MASK; + long rs = ((qrem & LONG_MASK) << 32) | nl; + long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); + + if (unsignedLongCompare(estProduct, rs)) { + qhat--; + qrem = (int) ((qrem & LONG_MASK) + dhLong); + if ((qrem & LONG_MASK) >= dhLong) { + estProduct -= (dl & LONG_MASK); + rs = ((qrem & LONG_MASK) << 32) | nl; + if (unsignedLongCompare(estProduct, rs)) + qhat--; + } + } + } + + + // D4 Multiply and subtract + int borrow; + rem.value[limit - 1 + rem.offset] = 0; + if(needReminder) + borrow = mulsub(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset); + else + borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset); + + // D5 Test remainder + if (borrow + 0x80000000 > nh2) { + // D6 Add back + if(needReminder) + divadd(divisor, rem.value, limit - 1 + 1 + rem.offset); + qhat--; + } + + // Store the quotient digit + q[(limit - 1)] = qhat; + } + + + if(needReminder) { + // D8 Unnormalize + if (shift > 0) + rem.rightShift(shift); + rem.normalize(); + } + quotient.normalize(); + return needReminder ? rem : null; + } + + /** + * Divide this MutableBigInteger by the divisor represented by positive long + * value. The quotient will be placed into the provided quotient object & + * the remainder object is returned. + */ + private MutableBigInteger divideLongMagnitude(long ldivisor, MutableBigInteger quotient) { + // Remainder starts as dividend with space for a leading zero + MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]); + System.arraycopy(value, offset, rem.value, 1, intLen); + rem.intLen = intLen; + rem.offset = 1; + + int nlen = rem.intLen; + + int limit = nlen - 2 + 1; + if (quotient.value.length < limit) { + quotient.value = new int[limit]; + quotient.offset = 0; + } + quotient.intLen = limit; + int[] q = quotient.value; + + // D1 normalize the divisor + int shift = Long.numberOfLeadingZeros(ldivisor); + if (shift > 0) { + ldivisor<<=shift; + rem.leftShift(shift); + } + + // Must insert leading 0 in rem if its length did not change + if (rem.intLen == nlen) { + rem.offset = 0; + rem.value[0] = 0; + rem.intLen++; + } + + int dh = (int)(ldivisor >>> 32); + long dhLong = dh & LONG_MASK; + int dl = (int)(ldivisor & LONG_MASK); + + // D2 Initialize j + for (int j = 0; j < limit; j++) { + // D3 Calculate qhat + // estimate qhat + int qhat = 0; + int qrem = 0; + boolean skipCorrection = false; + int nh = rem.value[j + rem.offset]; + int nh2 = nh + 0x80000000; + int nm = rem.value[j + 1 + rem.offset]; + + if (nh == dh) { + qhat = ~0; + qrem = nh + nm; + skipCorrection = qrem + 0x80000000 < nh2; + } else { + long nChunk = (((long) nh) << 32) | (nm & LONG_MASK); + if (nChunk >= 0) { + qhat = (int) (nChunk / dhLong); + qrem = (int) (nChunk - (qhat * dhLong)); + } else { + long tmp = divWord(nChunk, dh); + qhat =(int)(tmp & LONG_MASK); + qrem = (int)(tmp>>>32); + } + } + + if (qhat == 0) + continue; + + if (!skipCorrection) { // Correct qhat + long nl = rem.value[j + 2 + rem.offset] & LONG_MASK; + long rs = ((qrem & LONG_MASK) << 32) | nl; + long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK); + + if (unsignedLongCompare(estProduct, rs)) { + qhat--; + qrem = (int) ((qrem & LONG_MASK) + dhLong); + if ((qrem & LONG_MASK) >= dhLong) { + estProduct -= (dl & LONG_MASK); + rs = ((qrem & LONG_MASK) << 32) | nl; + if (unsignedLongCompare(estProduct, rs)) + qhat--; + } + } + } + + // D4 Multiply and subtract + rem.value[j + rem.offset] = 0; + int borrow = mulsubLong(rem.value, dh, dl, qhat, j + rem.offset); + + // D5 Test remainder + if (borrow + 0x80000000 > nh2) { + // D6 Add back + divaddLong(dh,dl, rem.value, j + 1 + rem.offset); + qhat--; + } + + // Store the quotient digit + q[j] = qhat; + } // D7 loop on j // D8 Unnormalize if (shift > 0) @@ -1064,6 +1316,46 @@ } /** + * A primitive used for division by long. + * Specialized version of the method divadd. + * dh is a high part of the divisor, dl is a low part + */ + private int divaddLong(int dh, int dl, int[] result, int offset) { + long carry = 0; + + long sum = (dl & LONG_MASK) + (result[1+offset] & LONG_MASK); + result[1+offset] = (int)sum; + + sum = (dh & LONG_MASK) + (result[offset] & LONG_MASK) + carry; + result[offset] = (int)sum; + carry = sum >>> 32; + return (int)carry; + } + + /** + * This method is used for division by long. + * Specialized version of the method sulsub. + * dh is a high part of the divisor, dl is a low part + */ + private int mulsubLong(int[] q, int dh, int dl, int x, int offset) { + long xLong = x & LONG_MASK; + offset += 2; + long product = (dl & LONG_MASK) * xLong; + long difference = q[offset] - product; + q[offset--] = (int)difference; + long carry = (product >>> 32) + + (((difference & LONG_MASK) > + (((~(int)product) & LONG_MASK))) ? 1:0); + product = (dh & LONG_MASK) * xLong + carry; + difference = q[offset] - product; + q[offset--] = (int)difference; + carry = (product >>> 32) + + (((difference & LONG_MASK) > + (((~(int)product) & LONG_MASK))) ? 1:0); + return (int)carry; + } + + /** * Compare two longs as if they were unsigned. * Returns true iff one is bigger than two. */ @@ -1075,19 +1367,22 @@ * This method divides a long quantity by an int to estimate * qhat for two multi precision numbers. It is used when * the signed value of n is less than zero. + * Returns long value where high 32 bits contain reminder value and + * low 32 bits contain quotient value. */ - private void divWord(int[] result, long n, int d) { + static long divWord(long n, int d) { long dLong = d & LONG_MASK; - + long r; + long q; if (dLong == 1) { - result[0] = (int)n; - result[1] = 0; - return; + q = (int)n; + r = 0; + return (r << 32) | (q & LONG_MASK); } // Approximate the quotient and remainder - long q = (n >>> 1) / (dLong >>> 1); - long r = n - q*dLong; + q = (n >>> 1) / (dLong >>> 1); + r = n - q*dLong; // Correct the approximation while (r < 0) { @@ -1098,10 +1393,8 @@ r -= dLong; q++; } - // n - q*dlong == r && 0 <= r