1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
33 #include <libpspp/assertion.h>
34 #include <libpspp/float-format.h>
35 #include <libpspp/integer-format.h>
36 #include <libpspp/message.h>
37 #include <libpspp/misc.h>
38 #include <libpspp/misc.h>
39 #include <libpspp/str.h>
44 #define _(msgid) gettext (msgid)
46 /* A representation of a number that can be quickly rounded to
47 any desired number of decimal places (up to a specified
51 char string[64]; /* Magnitude of number with excess precision. */
52 int integer_digits; /* Number of digits before decimal point. */
53 int leading_nines; /* Number of `9's or `.'s at start of string. */
54 int leading_zeros; /* Number of `0's or `.'s at start of string. */
55 bool negative; /* Is the number negative? */
58 static void rounder_init (struct rounder *, double number, int max_decimals);
59 static int rounder_width (const struct rounder *, int decimals,
60 int *integer_digits, bool *negative);
61 static void rounder_format (const struct rounder *, int decimals,
64 /* Format of integers in output (SET WIB). */
65 static enum integer_format output_integer_format = INTEGER_NATIVE;
67 /* Format of reals in output (SET WRB). */
68 static enum float_format output_float_format = FLOAT_NATIVE_DOUBLE;
70 typedef void data_out_converter_func (const union value *,
71 const struct fmt_spec *,
73 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
74 static data_out_converter_func output_##METHOD;
77 static bool output_decimal (const struct rounder *, const struct fmt_spec *,
78 bool require_affixes, char *);
79 static bool output_scientific (double, const struct fmt_spec *,
80 bool require_affixes, char *);
82 static double power10 (int) PURE_FUNCTION;
83 static double power256 (int) PURE_FUNCTION;
85 static void output_infinite (double, const struct fmt_spec *, char *);
86 static void output_missing (const struct fmt_spec *, char *);
87 static void output_overflow (const struct fmt_spec *, char *);
88 static bool output_bcd_integer (double, int digits, char *);
89 static void output_binary_integer (uint64_t, int bytes, enum integer_format,
91 static void output_hex (const void *, size_t bytes, char *);
93 /* Converts the INPUT value into printable form in the exactly
94 FORMAT->W characters in OUTPUT according to format
95 specification FORMAT. The output is recoded from native form
96 into the given legacy character ENCODING. No null terminator
97 is appended to the buffer. */
99 data_out_legacy (const union value *input, enum legacy_encoding encoding,
100 const struct fmt_spec *format, char *output)
102 static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
104 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) output_##METHOD,
105 #include "format.def"
108 assert (fmt_check_output (format));
110 converters[format->type] (input, format, output);
111 if (encoding != LEGACY_NATIVE
112 && fmt_get_category (format->type) != FMT_CAT_BINARY)
113 legacy_recode (LEGACY_NATIVE, output, encoding, output, format->w);
116 /* Same as data_out_legacy with ENCODING set to LEGACY_NATIVE. */
118 data_out (const union value *value, const struct fmt_spec *format,
121 return data_out_legacy (value, LEGACY_NATIVE, format, output);
124 /* Returns the current output integer format. */
126 data_out_get_integer_format (void)
128 return output_integer_format;
131 /* Sets the output integer format to INTEGER_FORMAT. */
133 data_out_set_integer_format (enum integer_format integer_format)
135 output_integer_format = integer_format;
138 /* Returns the current output float format. */
140 data_out_get_float_format (void)
142 return output_float_format;
145 /* Sets the output float format to FLOAT_FORMAT. */
147 data_out_set_float_format (enum float_format float_format)
149 output_float_format = float_format;
152 /* Main conversion functions. */
154 /* Outputs F, COMMA, DOT, DOLLAR, PCT, E, CCA, CCB, CCC, CCD, and
157 output_number (const union value *input, const struct fmt_spec *format,
160 double number = input->f;
162 if (number == SYSMIS)
163 output_missing (format, output);
164 else if (!isfinite (number))
165 output_infinite (number, format, output);
168 if (format->type != FMT_E && fabs (number) < 1.5 * power10 (format->w))
171 rounder_init (&r, number, format->d);
173 if (output_decimal (&r, format, true, output)
174 || output_scientific (number, format, true, output)
175 || output_decimal (&r, format, false, output))
179 if (!output_scientific (number, format, false, output))
180 output_overflow (format, output);
184 /* Outputs N format. */
186 output_N (const union value *input, const struct fmt_spec *format,
189 double number = input->f * power10 (format->d);
190 if (input->f == SYSMIS || number < 0)
191 output_missing (format, output);
195 number = fabs (round (number));
196 if (number < power10 (format->w)
197 && sprintf (buf, "%0*.0f", format->w, number) == format->w)
198 memcpy (output, buf, format->w);
200 output_overflow (format, output);
204 /* Outputs Z format. */
206 output_Z (const union value *input, const struct fmt_spec *format,
209 double number = input->f * power10 (format->d);
211 if (input->f == SYSMIS)
212 output_missing (format, output);
213 else if (fabs (number) >= power10 (format->w)
214 || sprintf (buf, "%0*.0f", format->w,
215 fabs (round (number))) != format->w)
216 output_overflow (format, output);
219 if (number < 0 && strspn (buf, "0") < format->w)
221 char *p = &buf[format->w - 1];
222 *p = "}JKLMNOPQR"[*p - '0'];
224 memcpy (output, buf, format->w);
228 /* Outputs P format. */
230 output_P (const union value *input, const struct fmt_spec *format,
233 if (output_bcd_integer (fabs (input->f * power10 (format->d)),
234 format->w * 2 - 1, output)
236 output[format->w - 1] |= 0xd;
238 output[format->w - 1] |= 0xf;
241 /* Outputs PK format. */
243 output_PK (const union value *input, const struct fmt_spec *format,
246 output_bcd_integer (input->f * power10 (format->d), format->w * 2, output);
249 /* Outputs IB format. */
251 output_IB (const union value *input, const struct fmt_spec *format,
254 double number = round (input->f * power10 (format->d));
255 if (input->f == SYSMIS
256 || number >= power256 (format->w) / 2 - 1
257 || number < -power256 (format->w) / 2)
258 memset (output, 0, format->w);
261 uint64_t integer = fabs (number);
264 output_binary_integer (integer, format->w, output_integer_format,
269 /* Outputs PIB format. */
271 output_PIB (const union value *input, const struct fmt_spec *format,
274 double number = round (input->f * power10 (format->d));
275 if (input->f == SYSMIS
276 || number < 0 || number >= power256 (format->w))
277 memset (output, 0, format->w);
279 output_binary_integer (number, format->w, output_integer_format, output);
282 /* Outputs PIBHEX format. */
284 output_PIBHEX (const union value *input, const struct fmt_spec *format,
287 double number = round (input->f);
288 if (input->f == SYSMIS)
289 output_missing (format, output);
290 else if (input->f < 0 || number >= power256 (format->w / 2))
291 output_overflow (format, output);
295 output_binary_integer (number, format->w / 2, INTEGER_MSB_FIRST, tmp);
296 output_hex (tmp, format->w / 2, output);
300 /* Outputs RB format. */
302 output_RB (const union value *input, const struct fmt_spec *format,
306 memcpy (output, &d, format->w);
309 /* Outputs RBHEX format. */
311 output_RBHEX (const union value *input, const struct fmt_spec *format,
315 output_hex (&d, format->w / 2, output);
318 /* Outputs DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, WKYR,
319 DATETIME, TIME, and DTIME formats. */
321 output_date (const union value *input, const struct fmt_spec *format,
324 double number = input->f;
325 int year, month, day, yday;
327 const char *template = fmt_date_template (format->type);
328 size_t template_width = strlen (template);
329 int excess_width = format->w - template_width;
334 assert (format->w >= template_width);
335 if (number == SYSMIS)
338 if (fmt_get_category (format->type) == FMT_CAT_DATE)
342 calendar_offset_to_gregorian (number / 60. / 60. / 24.,
343 &year, &month, &day, &yday);
344 number = fmod (number, 60. * 60. * 24.);
347 year = month = day = yday = 0;
349 while (*template != '\0')
353 while (template[count] == ch)
361 p += sprintf (p, "%02d", day);
363 p += sprintf (p, "%03d", yday);
367 p += sprintf (p, "%02d", month);
370 static const char *months[12] =
372 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
373 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
375 p = stpcpy (p, months[month - 1]);
379 if (count >= 4 || excess_width >= 2)
382 p += sprintf (p, "%04d", year);
383 else if (format->type == FMT_DATETIME)
384 p = stpcpy (p, "****");
390 int offset = year - get_epoch ();
391 if (offset < 0 || offset > 99)
393 p += sprintf (p, "%02d", abs (year) % 100);
397 p += sprintf (p, "%d", (month - 1) / 3 + 1);
400 p += sprintf (p, "%2d", (yday - 1) / 7 + 1);
405 number = fabs (number);
406 p += sprintf (p, "%*.0f", count, floor (number / 60. / 60. / 24.));
407 number = fmod (number, 60. * 60. * 24.);
412 number = fabs (number);
413 p += sprintf (p, "%0*.0f", count, floor (number / 60. / 60.));
414 number = fmod (number, 60. * 60.);
417 p += sprintf (p, "%02d", (int) floor (number / 60.));
418 number = fmod (number, 60.);
419 excess_width = format->w - (p - tmp);
420 if (excess_width < 0)
422 if (excess_width == 3 || excess_width == 4
423 || (excess_width >= 5 && format->d == 0))
424 p += sprintf (p, ":%02d", (int) number);
425 else if (excess_width >= 5)
427 int d = MIN (format->d, excess_width - 4);
429 sprintf (p, ":%0*.*f", w, d, number);
430 if (fmt_decimal_char (FMT_F) != '.')
432 char *cp = strchr (p, '.');
434 *cp = fmt_decimal_char (FMT_F);
449 buf_copy_lpad (output, format->w, tmp, p - tmp);
453 output_overflow (format, output);
457 output_missing (format, output);
461 /* Outputs WKDAY format. */
463 output_WKDAY (const union value *input, const struct fmt_spec *format,
466 static const char *weekdays[7] =
468 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
469 "THURSDAY", "FRIDAY", "SATURDAY",
472 if (input->f >= 1 && input->f < 8)
473 buf_copy_str_rpad (output, format->w, weekdays[(int) input->f - 1]);
476 if (input->f != SYSMIS)
477 msg (ME, _("Weekday number %f is not between 1 and 7."), input->f);
478 output_missing (format, output);
482 /* Outputs MONTH format. */
484 output_MONTH (const union value *input, const struct fmt_spec *format,
487 static const char *months[12] =
489 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
490 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
493 if (input->f >= 1 && input->f < 13)
494 buf_copy_str_rpad (output, format->w, months[(int) input->f - 1]);
497 if (input->f != SYSMIS)
498 msg (ME, _("Month number %f is not between 1 and 12."), input->f);
499 output_missing (format, output);
503 /* Outputs A format. */
505 output_A (const union value *input, const struct fmt_spec *format,
508 memcpy (output, input->s, format->w);
511 /* Outputs AHEX format. */
513 output_AHEX (const union value *input, const struct fmt_spec *format,
516 output_hex (input->s, format->w, output);
519 /* Decimal and scientific formatting. */
521 /* If REQUEST plus the current *WIDTH fits within MAX_WIDTH,
522 increments *WIDTH by REQUEST and return true.
523 Otherwise returns false without changing *WIDTH. */
525 allocate_space (int request, int max_width, int *width)
527 assert (*width <= max_width);
528 if (request + *width <= max_width)
537 /* Tries to compose the number represented by R, in the style of
538 FORMAT, into OUTPUT. Returns true if successful, false on
539 failure, which occurs if FORMAT's width is too narrow. If
540 REQUIRE_AFFIXES is true, then the prefix and suffix specified
541 by FORMAT's style must be included; otherwise, they may be
542 omitted to make the number fit. */
544 output_decimal (const struct rounder *r, const struct fmt_spec *format,
545 bool require_affixes, char *output)
547 const struct fmt_number_style *style = fmt_get_style (format->type);
550 for (decimals = format->d; decimals >= 0; decimals--)
552 /* Formatted version of magnitude of NUMBER. */
555 /* Number of digits in MAGNITUDE's integer and fractional parts. */
558 /* Amount of space within the field width already claimed.
559 Initially this is the width of MAGNITUDE, then it is reduced
560 in stages as space is allocated to prefixes and suffixes and
561 grouping characters. */
564 /* Include various decorations? */
569 /* Position in output. */
572 /* Make sure there's room for the number's magnitude, plus
573 the negative suffix, plus (if negative) the negative
575 width = rounder_width (r, decimals, &integer_digits, &add_neg_prefix);
576 width += ss_length (style->neg_suffix);
578 width += ss_length (style->neg_prefix);
579 if (width > format->w)
582 /* If there's room for the prefix and suffix, allocate
583 space. If the affixes are required, but there's no
585 add_affixes = allocate_space (fmt_affix_width (style),
587 if (!add_affixes && require_affixes)
590 /* Check whether we should include grouping characters.
591 We need room for a complete set or we don't insert any at all.
592 We don't include grouping characters if decimal places were
593 requested but they were all dropped. */
594 add_grouping = (style->grouping != 0
595 && integer_digits > 3
596 && (format->d == 0 || decimals > 0)
597 && allocate_space ((integer_digits - 1) / 3,
600 /* Format the number's magnitude. */
601 rounder_format (r, decimals, magnitude);
603 /* Assemble number. */
605 if (format->w > width)
606 p = mempset (p, ' ', format->w - width);
608 p = mempcpy (p, ss_data (style->neg_prefix),
609 ss_length (style->neg_prefix));
611 p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix));
613 p = mempcpy (p, magnitude, integer_digits);
617 for (i = 0; i < integer_digits; i++)
619 if (i > 0 && (integer_digits - i) % 3 == 0)
620 *p++ = style->grouping;
626 *p++ = style->decimal;
627 p = mempcpy (p, &magnitude[integer_digits + 1], decimals);
630 p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix));
632 p = mempcpy (p, ss_data (style->neg_suffix),
633 ss_length (style->neg_suffix));
635 p = mempset (p, ' ', ss_length (style->neg_suffix));
636 assert (p == output + format->w);
643 /* Formats NUMBER into OUTPUT in scientific notation according to
644 the style of the format specified in FORMAT. */
646 output_scientific (double number, const struct fmt_spec *format,
647 bool require_affixes, char *output)
649 const struct fmt_number_style *style = fmt_get_style (format->type);
655 /* Allocate minimum required space. */
656 width = 6 + ss_length (style->neg_suffix);
658 width += ss_length (style->neg_prefix);
659 if (width > format->w)
662 /* Check for room for prefix and suffix. */
663 add_affixes = allocate_space (fmt_affix_width (style), format->w, &width);
664 if (require_affixes && !add_affixes)
667 /* Figure out number of characters we can use for the fraction,
668 if any. (If that turns out to be 1, then we'll output a
669 decimal point without any digits following; that's what the
670 # flag does in the call to sprintf, below.) */
671 fraction_width = MIN (MIN (format->d + 1, format->w - width), 16);
672 if (format->type != FMT_E && fraction_width == 1)
674 width += fraction_width;
676 /* Format (except suffix). */
678 if (width < format->w)
679 p = mempset (p, ' ', format->w - width);
681 p = mempcpy (p, ss_data (style->neg_prefix),
682 ss_length (style->neg_prefix));
684 p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix));
685 if (fraction_width > 0)
686 sprintf (p, "%#.*E", fraction_width - 1, fabs (number));
688 sprintf (p, "%.0E", fabs (number));
690 /* The C locale always uses a period `.' as a decimal point.
691 Translate to comma if necessary. */
692 if (style->decimal != '.')
694 char *cp = strchr (p, '.');
696 *cp = style->decimal;
699 /* Make exponent have exactly three digits, plus sign. */
701 char *cp = strchr (p, 'E') + 1;
702 long int exponent = strtol (cp, NULL, 10);
703 if (abs (exponent) > 999)
705 sprintf (cp, "%+04ld", exponent);
709 p = strchr (p, '\0');
711 p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix));
713 p = mempcpy (p, ss_data (style->neg_suffix),
714 ss_length (style->neg_suffix));
716 p = mempset (p, ' ', ss_length (style->neg_suffix));
718 assert (p == buf + format->w);
719 memcpy (output, buf, format->w);
724 /* Returns true if the magnitude represented by R should be
725 rounded up when chopped off at DECIMALS decimal places, false
726 if it should be rounded down. */
728 should_round_up (const struct rounder *r, int decimals)
730 int digit = r->string[r->integer_digits + decimals + 1];
731 assert (digit >= '0' && digit <= '9');
735 /* Initializes R for formatting the magnitude of NUMBER to no
736 more than MAX_DECIMAL decimal places. */
738 rounder_init (struct rounder *r, double number, int max_decimals)
740 assert (fabs (number) < 1e41);
741 assert (max_decimals >= 0 && max_decimals <= 16);
742 if (max_decimals == 0)
744 /* Fast path. No rounding needed.
746 We append ".00" to the integer representation because
747 round_up assumes that fractional digits are present. */
748 sprintf (r->string, "%.0f.00", fabs (round (number)));
754 This is more difficult than it really should be because
755 we have to make sure that numbers that are exactly
756 halfway between two representations are always rounded
757 away from zero. This is not what sprintf normally does
758 (usually it rounds to even), so we have to fake it as
759 best we can, by formatting with extra precision and then
760 doing the rounding ourselves.
762 We take up to two rounds to format numbers. In the
763 first round, we obtain 2 digits of precision beyond
764 those requested by the user. If those digits are
765 exactly "50", then in a second round we format with as
766 many digits as are significant in a "double".
768 It might be better to directly implement our own
769 floating-point formatting routine instead of relying on
770 the system's sprintf implementation. But the classic
771 Steele and White paper on printing floating-point
772 numbers does not hint how to do what we want, and it's
773 not obvious how to change their algorithms to do so. It
774 would also be a lot of work. */
775 sprintf (r->string, "%.*f", max_decimals + 2, fabs (number));
776 if (!strcmp (r->string + strlen (r->string) - 2, "50"))
778 int binary_exponent, decimal_exponent, format_decimals;
779 frexp (number, &binary_exponent);
780 decimal_exponent = binary_exponent * 3 / 10;
781 format_decimals = (DBL_DIG + 1) - decimal_exponent;
782 if (format_decimals > max_decimals + 2)
783 sprintf (r->string, "%.*f", format_decimals, fabs (number));
787 if (r->string[0] == '0')
788 memmove (r->string, &r->string[1], strlen (r->string));
790 r->leading_zeros = strspn (r->string, "0.");
791 r->leading_nines = strspn (r->string, "9.");
792 r->integer_digits = strchr (r->string, '.') - r->string;
793 r->negative = number < 0;
796 /* Returns the number of characters required to format the
797 magnitude represented by R to DECIMALS decimal places.
798 The return value includes integer digits and a decimal point
799 and fractional digits, if any, but it does not include any
800 negative prefix or suffix or other affixes.
802 *INTEGER_DIGITS is set to the number of digits before the
803 decimal point in the output, between 0 and 40.
805 If R represents a negative number and its rounded
806 representation would include at least one nonzero digit,
807 *NEGATIVE is set to true; otherwise, it is set to false. */
809 rounder_width (const struct rounder *r, int decimals,
810 int *integer_digits, bool *negative)
812 /* Calculate base measures. */
813 int width = r->integer_digits;
815 width += decimals + 1;
816 *integer_digits = r->integer_digits;
817 *negative = r->negative;
819 /* Rounding can cause adjustments. */
820 if (should_round_up (r, decimals))
822 /* Rounding up leading 9s adds a new digit (a 1). */
823 if (r->leading_nines >= width)
832 if (r->leading_zeros >= width)
834 /* All digits that remain after rounding are zeros.
835 Therefore we drop the negative sign. */
837 if (r->integer_digits == 0 && decimals == 0)
839 /* No digits at all are left. We need to display
840 at least a single digit (a zero). */
850 /* Formats the magnitude represented by R into OUTPUT, rounding
851 to DECIMALS decimal places. Exactly as many characters as
852 indicated by rounder_width are written. No terminating null
855 rounder_format (const struct rounder *r, int decimals, char *output)
857 int base_width = r->integer_digits + (decimals > 0 ? decimals + 1 : 0);
858 if (should_round_up (r, decimals))
860 if (r->leading_nines < base_width)
862 /* Rounding up. This is the common case where rounding
863 up doesn't add an extra digit. */
865 memcpy (output, r->string, base_width);
866 for (p = output + base_width - 1; ; p--)
868 assert (p >= output);
871 else if (*p >= '0' && *p <= '8')
882 /* Rounding up leading 9s causes the result to be a 1
883 followed by a number of 0s, plus a decimal point. */
886 p = mempset (p, '0', r->integer_digits);
890 p = mempset (p, '0', decimals);
892 assert (p == output + base_width + 1);
898 if (r->integer_digits != 0 || decimals != 0)
900 /* Common case: just copy the digits. */
901 memcpy (output, r->string, base_width);
905 /* No digits remain. The output is just a zero. */
911 /* Helper functions. */
914 static double PURE_FUNCTION
917 static const double p[] =
919 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
920 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
921 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
922 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
925 return x >= 0 && x < sizeof p / sizeof *p ? p[x] : pow (10.0, x);
928 /* Returns 256**X. */
929 static double PURE_FUNCTION
932 static const double p[] =
942 18446744073709551616.0
944 return x >= 0 && x < sizeof p / sizeof *p ? p[x] : pow (256.0, x);
947 /* Formats non-finite NUMBER into OUTPUT according to the width
950 output_infinite (double number, const struct fmt_spec *format, char *output)
952 assert (!isfinite (number));
960 else if (isinf (number))
961 s = number > 0 ? "+Infinity" : "-Infinity";
965 buf_copy_str_lpad (output, format->w, s);
968 output_overflow (format, output);
971 /* Formats OUTPUT as a missing value for the given FORMAT. */
973 output_missing (const struct fmt_spec *format, char *output)
975 memset (output, ' ', format->w);
977 if (format->type != FMT_N)
979 int dot_ofs = (format->type == FMT_PCT ? 2
980 : format->type == FMT_E ? 5
982 output[MAX (0, format->w - format->d - dot_ofs)] = '.';
985 output[format->w - 1] = '.';
988 /* Formats OUTPUT for overflow given FORMAT. */
990 output_overflow (const struct fmt_spec *format, char *output)
992 memset (output, '*', format->w);
995 /* Converts the integer part of NUMBER to a packed BCD number
996 with the given number of DIGITS in OUTPUT. If DIGITS is odd,
997 the least significant nibble of the final byte in OUTPUT is
998 set to 0. Returns true if successful, false if NUMBER is not
999 representable. On failure, OUTPUT is cleared to all zero
1002 output_bcd_integer (double number, int digits, char *output)
1006 assert (digits < sizeof decimal);
1007 if (number != SYSMIS
1009 && number < power10 (digits)
1010 && sprintf (decimal, "%0*.0f", digits, round (number)) == digits)
1012 const char *src = decimal;
1015 for (i = 0; i < digits / 2; i++)
1017 int d0 = *src++ - '0';
1018 int d1 = *src++ - '0';
1019 *output++ = (d0 << 4) + d1;
1022 *output = (*src - '0') << 4;
1028 memset (output, 0, DIV_RND_UP (digits, 2));
1033 /* Writes VALUE to OUTPUT as a BYTES-byte binary integer of the
1034 given INTEGER_FORMAT. */
1036 output_binary_integer (uint64_t value, int bytes,
1037 enum integer_format integer_format, char *output)
1039 integer_put (value, integer_format, output, bytes);
1042 /* Converts the BYTES bytes in DATA to twice as many hexadecimal
1043 digits in OUTPUT. */
1045 output_hex (const void *data_, size_t bytes, char *output)
1047 const uint8_t *data = data_;
1050 for (i = 0; i < bytes; i++)
1052 static const char hex_digits[] = "0123456789ABCDEF";
1053 *output++ = hex_digits[data[i] >> 4];
1054 *output++ = hex_digits[data[i] & 15];