View Javadoc
1   package nom.tam.util;
2   
3   /*
4    * #%L
5    * nom.tam FITS library
6    * %%
7    * Copyright (C) 2004 - 2024 nom-tam-fits
8    * %%
9    * This is free and unencumbered software released into the public domain.
10   *
11   * Anyone is free to copy, modify, publish, use, compile, sell, or
12   * distribute this software, either in source code form or as a compiled
13   * binary, for any purpose, commercial or non-commercial, and by any
14   * means.
15   *
16   * In jurisdictions that recognize copyright laws, the author or authors
17   * of this software dedicate any and all copyright interest in the
18   * software to the public domain. We make this dedication for the benefit
19   * of the public at large and to the detriment of our heirs and
20   * successors. We intend this dedication to be an overt act of
21   * relinquishment in perpetuity of all present and future rights to this
22   * software under copyright law.
23   *
24   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30   * OTHER DEALINGS IN THE SOFTWARE.
31   * #L%
32   */
33  
34  /**
35   * This class provides mechanisms for efficiently formatting numbers and Strings. Data is appended to existing byte
36   * arrays. Note that the formatting of real or double values may differ slightly (in the last bit) from the standard
37   * Java packages since this routines are optimized for speed rather than accuracy.
38   * <p>
39   * The methods in this class create no objects.
40   * <p>
41   * If a number cannot fit into the requested space the truncateOnOverlow flag controls whether the formatter will
42   * attempt to append it using the available length in the output (a la C or Perl style formats). If this flag is set, or
43   * if the number cannot fit into space left in the buffer it is 'truncated' and the requested space is filled with a
44   * truncation fill character. A TruncationException may be thrown if the truncationThrow flag is set.
45   * <p>
46   * This class does not explicitly support separate methods for formatting reals in exponential notation. Real numbers
47   * near one are by default formatted in decimal notation while numbers with large (or very negative) exponents are
48   * formatted in exponential notation. By setting the limits at which these transitions take place the user can force
49   * either exponential or decimal notation.
50   * 
51   * @deprecated This class should not be exposed in the public API and is intended for internal use only in ASCII tables.
52   *                 Also, it may have overlapping functionality with other classes, which should probably be eliminated
53   *                 for simplicity's sake (and thus less chance of nasty bugs).
54   * 
55   * @see        ByteParser
56   */
57  @Deprecated
58  public final class ByteFormatter {
59  
60      /** String representation of NaN values */
61      public static final String NOT_A_NUMBER = "NaN";
62  
63      /** String representation of (positive) infinity values */
64      public static final String INFINITY = "Infinity";
65  
66      /** String representation of (negative) infinity values */
67      public static final String NEGATIVE_INFINITY = "-Infinity";
68  
69      /**
70       * Maximum magnitude to print in non-scientific notation.
71       */
72      private static final double DEFAULT_SIMPLE_MAX = 1.e6;
73  
74      /**
75       * Minimum magnitude to print in non-scientific notation.
76       */
77      private static final double DEFAULT_SIMPLE_MIN = 1.e-3;
78  
79      /**
80       * Digits. We could handle other bases by extending or truncating this list and changing the division by 10 (and
81       * it's factors) at various locations.
82       */
83      private static final byte[] DIGITS = {(byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
84              (byte) '6', (byte) '7', (byte) '8', (byte) '9'};
85  
86      private static final long DOUBLE_EXPONENT_BIT_MASK = 0x7FF0000000000000L;
87  
88      private static final int DOUBLE_EXPONENT_EXCESS = 52;
89  
90      /**
91       * The hidden bit in normalized double numbers.
92       */
93      private static final long DOUBLE_EXPONENT_NORMALIZE_BIT = 0x0010000000000000L;
94  
95      /**
96       * Used to check if double is normalized
97       */
98      private static final int DOUBLE_MIN_EXPONENT = -1023;
99  
100     private static final int DOUBLE_SHIFT_BASE = 17;
101 
102     private static final int DOUBLE_SHIFT_LIMIT = 200;
103 
104     private static final long DOUBLE_VALUE_BIT_MASK = 0x000FFFFFFFFFFFFFL;
105 
106     private static final int FLOAT_EXPONENT_BIT_MASK = 0x7F800000;
107 
108     private static final int FLOAT_EXPONENT_EXCESS = 23;
109 
110     /**
111      * The hidden bit in normalized floating point numbers.
112      */
113     private static final int FLOAT_EXPONENT_NORMALIZE_BIT = 0x00800000;
114 
115     /**
116      * Used to check if float is normalized
117      */
118     private static final int FLOAT_MIN_EXPONENT = -127;
119 
120     private static final int FLOAT_SHIFT_BASE = 8;
121 
122     private static final int FLOAT_SHIFT_LIMIT = 30;
123 
124     private static final int FLOAT_VALUE_BIT_MASK = 0x007FFFFF;
125 
126     private static final double I_LOG_10 = 1. / Math.log(ByteFormatter.NUMBER_BASE);
127 
128     private static final long LONG_TO_INT_MODULO = 1000000000L;
129 
130     private static final int MAX_LONG_LENGTH = 19;
131 
132     /**
133      * The maximum single digit integer. Special case handling when rounding up and when incrementing the exponent.
134      */
135 
136     private static final int MAXIMUM_SINGLE_DIGIT_INTEGER = 9;
137 
138     /**
139      * The maximum two digit integer. When we increment an exponent of this value, the exponent gets longer. Don't need
140      * to worry about 999 since exponents can't be that big.
141      */
142     private static final int MAXIMUM_TWO_DIGIT_INTEGER = 99;
143 
144     private static final int TEMP_BUFFER_SIZE = 32;
145 
146     /**
147      * The underlying number base used in this class.
148      */
149     private static final int NUMBER_BASE = 10;
150 
151     /**
152      * Powers of 10. We over extend on both sides. These should perhaps be tabulated rather than computed though it may
153      * be faster to calculate them than to read in the extra bytes in the class file.
154      */
155     private static final double[] NUMBER_BASE_POWERS;
156 
157     /**
158      * What do we use to fill when we cannot print the number?Default is often used in Fortran.
159      */
160     private static final byte TRUNCATION_FILL = (byte) '*';
161 
162     /**
163      * What index of tenpow is 10^0
164      */
165     private static final int ZERO_POW;
166 
167     static { // Static initializer
168         int min = (int) Math.floor((int) (Math.log(Double.MIN_VALUE) * ByteFormatter.I_LOG_10));
169         int max = (int) Math.floor((int) (Math.log(Double.MAX_VALUE) * ByteFormatter.I_LOG_10));
170         max++;
171         NUMBER_BASE_POWERS = new double[max - min + 1];
172         for (int i = 0; i < ByteFormatter.NUMBER_BASE_POWERS.length; i++) {
173             ByteFormatter.NUMBER_BASE_POWERS[i] = Math.pow(ByteFormatter.NUMBER_BASE, i + min);
174         }
175         ZERO_POW = -min;
176     }
177 
178     /**
179      * Internal buffers used in formatting fields
180      */
181     private final byte[] tbuf1 = new byte[ByteFormatter.TEMP_BUFFER_SIZE];
182 
183     private final byte[] tbuf2 = new byte[ByteFormatter.TEMP_BUFFER_SIZE];
184 
185     /**
186      * This method formats a double given a decimal mantissa and exponent information.
187      *
188      * @param  val   The original number
189      * @param  buf   Output buffer
190      * @param  off   Offset into buffer
191      * @param  len   Maximum number of characters to use in buffer.
192      * @param  mant  A decimal mantissa for the number.
193      * @param  lmant The number of characters in the mantissa
194      * @param  shift The exponent of the power of 10 that we shifted val to get the given mantissa.
195      *
196      * @return       Offset of next available character in buffer.
197      */
198     private int combineReal(double val, byte[] buf, int off, int len, byte[] mant, int lmant, int shift) {
199 
200         // First get the minimum size for the number
201 
202         double pos = Math.abs(val);
203         boolean simple = false;
204         int minSize;
205         int maxSize;
206 
207         if (pos >= ByteFormatter.DEFAULT_SIMPLE_MIN && pos <= ByteFormatter.DEFAULT_SIMPLE_MAX) {
208             simple = true;
209         }
210 
211         int exp = lmant - shift - 1;
212         int lexp = 0;
213 
214         if (!simple) {
215             lexp = format(exp, tbuf2, 0, ByteFormatter.TEMP_BUFFER_SIZE);
216 
217             minSize = lexp + 2; // e.g., 2e-12
218             maxSize = lexp + lmant + 2; // add in "." and e
219         } else if (exp >= 0) {
220             minSize = exp + 1; // e.g. 32
221 
222             // Special case. E.g., 99.9 has
223             // minumum size of 3.
224             int i;
225             for (i = 0; i < lmant && i <= exp; i++) {
226                 if (mant[i] != (byte) '9') {
227                     break;
228                 }
229             }
230             if (i > exp && i < lmant && mant[i] >= (byte) '5') {
231                 minSize++;
232             }
233 
234             maxSize = lmant + 1; // Add in "."
235             if (maxSize <= minSize) { // Very large numbers.
236                 maxSize = minSize + 1;
237             }
238         } else {
239             minSize = 2;
240             maxSize = 1 + Math.abs(exp) + lmant;
241         }
242         if (val < 0) {
243             minSize++;
244         }
245 
246         // Can the number fit?
247         if (minSize > len || minSize > buf.length - off) {
248             truncationFiller(buf, off, len);
249             return off + len;
250         }
251 
252         // Now begin filling in the buffer.
253         if (val < 0) {
254             buf[off] = (byte) '-';
255             off++;
256             len--;
257         }
258 
259         if (simple) {
260             return Math.abs(mantissa(mant, lmant, exp, simple, buf, off, len));
261         }
262         off = mantissa(mant, lmant, 0, simple, buf, off, len - lexp - 1);
263         if (off < 0) {
264             off = -off;
265             len -= off;
266             // Handle the expanded exponent by filling
267             if (exp == MAXIMUM_SINGLE_DIGIT_INTEGER || exp == MAXIMUM_TWO_DIGIT_INTEGER) {
268                 // Cannot fit...
269                 if (off + len == minSize) {
270                     truncationFiller(buf, off, len);
271                     return off + len;
272                 }
273                 // Steal a character from the mantissa.
274                 off--;
275             }
276             exp++;
277             lexp = format(exp, tbuf2, 0, ByteFormatter.TEMP_BUFFER_SIZE);
278         }
279         buf[off] = (byte) 'E';
280         off++;
281         System.arraycopy(tbuf2, 0, buf, off, lexp);
282         return off + lexp;
283     }
284 
285     /**
286      * Format a boolean into an existing array.
287      *
288      * @param  val   value to write
289      * @param  array the array to fill
290      *
291      * @return       Offset of next available character in buffer.
292      */
293     public int format(boolean val, byte[] array) {
294         return format(val, array, 0, array.length);
295     }
296 
297     /**
298      * Format a boolean into an existing array
299      *
300      * @param  val   The boolean to be formatted
301      * @param  array The buffer in which to format the data.
302      * @param  off   The starting offset within the buffer.
303      * @param  len   The maximum number of characters to use use in formatting the number.
304      *
305      * @return       Offset of next available character in buffer.
306      */
307     public int format(boolean val, byte[] array, int off, int len) {
308         if (len > 0) {
309             if (val) {
310                 array[off] = (byte) 'T';
311             } else {
312                 array[off] = (byte) 'F';
313             }
314             off++;
315         }
316         return off;
317     }
318 
319     /**
320      * Format a double into an array.
321      *
322      * @param  val   The double to be formatted.
323      * @param  array The array in which to place the result.
324      *
325      * @return       The number of characters used. @ * if the value was truncated
326      */
327     public int format(double val, byte[] array) {
328         return format(val, array, 0, array.length);
329     }
330 
331     /**
332      * Format a double into an existing character array.
333      * <p>
334      * This is hard to do exactly right... The JDK code does stuff with rational arithmetic and so forth. We use a much
335      * simpler algorithm which may give an answer off in the lowest order bit. Since this is pure Java, it should still
336      * be consistent from machine to machine.
337      * <p>
338      * Recall that the binary representation of the double is of the form <code>d = 0.bbbbbbbb x 2<sup>n</sup></code>
339      * where there are up to 53 binary digits in the binary fraction (including the assumed leading 1 bit for normalized
340      * numbers). We find a value m such that <code>10<sup>m</sup> d</code> is between <code>2<sup>53</sup></code> and
341      * <code>2<sup>63</sup></code>. This product will be exactly convertible to a long with no loss of precision.
342      * Getting the decimal representation for that is trivial (see formatLong). This is a decimal mantissa and we have
343      * an exponent (<code>-m</code>). All we have to do is manipulate the decimal point to where we want to see it.
344      * Errors can arise due to roundoff in the scaling multiplication, but should be no more than a single bit.
345      *
346      * @param  val Double to be formatted
347      * @param  buf Buffer in which result is to be stored
348      * @param  off Offset within buffer
349      * @param  len Maximum length of integer
350      *
351      * @return     offset of next unused character in input buffer.
352      */
353     public int format(double val, byte[] buf, int off, int len) {
354 
355         double pos = Math.abs(val);
356 
357         // Special cases -- It is OK if these get truncated.
358         if (pos == 0.) {
359             return format("0.0", buf, off, len);
360         }
361         if (Double.isNaN(val)) {
362             return format(NOT_A_NUMBER, buf, off, len);
363         }
364         if (Double.isInfinite(val)) {
365             if (val > 0) {
366                 return format(INFINITY, buf, off, len);
367             }
368             return format(NEGATIVE_INFINITY, buf, off, len);
369         }
370 
371         int power = (int) (Math.log(pos) * ByteFormatter.I_LOG_10);
372         int shift = DOUBLE_SHIFT_BASE - power;
373         double scale;
374         double scale2 = 1;
375 
376         // Scale the number so that we get a number ~ n x 10^17.
377         if (shift < DOUBLE_SHIFT_LIMIT) {
378             scale = ByteFormatter.NUMBER_BASE_POWERS[shift + ByteFormatter.ZERO_POW];
379         } else {
380             // Can get overflow if the original number is
381             // very small, so we break out the shift
382             // into two multipliers.
383             scale2 = ByteFormatter.NUMBER_BASE_POWERS[DOUBLE_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
384             scale = ByteFormatter.NUMBER_BASE_POWERS[shift - DOUBLE_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
385         }
386 
387         pos = pos * scale * scale2;
388 
389         // Parse the double bits.
390 
391         long bits = Double.doubleToLongBits(pos);
392 
393         // The exponent should be a little more than 52.
394         int exp = (int) (((bits & DOUBLE_EXPONENT_BIT_MASK) >> DOUBLE_EXPONENT_EXCESS) + DOUBLE_MIN_EXPONENT);
395 
396         long numb = bits & DOUBLE_VALUE_BIT_MASK;
397 
398         // this can never be false because the min exponent of a double is -1022
399         // but lets keep it if we need it for big decimals
400         if (exp > DOUBLE_MIN_EXPONENT) {
401             // Normalized....
402             numb |= DOUBLE_EXPONENT_NORMALIZE_BIT;
403         } else {
404             // Denormalized
405             exp++;
406         }
407 
408         // Multiple this number by the excess of the exponent
409         // over 52. This completes the conversion of double to long.
410         numb = numb << exp - DOUBLE_EXPONENT_EXCESS;
411 
412         // Get a decimal mantissa.
413         int ndig = format(numb, tbuf1, 0, ByteFormatter.TEMP_BUFFER_SIZE);
414 
415         // Now format the double.
416 
417         return combineReal(val, buf, off, len, tbuf1, ndig, shift);
418     }
419 
420     /**
421      * Format a float into an array.
422      *
423      * @param  val   The float to be formatted.
424      * @param  array The array in which to place the result.
425      *
426      * @return       The number of characters used. @ * if the value was truncated
427      */
428     public int format(float val, byte[] array) {
429         return format(val, array, 0, array.length);
430     }
431 
432     /**
433      * Format a float into an existing byteacter array.
434      * <p>
435      * This is hard to do exactly right... The JDK code does stuff with rational arithmetic and so forth. We use a much
436      * simpler algorithm which may give an answer off in the lowest order bit. Since this is pure Java, it should still
437      * be consistent from machine to machine.
438      * <p>
439      * Recall that the binary representation of the float is of the form <code>d = 0.bbbbbbbb x 2<sup>n</sup></code>
440      * where there are up to 24 binary digits in the binary fraction (including the assumed leading 1 bit for normalized
441      * numbers). We find a value m such that <code>10<sup>m</sup> d</code> is between <code>2<sup>24</sup></code> and
442      * <code>2<sup>32</sup></code>. This product will be exactly convertible to an int with no loss of precision.
443      * Getting the decimal representation for that is trivial (see formatInteger). This is a decimal mantissa and we
444      * have an exponent ( <code>-m</code>). All we have to do is manipulate the decimal point to where we want to see
445      * it. Errors can arise due to roundoff in the scaling multiplication, but should be very small.
446      *
447      * @param  val Float to be formatted
448      * @param  buf Buffer in which result is to be stored
449      * @param  off Offset within buffer
450      * @param  len Maximum length of field
451      *
452      * @return     Offset of next character in buffer. @ * if the value was truncated
453      */
454     public int format(float val, byte[] buf, int off, int len) {
455 
456         float pos = Math.abs(val);
457 
458         // Special cases
459         if (pos == 0.) {
460             return format("0.0", buf, off, len);
461         }
462         if (Float.isNaN(val)) {
463             return format(NOT_A_NUMBER, buf, off, len);
464         }
465         if (Float.isInfinite(val)) {
466             if (val > 0) {
467                 return format("Infinity", buf, off, len);
468             }
469             return format("-Infinity", buf, off, len);
470         }
471 
472         int power = (int) Math.floor(Math.log(pos) * ByteFormatter.I_LOG_10);
473         int shift = FLOAT_SHIFT_BASE - power;
474         float scale;
475         float scale2 = 1;
476 
477         // Scale the number so that we get a number ~ n x 10^8.
478         if (shift < FLOAT_SHIFT_LIMIT) {
479             scale = (float) ByteFormatter.NUMBER_BASE_POWERS[shift + ByteFormatter.ZERO_POW];
480         } else {
481             // Can get overflow if the original number is
482             // very small, so we break out the shift
483             // into two multipliers.
484             scale2 = (float) ByteFormatter.NUMBER_BASE_POWERS[FLOAT_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
485             scale = (float) ByteFormatter.NUMBER_BASE_POWERS[shift - FLOAT_SHIFT_LIMIT + ByteFormatter.ZERO_POW];
486         }
487 
488         pos = pos * scale * scale2;
489 
490         // Parse the float bits.
491 
492         int bits = Float.floatToIntBits(pos);
493 
494         // The exponent should be a little more than 23
495         int exp = ((bits & FLOAT_EXPONENT_BIT_MASK) >> FLOAT_EXPONENT_EXCESS) + FLOAT_MIN_EXPONENT;
496 
497         int numb = bits & FLOAT_VALUE_BIT_MASK;
498 
499         if (exp > FLOAT_MIN_EXPONENT) {
500             // Normalized....
501             numb |= FLOAT_EXPONENT_NORMALIZE_BIT;
502         } else {
503             // Denormalized
504             exp++;
505         }
506 
507         // Multiple this number by the excess of the exponent
508         // over 24. This completes the conversion of float to int
509         // (<<= did not work on Alpha TruUnix)
510 
511         numb = numb << exp - FLOAT_EXPONENT_EXCESS;
512 
513         // Get a decimal mantissa.
514         int ndig = format(numb, tbuf1, 0, ByteFormatter.TEMP_BUFFER_SIZE);
515 
516         // Now format the float.
517 
518         return combineReal(val, buf, off, len, tbuf1, ndig, shift);
519     }
520 
521     /**
522      * Format an int into an array.
523      *
524      * @param  val   The int to be formatted.
525      * @param  array The array in which to place the result.
526      *
527      * @return       The number of characters used. @ * if the value was truncated
528      */
529     public int format(int val, byte[] array) {
530         return format(val, array, 0, array.length);
531     }
532 
533     /**
534      * Format an int into an existing array.
535      *
536      * @param  val Integer to be formatted
537      * @param  buf Buffer in which result is to be stored
538      * @param  off Offset within buffer
539      * @param  len Maximum length of integer
540      *
541      * @return     offset of next unused character in input buffer.
542      */
543     public int format(int val, byte[] buf, int off, int len) {
544 
545         // Special case
546         if (val == Integer.MIN_VALUE) {
547             if (len > ByteFormatter.NUMBER_BASE) {
548                 return format("-2147483648", buf, off, len);
549             }
550             truncationFiller(buf, off, len);
551             return off + len;
552         }
553 
554         int pos = Math.abs(val);
555 
556         // First count the number of characters in the result.
557         // Otherwise we need to use an intermediary buffer.
558 
559         int ndig = 1;
560         int dmax = ByteFormatter.NUMBER_BASE;
561 
562         while (ndig < ByteFormatter.NUMBER_BASE && pos >= dmax) {
563             ndig++;
564             dmax *= ByteFormatter.NUMBER_BASE;
565         }
566 
567         if (val < 0) {
568             ndig++;
569         }
570 
571         // Truncate if necessary.
572         if (ndig > len || ndig > buf.length - off) {
573             truncationFiller(buf, off, len);
574             return off + len;
575         }
576 
577         // Now insert the actual characters we want -- backwards
578         // We use a do{} while() to handle the caByteFormatterse of 0.
579 
580         off += ndig;
581 
582         int xoff = off - 1;
583         do {
584             buf[xoff] = ByteFormatter.DIGITS[pos % ByteFormatter.NUMBER_BASE];
585             xoff--;
586             pos /= ByteFormatter.NUMBER_BASE;
587         } while (pos > 0);
588 
589         if (val < 0) {
590             buf[xoff] = (byte) '-';
591         }
592 
593         return off;
594     }
595 
596     /**
597      * Format a long into an array.
598      *
599      * @param  val   The long to be formatted.
600      * @param  array The array in which to place the result.
601      *
602      * @return       The number of characters used. @ * if the value was truncated
603      */
604     public int format(long val, byte[] array) {
605         return format(val, array, 0, array.length);
606     }
607 
608     /**
609      * Format a long into an existing array.
610      *
611      * @param  val Long to be formatted
612      * @param  buf Buffer in which result is to be stored
613      * @param  off Offset within buffer
614      * @param  len Maximum length of integer
615      *
616      * @return     offset of next unused character in input buffer. @ * if the value was truncated
617      */
618     public int format(long val, byte[] buf, int off, int len) {
619         // Special case
620         if (val == Long.MIN_VALUE) {
621             if (len > MAX_LONG_LENGTH) {
622                 return format("-9223372036854775808", buf, off, len);
623             }
624             truncationFiller(buf, off, len);
625             return off + len;
626         }
627         long pos = Math.abs(val);
628         // First count the number of characters in the result.
629         // Otherwise we need to use an intermediary buffer.
630         int ndig = 1;
631         long dmax = ByteFormatter.NUMBER_BASE;
632         // Might be faster to try to do this partially in ints
633         while (ndig < MAX_LONG_LENGTH && pos >= dmax) {
634             ndig++;
635             dmax *= ByteFormatter.NUMBER_BASE;
636         }
637         if (val < 0) {
638             ndig++;
639         }
640         // Truncate if necessary.
641         if (ndig > len || ndig > buf.length - off) {
642             truncationFiller(buf, off, len);
643             return off + len;
644         }
645         // Now insert the actual characters we want -- backwards.
646         off += ndig;
647         int xoff = off - 1;
648         buf[xoff] = (byte) '0';
649         boolean last = pos == 0;
650         while (!last) {
651             // Work on ints rather than longs.
652             int giga = (int) (pos % LONG_TO_INT_MODULO);
653             pos /= LONG_TO_INT_MODULO;
654             last = pos == 0;
655             for (int i = 0; i < MAXIMUM_SINGLE_DIGIT_INTEGER; i++) {
656 
657                 buf[xoff] = ByteFormatter.DIGITS[giga % ByteFormatter.NUMBER_BASE];
658                 xoff--;
659                 giga /= ByteFormatter.NUMBER_BASE;
660                 if (last && giga == 0) {
661                     break;
662                 }
663             }
664         }
665 
666         if (val < 0) {
667             buf[xoff] = (byte) '-';
668         }
669 
670         return off;
671     }
672 
673     /**
674      * Insert a string at the beginning of an array. * @return Offset of next available character in buffer.
675      *
676      * @param  val   The string to be inserted. A null string will insert len spaces.
677      * @param  array The buffer in which to insert the string.
678      *
679      * @return       Offset of next available character in buffer.
680      */
681     public int format(String val, byte[] array) {
682         return format(val, array, 0, array.length);
683     }
684 
685     /**
686      * Insert a String into an existing character array. If the String is longer than len, then only the the initial len
687      * characters will be inserted.
688      *
689      * @param  val   The string to be inserted. A null string will insert len spaces.
690      * @param  array The buffer in which to insert the string.
691      * @param  off   The starting offset to insert the string.
692      * @param  len   The maximum number of characters to insert.
693      *
694      * @return       Offset of next available character in buffer.
695      */
696     public int format(String val, byte[] array, int off, int len) {
697 
698         if (val == null) {
699             for (int i = 0; i < len; i++) {
700                 array[off + i] = (byte) ' ';
701             }
702             return off + len;
703         }
704 
705         int slen = val.length();
706 
707         if (slen > len || slen > array.length - off) {
708             val = val.substring(0, len);
709             slen = len;
710         }
711 
712         System.arraycopy(AsciiFuncs.getBytes(val), 0, array, off, slen);
713         return off + slen;
714     }
715 
716     /**
717      * Write the mantissa of the number. This method addresses the subtleties involved in rounding numbers.
718      */
719     private int mantissa(byte[] mant, int lmant, int exp, boolean simple, byte[] buf, int off, int len) {
720 
721         // Save in case we need to extend the number.
722         int off0 = off;
723         int pos = 0;
724 
725         if (exp < 0) {
726             buf[off] = (byte) '0';
727             len--;
728             off++;
729             if (len > 0) {
730                 buf[off] = (byte) '.';
731                 off++;
732                 len--;
733             }
734             // Leading 0s in small numbers.
735             int cexp = exp;
736             while (cexp < -1 && len > 0) {
737                 buf[off] = (byte) '0';
738                 cexp++;
739                 off++;
740                 len--;
741             }
742 
743         } else {
744 
745             // Print out all digits to the left of the decimal.
746             while (exp >= 0 && pos < lmant) {
747                 buf[off] = mant[pos];
748                 off++;
749                 pos++;
750                 len--;
751                 exp--;
752             }
753             // Trust we have enough space for this.
754             for (int i = 0; i <= exp; i++) {
755                 buf[off] = (byte) '0';
756                 off++;
757                 len--;
758             }
759 
760             // Add in a decimal if we have space.
761             if (len > 0) {
762                 buf[off] = (byte) '.';
763                 len--;
764                 off++;
765             }
766         }
767 
768         // Now handle the digits to the right of the decimal.
769         while (len > 0 && pos < lmant) {
770             buf[off] = mant[pos];
771             off++;
772             exp--;
773             len--;
774             pos++;
775         }
776 
777         // Now handle rounding.
778 
779         if (pos < lmant && mant[pos] >= (byte) '5') {
780             int i;
781 
782             // Increment to the left until we find a non-9
783             for (i = off - 1; i >= off0; i--) {
784 
785                 if (buf[i] == (byte) '.' || buf[i] == (byte) '-') {
786                     continue;
787                 }
788                 if (buf[i] != (byte) '9') {
789                     buf[i]++;
790                     break;
791                 }
792                 buf[i] = (byte) '0';
793             }
794 
795             // Now we handle 99.99 case. This can cause problems
796             // in two cases. If we are not using scientific notation
797             // then we may want to convert 99.9 to 100., i.e.,
798             // we need to move the decimal point. If there is no
799             // decimal point, then we must not be truncating on overflow
800             // but we should be allowed to write it to the
801             // next character (i.e., we are not at the end of buf).
802             //
803             // If we are printing in scientific notation, then we want
804             // to convert 9.99 to 1.00, i.e. we do not move the decimal.
805             // However we need to signal that the exponent should be
806             // incremented by one.
807             //
808             // We cannot have aligned the number, since that requires
809             // the full precision number to fit within the requested
810             // length, and we would have printed out the entire
811             // mantissa (i.e., pos >= lmant)
812 
813             if (i < off0) {
814 
815                 buf[off0] = (byte) '1';
816                 boolean foundDecimal = false;
817                 for (i = off0 + 1; i < off; i++) {
818                     if (buf[i] == (byte) '.') {
819                         foundDecimal = true;
820                         if (simple) {
821                             buf[i] = (byte) '0';
822                             i++;
823                             if (i < off) {
824                                 buf[i] = (byte) '.';
825                             }
826                         }
827                         break;
828                     }
829                 }
830                 if (simple && !foundDecimal) {
831                     buf[off + 1] = (byte) '0'; // 99 went to 100
832                     off++;
833                 }
834 
835                 off = -off; // Signal to change exponent if necessary.
836             }
837 
838         }
839 
840         return off;
841     }
842 
843     /**
844      * Fill the buffer with truncation characters. After filling the buffer, a TruncationException will be thrown if the
845      * appropriate flag is set.
846      */
847     private void truncationFiller(byte[] buffer, int offset, int length) {
848         for (int i = offset; i < offset + length; i++) {
849             buffer[i] = ByteFormatter.TRUNCATION_FILL;
850         }
851     }
852 
853 }