1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <libpspp/message.h>
28 #include <libpspp/assertion.h>
29 #include <libpspp/message.h>
31 #include <libpspp/magic.h>
32 #include <libpspp/misc.h>
33 #include <libpspp/misc.h>
35 #include <libpspp/str.h>
39 #define _(msgid) gettext (msgid)
41 /* Public functions. */
43 typedef int numeric_converter (char *, const struct fmt_spec *, double);
44 static numeric_converter convert_F, convert_N, convert_E, convert_F_plus;
45 static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
46 static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
47 static numeric_converter convert_RBHEX, convert_CCx, convert_date;
48 static numeric_converter convert_time, convert_WKDAY, convert_MONTH;
50 static numeric_converter try_F, convert_infinite;
52 typedef int string_converter (char *, const struct fmt_spec *, const char *);
53 static string_converter convert_A, convert_AHEX;
55 /* Converts binary value V into printable form in the exactly
56 FP->W character in buffer S according to format specification
57 FP. No null terminator is appended to the buffer. */
59 data_out (char *s, const struct fmt_spec *fp, const union value *v)
63 assert (fmt_check_output (fp));
64 if (fmt_is_numeric (fp->type))
66 enum fmt_category category = fmt_get_category (fp->type);
69 /* Handle SYSMIS turning into blanks. */
70 if (!(category & (FMT_CAT_CUSTOM | FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL))
73 memset (s, ' ', fp->w);
74 s[fp->w - fp->d - 1] = '.';
78 /* Handle decimal shift. */
79 if ((category & (FMT_CAT_LEGACY | FMT_CAT_BINARY))
82 number *= pow (10.0, fp->d);
87 ok = convert_F (s, fp, number);
91 ok = convert_N (s, fp, number);
95 ok = convert_E (s, fp, number);
98 case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
99 ok = convert_F_plus (s, fp, number);
103 ok = convert_Z (s, fp, number);
113 ok = convert_IB (s, fp, number);
117 ok = convert_P (s, fp, number);
121 ok = convert_PIB (s, fp, number);
125 ok = convert_PIBHEX (s, fp, number);
129 ok = convert_PK (s, fp, number);
133 ok = convert_RB (s, fp, number);
137 ok = convert_RBHEX (s, fp, number);
140 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
141 ok = convert_CCx (s, fp, number);
144 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
145 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
147 ok = convert_date (s, fp, number);
150 case FMT_TIME: case FMT_DTIME:
151 ok = convert_time (s, fp, number);
155 ok = convert_WKDAY (s, fp, number);
159 ok = convert_MONTH (s, fp, number);
168 /* String formatting. */
169 const char *string = v->s;
174 ok = convert_A (s, fp, string);
178 ok = convert_AHEX (s, fp, string);
186 /* Error handling. */
188 strncpy (s, "ERROR", fp->w);
193 /* Main conversion functions. */
195 static void insert_commas (char *dst, const char *src,
196 const struct fmt_spec *fp);
197 static int year4 (int year);
198 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
201 #error Write your own floating-point output routines.
204 /* Converts a number between 0 and 15 inclusive to a `hexit'
206 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
208 /* Table of powers of 10. */
209 static const double power10[] =
212 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
213 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
214 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
215 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
218 /* Handles F format. */
220 convert_F (char *dst, const struct fmt_spec *fp, double number)
222 if (!try_F (dst, fp, number))
223 convert_E (dst, fp, number);
227 /* Handles N format. */
229 convert_N (char *dst, const struct fmt_spec *fp, double number)
231 double d = floor (number);
233 if (d < 0 || d == SYSMIS)
235 msg (ME, _("The N output format cannot be used to output a "
236 "negative number or the system-missing value."));
240 if (d < power10[fp->w])
243 sprintf (buf, "%0*.0f", fp->w, number);
244 memcpy (dst, buf, fp->w);
247 memset (dst, '*', fp->w);
252 /* Handles E format. Also operates as fallback for some other
255 convert_E (char *dst, const struct fmt_spec *fp, double number)
257 /* Temporary buffer. */
260 /* Ranged number of decimal places. */
263 if (!finite (number))
264 return convert_infinite (dst, fp, number);
266 /* Check that the format is wide enough.
267 Although PSPP generally checks this, convert_E() can be called as
268 a fallback from other formats which do not check. */
271 memset (dst, '*', fp->w);
275 /* Put decimal places in usable range. */
276 d = min (fp->d, fp->w - 6);
281 sprintf (buf, "%*.*E", fp->w, d, number);
283 /* What we do here is force the exponent part to have four
284 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
285 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
286 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
287 Note that ANSI C guarantees at least two digits in the
289 if (fabs (number) > 1e99)
291 /* Pointer to the `E' in buf. */
294 cp = strchr (buf, 'E');
297 /* Exponent better not be bigger than an int. */
298 int exp = atoi (cp + 1);
300 if (abs (exp) > 99 && abs (exp) < 1000)
302 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
308 else if (abs (exp) >= 1000)
309 memset (buf, '*', fp->w);
313 /* The C locale always uses a period `.' as a decimal point.
314 Translate to comma if necessary. */
315 if (fmt_decimal_char (fp->type) != '.')
317 char *cp = strchr (buf, '.');
319 *cp = fmt_decimal_char (fp->type);
322 memcpy (dst, buf, fp->w);
326 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
328 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
332 if (try_F (buf, fp, number))
333 insert_commas (dst, buf, fp);
335 convert_E (dst, fp, number);
341 convert_Z (char *dst, const struct fmt_spec *fp, double number)
343 static bool warned = false;
348 _("Quality of zoned decimal (Z) output format code is "
349 "suspect. Check your results. Report bugs to %s."),
354 if (number == SYSMIS)
356 msg (ME, _("The system-missing value cannot be output as a zoned "
366 d = fabs (floor (number));
367 if (d >= power10[fp->w])
369 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
370 number, fp->w, fp->d);
374 sprintf (buf, "%*.0f", fp->w, number);
375 for (i = 0; i < fp->w; i++)
376 dst[i] = (buf[i] - '0') | 0xf0;
378 dst[fp->w - 1] &= 0xdf;
385 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
387 memcpy(dst, string, fp->w);
392 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
396 for (i = 0; i < fp->w / 2; i++)
398 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
399 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
406 convert_IB (char *dst, const struct fmt_spec *fp, double number)
408 /* Strategy: Basically the same as convert_PIBHEX() but with
409 base 256. Then negate the two's-complement result if number
412 /* Used for constructing the two's-complement result. */
415 /* Fraction (mantissa). */
421 /* Difference between exponent and (-8*fp->w-1). */
427 /* Make the exponent (-8*fp->w-1). */
428 frac = frexp (fabs (number), &exp);
429 diff = exp - (-8 * fp->w - 1);
431 frac *= ldexp (1.0, diff);
433 /* Extract each base-256 digit. */
434 for (i = 0; i < fp->w; i++)
438 temp[i] = floor (frac);
441 /* Perform two's-complement negation if number is negative. */
444 /* Perform NOT operation. */
445 for (i = 0; i < fp->w; i++)
447 /* Add 1 to the whole number. */
448 for (i = fp->w - 1; i >= 0; i--)
455 memcpy (dst, temp, fp->w);
456 #ifndef WORDS_BIGENDIAN
457 buf_reverse (dst, fp->w);
464 convert_P (char *dst, const struct fmt_spec *fp, double number)
466 /* Buffer for fp->w*2-1 characters + a decimal point if library is
467 not quite compliant + a null. */
473 /* Main extraction. */
474 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
476 for (i = 0; i < fp->w; i++)
477 ((unsigned char *) dst)[i]
478 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
481 dst[fp->w - 1] &= 0xf0;
483 dst[fp->w - 1] |= 0xf;
485 dst[fp->w - 1] |= 0xd;
491 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
493 /* Strategy: Basically the same as convert_IB(). */
495 /* Fraction (mantissa). */
501 /* Difference between exponent and (-8*fp->w). */
507 /* Make the exponent (-8*fp->w). */
508 frac = frexp (fabs (number), &exp);
509 diff = exp - (-8 * fp->w);
511 frac *= ldexp (1.0, diff);
513 /* Extract each base-256 digit. */
514 for (i = 0; i < fp->w; i++)
518 ((unsigned char *) dst)[i] = floor (frac);
520 #ifndef WORDS_BIGENDIAN
521 buf_reverse (dst, fp->w);
528 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
530 /* Strategy: Use frexp() to create a normalized result (but mostly
531 to find the base-2 exponent), then change the base-2 exponent to
532 (-4*fp->w) using multiplication and division by powers of two.
533 Extract each hexit by multiplying by 16. */
535 /* Fraction (mantissa). */
541 /* Difference between exponent and (-4*fp->w). */
547 /* Make the exponent (-4*fp->w). */
548 frac = frexp (fabs (number), &exp);
549 diff = exp - (-4 * fp->w);
551 frac *= ldexp (1.0, diff);
553 /* Extract each hexit. */
554 for (i = 0; i < fp->w; i++)
558 *dst++ = MAKE_HEXIT ((int) floor (frac));
565 convert_PK (char *dst, const struct fmt_spec *fp, double number)
567 /* Buffer for fp->w*2 characters + a decimal point if library is not
568 quite compliant + a null. */
574 /* Main extraction. */
575 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
577 for (i = 0; i < fp->w; i++)
578 ((unsigned char *) dst)[i]
579 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
585 convert_RB (char *dst, const struct fmt_spec *fp, double number)
595 memcpy (dst, u.c, fp->w);
601 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
613 for (i = 0; i < fp->w / 2; i++)
615 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
616 *dst++ = MAKE_HEXIT (u.c[i] & 15);
623 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
625 if (try_CCx (dst, fp, number))
635 return convert_F_plus (dst, &f, number);
640 convert_date (char *dst, const struct fmt_spec *fp, double number)
642 static const char *months[12] =
644 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
645 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
649 int ofs = number / 86400.;
650 int month, day, year;
655 calendar_offset_to_gregorian (ofs, &year, &month, &day);
660 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
662 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
666 sprintf (buf, "%02d.%02d.%04d", day, month, year);
668 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
672 sprintf (buf, "%04d/%02d/%02d", year, month, day);
674 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
678 sprintf (buf, "%02d/%02d/%04d", month, day, year);
680 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
684 int yday = calendar_offset_to_yday (ofs);
687 sprintf (buf, "%02d%03d", year % 100, yday);
688 else if (year4 (year))
689 sprintf (buf, "%04d%03d", year, yday);
695 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
697 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
701 sprintf (buf, "%s% 04d", months[month - 1], year);
703 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
707 int yday = calendar_offset_to_yday (ofs);
710 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
712 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
719 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
720 day, months[month - 1], year,
721 (int) fmod (floor (number / 60. / 60.), 24.),
722 (int) fmod (floor (number / 60.), 60.));
727 if (fp->w >= 22 && fp->d > 0)
729 d = min (fp->d, fp->w - 21);
738 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
748 buf_copy_str_rpad (dst, fp->w, buf);
753 convert_time (char *dst, const struct fmt_spec *fp, double number)
761 if (fabs (number) > 1e20)
763 msg (ME, _("Time value %g too large in magnitude to convert to "
764 "alphanumeric time."), number);
772 *cp++ = '-', time = -time;
773 if (fp->type == FMT_DTIME)
775 double days = floor (time / 60. / 60. / 24.);
776 cp = spprintf (temp_buf, "%02.0f ", days);
777 time = time - days * 60. * 60. * 24.;
783 cp = spprintf (cp, "%02.0f:%02.0f",
784 fmod (floor (time / 60. / 60.), 24.),
785 fmod (floor (time / 60.), 60.));
791 if (width >= 10 && fp->d >= 0 && fp->d != 0)
792 d = min (fp->d, width - 9), w = 3 + d;
796 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
798 buf_copy_str_rpad (dst, fp->w, temp_buf);
804 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
806 static const char *weekdays[7] =
808 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
809 "THURSDAY", "FRIDAY", "SATURDAY",
812 if (wkday < 1 || wkday > 7)
814 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
818 buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
824 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
826 static const char *months[12] =
828 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
829 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
832 if (month < 1 || month > 12)
834 msg (ME, _("Month index %f does not lie between 1 and 12."),
839 buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
844 /* Helper functions. */
846 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
847 for format spec *FP. */
849 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
851 /* Number of leading spaces in the number. This is the amount of
852 room we have for inserting commas and dollar signs. */
855 /* Number of digits before the decimal point. This is used to
856 determine the Number of commas to insert. */
859 /* Number of commas to insert. */
862 /* Number of items ,%$ to insert. */
865 /* Number of n_items items not to use for commas. */
868 /* Digit iterator. */
871 /* Source pointer. */
874 /* Count spaces and digits. */
876 while (sp < src + fp->w && *sp == ' ')
883 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
885 n_commas = (n_digits - 1) / 3;
886 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
888 /* Check whether we have enough space to do insertions. */
889 if (!n_spaces || !n_items)
891 memcpy (dst, src, fp->w);
894 if (n_items > n_spaces)
899 memcpy (dst, src, fp->w);
904 /* Put spaces at the beginning if there's extra room. */
905 if (n_spaces > n_items)
907 memset (dst, ' ', n_spaces - n_items);
908 dst += n_spaces - n_items;
911 /* Insert $ and reserve space for %. */
913 if (fp->type == FMT_DOLLAR)
918 else if (fp->type == FMT_PCT)
921 /* Copy negative sign and digits, inserting commas. */
922 if (sp - src > n_spaces)
924 for (i = n_digits; i; i--)
926 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
929 *dst++ = fmt_grouping_char (fp->type);
934 /* Copy decimal places and insert % if necessary. */
935 memcpy (dst, sp, fp->w - (sp - src));
936 if (fp->type == FMT_PCT && n_items > 0)
937 dst[fp->w - (sp - src)] = '%';
940 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
945 if (year >= 1 && year <= 9999)
947 msg (ME, _("Year %d cannot be represented in four digits for "
948 "output formatting purposes."), year);
953 try_CCx (char *dst, const struct fmt_spec *fp, double number)
955 const struct fmt_number_style *style = fmt_get_style (fp->type);
963 /* Determine length available, decimal character for number
965 f.type = style->decimal == fmt_decimal_char (FMT_COMMA) ? FMT_COMMA : FMT_DOT;
966 f.w = fp->w - fmt_affix_width (style);
968 f.w -= fmt_neg_affix_width (style) - 1;
970 /* Convert -0 to +0. */
971 number = fabs (number);
977 /* There's room for all that currency crap. Let's do the F
979 if (!convert_F (buf, &f, number) || *buf == '*')
981 insert_commas (buf2, buf, &f);
983 /* Postprocess back into buf. */
986 cp = mempcpy (cp, ss_data (style->neg_prefix),
987 ss_length (style->neg_prefix));
988 cp = mempcpy (cp, ss_data (style->prefix), ss_length (style->prefix));
994 assert ((number >= 0) ^ (*bp == '-'));
998 memcpy (cp, bp, f.w - (bp - buf2));
999 cp += f.w - (bp - buf2);
1001 cp = mempcpy (cp, ss_data (style->suffix), ss_length (style->suffix));
1003 cp = mempcpy (cp, ss_data (style->neg_suffix),
1004 ss_length (style->neg_suffix));
1006 /* Copy into dst. */
1007 assert (cp - buf <= fp->w);
1008 if (cp - buf < fp->w)
1010 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1011 memset (dst, ' ', fp->w - (cp - buf));
1014 memcpy (dst, buf, fp->w);
1020 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1023 /* Tries to format NUMBER into DST as the F format specified in
1024 *FP. Return true if successful, false on failure. */
1026 try_F (char *dst, const struct fmt_spec *fp, double number)
1028 assert (fp->w <= 40);
1029 if (finite (number))
1031 if (fabs (number) < power10[fp->w])
1033 /* The value may fit in the field. */
1036 /* There are no decimal places, so there's no way
1037 that the value can be shortened. Either it fits
1040 sprintf (buf, "%*.0f", fp->w, number);
1041 if (strlen (buf) <= fp->w)
1043 buf_copy_str_lpad (dst, fp->w, buf);
1051 /* First try to format it with 2 extra decimal
1052 places. This gives us a good chance of not
1053 needing even more decimal places, but it also
1054 avoids wasting too much time formatting more
1055 decimal places on the first try. */
1056 int result = format_and_round (dst, number, fp, fp->d + 2);
1061 /* 2 extra decimal places weren't enough to
1062 correctly round. Try again with the maximum
1063 number of places. */
1064 return format_and_round (dst, number, fp, LDBL_DIG + 1);
1069 /* The value is too big to fit in the field. */
1074 return convert_infinite (dst, fp, number);
1077 /* Tries to compose NUMBER into DST in format FP by first
1078 formatting it with DECIMALS decimal places, then rounding off
1079 to as many decimal places will fit or the number specified in
1080 FP, whichever is fewer.
1082 Returns 1 if conversion succeeds, 0 if this try at conversion
1083 failed and so will any other tries (because the integer part
1084 of the number is too long), or -1 if this try failed but
1085 another with higher DECIMALS might succeed (because we'd be
1086 able to properly round). */
1088 format_and_round (char *dst, double number, const struct fmt_spec *fp,
1091 /* Number of characters before the decimal point,
1092 which includes digits and possibly a minus sign. */
1095 /* Number of digits in the output fraction,
1096 which may be smaller than fp->d if there's not enough room. */
1097 int fraction_digits;
1099 /* Points to last digit that will remain in the fraction after
1101 char *final_frac_dig;
1108 assert (decimals > fp->d);
1109 if (decimals > LDBL_DIG)
1110 decimals = LDBL_DIG + 1;
1112 sprintf (buf, "%.*f", decimals, number);
1114 /* Omit integer part if it's 0. */
1115 if (!memcmp (buf, "0.", 2))
1116 memmove (buf, buf + 1, strlen (buf));
1117 else if (!memcmp (buf, "-0.", 3))
1118 memmove (buf + 1, buf + 2, strlen (buf + 1));
1120 predot_chars = strcspn (buf, ".");
1121 if (predot_chars > fp->w)
1123 /* Can't possibly fit. */
1126 else if (predot_chars == fp->w)
1128 /* Exact fit for integer part and sign. */
1129 memcpy (dst, buf, fp->w);
1132 else if (predot_chars + 1 == fp->w)
1134 /* There's room for the decimal point, but not for any
1135 digits of the fraction.
1136 Right-justify the integer part and sign. */
1138 memcpy (dst + 1, buf, fp->w - 1);
1142 /* It looks like we have room for at least one digit of the
1143 fraction. Figure out how many. */
1144 fraction_digits = fp->w - predot_chars - 1;
1145 if (fraction_digits > fp->d)
1146 fraction_digits = fp->d;
1147 final_frac_dig = buf + predot_chars + fraction_digits;
1149 /* Decide rounding direction and truncate string. */
1150 if (final_frac_dig[1] == '5'
1151 && strspn (final_frac_dig + 2, "0") == strlen (final_frac_dig + 2))
1154 if (decimals <= LDBL_DIG)
1156 /* Don't have enough fractional digits to know which way to
1157 round. We can format with more decimal places, so go
1163 /* We used up all our fractional digits and still don't
1164 know. Round to even. */
1165 round_up = (final_frac_dig[0] - '0') % 2 != 0;
1169 round_up = final_frac_dig[1] >= '5';
1170 final_frac_dig[1] = '\0';
1175 char *cp = final_frac_dig;
1178 if (*cp >= '0' && *cp <= '8')
1183 else if (*cp == '9')
1186 assert (*cp == '.');
1188 if (cp == buf || *--cp == '-')
1192 /* Tried to go past the leftmost digit. Insert a 1. */
1193 memmove (cp + 1, cp, strlen (cp) + 1);
1196 length = strlen (buf);
1199 /* Inserting the `1' overflowed our space.
1200 Drop a decimal place. */
1201 buf[--length] = '\0';
1203 /* If that was the last decimal place, drop the
1204 decimal point too. */
1205 if (buf[length - 1] == '.')
1206 buf[length - 1] = '\0';
1214 /* Omit `-' if value output is zero. */
1215 if (buf[0] == '-' && buf[strspn (buf, "-.0")] == '\0')
1216 memmove (buf, buf + 1, strlen (buf));
1218 buf_copy_str_lpad (dst, fp->w, buf);
1222 /* Formats non-finite NUMBER into DST according to the width
1225 convert_infinite (char *dst, const struct fmt_spec *fp, double number)
1227 assert (!finite (number));
1235 else if (isinf (number))
1236 s = number > 0 ? "+Infinity" : "-Infinity";
1240 buf_copy_str_lpad (dst, fp->w, s);
1243 memset (dst, '*', fp->w);