1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java Thu Oct 03 15:40:35 2013 +0200
1.3 @@ -0,0 +1,715 @@
1.4 +/*
1.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +/*
1.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
1.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
1.32 + *
1.33 + * The original version of this source code and documentation is copyrighted
1.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
1.35 + * materials are provided under terms of a License Agreement between Taligent
1.36 + * and Sun. This technology is protected by multiple US and International
1.37 + * patents. This notice and attribution to Taligent may not be removed.
1.38 + * Taligent is a registered trademark of Taligent, Inc.
1.39 + *
1.40 + */
1.41 +
1.42 +package java.text;
1.43 +
1.44 +import java.math.BigDecimal;
1.45 +import java.math.BigInteger;
1.46 +import java.math.RoundingMode;
1.47 +
1.48 +/**
1.49 + * Digit List. Private to DecimalFormat.
1.50 + * Handles the transcoding
1.51 + * between numeric values and strings of characters. Only handles
1.52 + * non-negative numbers. The division of labor between DigitList and
1.53 + * DecimalFormat is that DigitList handles the radix 10 representation
1.54 + * issues; DecimalFormat handles the locale-specific issues such as
1.55 + * positive/negative, grouping, decimal point, currency, and so on.
1.56 + *
1.57 + * A DigitList is really a representation of a floating point value.
1.58 + * It may be an integer value; we assume that a double has sufficient
1.59 + * precision to represent all digits of a long.
1.60 + *
1.61 + * The DigitList representation consists of a string of characters,
1.62 + * which are the digits radix 10, from '0' to '9'. It also has a radix
1.63 + * 10 exponent associated with it. The value represented by a DigitList
1.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
1.65 + * derived by placing all the digits of the list to the right of the
1.66 + * decimal point, by 10^exponent.
1.67 + *
1.68 + * @see Locale
1.69 + * @see Format
1.70 + * @see NumberFormat
1.71 + * @see DecimalFormat
1.72 + * @see ChoiceFormat
1.73 + * @see MessageFormat
1.74 + * @author Mark Davis, Alan Liu
1.75 + */
1.76 +final class DigitList implements Cloneable {
1.77 + /**
1.78 + * The maximum number of significant digits in an IEEE 754 double, that
1.79 + * is, in a Java double. This must not be increased, or garbage digits
1.80 + * will be generated, and should not be decreased, or accuracy will be lost.
1.81 + */
1.82 + public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
1.83 +
1.84 + /**
1.85 + * These data members are intentionally public and can be set directly.
1.86 + *
1.87 + * The value represented is given by placing the decimal point before
1.88 + * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
1.89 + * the decimal point and the first nonzero digit are implied. If decimalAt
1.90 + * is > count, then trailing zeros between the digits[count-1] and the
1.91 + * decimal point are implied.
1.92 + *
1.93 + * Equivalently, the represented value is given by f * 10^decimalAt. Here
1.94 + * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
1.95 + * the right of the decimal.
1.96 + *
1.97 + * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
1.98 + * don't allow denormalized numbers because our exponent is effectively of
1.99 + * unlimited magnitude. The count value contains the number of significant
1.100 + * digits present in digits[].
1.101 + *
1.102 + * Zero is represented by any DigitList with count == 0 or with each digits[i]
1.103 + * for all i <= count == '0'.
1.104 + */
1.105 + public int decimalAt = 0;
1.106 + public int count = 0;
1.107 + public char[] digits = new char[MAX_COUNT];
1.108 +
1.109 + private char[] data;
1.110 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
1.111 + private boolean isNegative = false;
1.112 +
1.113 + /**
1.114 + * Return true if the represented number is zero.
1.115 + */
1.116 + boolean isZero() {
1.117 + for (int i=0; i < count; ++i) {
1.118 + if (digits[i] != '0') {
1.119 + return false;
1.120 + }
1.121 + }
1.122 + return true;
1.123 + }
1.124 +
1.125 + /**
1.126 + * Set the rounding mode
1.127 + */
1.128 + void setRoundingMode(RoundingMode r) {
1.129 + roundingMode = r;
1.130 + }
1.131 +
1.132 + /**
1.133 + * Clears out the digits.
1.134 + * Use before appending them.
1.135 + * Typically, you set a series of digits with append, then at the point
1.136 + * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
1.137 + * then go on appending digits.
1.138 + */
1.139 + public void clear () {
1.140 + decimalAt = 0;
1.141 + count = 0;
1.142 + }
1.143 +
1.144 + /**
1.145 + * Appends a digit to the list, extending the list when necessary.
1.146 + */
1.147 + public void append(char digit) {
1.148 + if (count == digits.length) {
1.149 + char[] data = new char[count + 100];
1.150 + System.arraycopy(digits, 0, data, 0, count);
1.151 + digits = data;
1.152 + }
1.153 + digits[count++] = digit;
1.154 + }
1.155 +
1.156 + /**
1.157 + * Utility routine to get the value of the digit list
1.158 + * If (count == 0) this throws a NumberFormatException, which
1.159 + * mimics Long.parseLong().
1.160 + */
1.161 + public final double getDouble() {
1.162 + if (count == 0) {
1.163 + return 0.0;
1.164 + }
1.165 +
1.166 + StringBuffer temp = getStringBuffer();
1.167 + temp.append('.');
1.168 + temp.append(digits, 0, count);
1.169 + temp.append('E');
1.170 + temp.append(decimalAt);
1.171 + return Double.parseDouble(temp.toString());
1.172 + }
1.173 +
1.174 + /**
1.175 + * Utility routine to get the value of the digit list.
1.176 + * If (count == 0) this returns 0, unlike Long.parseLong().
1.177 + */
1.178 + public final long getLong() {
1.179 + // for now, simple implementation; later, do proper IEEE native stuff
1.180 +
1.181 + if (count == 0) {
1.182 + return 0;
1.183 + }
1.184 +
1.185 + // We have to check for this, because this is the one NEGATIVE value
1.186 + // we represent. If we tried to just pass the digits off to parseLong,
1.187 + // we'd get a parse failure.
1.188 + if (isLongMIN_VALUE()) {
1.189 + return Long.MIN_VALUE;
1.190 + }
1.191 +
1.192 + StringBuffer temp = getStringBuffer();
1.193 + temp.append(digits, 0, count);
1.194 + for (int i = count; i < decimalAt; ++i) {
1.195 + temp.append('0');
1.196 + }
1.197 + return Long.parseLong(temp.toString());
1.198 + }
1.199 +
1.200 + public final BigDecimal getBigDecimal() {
1.201 + if (count == 0) {
1.202 + if (decimalAt == 0) {
1.203 + return BigDecimal.ZERO;
1.204 + } else {
1.205 + return new BigDecimal("0E" + decimalAt);
1.206 + }
1.207 + }
1.208 +
1.209 + if (decimalAt == count) {
1.210 + return new BigDecimal(digits, 0, count);
1.211 + } else {
1.212 + return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
1.213 + }
1.214 + }
1.215 +
1.216 + /**
1.217 + * Return true if the number represented by this object can fit into
1.218 + * a long.
1.219 + * @param isPositive true if this number should be regarded as positive
1.220 + * @param ignoreNegativeZero true if -0 should be regarded as identical to
1.221 + * +0; otherwise they are considered distinct
1.222 + * @return true if this number fits into a Java long
1.223 + */
1.224 + boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
1.225 + // Figure out if the result will fit in a long. We have to
1.226 + // first look for nonzero digits after the decimal point;
1.227 + // then check the size. If the digit count is 18 or less, then
1.228 + // the value can definitely be represented as a long. If it is 19
1.229 + // then it may be too large.
1.230 +
1.231 + // Trim trailing zeros. This does not change the represented value.
1.232 + while (count > 0 && digits[count - 1] == '0') {
1.233 + --count;
1.234 + }
1.235 +
1.236 + if (count == 0) {
1.237 + // Positive zero fits into a long, but negative zero can only
1.238 + // be represented as a double. - bug 4162852
1.239 + return isPositive || ignoreNegativeZero;
1.240 + }
1.241 +
1.242 + if (decimalAt < count || decimalAt > MAX_COUNT) {
1.243 + return false;
1.244 + }
1.245 +
1.246 + if (decimalAt < MAX_COUNT) return true;
1.247 +
1.248 + // At this point we have decimalAt == count, and count == MAX_COUNT.
1.249 + // The number will overflow if it is larger than 9223372036854775807
1.250 + // or smaller than -9223372036854775808.
1.251 + for (int i=0; i<count; ++i) {
1.252 + char dig = digits[i], max = LONG_MIN_REP[i];
1.253 + if (dig > max) return false;
1.254 + if (dig < max) return true;
1.255 + }
1.256 +
1.257 + // At this point the first count digits match. If decimalAt is less
1.258 + // than count, then the remaining digits are zero, and we return true.
1.259 + if (count < decimalAt) return true;
1.260 +
1.261 + // Now we have a representation of Long.MIN_VALUE, without the leading
1.262 + // negative sign. If this represents a positive value, then it does
1.263 + // not fit; otherwise it fits.
1.264 + return !isPositive;
1.265 + }
1.266 +
1.267 + /**
1.268 + * Set the digit list to a representation of the given double value.
1.269 + * This method supports fixed-point notation.
1.270 + * @param isNegative Boolean value indicating whether the number is negative.
1.271 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
1.272 + * or a value <= 0.
1.273 + * @param maximumFractionDigits The most fractional digits which should
1.274 + * be converted.
1.275 + */
1.276 + public final void set(boolean isNegative, double source, int maximumFractionDigits) {
1.277 + set(isNegative, source, maximumFractionDigits, true);
1.278 + }
1.279 +
1.280 + /**
1.281 + * Set the digit list to a representation of the given double value.
1.282 + * This method supports both fixed-point and exponential notation.
1.283 + * @param isNegative Boolean value indicating whether the number is negative.
1.284 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
1.285 + * or a value <= 0.
1.286 + * @param maximumDigits The most fractional or total digits which should
1.287 + * be converted.
1.288 + * @param fixedPoint If true, then maximumDigits is the maximum
1.289 + * fractional digits to be converted. If false, total digits.
1.290 + */
1.291 + final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
1.292 + set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
1.293 + }
1.294 +
1.295 + /**
1.296 + * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
1.297 + * DDDDDE+/-DDDDD.
1.298 + */
1.299 + final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
1.300 + this.isNegative = isNegative;
1.301 + int len = s.length();
1.302 + char[] source = getDataChars(len);
1.303 + s.getChars(0, len, source, 0);
1.304 +
1.305 + decimalAt = -1;
1.306 + count = 0;
1.307 + int exponent = 0;
1.308 + // Number of zeros between decimal point and first non-zero digit after
1.309 + // decimal point, for numbers < 1.
1.310 + int leadingZerosAfterDecimal = 0;
1.311 + boolean nonZeroDigitSeen = false;
1.312 +
1.313 + for (int i = 0; i < len; ) {
1.314 + char c = source[i++];
1.315 + if (c == '.') {
1.316 + decimalAt = count;
1.317 + } else if (c == 'e' || c == 'E') {
1.318 + exponent = parseInt(source, i, len);
1.319 + break;
1.320 + } else {
1.321 + if (!nonZeroDigitSeen) {
1.322 + nonZeroDigitSeen = (c != '0');
1.323 + if (!nonZeroDigitSeen && decimalAt != -1)
1.324 + ++leadingZerosAfterDecimal;
1.325 + }
1.326 + if (nonZeroDigitSeen) {
1.327 + digits[count++] = c;
1.328 + }
1.329 + }
1.330 + }
1.331 + if (decimalAt == -1) {
1.332 + decimalAt = count;
1.333 + }
1.334 + if (nonZeroDigitSeen) {
1.335 + decimalAt += exponent - leadingZerosAfterDecimal;
1.336 + }
1.337 +
1.338 + if (fixedPoint) {
1.339 + // The negative of the exponent represents the number of leading
1.340 + // zeros between the decimal and the first non-zero digit, for
1.341 + // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
1.342 + // is more than the maximum fraction digits, then we have an underflow
1.343 + // for the printed representation.
1.344 + if (-decimalAt > maximumDigits) {
1.345 + // Handle an underflow to zero when we round something like
1.346 + // 0.0009 to 2 fractional digits.
1.347 + count = 0;
1.348 + return;
1.349 + } else if (-decimalAt == maximumDigits) {
1.350 + // If we round 0.0009 to 3 fractional digits, then we have to
1.351 + // create a new one digit in the least significant location.
1.352 + if (shouldRoundUp(0)) {
1.353 + count = 1;
1.354 + ++decimalAt;
1.355 + digits[0] = '1';
1.356 + } else {
1.357 + count = 0;
1.358 + }
1.359 + return;
1.360 + }
1.361 + // else fall through
1.362 + }
1.363 +
1.364 + // Eliminate trailing zeros.
1.365 + while (count > 1 && digits[count - 1] == '0') {
1.366 + --count;
1.367 + }
1.368 +
1.369 + // Eliminate digits beyond maximum digits to be displayed.
1.370 + // Round up if appropriate.
1.371 + round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
1.372 + }
1.373 +
1.374 + /**
1.375 + * Round the representation to the given number of digits.
1.376 + * @param maximumDigits The maximum number of digits to be shown.
1.377 + * Upon return, count will be less than or equal to maximumDigits.
1.378 + */
1.379 + private final void round(int maximumDigits) {
1.380 + // Eliminate digits beyond maximum digits to be displayed.
1.381 + // Round up if appropriate.
1.382 + if (maximumDigits >= 0 && maximumDigits < count) {
1.383 + if (shouldRoundUp(maximumDigits)) {
1.384 + // Rounding up involved incrementing digits from LSD to MSD.
1.385 + // In most cases this is simple, but in a worst case situation
1.386 + // (9999..99) we have to adjust the decimalAt value.
1.387 + for (;;) {
1.388 + --maximumDigits;
1.389 + if (maximumDigits < 0) {
1.390 + // We have all 9's, so we increment to a single digit
1.391 + // of one and adjust the exponent.
1.392 + digits[0] = '1';
1.393 + ++decimalAt;
1.394 + maximumDigits = 0; // Adjust the count
1.395 + break;
1.396 + }
1.397 +
1.398 + ++digits[maximumDigits];
1.399 + if (digits[maximumDigits] <= '9') break;
1.400 + // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
1.401 + }
1.402 + ++maximumDigits; // Increment for use as count
1.403 + }
1.404 + count = maximumDigits;
1.405 +
1.406 + // Eliminate trailing zeros.
1.407 + while (count > 1 && digits[count-1] == '0') {
1.408 + --count;
1.409 + }
1.410 + }
1.411 + }
1.412 +
1.413 +
1.414 + /**
1.415 + * Return true if truncating the representation to the given number
1.416 + * of digits will result in an increment to the last digit. This
1.417 + * method implements the rounding modes defined in the
1.418 + * java.math.RoundingMode class.
1.419 + * [bnf]
1.420 + * @param maximumDigits the number of digits to keep, from 0 to
1.421 + * <code>count-1</code>. If 0, then all digits are rounded away, and
1.422 + * this method returns true if a one should be generated (e.g., formatting
1.423 + * 0.09 with "#.#").
1.424 + * @exception ArithmeticException if rounding is needed with rounding
1.425 + * mode being set to RoundingMode.UNNECESSARY
1.426 + * @return true if digit <code>maximumDigits-1</code> should be
1.427 + * incremented
1.428 + */
1.429 + private boolean shouldRoundUp(int maximumDigits) {
1.430 + if (maximumDigits < count) {
1.431 + switch(roundingMode) {
1.432 + case UP:
1.433 + for (int i=maximumDigits; i<count; ++i) {
1.434 + if (digits[i] != '0') {
1.435 + return true;
1.436 + }
1.437 + }
1.438 + break;
1.439 + case DOWN:
1.440 + break;
1.441 + case CEILING:
1.442 + for (int i=maximumDigits; i<count; ++i) {
1.443 + if (digits[i] != '0') {
1.444 + return !isNegative;
1.445 + }
1.446 + }
1.447 + break;
1.448 + case FLOOR:
1.449 + for (int i=maximumDigits; i<count; ++i) {
1.450 + if (digits[i] != '0') {
1.451 + return isNegative;
1.452 + }
1.453 + }
1.454 + break;
1.455 + case HALF_UP:
1.456 + if (digits[maximumDigits] >= '5') {
1.457 + return true;
1.458 + }
1.459 + break;
1.460 + case HALF_DOWN:
1.461 + if (digits[maximumDigits] > '5') {
1.462 + return true;
1.463 + } else if (digits[maximumDigits] == '5' ) {
1.464 + for (int i=maximumDigits+1; i<count; ++i) {
1.465 + if (digits[i] != '0') {
1.466 + return true;
1.467 + }
1.468 + }
1.469 + }
1.470 + break;
1.471 + case HALF_EVEN:
1.472 + // Implement IEEE half-even rounding
1.473 + if (digits[maximumDigits] > '5') {
1.474 + return true;
1.475 + } else if (digits[maximumDigits] == '5' ) {
1.476 + for (int i=maximumDigits+1; i<count; ++i) {
1.477 + if (digits[i] != '0') {
1.478 + return true;
1.479 + }
1.480 + }
1.481 + return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
1.482 + }
1.483 + break;
1.484 + case UNNECESSARY:
1.485 + for (int i=maximumDigits; i<count; ++i) {
1.486 + if (digits[i] != '0') {
1.487 + throw new ArithmeticException(
1.488 + "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
1.489 + }
1.490 + }
1.491 + break;
1.492 + default:
1.493 + assert false;
1.494 + }
1.495 + }
1.496 + return false;
1.497 + }
1.498 +
1.499 + /**
1.500 + * Utility routine to set the value of the digit list from a long
1.501 + */
1.502 + public final void set(boolean isNegative, long source) {
1.503 + set(isNegative, source, 0);
1.504 + }
1.505 +
1.506 + /**
1.507 + * Set the digit list to a representation of the given long value.
1.508 + * @param isNegative Boolean value indicating whether the number is negative.
1.509 + * @param source Value to be converted; must be >= 0 or ==
1.510 + * Long.MIN_VALUE.
1.511 + * @param maximumDigits The most digits which should be converted.
1.512 + * If maximumDigits is lower than the number of significant digits
1.513 + * in source, the representation will be rounded. Ignored if <= 0.
1.514 + */
1.515 + public final void set(boolean isNegative, long source, int maximumDigits) {
1.516 + this.isNegative = isNegative;
1.517 +
1.518 + // This method does not expect a negative number. However,
1.519 + // "source" can be a Long.MIN_VALUE (-9223372036854775808),
1.520 + // if the number being formatted is a Long.MIN_VALUE. In that
1.521 + // case, it will be formatted as -Long.MIN_VALUE, a number
1.522 + // which is outside the legal range of a long, but which can
1.523 + // be represented by DigitList.
1.524 + if (source <= 0) {
1.525 + if (source == Long.MIN_VALUE) {
1.526 + decimalAt = count = MAX_COUNT;
1.527 + System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
1.528 + } else {
1.529 + decimalAt = count = 0; // Values <= 0 format as zero
1.530 + }
1.531 + } else {
1.532 + // Rewritten to improve performance. I used to call
1.533 + // Long.toString(), which was about 4x slower than this code.
1.534 + int left = MAX_COUNT;
1.535 + int right;
1.536 + while (source > 0) {
1.537 + digits[--left] = (char)('0' + (source % 10));
1.538 + source /= 10;
1.539 + }
1.540 + decimalAt = MAX_COUNT - left;
1.541 + // Don't copy trailing zeros. We are guaranteed that there is at
1.542 + // least one non-zero digit, so we don't have to check lower bounds.
1.543 + for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
1.544 + ;
1.545 + count = right - left + 1;
1.546 + System.arraycopy(digits, left, digits, 0, count);
1.547 + }
1.548 + if (maximumDigits > 0) round(maximumDigits);
1.549 + }
1.550 +
1.551 + /**
1.552 + * Set the digit list to a representation of the given BigDecimal value.
1.553 + * This method supports both fixed-point and exponential notation.
1.554 + * @param isNegative Boolean value indicating whether the number is negative.
1.555 + * @param source Value to be converted; must not be a value <= 0.
1.556 + * @param maximumDigits The most fractional or total digits which should
1.557 + * be converted.
1.558 + * @param fixedPoint If true, then maximumDigits is the maximum
1.559 + * fractional digits to be converted. If false, total digits.
1.560 + */
1.561 + final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
1.562 + String s = source.toString();
1.563 + extendDigits(s.length());
1.564 +
1.565 + set(isNegative, s, maximumDigits, fixedPoint);
1.566 + }
1.567 +
1.568 + /**
1.569 + * Set the digit list to a representation of the given BigInteger value.
1.570 + * @param isNegative Boolean value indicating whether the number is negative.
1.571 + * @param source Value to be converted; must be >= 0.
1.572 + * @param maximumDigits The most digits which should be converted.
1.573 + * If maximumDigits is lower than the number of significant digits
1.574 + * in source, the representation will be rounded. Ignored if <= 0.
1.575 + */
1.576 + final void set(boolean isNegative, BigInteger source, int maximumDigits) {
1.577 + this.isNegative = isNegative;
1.578 + String s = source.toString();
1.579 + int len = s.length();
1.580 + extendDigits(len);
1.581 + s.getChars(0, len, digits, 0);
1.582 +
1.583 + decimalAt = len;
1.584 + int right;
1.585 + for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
1.586 + ;
1.587 + count = right + 1;
1.588 +
1.589 + if (maximumDigits > 0) {
1.590 + round(maximumDigits);
1.591 + }
1.592 + }
1.593 +
1.594 + /**
1.595 + * equality test between two digit lists.
1.596 + */
1.597 + public boolean equals(Object obj) {
1.598 + if (this == obj) // quick check
1.599 + return true;
1.600 + if (!(obj instanceof DigitList)) // (1) same object?
1.601 + return false;
1.602 + DigitList other = (DigitList) obj;
1.603 + if (count != other.count ||
1.604 + decimalAt != other.decimalAt)
1.605 + return false;
1.606 + for (int i = 0; i < count; i++)
1.607 + if (digits[i] != other.digits[i])
1.608 + return false;
1.609 + return true;
1.610 + }
1.611 +
1.612 + /**
1.613 + * Generates the hash code for the digit list.
1.614 + */
1.615 + public int hashCode() {
1.616 + int hashcode = decimalAt;
1.617 +
1.618 + for (int i = 0; i < count; i++) {
1.619 + hashcode = hashcode * 37 + digits[i];
1.620 + }
1.621 +
1.622 + return hashcode;
1.623 + }
1.624 +
1.625 + /**
1.626 + * Creates a copy of this object.
1.627 + * @return a clone of this instance.
1.628 + */
1.629 + public Object clone() {
1.630 + try {
1.631 + DigitList other = (DigitList) super.clone();
1.632 + char[] newDigits = new char[digits.length];
1.633 + System.arraycopy(digits, 0, newDigits, 0, digits.length);
1.634 + other.digits = newDigits;
1.635 + other.tempBuffer = null;
1.636 + return other;
1.637 + } catch (CloneNotSupportedException e) {
1.638 + throw new InternalError();
1.639 + }
1.640 + }
1.641 +
1.642 + /**
1.643 + * Returns true if this DigitList represents Long.MIN_VALUE;
1.644 + * false, otherwise. This is required so that getLong() works.
1.645 + */
1.646 + private boolean isLongMIN_VALUE() {
1.647 + if (decimalAt != count || count != MAX_COUNT) {
1.648 + return false;
1.649 + }
1.650 +
1.651 + for (int i = 0; i < count; ++i) {
1.652 + if (digits[i] != LONG_MIN_REP[i]) return false;
1.653 + }
1.654 +
1.655 + return true;
1.656 + }
1.657 +
1.658 + private static final int parseInt(char[] str, int offset, int strLen) {
1.659 + char c;
1.660 + boolean positive = true;
1.661 + if ((c = str[offset]) == '-') {
1.662 + positive = false;
1.663 + offset++;
1.664 + } else if (c == '+') {
1.665 + offset++;
1.666 + }
1.667 +
1.668 + int value = 0;
1.669 + while (offset < strLen) {
1.670 + c = str[offset++];
1.671 + if (c >= '0' && c <= '9') {
1.672 + value = value * 10 + (c - '0');
1.673 + } else {
1.674 + break;
1.675 + }
1.676 + }
1.677 + return positive ? value : -value;
1.678 + }
1.679 +
1.680 + // The digit part of -9223372036854775808L
1.681 + private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
1.682 +
1.683 + public String toString() {
1.684 + if (isZero()) {
1.685 + return "0";
1.686 + }
1.687 + StringBuffer buf = getStringBuffer();
1.688 + buf.append("0.");
1.689 + buf.append(digits, 0, count);
1.690 + buf.append("x10^");
1.691 + buf.append(decimalAt);
1.692 + return buf.toString();
1.693 + }
1.694 +
1.695 + private StringBuffer tempBuffer;
1.696 +
1.697 + private StringBuffer getStringBuffer() {
1.698 + if (tempBuffer == null) {
1.699 + tempBuffer = new StringBuffer(MAX_COUNT);
1.700 + } else {
1.701 + tempBuffer.setLength(0);
1.702 + }
1.703 + return tempBuffer;
1.704 + }
1.705 +
1.706 + private void extendDigits(int len) {
1.707 + if (len > digits.length) {
1.708 + digits = new char[len];
1.709 + }
1.710 + }
1.711 +
1.712 + private final char[] getDataChars(int length) {
1.713 + if (data == null || data.length < length) {
1.714 + data = new char[length];
1.715 + }
1.716 + return data;
1.717 + }
1.718 +}