KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > lang > TypeFormat


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.lang;
10
11 import j2me.lang.CharSequence;
12
13 import java.io.IOException;
14
15 /**
16  * <p> This class provides utility methods to parse <code>CharSequence</code>
17  * into primitive types and to format primitive types into an
18  * <code>Appendable</code>.</p>
19  *
20  * <p> Methods from this utility class <b>do not create temporary objects</b>
21  * and are typically faster than standard library methods (e.g
22  * <code>TypeFormat#parseDouble</code> is up to 15x faster than
23  * <code>Double.parseDouble</code>).</p>
24  *
25  * <p> For non-primitive objects, formatting is typically performed using
26  * specialized {@link TextFormat} instances.</p>
27  *
28  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
29  * @version 3.2, May 8, 2005
30  */

31 public final class TypeFormat {
32
33     /**
34      * Holds the characters used to represent numbers.
35      */

36     private final static char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6',
37             '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
38             'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
39             'x', 'y', 'z' };
40
41     /**
42      * Default constructor (forbids derivation).
43      */

44     private TypeFormat() {
45     }
46
47     /**
48      * Returns the index within the specified character sequence of the first
49      * occurrence of the specified pattern searching forward from the specified
50      * index (general purpose parsing function).
51      *
52      * @param pattern the character sequence to search for.
53      * @param chars the character sequence being searched.
54      * @param fromIndex the index in <code>chars</code> to start the search
55      * from.
56      * @return the index in the range
57      * <code>[fromIndex, chars.length()-pattern.length()]</code>
58      * or <code>-1</code> if the character sequence is not found.
59      */

60     public static int indexOf(CharSequence pattern, CharSequence chars,
61             int fromIndex) {
62         int patternLength = pattern.length();
63         fromIndex = Math.max(0, fromIndex);
64         if (patternLength != 0) { // At least one character to search for.
65
char firstChar = pattern.charAt(0);
66             int last = chars.length() - patternLength;
67             for (int i = fromIndex; i <= last; i++) {
68                 if (chars.charAt(i) == firstChar) {
69                     boolean match = true;
70                     for (int j = 1; j < patternLength; j++) {
71                         if (chars.charAt(i + j) != pattern.charAt(j)) {
72                             match = false;
73                             break;
74                         }
75                     }
76                     if (match) {
77                         return i;
78                     }
79                 }
80             }
81             return -1;
82         } else {
83             return Math.min(0, fromIndex);
84         }
85     }
86
87     /**
88      * Returns the index within the specified character sequence of the last
89      * occurrence of the specified pattern searching backward from the specified
90      * index (general purpose parsing function).
91      *
92      * @param pattern the character sequence to search for.
93      * @param chars the character sequence being searched.
94      * @param fromIndex the index in <code>chars</code> to start the backward
95      * search from.
96      * @return the index in the range
97      * <code>[fromIndex, chars.length()-pattern.length()]</code>
98      * or <code>-1</code> if the character sequence is not found.
99      */

100     public static int lastIndexOf(CharSequence pattern, CharSequence chars,
101             int fromIndex) {
102         int patternLength = pattern.length();
103         fromIndex = Math.min(chars.length() - pattern.length(), fromIndex);
104         if (patternLength != 0) { // At least one character to search for.
105
char firstChar = pattern.charAt(0);
106             for (int i = fromIndex; i >= 0; i--) {
107                 if (chars.charAt(i) == firstChar) {
108                     boolean match = true;
109                     for (int j = 1; j < patternLength; j++) {
110                         if (chars.charAt(i + j) != pattern.charAt(j)) {
111                             match = false;
112                             break;
113                         }
114                     }
115                     if (match) {
116                         return i;
117                     }
118                 }
119             }
120             return -1;
121         } else {
122             return Math.max(-1, fromIndex);
123         }
124     }
125
126     /**
127      * Parses the specified <code>CharSequence</code> as a <code>boolean</code>.
128      *
129      * @param chars the character sequence to parse.
130      * @return the corresponding <code>boolean</code>.
131      */

132     public static boolean parseBoolean(CharSequence chars) {
133         return (chars.length() == 4)
134                 && (chars.charAt(0) == 't' || chars.charAt(0) == 'T')
135                 && (chars.charAt(1) == 'r' || chars.charAt(1) == 'R')
136                 && (chars.charAt(2) == 'u' || chars.charAt(2) == 'U')
137                 && (chars.charAt(3) == 'e' || chars.charAt(3) == 'E');
138     }
139
140     /**
141      * Parses the specified <code>CharSequence</code> as a signed decimal
142      * <code>byte</code>.
143      *
144      * @param chars the character sequence to parse.
145      * @return <code>parseByte(chars, 10)</code>
146      * @throws NumberFormatException if the specified character sequence
147      * does not contain a parsable <code>byte</code>.
148      * @see #parseByte(CharSequence, int)
149      */

150     public static byte parseByte(CharSequence chars) {
151         return parseByte(chars, 10);
152     }
153
154     /**
155      * Parses the specified <code>CharSequence</code> as a signed
156      * <code>byte</code> in the specified radix. The characters in the string
157      * must all be digits of the specified radix, except the first character
158      * which may be a plus sign <code>'+'</code> or a minus sign
159      * <code>'-'</code>.
160      *
161      * @param chars the character sequence to parse.
162      * @param radix the radix to be used while parsing.
163      * @return the corresponding <code>byte</code>.
164      * @throws NumberFormatException if the specified character sequence
165      * does not contain a parsable <code>short</code>.
166      */

167     public static byte parseByte(CharSequence chars, int radix) {
168         try {
169             boolean isNegative = (chars.charAt(0) == '-') ? true : false;
170             int result = 0;
171             int limit = (isNegative) ? Byte.MIN_VALUE : -Byte.MAX_VALUE;
172             int multmin = limit / radix;
173             int length = chars.length();
174             int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
175             while (true) {
176                 int digit = Character.digit(chars.charAt(i), radix);
177                 int tmp = result * radix;
178                 if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow.
179
throw new NumberFormatException("For input characters: \""
180                             + chars.toString() + "\"");
181                 }
182                 // Accumulates negatively.
183
result = tmp - digit;
184                 if (++i >= length) {
185                     break;
186                 }
187             }
188             return (byte) (isNegative ? result : -result);
189         } catch (IndexOutOfBoundsException e) {
190             throw new NumberFormatException("For input characters: \""
191                     + chars.toString() + "\"");
192         }
193     }
194
195     /**
196      * Parses the specified <code>CharSequence</code> as a signed decimal
197      * <code>short</code>.
198      *
199      * @param chars the character sequence to parse.
200      * @return <code>parseShort(chars, 10)</code>
201      * @throws NumberFormatException if the specified character sequence
202      * does not contain a parsable <code>short</code>.
203      * @see #parseShort(CharSequence, int)
204      */

205     public static short parseShort(CharSequence chars) {
206         return parseShort(chars, 10);
207     }
208
209     /**
210      * Parses the specified <code>CharSequence</code> as a signed
211      * <code>short</code> in the specified radix. The characters in the string
212      * must all be digits of the specified radix, except the first character
213      * which may be a plus sign <code>'+'</code> or a minus sign
214      * <code>'-'</code>.
215      *
216      * @param chars the character sequence to parse.
217      * @param radix the radix to be used while parsing.
218      * @return the corresponding <code>short</code>.
219      * @throws NumberFormatException if the specified character sequence
220      * does not contain a parsable <code>short</code>.
221      */

222     public static short parseShort(CharSequence chars, int radix) {
223         try {
224             boolean isNegative = (chars.charAt(0) == '-') ? true : false;
225             int result = 0;
226             int limit = (isNegative) ? Short.MIN_VALUE : -Short.MAX_VALUE;
227             int multmin = limit / radix;
228             int length = chars.length();
229             int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
230             while (true) {
231                 int digit = Character.digit(chars.charAt(i), radix);
232                 int tmp = result * radix;
233                 if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow.
234
throw new NumberFormatException("For input characters: \""
235                             + chars.toString() + "\"");
236                 }
237                 // Accumulates negatively.
238
result = tmp - digit;
239                 if (++i >= length) {
240                     break;
241                 }
242             }
243             return (short) (isNegative ? result : -result);
244         } catch (IndexOutOfBoundsException e) {
245             throw new NumberFormatException("For input characters: \""
246                     + chars.toString() + "\"");
247         }
248     }
249
250     /**
251      * Parses the specified <code>CharSequence</code> as a signed decimal
252      * <code>int</code>.
253      *
254      * @param chars the character sequence to parse.
255      * @return <code>parseInt(chars, 10)</code>
256      * @throws NumberFormatException if the specified character sequence
257      * does not contain a parsable <code>int</code>.
258      * @see #parseInt(CharSequence, int)
259      */

260     public static int parseInt(CharSequence chars) {
261         return parseInt(chars, 10);
262     }
263
264     /**
265      * Parses the specified <code>CharSequence</code> as a signed
266      * <code>int</code> in the specified radix. The characters in the string
267      * must all be digits of the specified radix, except the first character
268      * which may be a plus sign <code>'+'</code> or a minus sign
269      * <code>'-'</code>.
270      *
271      * @param chars the character sequence to parse.
272      * @param radix the radix to be used while parsing.
273      * @return the corresponding <code>int</code>.
274      * @throws NumberFormatException if the specified character sequence
275      * does not contain a parsable <code>int</code>.
276      */

277     public static int parseInt(CharSequence chars, int radix) {
278         try {
279             boolean isNegative = (chars.charAt(0) == '-') ? true : false;
280             int result = 0;
281             int limit = (isNegative) ? Integer.MIN_VALUE : -Integer.MAX_VALUE;
282             int multmin = limit / radix;
283             int length = chars.length();
284             int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
285             while (true) {
286                 int digit = Character.digit(chars.charAt(i), radix);
287                 int tmp = result * radix;
288                 if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow.
289
throw new NumberFormatException("For input characters: \""
290                             + chars.toString() + "\"");
291                 }
292                 // Accumulates negatively to avoid surprises near MAX_VALUE
293
result = tmp - digit;
294                 if (++i >= length) {
295                     break;
296                 }
297             }
298             return isNegative ? result : -result;
299         } catch (IndexOutOfBoundsException e) {
300             throw new NumberFormatException("For input characters: \""
301                     + chars.toString() + "\"");
302         }
303     }
304
305     /**
306      * Parses the specified <code>CharSequence</code> as a signed decimal
307      * <code>long</code>.
308      *
309      * @param chars the character sequence to parse.
310      * @return <code>parseLong(chars, 10)</code>
311      * @throws NumberFormatException if the specified character sequence
312      * does not contain a parsable <code>long</code>.
313      * @see #parseLong(CharSequence, int)
314      */

315     public static long parseLong(CharSequence chars) {
316         return parseLong(chars, 10);
317     }
318
319     /**
320      * Parses the specified <code>CharSequence</code> as a signed
321      * <code>long</code> in the specified radix. The characters in the string
322      * must all be digits of the specified radix, except the first character
323      * which may be a plus sign <code>'+'</code> or a minus sign
324      * <code>'-'</code>.
325      *
326      * @param chars the character sequence to parse.
327      * @param radix the radix to be used while parsing.
328      * @return the corresponding <code>long</code>.
329      * @throws NumberFormatException if the specified character sequence
330      * does not contain a parsable <code>long</code>.
331      */

332     public static long parseLong(CharSequence chars, int radix) {
333         try {
334             boolean isNegative = (chars.charAt(0) == '-') ? true : false;
335             long result = 0;
336             long limit = (isNegative) ? Long.MIN_VALUE : -Long.MAX_VALUE;
337             long multmin = limit / radix;
338             int length = chars.length();
339             int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
340             while (true) {
341                 int digit = Character.digit(chars.charAt(i), radix);
342                 long tmp = result * radix;
343                 if ((digit < 0) || (result < multmin) || (tmp < limit + digit)) { // Overflow.
344
throw new NumberFormatException("For input characters: \""
345                             + chars.toString() + "\"");
346                 }
347                 // Accumulates negatively to avoid surprises near MAX_VALUE
348
result = tmp - digit;
349                 if (++i >= length) {
350                     break;
351                 }
352             }
353             return isNegative ? result : -result;
354         } catch (IndexOutOfBoundsException e) {
355             throw new NumberFormatException("For input characters: \""
356                     + chars.toString() + "\"");
357         }
358     }
359
360     /**
361      * Parses this <code>CharSequence</code> as a <code>float</code>.
362      *
363      * @param chars the character sequence to parse.
364      * @return the float number represented by the specified character sequence.
365      * @throws NumberFormatException if the character sequence does not contain
366      * a parsable <code>float</code>.
367      /*@FLOATING_POINT@
368      public static float parseFloat(CharSequence chars) {
369      double d = parseDouble(chars);
370      if ((d >= -3.4028235e+38f) && (d <= 3.4028235e+38f)) {
371      return (float) d;
372      } else {
373      throw new NumberFormatException(
374      "Float overflow for input characters: \""
375      + chars.toString() + "\"");
376      }
377      }
378      /**/

379
380     /**
381      * Parses this <code>CharSequence</code> as a <code>double</code>.
382      *
383      * @param chars the character sequence to parse.
384      * @return the double number represented by this character sequence.
385      * @throws NumberFormatException if the character sequence does not contain
386      * a parsable <code>double</code>.
387      /*@FLOATING_POINT@
388      public static double parseDouble(CharSequence chars)
389      throws NumberFormatException {
390      try {
391      int length = chars.length();
392      long result = 0;
393      int exp = 0;
394
395      boolean isNegative = (chars.charAt(0) == '-') ? true : false;
396      int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
397
398      // Checks special cases NaN or Infinity.
399      if ((chars.charAt(i) == 'N') || (chars.charAt(i) == 'I')) {
400      if (chars.toString().equals("NaN")) {
401      return 0.0 / 0.0; // Double.NaN;
402      } else if (chars.subSequence(i, length).toString().equals(
403      "Infinity")) {
404      return isNegative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
405      }
406      }
407
408      // Reads decimal number.
409      boolean fraction = false;
410      while (true) {
411      char c = chars.charAt(i);
412      if ((c == '.') && (!fraction)) {
413      fraction = true;
414      } else if ((c == 'e') || (c == 'E')) {
415      break;
416      } else if ((c >= '0') && (c <= '9')) {
417      result = result * 10 + (c - '0');
418      if (fraction) {
419      exp--;
420      }
421      } else {
422      throw new NumberFormatException("For input characters: \""
423      + chars.toString() + "\"");
424      }
425      if (++i >= length) {
426      break;
427      }
428      }
429      result = isNegative ? -result : result;
430
431      // Reads exponent (if any).
432      if (i < length) {
433      i++;
434      boolean negE = (chars.charAt(i) == '-') ? true : false;
435      i = (negE || (chars.charAt(i) == '+')) ? i + 1 : i;
436      int valE = 0;
437      while (true) {
438      char c = chars.charAt(i);
439      if ((c >= '0') && (c <= '9')) {
440      valE = valE * 10 + (c - '0');
441      if (valE > 10000000) { // Hard-limit to avoid overflow.
442      valE = 10000000;
443      }
444      } else {
445      throw new NumberFormatException(
446      "For input characters: \"" + chars.toString()
447      + "\"");
448      }
449      if (++i >= length) {
450      break;
451      }
452      }
453      exp += negE ? -valE : valE;
454      }
455
456      // Returns product decimal number with exponent.
457      return multE(result, exp);
458
459      } catch (IndexOutOfBoundsException e) {
460      throw new NumberFormatException("For input characters: \""
461      + chars.toString() + "\"");
462      }
463      }
464      /**/

465
466     /**
467      * Formats the specified <code>boolean</code> and appends the resulting
468      * text to the <code>Appendable</code> argument.
469      *
470      * @param b a <code>boolean</code>.
471      * @param chars the <code>Appendable</code> to append.
472      * @return the specified <code>StringBuffer</code> object.
473      * @throws IOException if an I/O exception occurs.
474      * @see #parseBoolean
475      */

476     public static Appendable format(boolean b, Appendable chars)
477             throws IOException {
478         return b ? append(chars, "true") : append(chars, "false");
479     }
480
481     /**
482      * Formats the specified <code>int</code> and appends the resulting
483      * text (decimal representation) to the <code>Appendable</code> argument.
484      *
485      * <p> Note: This method is preferred to <code>Appendable.append(int)
486      * </code> as it does not create temporary <code>String</code>
487      * objects (several times faster for small numbers).</p>
488      *
489      * @param i the <code>int</code> number.
490      * @param chars the <code>Appendable</code> to append.
491      * @return the specified <code>Appendable</code> object.
492      * @throws IOException if an I/O exception occurs.
493      * @see #parseInt
494      */

495     public static Appendable format(int i, Appendable chars) throws IOException {
496         if (i <= 0) {
497             if (i == Integer.MIN_VALUE) { // Negation would overflow.
498
return append(chars, "-2147483648"); // 11 char max.
499
} else if (i == 0) {
500                 return chars.append('0');
501             }
502             i = -i;
503             chars.append('-');
504         }
505         int j = 1;
506         for (; (j < 10) && (i >= INT_POW_10[j]); j++) {
507         }
508         // POW_10[j] > i >= POW_10[j-1]
509
for (j--; j >= 0; j--) {
510             int pow10 = INT_POW_10[j];
511             int digit = i / pow10;
512             i -= digit * pow10;
513             chars.append(DIGITS[digit]);
514         }
515         return chars;
516     }
517
518     private static final int[] INT_POW_10 = new int[10];
519     static {
520         int pow = 1;
521         for (int i = 0; i < 10; i++) {
522             INT_POW_10[i] = pow;
523             pow *= 10;
524         }
525     }
526
527     /**
528      * Formats the specified <code>int</code> in the specified radix and appends
529      * the resulting text to the <code>Appendable</code> argument.
530      *
531      * @param i the <code>int</code> number.
532      * @param radix the radix.
533      * @param chars the <code>Appendable</code> to append.
534      * @return the specified <code>Appendable</code> object.
535      * @throws IllegalArgumentException if radix is not in [2 .. 36] range.
536      * @throws IOException if an I/O exception occurs.
537      * @see #parseInt(CharSequence, int)
538      */

539     public static Appendable format(int i, int radix, Appendable chars)
540             throws IOException {
541         if (radix == 10) {
542             return format(i, chars); // Faster version.
543
} else if (radix < 2 || radix > 36) {
544             throw new IllegalArgumentException("radix: " + radix);
545         }
546         if (i < 0) {
547             chars.append('-');
548         } else {
549             i = -i;
550         }
551         format2(i, radix, chars);
552         return chars;
553     }
554
555     private static void format2(int i, int radix, Appendable chars)
556             throws IOException {
557         if (i <= -radix) {
558             format2(i / radix, radix, chars);
559             chars.append(DIGITS[-(i % radix)]);
560         } else {
561             chars.append(DIGITS[-i]);
562         }
563     }
564
565     /**
566      * Formats the specified <code>long</code> and appends the resulting
567      * text (decimal representation) to the <code>Appendable</code> argument.
568      *
569      * <p> Note: This method is preferred to <code>Appendable.append(long)
570      * </code> as it does not create temporary <code>String</code>
571      * objects (several times faster for small numbers).</p>
572      *
573      * @param l the <code>long</code> number.
574      * @param chars the <code>Appendable</code> to append.
575      * @return the specified <code>Appendable</code> object.
576      * @throws IOException if an I/O exception occurs.
577      * @see #parseLong
578      */

579     public static Appendable format(long l, Appendable chars)
580             throws IOException {
581         if (l <= 0) {
582             if (l == Long.MIN_VALUE) { // Negation would overflow.
583
return append(chars, "-9223372036854775808"); // 20 characters max.
584
} else if (l == 0) {
585                 return chars.append('0');
586             }
587             l = -l;
588             chars.append('-');
589         }
590         int j = 1;
591         for (; (j < 19) && (l >= LONG_POW_10[j]); j++) {
592         }
593         // POW_10[j] > l >= POW_10[j-1]
594
for (j--; j >= 0; j--) {
595             long pow10 = LONG_POW_10[j];
596             int digit = (int) (l / pow10);
597             l -= digit * pow10;
598             chars.append(DIGITS[digit]);
599         }
600         return chars;
601     }
602
603     private static final long[] LONG_POW_10 = new long[19];
604     static {
605         long pow = 1;
606         for (int i = 0; i < 19; i++) {
607             LONG_POW_10[i] = pow;
608             pow *= 10;
609         }
610     }
611
612     /**
613      * Formats the specified <code>long</code> in the specified radix and
614      * appends the resulting text to the <code>Appendable</code> argument.
615      *
616      * @param l the <code>long</code> number.
617      * @param radix the radix.
618      * @param chars the <code>Appendable</code> to append.
619      * @return the specified <code>Appendable</code> object.
620      * @throws IllegalArgumentException if radix is not in [2 .. 36] range.
621      * @throws IOException if an I/O exception occurs.
622      * @see #parseLong(CharSequence, int)
623      */

624     public static Appendable format(long l, int radix, Appendable chars)
625             throws IOException {
626         if (radix == 10) {
627             return format(l, chars); // Faster version.
628
} else if (radix < 2 || radix > 36) {
629             throw new IllegalArgumentException("radix: " + radix);
630         }
631         if (l < 0) {
632             chars.append('-');
633         } else {
634             l = -l;
635         }
636         format2(l, radix, chars);
637         return chars;
638     }
639
640     private static void format2(long l, int radix, Appendable chars)
641             throws IOException {
642         if (l <= -radix) {
643             format2(l / radix, radix, chars);
644             chars.append(DIGITS[(int) -(l % radix)]);
645         } else {
646             chars.append(DIGITS[(int) -l]);
647         }
648     }
649
650     /**
651      * Formats the specified <code>float</code> value.
652      *
653      * @param value the <code>float</code> value.
654      * @param chars the <code>Appendable</code> to append.
655      * @return <code>format(value, 10, Math.abs(value) > 1E7, false, sb)</code>
656      * @throws IOException if an I/O exception occurs.
657      * @see #format(double, int , boolean, boolean, Appendable)
658      /*@FLOATING_POINT@
659     public static Appendable format(float value, Appendable chars)
660             throws IOException {
661         return format(value, 10, MathLib.abs(value) > 1E7, false, chars);
662     }
663     /**/

664
665     /**
666      * Formats the specified <code>double</code> value.
667      *
668      * <p> Note : This method is preferred to <code>Double.toString(double)
669      * </code> or even <code>String.valueOf(double)</code> as it
670      * does not create temporary <code>String</code> or <code>
671      * FloatingDecimal</code> objects (several times faster,
672      * e.g. 15x faster for <code>Double.MAX_VALUE</code>).</p>
673      *
674      * @param value the <code>double</code> value.
675      * @param chars the <code>Appendable</code> to append.
676      * @return <code>format(value, 17, Math.abs(value) > 1E7, false, sb)</code>
677      * @throws IOException if an I/O exception occurs.
678      * @see #format(double, int , boolean, boolean, Appendable)
679      /*@FLOATING_POINT@
680     public static Appendable format(double value, Appendable chars)
681             throws IOException {
682         return format(value, 17, MathLib.abs(value) > 1E7, false, chars);
683     }
684     /**/

685
686     /**
687      * Formats the specified <code>double</code> value according to the
688      * specified formatting arguments.
689      *
690      * @param value the <code>double</code> value.
691      * @param digits the number of significative digits (excludes exponent).
692      * @param scientific <code>true</code> to forces the use of the scientific
693      * notation (e.g. <code>1.23E3</code>); <code>false</code>
694      * otherwise.
695      * @param showZero <code>true</code> if trailing fractional zeros are
696      * represented; <code>false</code> otherwise.
697      * @param chars the <code>Appendable</code> to append.
698      * @return the specified <code>Appendable</code> object.
699      * @throws IllegalArgumentException if <code>((digits > 19) ||
700      * (digits <= 0))</code>)
701      * @throws IOException if an I/O exception occurs.
702      /*@FLOATING_POINT@
703     public static Appendable format(double value, int digits,
704             boolean scientific, boolean showZero, Appendable chars) throws IOException {
705         if ((digits > 19) || (digits <= 0))
706             throw new IllegalArgumentException("digits: " + digits);
707         if (value != value) { // NaN
708             return append(chars, "NaN");
709         } else if (value == POSITIVE_INFINITY) {
710             return append(chars, "Infinity");
711         } else if (value == NEGATIVE_INFINITY) {
712             return append(chars, "-Infinity");
713         } else if (value == 0.0) {
714             if (digits == 1)
715                 return append(chars, "0");
716             if (!showZero)
717                 return append(chars, "0.0");
718             append(chars, "0.0");
719             for (int i = 2; i < digits; i++) {
720                 chars.append('0');
721             }
722             return chars;
723         }
724         if (value < 0) {
725             value = -value;
726             chars.append('-');
727         }
728         // Find the exponent e such as: value == 0.xxx * 10^e
729         int e = (value >= 1.0) ? 1 + minPow10(value) : - minPow10(1.0 / value);
730         double digitValue = multE(value, digits - e);
731         long mantissa = (long) (digitValue + 0.5);
732         if (scientific || (e <= 0) || (e > digits)) {
733             // Scientific notation has to be used ("x.xxxEyy").
734             format(mantissa / LONG_POW_10[digits - 1], chars);
735             formatFraction(mantissa % LONG_POW_10[digits - 1], digits - 1,
736                     showZero, chars);
737             chars.append('E');
738             format(e - 1, chars);
739         } else if (e == digits) { // Dot at last position ("xxxxx").
740             format(mantissa, chars);
741         } else { // Dot within the string ("xxxx.xxxxx").
742             format(mantissa / LONG_POW_10[digits - e], chars);
743             formatFraction(mantissa % LONG_POW_10[digits - e], digits
744                     - e, showZero, chars);
745         }
746         return chars;
747     }
748
749
750     private static final double POSITIVE_INFINITY = 1.0 / 0.0;
751
752     private static final double NEGATIVE_INFINITY = -1.0 / 0.0;
753
754     private static void formatFraction(long fraction, int digits,
755             boolean showZero, Appendable chars) throws IOException {
756         if (digits == 0)
757             return;
758         chars.append('.');
759         for (int i = digits; i > 0;) {
760             long pow10 = LONG_POW_10[--i];
761             int digit = (int) (fraction / pow10);
762             fraction -= digit * pow10;
763             chars.append(DIGITS[digit]);
764             if ((fraction == 0) && !showZero) {
765                 return; // No more than one trailing zero.
766             }
767         }
768     }
769     // Returns e such as 10^e <= value < 10^(e+1), value >= 1.0
770     private static int minPow10(double value) {
771         int minE = 0;
772         int maxE = DOUBLE_POW_10.length;
773         while (maxE - minE > 1) {
774             final int exp = (minE + maxE) >> 1;
775             if (value >= DOUBLE_POW_10[exp]) {
776                 minE = exp;
777             } else {
778                 maxE = exp;
779             }
780         }
781         return minE;
782     }
783     /**/

784
785     /**
786      * Appends the specified string argument to the specified appendable
787      * for backward compatibility when {@link String} was not a
788      * {@link CharSequence}.
789      *
790      * @param to the appendable.
791      * @param str the string to append.
792      * @return the specified appendable
793      * @throws IOException if an I/O exception occurs.
794      */

795     private static Appendable append(Appendable to, String str)
796             throws IOException {
797         for (int i = 0; i < str.length(); i++) {
798             to.append(str.charAt(i));
799         }
800         return to;
801     }
802
803     /**
804      * Returns the product of the specified value with <code>10</code> raised
805      * at the specified power exponent.
806      *
807      * @param value the value.
808      * @param E the exponent.
809      * @return <code>value * 10^E</code>
810      /*@FLOATING_POINT@
811      private static double multE(double value, int E) {
812      if (E >= 0) {
813      if (E <= 308) {
814      // Max: 1.7976931348623157E+308
815      return value * DOUBLE_POW_10[E];
816      } else {
817      value *= 1E21; // Exact multiplicand.
818      E = Math.min(308, E - 21);
819      return value * DOUBLE_POW_10[E];
820      }
821      } else {
822      if (E >= -308) {
823      return value / DOUBLE_POW_10[-E];
824      } else {
825      // Min: 4.9E-324
826      value /= 1E21; // Exact divisor.
827      E = Math.max(-308, E + 21);
828      return value / DOUBLE_POW_10[-E];
829      }
830      }
831      }
832
833      // Note: Approximation for exponents > 21. This may introduce round-off
834      // errors (e.g. 1E23 represented as "9.999999999999999E22").
835      private static final double[] DOUBLE_POW_10 = new double[] { 1E000, 1E001,
836      1E002, 1E003, 1E004, 1E005, 1E006, 1E007, 1E008, 1E009, 1E010,
837      1E011, 1E012, 1E013, 1E014, 1E015, 1E016, 1E017, 1E018, 1E019,
838      1E020, 1E021, 1E022, 1E023, 1E024, 1E025, 1E026, 1E027, 1E028,
839      1E029, 1E030, 1E031, 1E032, 1E033, 1E034, 1E035, 1E036, 1E037,
840      1E038, 1E039, 1E040, 1E041, 1E042, 1E043, 1E044, 1E045, 1E046,
841      1E047, 1E048, 1E049, 1E050, 1E051, 1E052, 1E053, 1E054, 1E055,
842      1E056, 1E057, 1E058, 1E059, 1E060, 1E061, 1E062, 1E063, 1E064,
843      1E065, 1E066, 1E067, 1E068, 1E069, 1E070, 1E071, 1E072, 1E073,
844      1E074, 1E075, 1E076, 1E077, 1E078, 1E079, 1E080, 1E081, 1E082,
845      1E083, 1E084, 1E085, 1E086, 1E087, 1E088, 1E089, 1E090, 1E091,
846      1E092, 1E093, 1E094, 1E095, 1E096, 1E097, 1E098, 1E099,
847
848      1E100, 1E101, 1E102, 1E103, 1E104, 1E105, 1E106, 1E107, 1E108,
849      1E109, 1E110, 1E111, 1E112, 1E113, 1E114, 1E115, 1E116, 1E117,
850      1E118, 1E119, 1E120, 1E121, 1E122, 1E123, 1E124, 1E125, 1E126,
851      1E127, 1E128, 1E129, 1E130, 1E131, 1E132, 1E133, 1E134, 1E135,
852      1E136, 1E137, 1E138, 1E139, 1E140, 1E141, 1E142, 1E143, 1E144,
853      1E145, 1E146, 1E147, 1E148, 1E149, 1E150, 1E151, 1E152, 1E153,
854      1E154, 1E155, 1E156, 1E157, 1E158, 1E159, 1E160, 1E161, 1E162,
855      1E163, 1E164, 1E165, 1E166, 1E167, 1E168, 1E169, 1E170, 1E171,
856      1E172, 1E173, 1E174, 1E175, 1E176, 1E177, 1E178, 1E179, 1E180,
857      1E181, 1E182, 1E183, 1E184, 1E185, 1E186, 1E187, 1E188, 1E189,
858      1E190, 1E191, 1E192, 1E193, 1E194, 1E195, 1E196, 1E197, 1E198,
859      1E199,
860
861      1E200, 1E201, 1E202, 1E203, 1E204, 1E205, 1E206, 1E207, 1E208,
862      1E209, 1E210, 1E211, 1E212, 1E213, 1E214, 1E215, 1E216, 1E217,
863      1E218, 1E219, 1E220, 1E221, 1E222, 1E223, 1E224, 1E225, 1E226,
864      1E227, 1E228, 1E229, 1E230, 1E231, 1E232, 1E233, 1E234, 1E235,
865      1E236, 1E237, 1E238, 1E239, 1E240, 1E241, 1E242, 1E243, 1E244,
866      1E245, 1E246, 1E247, 1E248, 1E249, 1E250, 1E251, 1E252, 1E253,
867      1E254, 1E255, 1E256, 1E257, 1E258, 1E259, 1E260, 1E261, 1E262,
868      1E263, 1E264, 1E265, 1E266, 1E267, 1E268, 1E269, 1E270, 1E271,
869      1E272, 1E273, 1E274, 1E275, 1E276, 1E277, 1E278, 1E279, 1E280,
870      1E281, 1E282, 1E283, 1E284, 1E285, 1E286, 1E287, 1E288, 1E289,
871      1E290, 1E291, 1E292, 1E293, 1E294, 1E295, 1E296, 1E297, 1E298,
872      1E299,
873
874      1E300, 1E301, 1E302, 1E303, 1E304, 1E305, 1E306, 1E307, 1E308 };
875      /**/

876 }
Popular Tags