]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/text/DigitList.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / text / DigitList.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 1996-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.text;\r
8 \r
9 import java.math.BigInteger;\r
10 \r
11 /**\r
12  * <code>DigitList</code> handles the transcoding between numeric values and\r
13  * strings of characters.  It only represents non-negative numbers.  The\r
14  * division of labor between <code>DigitList</code> and\r
15  * <code>DecimalFormat</code> is that <code>DigitList</code> handles the radix\r
16  * 10 representation issues and numeric conversion, including rounding;\r
17  * <code>DecimalFormat</code> handles the locale-specific issues such as\r
18  * positive and negative representation, digit grouping, decimal point,\r
19  * currency, and so on.\r
20  *\r
21  * <p>A <code>DigitList</code> is a representation of a finite numeric value.\r
22  * <code>DigitList</code> objects do not represent <code>NaN</code> or infinite\r
23  * values.  A <code>DigitList</code> value can be converted to a\r
24  * <code>BigDecimal</code> without loss of precision.  Conversion to other\r
25  * numeric formats may involve loss of precision, depending on the specific\r
26  * value.\r
27  *\r
28  * <p>The <code>DigitList</code> representation consists of a string of\r
29  * characters, which are the digits radix 10, from '0' to '9'.  It also has a\r
30  * base 10 exponent associated with it.  The value represented by a\r
31  * <code>DigitList</code> object can be computed by mulitplying the fraction\r
32  * <em>f</em>, where 0 <= <em>f</em> < 1, derived by placing all the digits of\r
33  * the list to the right of the decimal point, by 10^exponent.\r
34  *\r
35  * @see java.util.Locale\r
36  * @see java.text.Format\r
37  * @see NumberFormat\r
38  * @see DecimalFormat\r
39  * @see java.text.ChoiceFormat\r
40  * @see java.text.MessageFormat\r
41  * @version      1.18 08/12/98\r
42  * @author       Mark Davis, Alan Liu\r
43  * */\r
44 final class DigitList {\r
45     /**\r
46      * The maximum number of significant digits in an IEEE 754 double, that\r
47      * is, in a Java double.  This must not be increased, or garbage digits\r
48      * will be generated, and should not be decreased, or accuracy will be lost.\r
49      */\r
50     public static final int MAX_LONG_DIGITS = 19; // == Long.toString(Long.MAX_VALUE).length()\r
51     public static final int DBL_DIG = 17;\r
52 \r
53     /**\r
54      * These data members are intentionally public and can be set directly.\r
55      *\r
56      * The value represented is given by placing the decimal point before\r
57      * digits[decimalAt].  If decimalAt is < 0, then leading zeros between\r
58      * the decimal point and the first nonzero digit are implied.  If decimalAt\r
59      * is > count, then trailing zeros between the digits[count-1] and the\r
60      * decimal point are implied.\r
61      *\r
62      * Equivalently, the represented value is given by f * 10^decimalAt.  Here\r
63      * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to\r
64      * the right of the decimal.\r
65      *\r
66      * DigitList is normalized, so if it is non-zero, figits[0] is non-zero.  We\r
67      * don't allow denormalized numbers because our exponent is effectively of\r
68      * unlimited magnitude.  The count value contains the number of significant\r
69      * digits present in digits[].\r
70      *\r
71      * Zero is represented by any DigitList with count == 0 or with each digits[i]\r
72      * for all i <= count == '0'.\r
73      */\r
74     public int decimalAt = 0;\r
75     public int count = 0;\r
76     public byte[] digits = new byte[MAX_LONG_DIGITS];\r
77 \r
78     private final void ensureCapacity(int digitCapacity, int digitsToCopy) {\r
79         if (digitCapacity > digits.length) {\r
80             byte[] newDigits = new byte[digitCapacity * 2];\r
81             System.arraycopy(digits, 0, newDigits, 0, digitsToCopy);\r
82             digits = newDigits;\r
83         }\r
84     }\r
85 \r
86     /**\r
87      * Return true if the represented number is zero.\r
88      */\r
89     boolean isZero()\r
90     {\r
91         for (int i=0; i<count; ++i) if (digits[i] != '0') return false;\r
92         return true;\r
93     }\r
94 \r
95 // Unused as of ICU 2.6 - alan\r
96 //    /**\r
97 //     * Clears out the digits.\r
98 //     * Use before appending them.\r
99 //     * Typically, you set a series of digits with append, then at the point\r
100 //     * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;\r
101 //     * then go on appending digits.\r
102 //     */\r
103 //    public void clear () {\r
104 //        decimalAt = 0;\r
105 //        count = 0;\r
106 //    }\r
107 \r
108     /**\r
109      * Appends digits to the list.\r
110      */\r
111     public void append (int digit) {\r
112         ensureCapacity(count+1, count);\r
113         digits[count++] = (byte) digit;\r
114     }\r
115     /**\r
116      * Utility routine to get the value of the digit list\r
117      * If (count == 0) this throws a NumberFormatException, which\r
118      * mimics Long.parseLong().\r
119      */\r
120     public final double getDouble() {\r
121         if (count == 0) return 0.0;\r
122         StringBuilder temp = new StringBuilder(count);\r
123         temp.append('.');\r
124         for (int i = 0; i < count; ++i) temp.append((char)(digits[i]));\r
125         temp.append('E');\r
126         temp.append(Integer.toString(decimalAt));\r
127         return Double.valueOf(temp.toString()).doubleValue();\r
128         // long value = Long.parseLong(temp.toString());\r
129         // return (value * Math.pow(10, decimalAt - count));\r
130     }\r
131 \r
132     /**\r
133      * Utility routine to get the value of the digit list.\r
134      * If (count == 0) this returns 0, unlike Long.parseLong().\r
135      */\r
136     public final long getLong() {\r
137         // for now, simple implementation; later, do proper IEEE native stuff\r
138 \r
139         if (count == 0) return 0;\r
140 \r
141         // We have to check for this, because this is the one NEGATIVE value\r
142         // we represent.  If we tried to just pass the digits off to parseLong,\r
143         // we'd get a parse failure.\r
144         if (isLongMIN_VALUE()) return Long.MIN_VALUE;\r
145 \r
146         StringBuilder temp = new StringBuilder(count);\r
147         for (int i = 0; i < decimalAt; ++i)\r
148         {\r
149             temp.append((i < count) ? (char)(digits[i]) : '0');\r
150         }\r
151         return Long.parseLong(temp.toString());\r
152     }\r
153 \r
154     /**\r
155      * Return a <code>BigInteger</code> representing the value stored in this\r
156      * <code>DigitList</code>.  This method assumes that this object contains\r
157      * an integral value; if not, it will return an incorrect value.\r
158      * [bnf]\r
159      * @param isPositive determines the sign of the returned result\r
160      * @return the value of this object as a <code>BigInteger</code>\r
161      */\r
162     public BigInteger getBigInteger(boolean isPositive) {\r
163         if (isZero()) return BigInteger.valueOf(0);\r
164         //Eclipse stated the following is "dead code"\r
165         /*if (false) {\r
166             StringBuilder stringRep = new StringBuilder(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         StringBuilder stringRep = new StringBuilder(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     /**\r
232      * Return a <code>BigDecimal</code> representing the value stored in this\r
233      * <code>DigitList</code>.\r
234      * [bnf]\r
235      * @param isPositive determines the sign of the returned result\r
236      * @return the value of this object as a <code>BigDecimal</code>\r
237      */\r
238     ///CLOVER:OFF\r
239     // The method is in a protected class and is not called by anything\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             StringBuilder significantDigits = new StringBuilder(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     ///CLOVER:ON\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             StringBuilder significantDigits = new StringBuilder(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     /**\r
728      * Set the digit list to a representation of the given BigDecimal value.\r
729      * [bnf]\r
730      * @param source Value to be converted\r
731      * @param maximumDigits The most digits which should be converted.\r
732      * If maximumDigits is lower than the number of significant digits\r
733      * in source, the representation will be rounded.  Ignored if <= 0.\r
734      * @param fixedPoint If true, then maximumDigits is the maximum\r
735      * fractional digits to be converted.  If false, total digits.\r
736      */\r
737     public final void set(java.math.BigDecimal source,\r
738                           int maximumDigits, boolean fixedPoint) {\r
739         setBigDecimalDigits(source.toString(), maximumDigits, fixedPoint);\r
740     }\r
741 \r
742     /*\r
743      * Set the digit list to a representation of the given BigDecimal value.\r
744      * [bnf]\r
745      * @param source Value to be converted\r
746      * @param maximumDigits The most digits which should be converted.\r
747      * If maximumDigits is lower than the number of significant digits\r
748      * in source, the representation will be rounded.  Ignored if <= 0.\r
749      * @param fixedPoint If true, then maximumDigits is the maximum\r
750      * fractional digits to be converted.  If false, total digits.\r
751      */\r
752     public final void set(com.ibm.icu.math.BigDecimal source,\r
753                           int maximumDigits, boolean fixedPoint) {\r
754         setBigDecimalDigits(source.toString(), maximumDigits, fixedPoint);\r
755     }\r
756 \r
757     /**\r
758      * Returns true if this DigitList represents Long.MIN_VALUE;\r
759      * false, otherwise.  This is required so that getLong() works.\r
760      */\r
761     private boolean isLongMIN_VALUE()\r
762     {\r
763         if (decimalAt != count || count != MAX_LONG_DIGITS)\r
764             return false;\r
765 \r
766             for (int i = 0; i < count; ++i)\r
767         {\r
768             if (digits[i] != LONG_MIN_REP[i]) return false;\r
769         }\r
770 \r
771         return true;\r
772     }\r
773 \r
774     private static byte[] LONG_MIN_REP;\r
775 \r
776     static\r
777     {\r
778         // Store the representation of LONG_MIN without the leading '-'\r
779         String s = Long.toString(Long.MIN_VALUE);\r
780         LONG_MIN_REP = new byte[MAX_LONG_DIGITS];\r
781         for (int i=0; i < MAX_LONG_DIGITS; ++i)\r
782         {\r
783             LONG_MIN_REP[i] = (byte)s.charAt(i + 1);\r
784         }\r
785     }\r
786 \r
787 // Unused -- Alan 2003-05\r
788 //    /**\r
789 //     * Return the floor of the log base 10 of a given double.\r
790 //     * This method compensates for inaccuracies which arise naturally when\r
791 //     * computing logs, and always give the correct value.  The parameter\r
792 //     * must be positive and finite.\r
793 //     */\r
794 //    private static final int log10(double d)\r
795 //    {\r
796 //        // The reason this routine is needed is that simply taking the\r
797 //        // log and dividing by log10 yields a result which may be off\r
798 //        // by 1 due to rounding errors.  For example, the naive log10\r
799 //        // of 1.0e300 taken this way is 299, rather than 300.\r
800 //        double log10 = Math.log(d) / LOG10;\r
801 //        int ilog10 = (int)Math.floor(log10);\r
802 //        // Positive logs could be too small, e.g. 0.99 instead of 1.0\r
803 //        if (log10 > 0 && d >= Math.pow(10, ilog10 + 1))\r
804 //        {\r
805 //            ++ilog10;\r
806 //        }\r
807 //        // Negative logs could be too big, e.g. -0.99 instead of -1.0\r
808 //        else if (log10 < 0 && d < Math.pow(10, ilog10))\r
809 //        {\r
810 //            --ilog10;\r
811 //        }\r
812 //        return ilog10;\r
813 //    }\r
814 //\r
815 //    private static final double LOG10 = Math.log(10.0);\r
816 \r
817     // (The following boilerplate methods are currently not called,\r
818     // and cannot be called by tests since this class is\r
819     // package-private.  The methods may be useful in the future, so\r
820     // we do not delete them.  2003-06-11 ICU 2.6 Alan)\r
821     ///CLOVER:OFF\r
822     /**\r
823      * equality test between two digit lists.\r
824      */\r
825     public boolean equals(Object obj) {\r
826         if (this == obj)                      // quick check\r
827             return true;\r
828         if (!(obj instanceof DigitList))         // (1) same object?\r
829             return false;\r
830         DigitList other = (DigitList) obj;\r
831         if (count != other.count ||\r
832         decimalAt != other.decimalAt)\r
833             return false;\r
834         for (int i = 0; i < count; i++)\r
835             if (digits[i] != other.digits[i])\r
836                 return false;\r
837         return true;\r
838     }\r
839 \r
840     /**\r
841      * Generates the hash code for the digit list.\r
842      */\r
843     public int hashCode() {\r
844         int hashcode = decimalAt;\r
845 \r
846         for (int i = 0; i < count; i++)\r
847             hashcode = hashcode * 37 + digits[i];\r
848 \r
849         return hashcode;\r
850     }\r
851 \r
852     public String toString()\r
853     {\r
854         if (isZero()) return "0";\r
855         StringBuilder buf = new StringBuilder("0.");\r
856         for (int i=0; i<count; ++i) buf.append((char)digits[i]);\r
857         buf.append("x10^");\r
858         buf.append(decimalAt);\r
859         return buf.toString();\r
860     }\r
861     ///CLOVER:ON\r
862 }\r