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