001: //##header
002: /*
003: *******************************************************************************
004: * Copyright (C) 1996-2005, International Business Machines Corporation and *
005: * others. All Rights Reserved. *
006: *******************************************************************************
007: */
008: package com.ibm.icu.text;
009:
010: import java.math.BigInteger;
011:
012: /**
013: * <code>DigitList</code> handles the transcoding between numeric values and
014: * strings of characters. It only represents non-negative numbers. The
015: * division of labor between <code>DigitList</code> and
016: * <code>DecimalFormat</code> is that <code>DigitList</code> handles the radix
017: * 10 representation issues and numeric conversion, including rounding;
018: * <code>DecimalFormat</code> handles the locale-specific issues such as
019: * positive and negative representation, digit grouping, decimal point,
020: * currency, and so on.
021: *
022: * <p>A <code>DigitList</code> is a representation of a finite numeric value.
023: * <code>DigitList</code> objects do not represent <code>NaN</code> or infinite
024: * values. A <code>DigitList</code> value can be converted to a
025: * <code>BigDecimal</code> without loss of precision. Conversion to other
026: * numeric formats may involve loss of precision, depending on the specific
027: * value.
028: *
029: * <p>The <code>DigitList</code> representation consists of a string of
030: * characters, which are the digits radix 10, from '0' to '9'. It also has a
031: * base 10 exponent associated with it. The value represented by a
032: * <code>DigitList</code> object can be computed by mulitplying the fraction
033: * <em>f</em>, where 0 <= <em>f</em> < 1, derived by placing all the digits of
034: * the list to the right of the decimal point, by 10^exponent.
035: *
036: * @see java.util.Locale
037: * @see java.text.Format
038: * @see NumberFormat
039: * @see DecimalFormat
040: * @see java.text.ChoiceFormat
041: * @see java.text.MessageFormat
042: * @version 1.18 08/12/98
043: * @author Mark Davis, Alan Liu
044: * */
045: final class DigitList {
046: /**
047: * The maximum number of significant digits in an IEEE 754 double, that
048: * is, in a Java double. This must not be increased, or garbage digits
049: * will be generated, and should not be decreased, or accuracy will be lost.
050: */
051: public static final int MAX_LONG_DIGITS = 19; // == Long.toString(Long.MAX_VALUE).length()
052: public static final int DBL_DIG = 17;
053:
054: /**
055: * These data members are intentionally public and can be set directly.
056: *
057: * The value represented is given by placing the decimal point before
058: * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
059: * the decimal point and the first nonzero digit are implied. If decimalAt
060: * is > count, then trailing zeros between the digits[count-1] and the
061: * decimal point are implied.
062: *
063: * Equivalently, the represented value is given by f * 10^decimalAt. Here
064: * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
065: * the right of the decimal.
066: *
067: * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
068: * don't allow denormalized numbers because our exponent is effectively of
069: * unlimited magnitude. The count value contains the number of significant
070: * digits present in digits[].
071: *
072: * Zero is represented by any DigitList with count == 0 or with each digits[i]
073: * for all i <= count == '0'.
074: */
075: public int decimalAt = 0;
076: public int count = 0;
077: public byte[] digits = new byte[MAX_LONG_DIGITS];
078:
079: private final void ensureCapacity(int digitCapacity,
080: int digitsToCopy) {
081: if (digitCapacity > digits.length) {
082: byte[] newDigits = new byte[digitCapacity * 2];
083: System.arraycopy(digits, 0, newDigits, 0, digitsToCopy);
084: digits = newDigits;
085: }
086: }
087:
088: /**
089: * Return true if the represented number is zero.
090: */
091: boolean isZero() {
092: for (int i = 0; i < count; ++i)
093: if (digits[i] != '0')
094: return false;
095: return true;
096: }
097:
098: // Unused as of ICU 2.6 - alan
099: // /**
100: // * Clears out the digits.
101: // * Use before appending them.
102: // * Typically, you set a series of digits with append, then at the point
103: // * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
104: // * then go on appending digits.
105: // */
106: // public void clear () {
107: // decimalAt = 0;
108: // count = 0;
109: // }
110:
111: /**
112: * Appends digits to the list.
113: */
114: public void append(int digit) {
115: ensureCapacity(count + 1, count);
116: digits[count++] = (byte) digit;
117: }
118:
119: /**
120: * Utility routine to get the value of the digit list
121: * If (count == 0) this throws a NumberFormatException, which
122: * mimics Long.parseLong().
123: */
124: public final double getDouble() {
125: if (count == 0)
126: return 0.0;
127: StringBuffer temp = new StringBuffer(count);
128: temp.append('.');
129: for (int i = 0; i < count; ++i)
130: temp.append((char) (digits[i]));
131: temp.append('E');
132: temp.append(Integer.toString(decimalAt));
133: return Double.valueOf(temp.toString()).doubleValue();
134: // long value = Long.parseLong(temp.toString());
135: // return (value * Math.pow(10, decimalAt - count));
136: }
137:
138: /**
139: * Utility routine to get the value of the digit list.
140: * If (count == 0) this returns 0, unlike Long.parseLong().
141: */
142: public final long getLong() {
143: // for now, simple implementation; later, do proper IEEE native stuff
144:
145: if (count == 0)
146: return 0;
147:
148: // We have to check for this, because this is the one NEGATIVE value
149: // we represent. If we tried to just pass the digits off to parseLong,
150: // we'd get a parse failure.
151: if (isLongMIN_VALUE())
152: return Long.MIN_VALUE;
153:
154: StringBuffer temp = new StringBuffer(count);
155: for (int i = 0; i < decimalAt; ++i) {
156: temp.append((i < count) ? (char) (digits[i]) : '0');
157: }
158: return Long.parseLong(temp.toString());
159: }
160:
161: /**
162: * Return a <code>BigInteger</code> representing the value stored in this
163: * <code>DigitList</code>. This method assumes that this object contains
164: * an integral value; if not, it will return an incorrect value.
165: * [bnf]
166: * @param isPositive determines the sign of the returned result
167: * @return the value of this object as a <code>BigInteger</code>
168: */
169: public BigInteger getBigInteger(boolean isPositive) {
170: if (isZero())
171: return BigInteger.valueOf(0);
172: if (false) {
173: StringBuffer stringRep = new StringBuffer(count);
174: if (!isPositive) {
175: stringRep.append('-');
176: }
177: for (int i = 0; i < count; ++i) {
178: stringRep.append((char) digits[i]);
179: }
180: int d = decimalAt;
181: while (d-- > count) {
182: stringRep.append('0');
183: }
184: return new BigInteger(stringRep.toString());
185: } else {
186: int len = decimalAt > count ? decimalAt : count;
187: if (!isPositive) {
188: len += 1;
189: }
190: char[] text = new char[len];
191: int n = 0;
192: if (!isPositive) {
193: text[0] = '-';
194: for (int i = 0; i < count; ++i) {
195: text[i + 1] = (char) digits[i];
196: }
197: n = count + 1;
198: } else {
199: for (int i = 0; i < count; ++i) {
200: text[i] = (char) digits[i];
201: }
202: n = count;
203: }
204: for (int i = n; i < text.length; ++i) {
205: text[i] = '0';
206: }
207: return new BigInteger(new String(text));
208: }
209: }
210:
211: private String getStringRep(boolean isPositive) {
212: if (isZero())
213: return "0";
214: StringBuffer stringRep = new StringBuffer(count + 1);
215: if (!isPositive) {
216: stringRep.append('-');
217: }
218: int d = decimalAt;
219: if (d < 0) {
220: stringRep.append('.');
221: while (d < 0) {
222: stringRep.append('0');
223: ++d;
224: }
225: d = -1;
226: }
227: for (int i = 0; i < count; ++i) {
228: if (d == i) {
229: stringRep.append('.');
230: }
231: stringRep.append((char) digits[i]);
232: }
233: while (d-- > count) {
234: stringRep.append('0');
235: }
236: return stringRep.toString();
237: }
238:
239: //#ifndef FOUNDATION
240: /**
241: * Return a <code>BigDecimal</code> representing the value stored in this
242: * <code>DigitList</code>.
243: * [bnf]
244: * @param isPositive determines the sign of the returned result
245: * @return the value of this object as a <code>BigDecimal</code>
246: */
247: public java.math.BigDecimal getBigDecimal(boolean isPositive) {
248: if (isZero())
249: return java.math.BigDecimal.valueOf(0);
250: return new java.math.BigDecimal(getStringRep(isPositive));
251: }
252:
253: //#endif
254:
255: /**
256: * Return an <code>ICU BigDecimal</code> representing the value stored in this
257: * <code>DigitList</code>.
258: * [bnf]
259: * @param isPositive determines the sign of the returned result
260: * @return the value of this object as a <code>BigDecimal</code>
261: */
262: public com.ibm.icu.math.BigDecimal getBigDecimalICU(
263: boolean isPositive) {
264: if (isZero())
265: return com.ibm.icu.math.BigDecimal.valueOf(0);
266: return new com.ibm.icu.math.BigDecimal(getStringRep(isPositive));
267: }
268:
269: /**
270: * Return whether or not this objects represented value is an integer.
271: * [bnf]
272: * @return true if the represented value of this object is an integer
273: */
274: boolean isIntegral() {
275: // Trim trailing zeros. This does not change the represented value.
276: while (count > 0 && digits[count - 1] == (byte) '0')
277: --count;
278: return count == 0 || decimalAt >= count;
279: }
280:
281: // Unused as of ICU 2.6 - alan
282: // /**
283: // * Return true if the number represented by this object can fit into
284: // * a long.
285: // */
286: // boolean fitsIntoLong(boolean isPositive)
287: // {
288: // // Figure out if the result will fit in a long. We have to
289: // // first look for nonzero digits after the decimal point;
290: // // then check the size. If the digit count is 18 or less, then
291: // // the value can definitely be represented as a long. If it is 19
292: // // then it may be too large.
293: //
294: // // Trim trailing zeros. This does not change the represented value.
295: // while (count > 0 && digits[count - 1] == (byte)'0') --count;
296: //
297: // if (count == 0) {
298: // // Positive zero fits into a long, but negative zero can only
299: // // be represented as a double. - bug 4162852
300: // return isPositive;
301: // }
302: //
303: // if (decimalAt < count || decimalAt > MAX_LONG_DIGITS) return false;
304: //
305: // if (decimalAt < MAX_LONG_DIGITS) return true;
306: //
307: // // At this point we have decimalAt == count, and count == MAX_LONG_DIGITS.
308: // // The number will overflow if it is larger than 9223372036854775807
309: // // or smaller than -9223372036854775808.
310: // for (int i=0; i<count; ++i)
311: // {
312: // byte dig = digits[i], max = LONG_MIN_REP[i];
313: // if (dig > max) return false;
314: // if (dig < max) return true;
315: // }
316: //
317: // // At this point the first count digits match. If decimalAt is less
318: // // than count, then the remaining digits are zero, and we return true.
319: // if (count < decimalAt) return true;
320: //
321: // // Now we have a representation of Long.MIN_VALUE, without the leading
322: // // negative sign. If this represents a positive value, then it does
323: // // not fit; otherwise it fits.
324: // return !isPositive;
325: // }
326:
327: // Unused as of ICU 2.6 - alan
328: // /**
329: // * Set the digit list to a representation of the given double value.
330: // * This method supports fixed-point notation.
331: // * @param source Value to be converted; must not be Inf, -Inf, Nan,
332: // * or a value <= 0.
333: // * @param maximumFractionDigits The most fractional digits which should
334: // * be converted.
335: // */
336: // public final void set(double source, int maximumFractionDigits)
337: // {
338: // set(source, maximumFractionDigits, true);
339: // }
340:
341: /**
342: * Set the digit list to a representation of the given double value.
343: * This method supports both fixed-point and exponential notation.
344: * @param source Value to be converted; must not be Inf, -Inf, Nan,
345: * or a value <= 0.
346: * @param maximumDigits The most fractional or total digits which should
347: * be converted.
348: * @param fixedPoint If true, then maximumDigits is the maximum
349: * fractional digits to be converted. If false, total digits.
350: */
351: final void set(double source, int maximumDigits, boolean fixedPoint) {
352: if (source == 0)
353: source = 0;
354: // Generate a representation of the form DDDDD, DDDDD.DDDDD, or
355: // DDDDDE+/-DDDDD.
356: String rep = Double.toString(source);
357:
358: set(rep, MAX_LONG_DIGITS);
359:
360: if (fixedPoint) {
361: // The negative of the exponent represents the number of leading
362: // zeros between the decimal and the first non-zero digit, for
363: // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
364: // is more than the maximum fraction digits, then we have an underflow
365: // for the printed representation.
366: if (-decimalAt > maximumDigits) {
367: count = 0;
368: return;
369: } else if (-decimalAt == maximumDigits) {
370: if (shouldRoundUp(0)) {
371: count = 1;
372: ++decimalAt;
373: digits[0] = (byte) '1';
374: } else {
375: count = 0;
376: }
377: return;
378: }
379: // else fall through
380: }
381:
382: // Eliminate trailing zeros.
383: while (count > 1 && digits[count - 1] == '0')
384: --count;
385:
386: // Eliminate digits beyond maximum digits to be displayed.
387: // Round up if appropriate.
388: round(fixedPoint ? (maximumDigits + decimalAt)
389: : maximumDigits == 0 ? -1 : maximumDigits);
390: }
391:
392: /**
393: * Given a string representation of the form DDDDD, DDDDD.DDDDD,
394: * or DDDDDE+/-DDDDD, set this object's value to it. Ignore
395: * any leading '-'.
396: */
397: private void set(String rep, int maxCount) {
398: decimalAt = -1;
399: count = 0;
400: int exponent = 0;
401: // Number of zeros between decimal point and first non-zero digit after
402: // decimal point, for numbers < 1.
403: int leadingZerosAfterDecimal = 0;
404: boolean nonZeroDigitSeen = false;
405: // Skip over leading '-'
406: int i = 0;
407: if (rep.charAt(i) == '-') {
408: ++i;
409: }
410: for (; i < rep.length(); ++i) {
411: char c = rep.charAt(i);
412: if (c == '.') {
413: decimalAt = count;
414: } else if (c == 'e' || c == 'E') {
415: ++i;
416: // Integer.parseInt doesn't handle leading '+' signs
417: if (rep.charAt(i) == '+') {
418: ++i;
419: }
420: exponent = Integer.valueOf(rep.substring(i)).intValue();
421: break;
422: } else if (count < maxCount) {
423: if (!nonZeroDigitSeen) {
424: nonZeroDigitSeen = (c != '0');
425: if (!nonZeroDigitSeen && decimalAt != -1) {
426: ++leadingZerosAfterDecimal;
427: }
428: }
429:
430: if (nonZeroDigitSeen) {
431: ensureCapacity(count + 1, count);
432: digits[count++] = (byte) c;
433: }
434: }
435: }
436: if (decimalAt == -1) {
437: decimalAt = count;
438: }
439: decimalAt += exponent - leadingZerosAfterDecimal;
440: }
441:
442: /**
443: * Return true if truncating the representation to the given number
444: * of digits will result in an increment to the last digit. This
445: * method implements half-even rounding, the default rounding mode.
446: * [bnf]
447: * @param maximumDigits the number of digits to keep, from 0 to
448: * <code>count-1</code>. If 0, then all digits are rounded away, and
449: * this method returns true if a one should be generated (e.g., formatting
450: * 0.09 with "#.#").
451: * @return true if digit <code>maximumDigits-1</code> should be
452: * incremented
453: */
454: private boolean shouldRoundUp(int maximumDigits) {
455: // variable not used boolean increment = false;
456: // Implement IEEE half-even rounding
457: /*Bug 4243108
458: format(0.0) gives "0.1" if preceded by parse("99.99") [Richard/GCL]
459: */
460: if (maximumDigits < count) {
461: if (digits[maximumDigits] > '5') {
462: return true;
463: } else if (digits[maximumDigits] == '5') {
464: for (int i = maximumDigits + 1; i < count; ++i) {
465: if (digits[i] != '0') {
466: return true;
467: }
468: }
469: return maximumDigits > 0
470: && (digits[maximumDigits - 1] % 2 != 0);
471: }
472: }
473: return false;
474: }
475:
476: /**
477: * Round the representation to the given number of digits.
478: * @param maximumDigits The maximum number of digits to be shown.
479: * Upon return, count will be less than or equal to maximumDigits.
480: * This now performs rounding when maximumDigits is 0, formerly it did not.
481: */
482: public final void round(int maximumDigits) {
483: // Eliminate digits beyond maximum digits to be displayed.
484: // Round up if appropriate.
485: // [bnf] rewritten to fix 4179818
486: if (maximumDigits >= 0 && maximumDigits < count) {
487: if (shouldRoundUp(maximumDigits)) {
488: // Rounding up involves incrementing digits from LSD to MSD.
489: // In most cases this is simple, but in a worst case situation
490: // (9999..99) we have to adjust the decimalAt value.
491: for (;;) {
492: --maximumDigits;
493: if (maximumDigits < 0) {
494: // We have all 9's, so we increment to a single digit
495: // of one and adjust the exponent.
496: digits[0] = (byte) '1';
497: ++decimalAt;
498: maximumDigits = 0; // Adjust the count
499: break;
500: }
501:
502: ++digits[maximumDigits];
503: if (digits[maximumDigits] <= '9')
504: break;
505: // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
506: }
507: ++maximumDigits; // Increment for use as count
508: }
509: count = maximumDigits;
510: /*Bug 4217661 DecimalFormat formats 1.001 to "1.00" instead of "1"
511: Eliminate trailing zeros. [Richard/GCL]
512: */
513: while (count > 1 && digits[count - 1] == '0') {
514: --count;
515: } //[Richard/GCL]
516: }
517: }
518:
519: /**
520: * Utility routine to set the value of the digit list from a long
521: */
522: public final void set(long source) {
523: set(source, 0);
524: }
525:
526: /**
527: * Set the digit list to a representation of the given long value.
528: * @param source Value to be converted; must be >= 0 or ==
529: * Long.MIN_VALUE.
530: * @param maximumDigits The most digits which should be converted.
531: * If maximumDigits is lower than the number of significant digits
532: * in source, the representation will be rounded. Ignored if <= 0.
533: */
534: public final void set(long source, int maximumDigits) {
535: // This method does not expect a negative number. However,
536: // "source" can be a Long.MIN_VALUE (-9223372036854775808),
537: // if the number being formatted is a Long.MIN_VALUE. In that
538: // case, it will be formatted as -Long.MIN_VALUE, a number
539: // which is outside the legal range of a long, but which can
540: // be represented by DigitList.
541: // [NEW] Faster implementation
542: if (source <= 0) {
543: if (source == Long.MIN_VALUE) {
544: decimalAt = count = MAX_LONG_DIGITS;
545: System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
546: } else {
547: count = 0;
548: decimalAt = 0;
549: }
550: } else {
551: int left = MAX_LONG_DIGITS;
552: int right;
553: while (source > 0) {
554: digits[--left] = (byte) (((long) '0') + (source % 10));
555: source /= 10;
556: }
557: decimalAt = MAX_LONG_DIGITS - left;
558: // Don't copy trailing zeros
559: // we are guaranteed that there is at least one non-zero digit,
560: // so we don't have to check lower bounds
561: for (right = MAX_LONG_DIGITS - 1; digits[right] == (byte) '0'; --right) {
562: }
563: count = right - left + 1;
564: System.arraycopy(digits, left, digits, 0, count);
565: }
566: if (maximumDigits > 0)
567: round(maximumDigits);
568: }
569:
570: /**
571: * Set the digit list to a representation of the given BigInteger value.
572: * [bnf]
573: * @param source Value to be converted
574: * @param maximumDigits The most digits which should be converted.
575: * If maximumDigits is lower than the number of significant digits
576: * in source, the representation will be rounded. Ignored if <= 0.
577: */
578: public final void set(BigInteger source, int maximumDigits) {
579: String stringDigits = source.toString();
580:
581: count = decimalAt = stringDigits.length();
582:
583: // Don't copy trailing zeros
584: while (count > 1 && stringDigits.charAt(count - 1) == '0')
585: --count;
586:
587: int offset = 0;
588: if (stringDigits.charAt(0) == '-') {
589: ++offset;
590: --count;
591: --decimalAt;
592: }
593:
594: ensureCapacity(count, 0);
595: for (int i = 0; i < count; ++i) {
596: digits[i] = (byte) stringDigits.charAt(i + offset);
597: }
598:
599: if (maximumDigits > 0)
600: round(maximumDigits);
601: }
602:
603: /**
604: * Internal method that sets this digit list to represent the
605: * given value. The value is given as a String of the format
606: * returned by BigDecimal.
607: * @param stringDigits value to be represented with the following
608: * syntax, expressed as a regular expression: -?\d*.?\d*
609: * Must not be an empty string.
610: * @param maximumDigits The most digits which should be converted.
611: * If maximumDigits is lower than the number of significant digits
612: * in source, the representation will be rounded. Ignored if <= 0.
613: * @param fixedPoint If true, then maximumDigits is the maximum
614: * fractional digits to be converted. If false, total digits.
615: */
616: private void setBigDecimalDigits(String stringDigits,
617: int maximumDigits, boolean fixedPoint) {
618: //| // Find the first non-zero digit, the decimal, and the last non-zero digit.
619: //| int first=-1, last=stringDigits.length()-1, decimal=-1;
620: //| for (int i=0; (first<0 || decimal<0) && i<=last; ++i) {
621: //| char c = stringDigits.charAt(i);
622: //| if (c == '.') {
623: //| decimal = i;
624: //| } else if (first < 0 && (c >= '1' && c <= '9')) {
625: //| first = i;
626: //| }
627: //| }
628: //|
629: //| if (first < 0) {
630: //| clear();
631: //| return;
632: //| }
633: //|
634: //| // At this point we know there is at least one non-zero digit, so the
635: //| // following loop is safe.
636: //| for (;;) {
637: //| char c = stringDigits.charAt(last);
638: //| if (c != '0' && c != '.') {
639: //| break;
640: //| }
641: //| --last;
642: //| }
643: //|
644: //| if (decimal < 0) {
645: //| decimal = stringDigits.length();
646: //| }
647: //|
648: //| count = last - first;
649: //| if (decimal < first || decimal > last) {
650: //| ++count;
651: //| }
652: //| decimalAt = decimal - first;
653: //| if (decimalAt < 0) {
654: //| ++decimalAt;
655: //| }
656: //|
657: //| ensureCapacity(count, 0);
658: //| for (int i = 0; i < count; ++i) {
659: //| digits[i] = (byte) stringDigits.charAt(first++);
660: //| if (first == decimal) {
661: //| ++first;
662: //| }
663: //| }
664:
665: // The maxDigits here could also be Integer.MAX_VALUE
666: set(stringDigits, stringDigits.length());
667:
668: // Eliminate digits beyond maximum digits to be displayed.
669: // Round up if appropriate.
670: // {dlf} Some callers depend on passing '0' to round to mean 'don't round', but
671: // rather than pass that information explicitly, we rely on some magic with maximumDigits
672: // and decimalAt. Unfortunately, this is no good, because there are cases where maximumDigits
673: // is zero and we do want to round, e.g. BigDecimal values -1 < x < 1. So since round
674: // changed to perform rounding when the argument is 0, we now force the argument
675: // to -1 in the situations where it matters.
676: round(fixedPoint ? (maximumDigits + decimalAt)
677: : maximumDigits == 0 ? -1 : maximumDigits);
678: }
679:
680: //#ifndef FOUNDATION
681: /**
682: * Set the digit list to a representation of the given BigDecimal value.
683: * [bnf]
684: * @param source Value to be converted
685: * @param maximumDigits The most digits which should be converted.
686: * If maximumDigits is lower than the number of significant digits
687: * in source, the representation will be rounded. Ignored if <= 0.
688: * @param fixedPoint If true, then maximumDigits is the maximum
689: * fractional digits to be converted. If false, total digits.
690: */
691: public final void set(java.math.BigDecimal source,
692: int maximumDigits, boolean fixedPoint) {
693: setBigDecimalDigits(source.toString(), maximumDigits,
694: fixedPoint);
695: }
696:
697: //#endif
698:
699: /*
700: * Set the digit list to a representation of the given BigDecimal value.
701: * [bnf]
702: * @param source Value to be converted
703: * @param maximumDigits The most digits which should be converted.
704: * If maximumDigits is lower than the number of significant digits
705: * in source, the representation will be rounded. Ignored if <= 0.
706: * @param fixedPoint If true, then maximumDigits is the maximum
707: * fractional digits to be converted. If false, total digits.
708: */
709: public final void set(com.ibm.icu.math.BigDecimal source,
710: int maximumDigits, boolean fixedPoint) {
711: setBigDecimalDigits(source.toString(), maximumDigits,
712: fixedPoint);
713: }
714:
715: /**
716: * Returns true if this DigitList represents Long.MIN_VALUE;
717: * false, otherwise. This is required so that getLong() works.
718: */
719: private boolean isLongMIN_VALUE() {
720: if (decimalAt != count || count != MAX_LONG_DIGITS)
721: return false;
722:
723: for (int i = 0; i < count; ++i) {
724: if (digits[i] != LONG_MIN_REP[i])
725: return false;
726: }
727:
728: return true;
729: }
730:
731: private static byte[] LONG_MIN_REP;
732:
733: static {
734: // Store the representation of LONG_MIN without the leading '-'
735: String s = Long.toString(Long.MIN_VALUE);
736: LONG_MIN_REP = new byte[MAX_LONG_DIGITS];
737: for (int i = 0; i < MAX_LONG_DIGITS; ++i) {
738: LONG_MIN_REP[i] = (byte) s.charAt(i + 1);
739: }
740: }
741:
742: // Unused -- Alan 2003-05
743: // /**
744: // * Return the floor of the log base 10 of a given double.
745: // * This method compensates for inaccuracies which arise naturally when
746: // * computing logs, and always give the correct value. The parameter
747: // * must be positive and finite.
748: // */
749: // private static final int log10(double d)
750: // {
751: // // The reason this routine is needed is that simply taking the
752: // // log and dividing by log10 yields a result which may be off
753: // // by 1 due to rounding errors. For example, the naive log10
754: // // of 1.0e300 taken this way is 299, rather than 300.
755: // double log10 = Math.log(d) / LOG10;
756: // int ilog10 = (int)Math.floor(log10);
757: // // Positive logs could be too small, e.g. 0.99 instead of 1.0
758: // if (log10 > 0 && d >= Math.pow(10, ilog10 + 1))
759: // {
760: // ++ilog10;
761: // }
762: // // Negative logs could be too big, e.g. -0.99 instead of -1.0
763: // else if (log10 < 0 && d < Math.pow(10, ilog10))
764: // {
765: // --ilog10;
766: // }
767: // return ilog10;
768: // }
769: //
770: // private static final double LOG10 = Math.log(10.0);
771:
772: // (The following boilerplate methods are currently not called,
773: // and cannot be called by tests since this class is
774: // package-private. The methods may be useful in the future, so
775: // we do not delete them. 2003-06-11 ICU 2.6 Alan)
776: ///CLOVER:OFF
777: /**
778: * equality test between two digit lists.
779: */
780: public boolean equals(Object obj) {
781: if (this == obj) // quick check
782: return true;
783: if (!(obj instanceof DigitList)) // (1) same object?
784: return false;
785: DigitList other = (DigitList) obj;
786: if (count != other.count || decimalAt != other.decimalAt)
787: return false;
788: for (int i = 0; i < count; i++)
789: if (digits[i] != other.digits[i])
790: return false;
791: return true;
792: }
793:
794: /**
795: * Generates the hash code for the digit list.
796: */
797: public int hashCode() {
798: int hashcode = decimalAt;
799:
800: for (int i = 0; i < count; i++)
801: hashcode = hashcode * 37 + digits[i];
802:
803: return hashcode;
804: }
805:
806: public String toString() {
807: if (isZero())
808: return "0";
809: StringBuffer buf = new StringBuffer("0.");
810: for (int i = 0; i < count; ++i)
811: buf.append((char) digits[i]);
812: buf.append("x10^");
813: buf.append(decimalAt);
814: return buf.toString();
815: }
816: ///CLOVER:ON
817: }
|