1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 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., 59 Temple Place - Suite 330, Boston, MA
37 #include "debug-print.h"
39 /* In older versions, numbers got their trailing zeros stripped.
40 Newer versions leave them on when there's room. Comment this next
41 line out for retro styling. */
44 /* Public functions. */
46 typedef int numeric_converter (char *, const struct fmt_spec *, double);
47 static numeric_converter convert_F, convert_N, convert_E, convert_F_plus;
48 static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
49 static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
50 static numeric_converter convert_RBHEX, convert_CCx, convert_date;
51 static numeric_converter convert_time, convert_WKDAY, convert_MONTH, try_F;
53 typedef int string_converter (char *, const struct fmt_spec *, const char *);
54 static string_converter convert_A, convert_AHEX;
56 /* Converts binary value V into printable form in the exactly
57 FP->W character in buffer S according to format specification
58 FP. No null terminator is appended to the buffer. */
60 data_out (char *s, const struct fmt_spec *fp, const union value *v)
62 int cat = formats[fp->type].cat;
65 if (!(cat & FCAT_STRING))
67 /* Numeric formatting. */
70 /* Handle SYSMIS turning into blanks. */
71 if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
73 memset (s, ' ', fp->w);
74 s[fp->w - fp->d - 1] = '.';
78 /* Handle decimal shift. */
79 if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
80 number *= pow (10.0, fp->d);
85 ok = convert_F (s, fp, number);
89 ok = convert_N (s, fp, number);
93 ok = convert_E (s, fp, number);
96 case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
97 ok = convert_F_plus (s, fp, number);
101 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);
169 /* String formatting. */
170 const char *string = v->s;
175 ok = convert_A (s, fp, string);
179 ok = convert_AHEX (s, fp, string);
188 /* Error handling. */
190 strncpy (s, "ERROR", fp->w);
193 /* Converts V into S in F format with width W and D decimal places,
194 then deletes trailing zeros. S is not null-terminated. */
196 num_to_string (double v, char *s, int w, int d)
198 /* Dummy to pass to convert_F. */
202 /* Pointer to `.' in S. */
205 /* Pointer to `E' in S. */
208 /* Number of characters to delete. */
215 /* Cut out the jokers. */
223 memcpy (temp, "NaN", 3);
228 memcpy (temp, "+Infinity", 9);
235 memcpy (temp, _("Unknown"), 7);
241 memset (s, ' ', pad);
252 decp = memchr (s, set_decimal, w);
256 /* If there's an `E' we can only delete 0s before the E. */
257 expp = memchr (s, 'E', w);
260 while (expp[-n - 1] == '0')
262 if (expp[-n - 1] == set_decimal)
264 memmove (&s[n], s, expp - s - n);
269 /* Otherwise delete all trailing 0s. */
271 while (s[w - n] == '0')
273 if (s[w - n] != set_decimal)
275 /* Avoid stripping `.0' to `'. */
276 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
281 memmove (&s[n], s, w - n);
286 /* Main conversion functions. */
288 static void insert_commas (char *dst, const char *src,
289 const struct fmt_spec *fp);
290 static int year4 (int year);
291 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
294 #error Write your own floating-point output routines.
299 Some of the routines in this file are likely very specific to
300 base-2 representation of floating-point numbers, most notably the
301 routines that use frexp() or ldexp(). These attempt to extract
302 individual digits by setting the base-2 exponent and
303 multiplying/dividing by powers of 2. In base-2 numeration systems,
304 this just nudges the exponent up or down, but in base-10 floating
305 point, such multiplications/division can cause catastrophic loss of
308 The author has never personally used a machine that didn't use
309 binary floating point formats, so he is unwilling, and perhaps
310 unable, to code around this "problem". */
312 /* Converts a number between 0 and 15 inclusive to a `hexit'
314 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
316 /* Table of powers of 10. */
317 static const double power10[] =
320 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
321 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
322 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
323 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
326 /* Handles F format. */
328 convert_F (char *dst, const struct fmt_spec *fp, double number)
330 if (!try_F (dst, fp, number))
331 convert_E (dst, fp, number);
335 /* Handles N format. */
337 convert_N (char *dst, const struct fmt_spec *fp, double number)
339 double d = floor (number);
341 if (d < 0 || d == SYSMIS)
343 msg (ME, _("The N output format cannot be used to output a "
344 "negative number or the system-missing value."));
348 if (d < power10[fp->w])
351 sprintf (buf, "%0*.0f", fp->w, number);
352 memcpy (dst, buf, fp->w);
355 memset (dst, '*', fp->w);
360 /* Handles E format. Also operates as fallback for some other
363 convert_E (char *dst, const struct fmt_spec *fp, double number)
365 /* Temporary buffer. */
368 /* Ranged number of decimal places. */
371 /* Check that the format is width enough.
372 Although PSPP generally checks this, convert_E() can be called as
373 a fallback from other formats which do not check. */
376 memset (dst, '*', fp->w);
380 /* Put decimal places in usable range. */
381 d = min (fp->d, fp->w - 6);
386 sprintf (buf, "%*.*E", fp->w, d, number);
388 /* What we do here is force the exponent part to have four
389 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
390 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
391 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
392 Note that ANSI C guarantees at least two digits in the
394 if (fabs (number) > 1e99)
396 /* Pointer to the `E' in buf. */
399 cp = strchr (buf, 'E');
402 /* Exponent better not be bigger than an int. */
403 int exp = atoi (cp + 1);
405 if (abs (exp) > 99 && abs (exp) < 1000)
407 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
413 else if (abs (exp) >= 1000)
414 memset (buf, '*', fp->w);
418 /* The C locale always uses a period `.' as a decimal point.
419 Translate to comma if necessary. */
420 if ((get_decimal() == ',' && fp->type != FMT_DOT)
421 || (get_decimal() == '.' && fp->type == FMT_DOT))
423 char *cp = strchr (buf, '.');
428 memcpy (dst, buf, fp->w);
432 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
434 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
438 if (try_F (buf, fp, number))
439 insert_commas (dst, buf, fp);
441 convert_E (dst, fp, number);
447 convert_Z (char *dst, const struct fmt_spec *fp, double number)
449 static int warned = 0;
454 _("Quality of zoned decimal (Z) output format code is "
455 "suspect. Check your results. Report bugs to %s."),
460 if (number == SYSMIS)
462 msg (ME, _("The system-missing value cannot be output as a zoned "
472 d = fabs (floor (number));
473 if (d >= power10[fp->w])
475 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
476 number, fp->w, fp->d);
480 sprintf (buf, "%*.0f", fp->w, number);
481 for (i = 0; i < fp->w; i++)
482 dst[i] = (buf[i] - '0') | 0xf0;
484 dst[fp->w - 1] &= 0xdf;
491 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
493 memcpy (dst, string, fp->w);
498 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
502 for (i = 0; i < fp->w / 2; i++)
504 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
505 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
512 convert_IB (char *dst, const struct fmt_spec *fp, double number)
514 /* Strategy: Basically the same as convert_PIBHEX() but with
515 base 256. Then negate the two's-complement result if number
518 /* Used for constructing the two's-complement result. */
521 /* Fraction (mantissa). */
527 /* Difference between exponent and (-8*fp->w-1). */
533 /* Make the exponent (-8*fp->w-1). */
534 frac = frexp (fabs (number), &exp);
535 diff = exp - (-8 * fp->w - 1);
537 frac *= ldexp (1.0, diff);
539 /* Extract each base-256 digit. */
540 for (i = 0; i < fp->w; i++)
544 temp[i] = floor (frac);
547 /* Perform two's-complement negation if number is negative. */
550 /* Perform NOT operation. */
551 for (i = 0; i < fp->w; i++)
553 /* Add 1 to the whole number. */
554 for (i = fp->w - 1; i >= 0; i--)
561 memcpy (dst, temp, fp->w);
562 #ifndef WORDS_BIGENDIAN
563 mm_reverse (dst, fp->w);
570 convert_P (char *dst, const struct fmt_spec *fp, double number)
572 /* Buffer for fp->w*2-1 characters + a decimal point if library is
573 not quite compliant + a null. */
579 /* Main extraction. */
580 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
582 for (i = 0; i < fp->w; i++)
583 ((unsigned char *) dst)[i]
584 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
587 dst[fp->w - 1] &= 0xf0;
589 dst[fp->w - 1] |= 0xf;
591 dst[fp->w - 1] |= 0xd;
597 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
599 /* Strategy: Basically the same as convert_IB(). */
601 /* Fraction (mantissa). */
607 /* Difference between exponent and (-8*fp->w). */
613 /* Make the exponent (-8*fp->w). */
614 frac = frexp (fabs (number), &exp);
615 diff = exp - (-8 * fp->w);
617 frac *= ldexp (1.0, diff);
619 /* Extract each base-256 digit. */
620 for (i = 0; i < fp->w; i++)
624 ((unsigned char *) dst)[i] = floor (frac);
626 #ifndef WORDS_BIGENDIAN
627 mm_reverse (dst, fp->w);
634 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
636 /* Strategy: Use frexp() to create a normalized result (but mostly
637 to find the base-2 exponent), then change the base-2 exponent to
638 (-4*fp->w) using multiplication and division by powers of two.
639 Extract each hexit by multiplying by 16. */
641 /* Fraction (mantissa). */
647 /* Difference between exponent and (-4*fp->w). */
653 /* Make the exponent (-4*fp->w). */
654 frac = frexp (fabs (number), &exp);
655 diff = exp - (-4 * fp->w);
657 frac *= ldexp (1.0, diff);
659 /* Extract each hexit. */
660 for (i = 0; i < fp->w; i++)
664 *dst++ = MAKE_HEXIT ((int) floor (frac));
671 convert_PK (char *dst, const struct fmt_spec *fp, double number)
673 /* Buffer for fp->w*2 characters + a decimal point if library is not
674 quite compliant + a null. */
680 /* Main extraction. */
681 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
683 for (i = 0; i < fp->w; i++)
684 ((unsigned char *) dst)[i]
685 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
691 convert_RB (char *dst, const struct fmt_spec *fp, double number)
701 memcpy (dst, u.c, fp->w);
707 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
719 for (i = 0; i < fp->w / 2; i++)
721 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
722 *dst++ = MAKE_HEXIT (u.c[i] & 15);
729 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
731 if (try_CCx (dst, fp, number))
741 return convert_F_plus (dst, &f, number);
746 convert_date (char *dst, const struct fmt_spec *fp, double number)
748 static const char *months[12] =
750 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
751 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
755 int ofs = number / 86400.;
756 int month, day, year;
761 calendar_offset_to_gregorian (ofs, &year, &month, &day);
766 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
768 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
772 sprintf (buf, "%02d.%02d.%04d", day, month, year);
774 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
778 sprintf (buf, "%04d/%02d/%02d", year, month, day);
780 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
784 sprintf (buf, "%02d/%02d/%04d", month, day, year);
786 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
790 int yday = calendar_offset_to_yday (ofs);
793 sprintf (buf, "%02d%03d", year % 100, yday);
794 else if (year4 (year))
795 sprintf (buf, "%04d%03d", year, yday);
801 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
803 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
807 sprintf (buf, "%s% 04d", months[month - 1], year);
809 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
813 int yday = calendar_offset_to_yday (ofs);
816 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
818 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
825 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
826 day, months[month - 1], year,
827 (int) fmod (floor (number / 60. / 60.), 24.),
828 (int) fmod (floor (number / 60.), 60.));
833 if (fp->w >= 22 && fp->d > 0)
835 d = min (fp->d, fp->w - 21);
844 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
854 st_bare_pad_copy (dst, buf, fp->w);
859 convert_time (char *dst, const struct fmt_spec *fp, double number)
867 if (fabs (number) > 1e20)
869 msg (ME, _("Time value %g too large in magnitude to convert to "
870 "alphanumeric time."), number);
878 *cp++ = '-', time = -time;
879 if (fp->type == FMT_DTIME)
881 double days = floor (time / 60. / 60. / 24.);
882 cp = spprintf (temp_buf, "%02.0f ", days);
883 time = time - days * 60. * 60. * 24.;
889 cp = spprintf (cp, "%02.0f:%02.0f",
890 fmod (floor (time / 60. / 60.), 24.),
891 fmod (floor (time / 60.), 60.));
897 if (width >= 10 && fp->d >= 0 && fp->d != 0)
898 d = min (fp->d, width - 9), w = 3 + d;
902 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
904 st_bare_pad_copy (dst, temp_buf, fp->w);
910 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
912 static const char *weekdays[7] =
914 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
915 "THURSDAY", "FRIDAY", "SATURDAY",
918 if (wkday < 1 || wkday > 7)
920 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
924 st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
930 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
932 static const char *months[12] =
934 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
935 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
938 if (month < 1 || month > 12)
940 msg (ME, _("Month index %f does not lie between 1 and 12."),
945 st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
950 /* Helper functions. */
952 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
953 for format spec *FP. */
955 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
957 /* Number of leading spaces in the number. This is the amount of
958 room we have for inserting commas and dollar signs. */
961 /* Number of digits before the decimal point. This is used to
962 determine the Number of commas to insert. */
965 /* Number of commas to insert. */
968 /* Number of items ,%$ to insert. */
971 /* Number of n_items items not to use for commas. */
974 /* Digit iterator. */
977 /* Source pointer. */
980 /* Count spaces and digits. */
982 while (sp < src + fp->w && *sp == ' ')
989 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
991 n_commas = (n_digits - 1) / 3;
992 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
994 /* Check whether we have enough space to do insertions. */
995 if (!n_spaces || !n_items)
997 memcpy (dst, src, fp->w);
1000 if (n_items > n_spaces)
1002 n_items -= n_commas;
1005 memcpy (dst, src, fp->w);
1010 /* Put spaces at the beginning if there's extra room. */
1011 if (n_spaces > n_items)
1013 memset (dst, ' ', n_spaces - n_items);
1014 dst += n_spaces - n_items;
1017 /* Insert $ and reserve space for %. */
1019 if (fp->type == FMT_DOLLAR)
1024 else if (fp->type == FMT_PCT)
1027 /* Copy negative sign and digits, inserting commas. */
1028 if (sp - src > n_spaces)
1030 for (i = n_digits; i; i--)
1032 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
1035 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
1040 /* Copy decimal places and insert % if necessary. */
1041 memcpy (dst, sp, fp->w - (sp - src));
1042 if (fp->type == FMT_PCT && n_items > 0)
1043 dst[fp->w - (sp - src)] = '%';
1046 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
1051 if (year >= 1 && year <= 9999)
1053 msg (ME, _("Year %d cannot be represented in four digits for "
1054 "output formatting purposes."), year);
1059 try_CCx (char *dst, const struct fmt_spec *fp, double number)
1061 const struct set_cust_currency *cc = get_cc(fp->type - FMT_CCA);
1069 /* Determine length available, decimal character for number
1071 f.type = cc->decimal == get_decimal() ? FMT_COMMA : FMT_DOT;
1072 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
1074 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
1076 /* Convert -0 to +0. */
1077 number = fabs (number);
1083 /* There's room for all that currency crap. Let's do the F
1084 conversion first. */
1085 if (!convert_F (buf, &f, number) || *buf == '*')
1087 insert_commas (buf2, buf, &f);
1089 /* Postprocess back into buf. */
1092 cp = stpcpy (cp, cc->neg_prefix);
1093 cp = stpcpy (cp, cc->prefix);
1099 assert ((number >= 0) ^ (*bp == '-'));
1103 memcpy (cp, bp, f.w - (bp - buf2));
1104 cp += f.w - (bp - buf2);
1106 cp = stpcpy (cp, cc->suffix);
1108 cp = stpcpy (cp, cc->neg_suffix);
1110 /* Copy into dst. */
1111 assert (cp - buf <= fp->w);
1112 if (cp - buf < fp->w)
1114 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1115 memset (dst, ' ', fp->w - (cp - buf));
1118 memcpy (dst, buf, fp->w);
1123 /* This routine relies on the underlying implementation of sprintf:
1125 If the number has a magnitude 1e40 or greater, then we needn't
1126 bother with it, since it's guaranteed to need processing in
1127 scientific notation.
1129 Otherwise, do a binary search for the base-10 magnitude of the
1130 thing. log10() is not accurate enough, and the alternatives are
1131 frightful. Besides, we never need as many as 6 (pairs of)
1132 comparisons. The algorithm used for searching is Knuth's Algorithm
1133 6.2.1C (Uniform binary search).
1135 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1136 LONG TIME! The rest of the program is heavily dependent on
1137 specific properties of this routine's output. LOG ALL CHANGES! */
1139 try_F (char *dst, const struct fmt_spec *fp, double number)
1141 /* This is the DELTA array from Knuth.
1142 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1143 static const int delta[8] =
1145 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1146 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1149 /* The number of digits in floor(number), including sign. This
1150 is `i' from Knuth. */
1151 int n_int = (40 + 1) / 2;
1153 /* Used to step through delta[]. This is `j' from Knuth. */
1156 /* Magnitude of number. This is `K' from Knuth. */
1159 /* Number of characters for the fractional part, including the
1163 /* Pointer into buf used for formatting. */
1166 /* Used to count characters formatted by nsprintf(). */
1169 /* Temporary buffer. */
1172 /* First check for infinities and NaNs. 12/13/96. */
1173 if (!finite (number))
1175 n = nsprintf (buf, "%f", number);
1177 memset (buf, '*', fp->w);
1180 memmove (&buf[fp->w - n], buf, n);
1181 memset (buf, ' ', fp->w - n);
1183 memcpy (dst, buf, fp->w);
1187 /* Then check for radically out-of-range values. */
1188 mag = fabs (number);
1189 if (mag >= power10[fp->w])
1196 /* Avoid printing `-.000'. 7/6/96. */
1201 /* Now perform a `uniform binary search' based on the tables
1202 power10[] and delta[]. After this step, nint is the number of
1203 digits in floor(number), including any sign. */
1206 if (mag >= power10[n_int])
1209 n_int += delta[j++];
1211 else if (mag < power10[n_int - 1])
1214 n_int -= delta[j++];
1220 /* If we have any decimal places, then there is a decimal point,
1226 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1227 only when fabs(number) < 1.0. */
1228 if (n_int + n_dec == 0)
1231 /* Give space for a minus sign. Moved 1/10/96. */
1235 /* Normally we only go through the loop once; occasionally twice.
1236 Three times or more indicates a very serious bug somewhere. */
1239 /* Check out the total length of the string. */
1241 if (n_int + n_dec > fp->w)
1243 /* The string is too long. Let's see what can be done. */
1245 /* If we can, just reduce the number of decimal places. */
1246 n_dec = fp->w - n_int;
1250 else if (n_int + n_dec < fp->w)
1252 /* The string is too short. Left-pad with spaces. */
1253 int n_spaces = fp->w - n_int - n_dec;
1254 memset (cp, ' ', n_spaces);
1258 /* Finally, format the number. */
1260 n = nsprintf (cp, "%.*f", n_dec - 1, number);
1262 n = nsprintf (cp, "%.0f", number);
1264 /* If number is positive and its magnitude is less than
1270 /* The value rounds to `.###'. */
1271 memmove (cp, &cp[1], n - 1);
1276 /* The value rounds to `1.###'. */
1281 /* Else if number is negative and its magnitude is less
1283 else if (number < 0 && n_int == 1)
1287 /* The value rounds to `-.###'. */
1288 memmove (&cp[1], &cp[2], n - 2);
1293 /* The value rounds to `-1.###'. */
1299 /* Check for a correct number of digits & decimal places & stuff.
1300 This is just a desperation check. Hopefully it won't fail too
1301 often, because then we have to run through the whole loop again:
1302 sprintf() is not a fast operation with floating-points! */
1303 if (n == n_int + n_dec)
1305 /* Convert periods `.' to commas `,' for our foreign friends. */
1306 if ((get_decimal() == ',' && fp->type != FMT_DOT)
1307 || (get_decimal() == '.' && fp->type == FMT_DOT))
1309 cp = strchr (cp, '.');
1314 memcpy (dst, buf, fp->w);
1318 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */