1 /*
2 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29 *
30 * The original version of this source code and documentation is copyrighted
31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 * materials are provided under terms of a License Agreement between Taligent
33 * and Sun. This technology is protected by multiple US and International
34 * patents. This notice and attribution to Taligent may not be removed.
35 * Taligent is a registered trademark of Taligent, Inc.
36 *
37 */
38
39 package java.text;
40
41 import java.math.BigDecimal;
42 import java.math.BigInteger;
43 import java.math.RoundingMode;
44 import jdk.internal.math.FloatingDecimal;
45
46 /**
47 * Digit List. Private to DecimalFormat.
48 * Handles the transcoding
49 * between numeric values and strings of characters. Only handles
50 * non-negative numbers. The division of labor between DigitList and
51 * DecimalFormat is that DigitList handles the radix 10 representation
52 * issues; DecimalFormat handles the locale-specific issues such as
53 * positive/negative, grouping, decimal point, currency, and so on.
54 *
55 * A DigitList is really a representation of a floating point value.
56 * It may be an integer value; we assume that a double has sufficient
57 * precision to represent all digits of a long.
58 *
59 * The DigitList representation consists of a string of characters,
60 * which are the digits radix 10, from '0' to '9'. It also has a radix
61 * 10 exponent associated with it. The value represented by a DigitList
62 * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
63 * derived by placing all the digits of the list to the right of the
64 * decimal point, by 10^exponent.
65 *
66 * @see Locale
67 * @see Format
68 * @see NumberFormat
69 * @see DecimalFormat
70 * @see ChoiceFormat
71 * @see MessageFormat
72 * @author Mark Davis, Alan Liu
73 */
74 final class DigitList implements Cloneable {
75 /**
76 * The maximum number of significant digits in an IEEE 754 double, that
77 * is, in a Java double. This must not be increased, or garbage digits
78 * will be generated, and should not be decreased, or accuracy will be lost.
79 */
80 public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
81
82 /**
83 * These data members are intentionally public and can be set directly.
84 *
85 * The value represented is given by placing the decimal point before
86 * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
87 * the decimal point and the first nonzero digit are implied. If decimalAt
88 * is > count, then trailing zeros between the digits[count-1] and the
89 * decimal point are implied.
90 *
91 * Equivalently, the represented value is given by f * 10^decimalAt. Here
92 * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
93 * the right of the decimal.
94 *
95 * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
96 * don't allow denormalized numbers because our exponent is effectively of
97 * unlimited magnitude. The count value contains the number of significant
98 * digits present in digits[].
99 *
100 * Zero is represented by any DigitList with count == 0 or with each digits[i]
101 * for all i <= count == '0'.
102 */
103 public int decimalAt = 0;
104 public int count = 0;
105 public char[] digits = new char[MAX_COUNT];
106
107 private char[] data;
108 private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
109 private boolean isNegative = false;
110
111 /**
112 * Return true if the represented number is zero.
113 */
114 boolean isZero() {
115 for (int i=0; i < count; ++i) {
116 if (digits[i] != '0') {
117 return false;
118 }
119 }
120 return true;
121 }
122
123 /**
124 * Set the rounding mode
125 */
126 void setRoundingMode(RoundingMode r) {
127 roundingMode = r;
128 }
129
130 /**
131 * Clears out the digits.
132 * Use before appending them.
133 * Typically, you set a series of digits with append, then at the point
134 * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
135 * then go on appending digits.
136 */
137 public void clear () {
138 decimalAt = 0;
139 count = 0;
140 }
141
142 /**
143 * Appends a digit to the list, extending the list when necessary.
144 */
145 public void append(char digit) {
146 if (count == digits.length) {
147 char[] data = new char[count + 100];
148 System.arraycopy(digits, 0, data, 0, count);
149 digits = data;
150 }
151 digits[count++] = digit;
152 }
153
154 /**
155 * Utility routine to get the value of the digit list
156 * If (count == 0) this throws a NumberFormatException, which
157 * mimics Long.parseLong().
158 */
159 public final double getDouble() {
160 if (count == 0) {
161 return 0.0;
162 }
163
164 StringBuffer temp = getStringBuffer();
165 temp.append('.');
166 temp.append(digits, 0, count);
167 temp.append('E');
168 temp.append(decimalAt);
169 return Double.parseDouble(temp.toString());
170 }
171
172 /**
173 * Utility routine to get the value of the digit list.
174 * If (count == 0) this returns 0, unlike Long.parseLong().
175 */
176 public final long getLong() {
177 // for now, simple implementation; later, do proper IEEE native stuff
178
179 if (count == 0) {
180 return 0;
181 }
182
183 // We have to check for this, because this is the one NEGATIVE value
184 // we represent. If we tried to just pass the digits off to parseLong,
185 // we'd get a parse failure.
186 if (isLongMIN_VALUE()) {
187 return Long.MIN_VALUE;
188 }
189
190 StringBuffer temp = getStringBuffer();
191 temp.append(digits, 0, count);
192 for (int i = count; i < decimalAt; ++i) {
193 temp.append('0');
194 }
195 return Long.parseLong(temp.toString());
196 }
197
198 public final BigDecimal getBigDecimal() {
199 if (count == 0) {
200 if (decimalAt == 0) {
201 return BigDecimal.ZERO;
202 } else {
203 return new BigDecimal("0E" + decimalAt);
204 }
205 }
206
207 if (decimalAt == count) {
208 return new BigDecimal(digits, 0, count);
209 } else {
210 return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
211 }
212 }
213
214 /**
215 * Return true if the number represented by this object can fit into
216 * a long.
217 * @param isPositive true if this number should be regarded as positive
218 * @param ignoreNegativeZero true if -0 should be regarded as identical to
219 * +0; otherwise they are considered distinct
220 * @return true if this number fits into a Java long
221 */
222 boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
223 // Figure out if the result will fit in a long. We have to
224 // first look for nonzero digits after the decimal point;
225 // then check the size. If the digit count is 18 or less, then
226 // the value can definitely be represented as a long. If it is 19
227 // then it may be too large.
228
229 // Trim trailing zeros. This does not change the represented value.
230 while (count > 0 && digits[count - 1] == '0') {
231 --count;
232 }
233
234 if (count == 0) {
235 // Positive zero fits into a long, but negative zero can only
236 // be represented as a double. - bug 4162852
237 return isPositive || ignoreNegativeZero;
238 }
239
240 if (decimalAt < count || decimalAt > MAX_COUNT) {
241 return false;
242 }
243
244 if (decimalAt < MAX_COUNT) return true;
245
246 // At this point we have decimalAt == count, and count == MAX_COUNT.
247 // The number will overflow if it is larger than 9223372036854775807
248 // or smaller than -9223372036854775808.
249 for (int i=0; i<count; ++i) {
250 char dig = digits[i], max = LONG_MIN_REP[i];
251 if (dig > max) return false;
252 if (dig < max) return true;
253 }
254
255 // At this point the first count digits match. If decimalAt is less
256 // than count, then the remaining digits are zero, and we return true.
257 if (count < decimalAt) return true;
258
259 // Now we have a representation of Long.MIN_VALUE, without the leading
260 // negative sign. If this represents a positive value, then it does
261 // not fit; otherwise it fits.
262 return !isPositive;
263 }
264
265 /**
266 * Set the digit list to a representation of the given double value.
267 * This method supports fixed-point notation.
268 * @param isNegative Boolean value indicating whether the number is negative.
269 * @param source Value to be converted; must not be Inf, -Inf, Nan,
270 * or a value <= 0.
271 * @param maximumFractionDigits The most fractional digits which should
272 * be converted.
273 */
274 final void set(boolean isNegative, double source, int maximumFractionDigits) {
275 set(isNegative, source, maximumFractionDigits, true);
276 }
277
278 /**
279 * Set the digit list to a representation of the given double value.
280 * This method supports both fixed-point and exponential notation.
281 * @param isNegative Boolean value indicating whether the number is negative.
282 * @param source Value to be converted; must not be Inf, -Inf, Nan,
283 * or a value <= 0.
284 * @param maximumDigits The most fractional or total digits which should
285 * be converted.
286 * @param fixedPoint If true, then maximumDigits is the maximum
287 * fractional digits to be converted. If false, total digits.
288 */
289 final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
290
291 FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source);
292 boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp();
293 boolean valueExactAsDecimal = fdConverter.decimalDigitsExact();
294 assert !fdConverter.isExceptional();
295 String digitsString = fdConverter.toJavaFormatString();
296
297 set(isNegative, digitsString,
298 hasBeenRoundedUp, valueExactAsDecimal,
299 maximumDigits, fixedPoint);
300 }
301
302 /**
303 * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
304 * DDDDDE+/-DDDDD.
305 * @param roundedUp whether or not rounding up has already happened.
306 * @param valueExactAsDecimal whether or not collected digits provide
307 * an exact decimal representation of the value.
308 */
309 private void set(boolean isNegative, String s,
310 boolean roundedUp, boolean valueExactAsDecimal,
311 int maximumDigits, boolean fixedPoint) {
312
313 this.isNegative = isNegative;
314 int len = s.length();
315 char[] source = getDataChars(len);
316 s.getChars(0, len, source, 0);
317
318 decimalAt = -1;
319 count = 0;
320 int exponent = 0;
321 // Number of zeros between decimal point and first non-zero digit after
322 // decimal point, for numbers < 1.
323 int leadingZerosAfterDecimal = 0;
324 boolean nonZeroDigitSeen = false;
325
326 for (int i = 0; i < len; ) {
327 char c = source[i++];
328 if (c == '.') {
329 decimalAt = count;
330 } else if (c == 'e' || c == 'E') {
331 exponent = parseInt(source, i, len);
332 break;
333 } else {
334 if (!nonZeroDigitSeen) {
335 nonZeroDigitSeen = (c != '0');
336 if (!nonZeroDigitSeen && decimalAt != -1)
337 ++leadingZerosAfterDecimal;
338 }
339 if (nonZeroDigitSeen) {
340 digits[count++] = c;
341 }
342 }
343 }
344 if (decimalAt == -1) {
345 decimalAt = count;
346 }
347 if (nonZeroDigitSeen) {
348 decimalAt += exponent - leadingZerosAfterDecimal;
349 }
350
351 if (fixedPoint) {
352 // The negative of the exponent represents the number of leading
353 // zeros between the decimal and the first non-zero digit, for
354 // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
355 // is more than the maximum fraction digits, then we have an underflow
356 // for the printed representation.
357 if (-decimalAt > maximumDigits) {
358 // Handle an underflow to zero when we round something like
359 // 0.0009 to 2 fractional digits.
360 count = 0;
361 return;
362 } else if (-decimalAt == maximumDigits) {
363 // If we round 0.0009 to 3 fractional digits, then we have to
364 // create a new one digit in the least significant location.
365 if (shouldRoundUp(0, roundedUp, valueExactAsDecimal)) {
366 count = 1;
367 ++decimalAt;
368 digits[0] = '1';
369 } else {
370 count = 0;
371 }
372 return;
373 }
374 // else fall through
375 }
376
377 // Eliminate trailing zeros.
378 while (count > 1 && digits[count - 1] == '0') {
379 --count;
380 }
381
382 // Eliminate digits beyond maximum digits to be displayed.
383 // Round up if appropriate.
384 round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits,
385 roundedUp, valueExactAsDecimal);
386
387 }
388
389 /**
390 * Round the representation to the given number of digits.
391 * @param maximumDigits The maximum number of digits to be shown.
392 * @param alreadyRounded whether or not rounding up has already happened.
393 * @param valueExactAsDecimal whether or not collected digits provide
394 * an exact decimal representation of the value.
395 *
396 * Upon return, count will be less than or equal to maximumDigits.
397 */
398 private final void round(int maximumDigits,
399 boolean alreadyRounded,
400 boolean valueExactAsDecimal) {
401 // Eliminate digits beyond maximum digits to be displayed.
402 // Round up if appropriate.
403 if (maximumDigits >= 0 && maximumDigits < count) {
404 if (shouldRoundUp(maximumDigits, alreadyRounded, valueExactAsDecimal)) {
405 // Rounding up involved incrementing digits from LSD to MSD.
406 // In most cases this is simple, but in a worst case situation
407 // (9999..99) we have to adjust the decimalAt value.
408 for (;;) {
409 --maximumDigits;
410 if (maximumDigits < 0) {
411 // We have all 9's, so we increment to a single digit
412 // of one and adjust the exponent.
413 digits[0] = '1';
414 ++decimalAt;
415 maximumDigits = 0; // Adjust the count
416 break;
417 }
418
419 ++digits[maximumDigits];
420 if (digits[maximumDigits] <= '9') break;
421 // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
422 }
423 ++maximumDigits; // Increment for use as count
424 }
425 count = maximumDigits;
426
427 // Eliminate trailing zeros.
428 while (count > 1 && digits[count-1] == '0') {
429 --count;
430 }
431 }
432 }
433
434
435 /**
436 * Return true if truncating the representation to the given number
437 * of digits will result in an increment to the last digit. This
438 * method implements the rounding modes defined in the
439 * java.math.RoundingMode class.
440 * [bnf]
441 * @param maximumDigits the number of digits to keep, from 0 to
442 * <code>count-1</code>. If 0, then all digits are rounded away, and
443 * this method returns true if a one should be generated (e.g., formatting
444 * 0.09 with "#.#").
445 * @param alreadyRounded whether or not rounding up has already happened.
446 * @param valueExactAsDecimal whether or not collected digits provide
447 * an exact decimal representation of the value.
448 * @exception ArithmeticException if rounding is needed with rounding
449 * mode being set to RoundingMode.UNNECESSARY
450 * @return true if digit <code>maximumDigits-1</code> should be
451 * incremented
452 */
453 private boolean shouldRoundUp(int maximumDigits,
454 boolean alreadyRounded,
455 boolean valueExactAsDecimal) {
456 if (maximumDigits < count) {
457 /*
458 * To avoid erroneous double-rounding or truncation when converting
459 * a binary double value to text, information about the exactness
460 * of the conversion result in FloatingDecimal, as well as any
461 * rounding done, is needed in this class.
462 *
463 * - For the HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below:
464 * In the case of formating float or double, We must take into
465 * account what FloatingDecimal has done in the binary to decimal
466 * conversion.
467 *
468 * Considering the tie cases, FloatingDecimal may round up the
469 * value (returning decimal digits equal to tie when it is below),
470 * or "truncate" the value to the tie while value is above it,
471 * or provide the exact decimal digits when the binary value can be
472 * converted exactly to its decimal representation given formating
473 * rules of FloatingDecimal ( we have thus an exact decimal
474 * representation of the binary value).
475 *
476 * - If the double binary value was converted exactly as a decimal
477 * value, then DigitList code must apply the expected rounding
478 * rule.
479 *
480 * - If FloatingDecimal already rounded up the decimal value,
481 * DigitList should neither round up the value again in any of
482 * the three rounding modes above.
483 *
484 * - If FloatingDecimal has truncated the decimal value to
485 * an ending '5' digit, DigitList should round up the value in
486 * all of the three rounding modes above.
487 *
488 *
489 * This has to be considered only if digit at maximumDigits index
490 * is exactly the last one in the set of digits, otherwise there are
491 * remaining digits after that position and we don't have to consider
492 * what FloatingDecimal did.
493 *
494 * - Other rounding modes are not impacted by these tie cases.
495 *
496 * - For other numbers that are always converted to exact digits
497 * (like BigInteger, Long, ...), the passed alreadyRounded boolean
498 * have to be set to false, and valueExactAsDecimal has to be set to
499 * true in the upper DigitList call stack, providing the right state
500 * for those situations..
501 */
502
503 switch(roundingMode) {
504 case UP:
505 for (int i=maximumDigits; i<count; ++i) {
506 if (digits[i] != '0') {
507 return true;
508 }
509 }
510 break;
511 case DOWN:
512 break;
513 case CEILING:
514 for (int i=maximumDigits; i<count; ++i) {
515 if (digits[i] != '0') {
516 return !isNegative;
517 }
518 }
519 break;
520 case FLOOR:
521 for (int i=maximumDigits; i<count; ++i) {
522 if (digits[i] != '0') {
523 return isNegative;
524 }
525 }
526 break;
527 case HALF_UP:
528 case HALF_DOWN:
529 if (digits[maximumDigits] > '5') {
530 // Value is above tie ==> must round up
531 return true;
532 } else if (digits[maximumDigits] == '5') {
533 // Digit at rounding position is a '5'. Tie cases.
534 if (maximumDigits != (count - 1)) {
535 // There are remaining digits. Above tie => must round up
536 return true;
537 } else {
538 // Digit at rounding position is the last one !
539 if (valueExactAsDecimal) {
540 // Exact binary representation. On the tie.
541 // Apply rounding given by roundingMode.
542 return roundingMode == RoundingMode.HALF_UP;
543 } else {
544 // Not an exact binary representation.
545 // Digit sequence either rounded up or truncated.
546 // Round up only if it was truncated.
547 return !alreadyRounded;
548 }
549 }
550 }
551 // Digit at rounding position is < '5' ==> no round up.
552 // Just let do the default, which is no round up (thus break).
553 break;
554 case HALF_EVEN:
555 // Implement IEEE half-even rounding
556 if (digits[maximumDigits] > '5') {
557 return true;
558 } else if (digits[maximumDigits] == '5' ) {
559 if (maximumDigits == (count - 1)) {
560 // the rounding position is exactly the last index :
561 if (alreadyRounded)
562 // If FloatingDecimal rounded up (value was below tie),
563 // then we should not round up again.
564 return false;
565
566 if (!valueExactAsDecimal)
567 // Otherwise if the digits don't represent exact value,
568 // value was above tie and FloatingDecimal truncated
569 // digits to tie. We must round up.
570 return true;
571 else {
572 // This is an exact tie value, and FloatingDecimal
573 // provided all of the exact digits. We thus apply
574 // HALF_EVEN rounding rule.
575 return ((maximumDigits > 0) &&
576 (digits[maximumDigits-1] % 2 != 0));
577 }
578 } else {
579 // Rounds up if it gives a non null digit after '5'
580 for (int i=maximumDigits+1; i<count; ++i) {
581 if (digits[i] != '0')
582 return true;
583 }
584 }
585 }
586 break;
587 case UNNECESSARY:
588 for (int i=maximumDigits; i<count; ++i) {
589 if (digits[i] != '0') {
590 throw new ArithmeticException(
591 "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
592 }
593 }
594 break;
595 default:
596 assert false;
597 }
598 }
599 return false;
600 }
601
602 /**
603 * Utility routine to set the value of the digit list from a long
604 */
605 final void set(boolean isNegative, long source) {
606 set(isNegative, source, 0);
607 }
608
609 /**
610 * Set the digit list to a representation of the given long value.
611 * @param isNegative Boolean value indicating whether the number is negative.
612 * @param source Value to be converted; must be >= 0 or ==
613 * Long.MIN_VALUE.
614 * @param maximumDigits The most digits which should be converted.
615 * If maximumDigits is lower than the number of significant digits
616 * in source, the representation will be rounded. Ignored if <= 0.
617 */
618 final void set(boolean isNegative, long source, int maximumDigits) {
619 this.isNegative = isNegative;
620
621 // This method does not expect a negative number. However,
622 // "source" can be a Long.MIN_VALUE (-9223372036854775808),
623 // if the number being formatted is a Long.MIN_VALUE. In that
624 // case, it will be formatted as -Long.MIN_VALUE, a number
625 // which is outside the legal range of a long, but which can
626 // be represented by DigitList.
627 if (source <= 0) {
628 if (source == Long.MIN_VALUE) {
629 decimalAt = count = MAX_COUNT;
630 System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
631 } else {
632 decimalAt = count = 0; // Values <= 0 format as zero
633 }
634 } else {
635 // Rewritten to improve performance. I used to call
636 // Long.toString(), which was about 4x slower than this code.
637 int left = MAX_COUNT;
638 int right;
639 while (source > 0) {
640 digits[--left] = (char)('0' + (source % 10));
641 source /= 10;
642 }
643 decimalAt = MAX_COUNT - left;
644 // Don't copy trailing zeros. We are guaranteed that there is at
645 // least one non-zero digit, so we don't have to check lower bounds.
646 for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
647 ;
648 count = right - left + 1;
649 System.arraycopy(digits, left, digits, 0, count);
650 }
651 if (maximumDigits > 0) round(maximumDigits, false, true);
652 }
653
654 /**
655 * Set the digit list to a representation of the given BigDecimal value.
656 * This method supports both fixed-point and exponential notation.
657 * @param isNegative Boolean value indicating whether the number is negative.
658 * @param source Value to be converted; must not be a value <= 0.
659 * @param maximumDigits The most fractional or total digits which should
660 * be converted.
661 * @param fixedPoint If true, then maximumDigits is the maximum
662 * fractional digits to be converted. If false, total digits.
663 */
664 final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
665 String s = source.toString();
666 extendDigits(s.length());
667
668 set(isNegative, s,
669 false, true,
670 maximumDigits, fixedPoint);
671 }
672
673 /**
674 * Set the digit list to a representation of the given BigInteger value.
675 * @param isNegative Boolean value indicating whether the number is negative.
676 * @param source Value to be converted; must be >= 0.
677 * @param maximumDigits The most digits which should be converted.
678 * If maximumDigits is lower than the number of significant digits
679 * in source, the representation will be rounded. Ignored if <= 0.
680 */
681 final void set(boolean isNegative, BigInteger source, int maximumDigits) {
682 this.isNegative = isNegative;
683 String s = source.toString();
684 int len = s.length();
685 extendDigits(len);
686 s.getChars(0, len, digits, 0);
687
688 decimalAt = len;
689 int right;
690 for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
691 ;
692 count = right + 1;
693
694 if (maximumDigits > 0) {
695 round(maximumDigits, false, true);
696 }
697 }
698
699 /**
700 * equality test between two digit lists.
701 */
702 public boolean equals(Object obj) {
703 if (this == obj) // quick check
704 return true;
705 if (!(obj instanceof DigitList)) // (1) same object?
706 return false;
707 DigitList other = (DigitList) obj;
708 if (count != other.count ||
709 decimalAt != other.decimalAt)
710 return false;
711 for (int i = 0; i < count; i++)
712 if (digits[i] != other.digits[i])
713 return false;
714 return true;
715 }
716
717 /**
718 * Generates the hash code for the digit list.
719 */
720 public int hashCode() {
721 int hashcode = decimalAt;
722
723 for (int i = 0; i < count; i++) {
724 hashcode = hashcode * 37 + digits[i];
725 }
726
727 return hashcode;
728 }
729
730 /**
731 * Creates a copy of this object.
732 * @return a clone of this instance.
733 */
734 public Object clone() {
735 try {
736 DigitList other = (DigitList) super.clone();
737 char[] newDigits = new char[digits.length];
738 System.arraycopy(digits, 0, newDigits, 0, digits.length);
739 other.digits = newDigits;
740 other.tempBuffer = null;
741 return other;
742 } catch (CloneNotSupportedException e) {
743 throw new InternalError(e);
744 }
745 }
746
747 /**
748 * Returns true if this DigitList represents Long.MIN_VALUE;
749 * false, otherwise. This is required so that getLong() works.
750 */
751 private boolean isLongMIN_VALUE() {
752 if (decimalAt != count || count != MAX_COUNT) {
753 return false;
754 }
755
756 for (int i = 0; i < count; ++i) {
757 if (digits[i] != LONG_MIN_REP[i]) return false;
758 }
759
760 return true;
761 }
762
763 private static final int parseInt(char[] str, int offset, int strLen) {
764 char c;
765 boolean positive = true;
766 if ((c = str[offset]) == '-') {
767 positive = false;
768 offset++;
769 } else if (c == '+') {
770 offset++;
771 }
772
773 int value = 0;
774 while (offset < strLen) {
775 c = str[offset++];
776 if (c >= '0' && c <= '9') {
777 value = value * 10 + (c - '0');
778 } else {
779 break;
780 }
781 }
782 return positive ? value : -value;
783 }
784
785 // The digit part of -9223372036854775808L
786 private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
787
788 public String toString() {
789 if (isZero()) {
790 return "0";
791 }
792 StringBuffer buf = getStringBuffer();
793 buf.append("0.");
794 buf.append(digits, 0, count);
795 buf.append("x10^");
796 buf.append(decimalAt);
797 return buf.toString();
798 }
799
800 private StringBuffer tempBuffer;
801
802 private StringBuffer getStringBuffer() {
803 if (tempBuffer == null) {
804 tempBuffer = new StringBuffer(MAX_COUNT);
805 } else {
806 tempBuffer.setLength(0);
807 }
808 return tempBuffer;
809 }
810
811 private void extendDigits(int len) {
812 if (len > digits.length) {
813 digits = new char[len];
814 }
815 }
816
817 private final char[] getDataChars(int length) {
818 if (data == null || data.length < length) {
819 data = new char[length];
820 }
821 return data;
822 }
823 }
824