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