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