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 }