|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  |  | 
|  | /* | 
|  |  * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved | 
|  |  * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved | 
|  |  * | 
|  |  *   The original version of this source code and documentation is copyrighted | 
|  |  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These | 
|  |  * materials are provided under terms of a License Agreement between Taligent | 
|  |  * and Sun. This technology is protected by multiple US and International | 
|  |  * patents. This notice and attribution to Taligent may not be removed. | 
|  |  *   Taligent is a registered trademark of Taligent, Inc. | 
|  |  * | 
|  |  */ | 
|  |  | 
|  | package java.text; | 
|  |  | 
|  | import java.math.BigDecimal; | 
|  | import java.math.BigInteger; | 
|  | import java.math.RoundingMode; | 
|  | import sun.misc.FloatingDecimal; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  | final class DigitList implements Cloneable { | 
|  |     /** | 
|  |      * The maximum number of significant digits in an IEEE 754 double, that | 
|  |      * is, in a Java double.  This must not be increased, or garbage digits | 
|  |      * will be generated, and should not be decreased, or accuracy will be lost. | 
|  |      */ | 
|  |     public static final int MAX_COUNT = 19;  | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public int decimalAt = 0; | 
|  |     public int count = 0; | 
|  |     public char[] digits = new char[MAX_COUNT]; | 
|  |  | 
|  |     private char[] data; | 
|  |     private RoundingMode roundingMode = RoundingMode.HALF_EVEN; | 
|  |     private boolean isNegative = false; | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     boolean isZero() { | 
|  |         for (int i=0; i < count; ++i) { | 
|  |             if (digits[i] != '0') { | 
|  |                 return false; | 
|  |             } | 
|  |         } | 
|  |         return true; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     void setRoundingMode(RoundingMode r) { | 
|  |         roundingMode = r; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public void clear () { | 
|  |         decimalAt = 0; | 
|  |         count = 0; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     public void append(char digit) { | 
|  |         if (count == digits.length) { | 
|  |             char[] data = new char[count + 100]; | 
|  |             System.arraycopy(digits, 0, data, 0, count); | 
|  |             digits = data; | 
|  |         } | 
|  |         digits[count++] = digit; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public final double getDouble() { | 
|  |         if (count == 0) { | 
|  |             return 0.0; | 
|  |         } | 
|  |  | 
|  |         StringBuffer temp = getStringBuffer(); | 
|  |         temp.append('.'); | 
|  |         temp.append(digits, 0, count); | 
|  |         temp.append('E'); | 
|  |         temp.append(decimalAt); | 
|  |         return Double.parseDouble(temp.toString()); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public final long getLong() { | 
|  |         // for now, simple implementation; later, do proper IEEE native stuff | 
|  |  | 
|  |         if (count == 0) { | 
|  |             return 0; | 
|  |         } | 
|  |  | 
|  |         // We have to check for this, because this is the one NEGATIVE value | 
|  |         // we represent.  If we tried to just pass the digits off to parseLong, | 
|  |          | 
|  |         if (isLongMIN_VALUE()) { | 
|  |             return Long.MIN_VALUE; | 
|  |         } | 
|  |  | 
|  |         StringBuffer temp = getStringBuffer(); | 
|  |         temp.append(digits, 0, count); | 
|  |         for (int i = count; i < decimalAt; ++i) { | 
|  |             temp.append('0'); | 
|  |         } | 
|  |         return Long.parseLong(temp.toString()); | 
|  |     } | 
|  |  | 
|  |     public final BigDecimal getBigDecimal() { | 
|  |         if (count == 0) { | 
|  |             if (decimalAt == 0) { | 
|  |                 return BigDecimal.ZERO; | 
|  |             } else { | 
|  |                 return new BigDecimal("0E" + decimalAt); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |        if (decimalAt == count) { | 
|  |            return new BigDecimal(digits, 0, count); | 
|  |        } else { | 
|  |            return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count); | 
|  |        } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) { | 
|  |         // Figure out if the result will fit in a long.  We have to | 
|  |         // first look for nonzero digits after the decimal point; | 
|  |         // then check the size.  If the digit count is 18 or less, then | 
|  |         // the value can definitely be represented as a long.  If it is 19 | 
|  |         // then it may be too large. | 
|  |  | 
|  |          | 
|  |         while (count > 0 && digits[count - 1] == '0') { | 
|  |             --count; | 
|  |         } | 
|  |  | 
|  |         if (count == 0) { | 
|  |             // Positive zero fits into a long, but negative zero can only | 
|  |              | 
|  |             return isPositive || ignoreNegativeZero; | 
|  |         } | 
|  |  | 
|  |         if (decimalAt < count || decimalAt > MAX_COUNT) { | 
|  |             return false; | 
|  |         } | 
|  |  | 
|  |         if (decimalAt < MAX_COUNT) return true; | 
|  |  | 
|  |         // At this point we have decimalAt == count, and count == MAX_COUNT. | 
|  |         // The number will overflow if it is larger than 9223372036854775807 | 
|  |          | 
|  |         for (int i=0; i<count; ++i) { | 
|  |             char dig = digits[i], max = LONG_MIN_REP[i]; | 
|  |             if (dig > max) return false; | 
|  |             if (dig < max) return true; | 
|  |         } | 
|  |  | 
|  |         // At this point the first count digits match.  If decimalAt is less | 
|  |          | 
|  |         if (count < decimalAt) return true; | 
|  |  | 
|  |         // Now we have a representation of Long.MIN_VALUE, without the leading | 
|  |         // negative sign.  If this represents a positive value, then it does | 
|  |          | 
|  |         return !isPositive; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, double source, int maximumFractionDigits) { | 
|  |         set(isNegative, source, maximumFractionDigits, true); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) { | 
|  |  | 
|  |         FloatingDecimal.BinaryToASCIIConverter fdConverter  = FloatingDecimal.getBinaryToASCIIConverter(source); | 
|  |         boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); | 
|  |         boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); | 
|  |         assert !fdConverter.isExceptional(); | 
|  |         String digitsString = fdConverter.toJavaFormatString(); | 
|  |  | 
|  |         set(isNegative, digitsString, | 
|  |             hasBeenRoundedUp, valueExactAsDecimal, | 
|  |             maximumDigits, fixedPoint); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private void set(boolean isNegative, String s, | 
|  |                      boolean roundedUp, boolean valueExactAsDecimal, | 
|  |                      int maximumDigits, boolean fixedPoint) { | 
|  |  | 
|  |         this.isNegative = isNegative; | 
|  |         int len = s.length(); | 
|  |         char[] source = getDataChars(len); | 
|  |         s.getChars(0, len, source, 0); | 
|  |  | 
|  |         decimalAt = -1; | 
|  |         count = 0; | 
|  |         int exponent = 0; | 
|  |         // Number of zeros between decimal point and first non-zero digit after | 
|  |          | 
|  |         int leadingZerosAfterDecimal = 0; | 
|  |         boolean nonZeroDigitSeen = false; | 
|  |  | 
|  |         for (int i = 0; i < len; ) { | 
|  |             char c = source[i++]; | 
|  |             if (c == '.') { | 
|  |                 decimalAt = count; | 
|  |             } else if (c == 'e' || c == 'E') { | 
|  |                 exponent = parseInt(source, i, len); | 
|  |                 break; | 
|  |             } else { | 
|  |                 if (!nonZeroDigitSeen) { | 
|  |                     nonZeroDigitSeen = (c != '0'); | 
|  |                     if (!nonZeroDigitSeen && decimalAt != -1) | 
|  |                         ++leadingZerosAfterDecimal; | 
|  |                 } | 
|  |                 if (nonZeroDigitSeen) { | 
|  |                     digits[count++] = c; | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |         if (decimalAt == -1) { | 
|  |             decimalAt = count; | 
|  |         } | 
|  |         if (nonZeroDigitSeen) { | 
|  |             decimalAt += exponent - leadingZerosAfterDecimal; | 
|  |         } | 
|  |  | 
|  |         if (fixedPoint) { | 
|  |             // The negative of the exponent represents the number of leading | 
|  |             // zeros between the decimal and the first non-zero digit, for | 
|  |             // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2).  If this | 
|  |             // is more than the maximum fraction digits, then we have an underflow | 
|  |              | 
|  |             if (-decimalAt > maximumDigits) { | 
|  |                 // Handle an underflow to zero when we round something like | 
|  |                  | 
|  |                 count = 0; | 
|  |                 return; | 
|  |             } else if (-decimalAt == maximumDigits) { | 
|  |                 // If we round 0.0009 to 3 fractional digits, then we have to | 
|  |                  | 
|  |                 if (shouldRoundUp(0, roundedUp, valueExactAsDecimal)) { | 
|  |                     count = 1; | 
|  |                     ++decimalAt; | 
|  |                     digits[0] = '1'; | 
|  |                 } else { | 
|  |                     count = 0; | 
|  |                 } | 
|  |                 return; | 
|  |             } | 
|  |             // else fall through | 
|  |         } | 
|  |  | 
|  |          | 
|  |         while (count > 1 && digits[count - 1] == '0') { | 
|  |             --count; | 
|  |         } | 
|  |  | 
|  |         // Eliminate digits beyond maximum digits to be displayed. | 
|  |          | 
|  |         round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits, | 
|  |               roundedUp, valueExactAsDecimal); | 
|  |  | 
|  |      } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private final void round(int maximumDigits, | 
|  |                              boolean alreadyRounded, | 
|  |                              boolean valueExactAsDecimal) { | 
|  |         // Eliminate digits beyond maximum digits to be displayed. | 
|  |          | 
|  |         if (maximumDigits >= 0 && maximumDigits < count) { | 
|  |             if (shouldRoundUp(maximumDigits, alreadyRounded, valueExactAsDecimal)) { | 
|  |                 // Rounding up involved incrementing digits from LSD to MSD. | 
|  |                 // In most cases this is simple, but in a worst case situation | 
|  |                  | 
|  |                 for (;;) { | 
|  |                     --maximumDigits; | 
|  |                     if (maximumDigits < 0) { | 
|  |                         // We have all 9's, so we increment to a single digit | 
|  |                          | 
|  |                         digits[0] = '1'; | 
|  |                         ++decimalAt; | 
|  |                         maximumDigits = 0;  | 
|  |                         break; | 
|  |                     } | 
|  |  | 
|  |                     ++digits[maximumDigits]; | 
|  |                     if (digits[maximumDigits] <= '9') break; | 
|  |                     // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this | 
|  |                 } | 
|  |                 ++maximumDigits;  | 
|  |             } | 
|  |             count = maximumDigits; | 
|  |  | 
|  |              | 
|  |             while (count > 1 && digits[count-1] == '0') { | 
|  |                 --count; | 
|  |             } | 
|  |         } | 
|  |     } | 
|  |  | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private boolean shouldRoundUp(int maximumDigits, | 
|  |                                   boolean alreadyRounded, | 
|  |                                   boolean valueExactAsDecimal) { | 
|  |         if (maximumDigits < count) { | 
|  |             /* | 
|  |              * To avoid erroneous double-rounding or truncation when converting | 
|  |              * a binary double value to text, information about the exactness | 
|  |              * of the conversion result in FloatingDecimal, as well as any | 
|  |              * rounding done, is needed in this class. | 
|  |              * | 
|  |              * - For the  HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below: | 
|  |              *   In the case of formating float or double, We must take into | 
|  |              *   account what FloatingDecimal has done in the binary to decimal | 
|  |              *   conversion. | 
|  |              * | 
|  |              *   Considering the tie cases, FloatingDecimal may round up the | 
|  |              *   value (returning decimal digits equal to tie when it is below), | 
|  |              *   or "truncate" the value to the tie while value is above it, | 
|  |              *   or provide the exact decimal digits when the binary value can be | 
|  |              *   converted exactly to its decimal representation given formating | 
|  |              *   rules of FloatingDecimal ( we have thus an exact decimal | 
|  |              *   representation of the binary value). | 
|  |              * | 
|  |              *   - If the double binary value was converted exactly as a decimal | 
|  |              *     value, then DigitList code must apply the expected rounding | 
|  |              *     rule. | 
|  |              * | 
|  |              *   - If FloatingDecimal already rounded up the decimal value, | 
|  |              *     DigitList should neither round up the value again in any of | 
|  |              *     the three rounding modes above. | 
|  |              * | 
|  |              *   - If FloatingDecimal has truncated the decimal value to | 
|  |              *     an ending '5' digit, DigitList should round up the value in | 
|  |              *     all of the three rounding modes above. | 
|  |              * | 
|  |              * | 
|  |              *   This has to be considered only if digit at maximumDigits index | 
|  |              *   is exactly the last one in the set of digits, otherwise there are | 
|  |              *   remaining digits after that position and we don't have to consider | 
|  |              *   what FloatingDecimal did. | 
|  |              * | 
|  |              * - Other rounding modes are not impacted by these tie cases. | 
|  |              * | 
|  |              * - For other numbers that are always converted to exact digits | 
|  |              *   (like BigInteger, Long, ...), the passed alreadyRounded boolean | 
|  |              *   have to be  set to false, and valueExactAsDecimal has to be set to | 
|  |              *   true in the upper DigitList call stack, providing the right state | 
|  |              *   for those situations.. | 
|  |              */ | 
|  |  | 
|  |             switch(roundingMode) { | 
|  |             case UP: | 
|  |                 for (int i=maximumDigits; i<count; ++i) { | 
|  |                     if (digits[i] != '0') { | 
|  |                         return true; | 
|  |                     } | 
|  |                 } | 
|  |                 break; | 
|  |             case DOWN: | 
|  |                 break; | 
|  |             case CEILING: | 
|  |                 for (int i=maximumDigits; i<count; ++i) { | 
|  |                     if (digits[i] != '0') { | 
|  |                         return !isNegative; | 
|  |                     } | 
|  |                 } | 
|  |                 break; | 
|  |             case FLOOR: | 
|  |                 for (int i=maximumDigits; i<count; ++i) { | 
|  |                     if (digits[i] != '0') { | 
|  |                         return isNegative; | 
|  |                     } | 
|  |                 } | 
|  |                 break; | 
|  |             case HALF_UP: | 
|  |             case HALF_DOWN: | 
|  |                 if (digits[maximumDigits] > '5') { | 
|  |                      | 
|  |                     return true; | 
|  |                 } else if (digits[maximumDigits] == '5') { | 
|  |                      | 
|  |                     if (maximumDigits != (count - 1)) { | 
|  |                          | 
|  |                         return true; | 
|  |                     } else { | 
|  |                          | 
|  |                         if (valueExactAsDecimal) { | 
|  |                             // Exact binary representation. On the tie. | 
|  |                              | 
|  |                             return roundingMode == RoundingMode.HALF_UP; | 
|  |                         } else { | 
|  |                             // Not an exact binary representation. | 
|  |                             // Digit sequence either rounded up or truncated. | 
|  |                              | 
|  |                             return !alreadyRounded; | 
|  |                         } | 
|  |                     } | 
|  |                 } | 
|  |                 // Digit at rounding position is < '5' ==> no round up. | 
|  |                  | 
|  |                 break; | 
|  |             case HALF_EVEN: | 
|  |                  | 
|  |                 if (digits[maximumDigits] > '5') { | 
|  |                     return true; | 
|  |                 } else if (digits[maximumDigits] == '5' ) { | 
|  |                     if (maximumDigits == (count - 1)) { | 
|  |                          | 
|  |                         if (alreadyRounded) | 
|  |                             // If FloatingDecimal rounded up (value was below tie), | 
|  |                              | 
|  |                             return false; | 
|  |  | 
|  |                         if (!valueExactAsDecimal) | 
|  |                             // Otherwise if the digits don't represent exact value, | 
|  |                             // value was above tie and FloatingDecimal truncated | 
|  |                              | 
|  |                             return true; | 
|  |                         else { | 
|  |                             // This is an exact tie value, and FloatingDecimal | 
|  |                             // provided all of the exact digits. We thus apply | 
|  |                              | 
|  |                             return ((maximumDigits > 0) && | 
|  |                                     (digits[maximumDigits-1] % 2 != 0)); | 
|  |                         } | 
|  |                     } else { | 
|  |                          | 
|  |                         for (int i=maximumDigits+1; i<count; ++i) { | 
|  |                             if (digits[i] != '0') | 
|  |                                 return true; | 
|  |                         } | 
|  |                     } | 
|  |                 } | 
|  |                 break; | 
|  |             case UNNECESSARY: | 
|  |                 for (int i=maximumDigits; i<count; ++i) { | 
|  |                     if (digits[i] != '0') { | 
|  |                         throw new ArithmeticException( | 
|  |                             "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY"); | 
|  |                     } | 
|  |                 } | 
|  |                 break; | 
|  |             default: | 
|  |                 assert false; | 
|  |             } | 
|  |         } | 
|  |         return false; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, long source) { | 
|  |         set(isNegative, source, 0); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, long source, int maximumDigits) { | 
|  |         this.isNegative = isNegative; | 
|  |  | 
|  |         // This method does not expect a negative number. However, | 
|  |         // "source" can be a Long.MIN_VALUE (-9223372036854775808), | 
|  |         // if the number being formatted is a Long.MIN_VALUE.  In that | 
|  |         // case, it will be formatted as -Long.MIN_VALUE, a number | 
|  |         // which is outside the legal range of a long, but which can | 
|  |          | 
|  |         if (source <= 0) { | 
|  |             if (source == Long.MIN_VALUE) { | 
|  |                 decimalAt = count = MAX_COUNT; | 
|  |                 System.arraycopy(LONG_MIN_REP, 0, digits, 0, count); | 
|  |             } else { | 
|  |                 decimalAt = count = 0;  | 
|  |             } | 
|  |         } else { | 
|  |             // Rewritten to improve performance.  I used to call | 
|  |              | 
|  |             int left = MAX_COUNT; | 
|  |             int right; | 
|  |             while (source > 0) { | 
|  |                 digits[--left] = (char)('0' + (source % 10)); | 
|  |                 source /= 10; | 
|  |             } | 
|  |             decimalAt = MAX_COUNT - left; | 
|  |             // Don't copy trailing zeros.  We are guaranteed that there is at | 
|  |              | 
|  |             for (right = MAX_COUNT - 1; digits[right] == '0'; --right) | 
|  |                 ; | 
|  |             count = right - left + 1; | 
|  |             System.arraycopy(digits, left, digits, 0, count); | 
|  |         } | 
|  |         if (maximumDigits > 0) round(maximumDigits, false, true); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { | 
|  |         String s = source.toString(); | 
|  |         extendDigits(s.length()); | 
|  |  | 
|  |         set(isNegative, s, | 
|  |             false, true, | 
|  |             maximumDigits, fixedPoint); | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     final void set(boolean isNegative, BigInteger source, int maximumDigits) { | 
|  |         this.isNegative = isNegative; | 
|  |         String s = source.toString(); | 
|  |         int len = s.length(); | 
|  |         extendDigits(len); | 
|  |         s.getChars(0, len, digits, 0); | 
|  |  | 
|  |         decimalAt = len; | 
|  |         int right; | 
|  |         for (right = len - 1; right >= 0 && digits[right] == '0'; --right) | 
|  |             ; | 
|  |         count = right + 1; | 
|  |  | 
|  |         if (maximumDigits > 0) { | 
|  |             round(maximumDigits, false, true); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     public boolean equals(Object obj) { | 
|  |         if (this == obj)                       | 
|  |             return true; | 
|  |         if (!(obj instanceof DigitList))          | 
|  |             return false; | 
|  |         DigitList other = (DigitList) obj; | 
|  |         if (count != other.count || | 
|  |         decimalAt != other.decimalAt) | 
|  |             return false; | 
|  |         for (int i = 0; i < count; i++) | 
|  |             if (digits[i] != other.digits[i]) | 
|  |                 return false; | 
|  |         return true; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     public int hashCode() { | 
|  |         int hashcode = decimalAt; | 
|  |  | 
|  |         for (int i = 0; i < count; i++) { | 
|  |             hashcode = hashcode * 37 + digits[i]; | 
|  |         } | 
|  |  | 
|  |         return hashcode; | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     public Object clone() { | 
|  |         try { | 
|  |             DigitList other = (DigitList) super.clone(); | 
|  |             char[] newDigits = new char[digits.length]; | 
|  |             System.arraycopy(digits, 0, newDigits, 0, digits.length); | 
|  |             other.digits = newDigits; | 
|  |             other.tempBuffer = null; | 
|  |             return other; | 
|  |         } catch (CloneNotSupportedException e) { | 
|  |             throw new InternalError(e); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |  | 
|  |      */ | 
|  |     private boolean isLongMIN_VALUE() { | 
|  |         if (decimalAt != count || count != MAX_COUNT) { | 
|  |             return false; | 
|  |         } | 
|  |  | 
|  |         for (int i = 0; i < count; ++i) { | 
|  |             if (digits[i] != LONG_MIN_REP[i]) return false; | 
|  |         } | 
|  |  | 
|  |         return true; | 
|  |     } | 
|  |  | 
|  |     private static final int parseInt(char[] str, int offset, int strLen) { | 
|  |         char c; | 
|  |         boolean positive = true; | 
|  |         if ((c = str[offset]) == '-') { | 
|  |             positive = false; | 
|  |             offset++; | 
|  |         } else if (c == '+') { | 
|  |             offset++; | 
|  |         } | 
|  |  | 
|  |         int value = 0; | 
|  |         while (offset < strLen) { | 
|  |             c = str[offset++]; | 
|  |             if (c >= '0' && c <= '9') { | 
|  |                 value = value * 10 + (c - '0'); | 
|  |             } else { | 
|  |                 break; | 
|  |             } | 
|  |         } | 
|  |         return positive ? value : -value; | 
|  |     } | 
|  |  | 
|  |      | 
|  |     private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray(); | 
|  |  | 
|  |     public String toString() { | 
|  |         if (isZero()) { | 
|  |             return "0"; | 
|  |         } | 
|  |         StringBuffer buf = getStringBuffer(); | 
|  |         buf.append("0."); | 
|  |         buf.append(digits, 0, count); | 
|  |         buf.append("x10^"); | 
|  |         buf.append(decimalAt); | 
|  |         return buf.toString(); | 
|  |     } | 
|  |  | 
|  |     private StringBuffer tempBuffer; | 
|  |  | 
|  |     private StringBuffer getStringBuffer() { | 
|  |         if (tempBuffer == null) { | 
|  |             tempBuffer = new StringBuffer(MAX_COUNT); | 
|  |         } else { | 
|  |             tempBuffer.setLength(0); | 
|  |         } | 
|  |         return tempBuffer; | 
|  |     } | 
|  |  | 
|  |     private void extendDigits(int len) { | 
|  |         if (len > digits.length) { | 
|  |             digits = new char[len]; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     private final char[] getDataChars(int length) { | 
|  |         if (data == null || data.length < length) { | 
|  |             data = new char[length]; | 
|  |         } | 
|  |         return data; | 
|  |     } | 
|  | } |