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
30 #include "julcal/julcal.h"
38 #include "debug-print.h"
40 /* In older versions, numbers got their trailing zeros stripped.
41 Newer versions leave them on when there's room. Comment this next
42 line out for retro styling. */
45 /* Public functions. */
47 typedef int numeric_converter (char *, const struct fmt_spec *, double);
48 static numeric_converter convert_F, convert_N, convert_E, convert_F_plus;
49 static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
50 static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
51 static numeric_converter convert_RBHEX, convert_CCx, convert_date;
52 static numeric_converter convert_time, convert_WKDAY, convert_MONTH, try_F;
54 typedef int string_converter (char *, const struct fmt_spec *, const char *);
55 static string_converter convert_A, convert_AHEX;
57 /* Converts binary value V into printable form in the exactly
58 FP->W character in buffer S according to format specification
59 FP. No null terminator is appended to the buffer. */
61 data_out (char *s, const struct fmt_spec *fp, const union value *v)
63 int cat = formats[fp->type].cat;
66 if (!(cat & FCAT_STRING))
68 /* Numeric formatting. */
71 /* Handle SYSMIS turning into blanks. */
72 if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
74 memset (s, ' ', fp->w);
75 s[fp->w - fp->d - 1] = '.';
79 /* Handle decimal shift. */
80 if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
81 number *= pow (10.0, fp->d);
86 ok = convert_F (s, fp, number);
90 ok = convert_N (s, fp, number);
94 ok = convert_E (s, fp, number);
97 case FMT_COMMA: case FMT_DOT: case FMT_DOLLAR: case FMT_PCT:
98 ok = convert_F_plus (s, fp, number);
102 ok = convert_Z (s, fp, number);
112 ok = convert_IB (s, fp, number);
116 ok = convert_P (s, fp, number);
120 ok = convert_PIB (s, fp, number);
124 ok = convert_PIBHEX (s, fp, number);
128 ok = convert_PK (s, fp, number);
132 ok = convert_RB (s, fp, number);
136 ok = convert_RBHEX (s, fp, number);
139 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
140 ok = convert_CCx (s, fp, number);
143 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
144 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
146 ok = convert_date (s, fp, number);
149 case FMT_TIME: case FMT_DTIME:
150 ok = convert_time (s, fp, number);
154 ok = convert_WKDAY (s, fp, number);
158 ok = convert_MONTH (s, fp, number);
167 /* String formatting. */
168 const char *string = v->s;
173 ok = convert_A (s, fp, string);
177 ok = convert_AHEX (s, fp, string);
185 /* Error handling. */
187 strncpy (s, "ERROR", fp->w);
190 /* Converts V into S in F format with width W and D decimal places,
191 then deletes trailing zeros. S is not null-terminated. */
193 num_to_string (double v, char *s, int w, int d)
195 /* Dummy to pass to convert_F. */
199 /* Pointer to `.' in S. */
202 /* Pointer to `E' in S. */
205 /* Number of characters to delete. */
212 /* Cut out the jokers. */
220 memcpy (temp, "NaN", 3);
225 memcpy (temp, "+Infinity", 9);
232 memcpy (temp, _("Unknown"), 7);
238 memset (s, ' ', pad);
249 decp = memchr (s, set_decimal, w);
253 /* If there's an `E' we can only delete 0s before the E. */
254 expp = memchr (s, 'E', w);
257 while (expp[-n - 1] == '0')
259 if (expp[-n - 1] == set_decimal)
261 memmove (&s[n], s, expp - s - n);
266 /* Otherwise delete all trailing 0s. */
268 while (s[w - n] == '0')
270 if (s[w - n] != set_decimal)
272 /* Avoid stripping `.0' to `'. */
273 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
278 memmove (&s[n], s, w - n);
283 /* Main conversion functions. */
285 static void insert_commas (char *dst, const char *src,
286 const struct fmt_spec *fp);
287 static int year4 (int year);
288 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
291 #error Write your own floating-point output routines.
296 Some of the routines in this file are likely very specific to
297 base-2 representation of floating-point numbers, most notably the
298 routines that use frexp() or ldexp(). These attempt to extract
299 individual digits by setting the base-2 exponent and
300 multiplying/dividing by powers of 2. In base-2 numeration systems,
301 this just nudges the exponent up or down, but in base-10 floating
302 point, such multiplications/division can cause catastrophic loss of
305 The author has never personally used a machine that didn't use
306 binary floating point formats, so he is unwilling, and perhaps
307 unable, to code around this "problem". */
309 /* Converts a number between 0 and 15 inclusive to a `hexit'
311 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
313 /* Table of powers of 10. */
314 static const double power10[] =
317 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
318 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
319 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
320 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
323 /* Handles F format. */
325 convert_F (char *dst, const struct fmt_spec *fp, double number)
327 if (!try_F (dst, fp, number))
328 convert_E (dst, fp, number);
332 /* Handles N format. */
334 convert_N (char *dst, const struct fmt_spec *fp, double number)
336 double d = floor (number);
338 if (d < 0 || d == SYSMIS)
340 msg (ME, _("The N output format cannot be used to output a "
341 "negative number or the system-missing value."));
345 if (d < power10[fp->w])
348 sprintf (buf, "%0*.0f", fp->w, number);
349 memcpy (dst, buf, fp->w);
352 memset (dst, '*', fp->w);
357 /* Handles E format. Also operates as fallback for some other
360 convert_E (char *dst, const struct fmt_spec *fp, double number)
362 /* Temporary buffer. */
365 /* Ranged number of decimal places. */
368 /* Check that the format is width enough.
369 Although PSPP generally checks this, convert_E() can be called as
370 a fallback from other formats which do not check. */
373 memset (dst, '*', fp->w);
377 /* Put decimal places in usable range. */
378 d = min (fp->d, fp->w - 6);
383 sprintf (buf, "%*.*E", fp->w, d, number);
385 /* What we do here is force the exponent part to have four
386 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
387 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
388 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
389 Note that ANSI C guarantees at least two digits in the
391 if (fabs (number) > 1e99)
393 /* Pointer to the `E' in buf. */
396 cp = strchr (buf, 'E');
399 /* Exponent better not be bigger than an int. */
400 int exp = atoi (cp + 1);
402 if (abs (exp) > 99 && abs (exp) < 1000)
404 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
410 else if (abs (exp) >= 1000)
411 memset (buf, '*', fp->w);
415 /* The C locale always uses a period `.' as a decimal point.
416 Translate to comma if necessary. */
417 if ((set_decimal == ',' && fp->type != FMT_DOT)
418 || (set_decimal == '.' && fp->type == FMT_DOT))
420 char *cp = strchr (buf, '.');
425 memcpy (dst, buf, fp->w);
429 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
431 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
435 if (try_F (buf, fp, number))
436 insert_commas (dst, buf, fp);
438 convert_E (dst, fp, number);
444 convert_Z (char *dst, const struct fmt_spec *fp, double number)
446 static int warned = 0;
451 _("Quality of zoned decimal (Z) output format code is "
452 "suspect. Check your results. Report bugs to %s."),
457 if (number == SYSMIS)
459 msg (ME, _("The system-missing value cannot be output as a zoned "
469 d = fabs (floor (number));
470 if (d >= power10[fp->w])
472 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
473 number, fp->w, fp->d);
477 sprintf (buf, "%*.0f", fp->w, number);
478 for (i = 0; i < fp->w; i++)
479 dst[i] = (buf[i] - '0') | 0xf0;
481 dst[fp->w - 1] &= 0xdf;
488 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
490 memcpy (dst, string, fp->w);
495 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
499 for (i = 0; i < fp->w / 2; i++)
501 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
502 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
509 convert_IB (char *dst, const struct fmt_spec *fp, double number)
511 /* Strategy: Basically the same as convert_PIBHEX() but with
512 base 256. Then negate the two's-complement result if number
515 /* Used for constructing the two's-complement result. */
518 /* Fraction (mantissa). */
524 /* Difference between exponent and (-8*fp->w-1). */
530 /* Make the exponent (-8*fp->w-1). */
531 frac = frexp (fabs (number), &exp);
532 diff = exp - (-8 * fp->w - 1);
534 frac *= ldexp (1.0, diff);
536 /* Extract each base-256 digit. */
537 for (i = 0; i < fp->w; i++)
541 temp[i] = floor (frac);
544 /* Perform two's-complement negation if number is negative. */
547 /* Perform NOT operation. */
548 for (i = 0; i < fp->w; i++)
550 /* Add 1 to the whole number. */
551 for (i = fp->w - 1; i >= 0; i--)
558 memcpy (dst, temp, fp->w);
559 #ifndef WORDS_BIGENDIAN
560 mm_reverse (dst, fp->w);
567 convert_P (char *dst, const struct fmt_spec *fp, double number)
569 /* Buffer for fp->w*2-1 characters + a decimal point if library is
570 not quite compliant + a null. */
576 /* Main extraction. */
577 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
579 for (i = 0; i < fp->w; i++)
580 ((unsigned char *) dst)[i]
581 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
584 dst[fp->w - 1] &= 0xf0;
586 dst[fp->w - 1] |= 0xf;
588 dst[fp->w - 1] |= 0xd;
594 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
596 /* Strategy: Basically the same as convert_IB(). */
598 /* Fraction (mantissa). */
604 /* Difference between exponent and (-8*fp->w). */
610 /* Make the exponent (-8*fp->w). */
611 frac = frexp (fabs (number), &exp);
612 diff = exp - (-8 * fp->w);
614 frac *= ldexp (1.0, diff);
616 /* Extract each base-256 digit. */
617 for (i = 0; i < fp->w; i++)
621 ((unsigned char *) dst)[i] = floor (frac);
623 #ifndef WORDS_BIGENDIAN
624 mm_reverse (dst, fp->w);
631 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
633 /* Strategy: Use frexp() to create a normalized result (but mostly
634 to find the base-2 exponent), then change the base-2 exponent to
635 (-4*fp->w) using multiplication and division by powers of two.
636 Extract each hexit by multiplying by 16. */
638 /* Fraction (mantissa). */
644 /* Difference between exponent and (-4*fp->w). */
650 /* Make the exponent (-4*fp->w). */
651 frac = frexp (fabs (number), &exp);
652 diff = exp - (-4 * fp->w);
654 frac *= ldexp (1.0, diff);
656 /* Extract each hexit. */
657 for (i = 0; i < fp->w; i++)
661 *dst++ = MAKE_HEXIT ((int) floor (frac));
668 convert_PK (char *dst, const struct fmt_spec *fp, double number)
670 /* Buffer for fp->w*2 characters + a decimal point if library is not
671 quite compliant + a null. */
677 /* Main extraction. */
678 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
680 for (i = 0; i < fp->w; i++)
681 ((unsigned char *) dst)[i]
682 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
688 convert_RB (char *dst, const struct fmt_spec *fp, double number)
698 memcpy (dst, u.c, fp->w);
704 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
716 for (i = 0; i < fp->w / 2; i++)
718 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
719 *dst++ = MAKE_HEXIT (u.c[i] & 15);
726 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
728 if (try_CCx (dst, fp, number))
738 return convert_F_plus (dst, &f, number);
743 convert_date (char *dst, const struct fmt_spec *fp, double number)
745 static const char *months[12] =
747 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
748 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
752 int month, day, year;
754 julian_to_calendar (number / 86400., &year, &month, &day);
759 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
761 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
765 sprintf (buf, "%02d.%02d.%04d", day, month, year);
767 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
771 sprintf (buf, "%04d/%02d/%02d", year, month, day);
773 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
777 sprintf (buf, "%02d/%02d/%04d", month, day, year);
779 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
783 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
788 sprintf (buf, "%04d%03d", year, yday);
791 sprintf (buf, "%02d%03d", year % 100, yday);
796 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
798 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
802 sprintf (buf, "%s% 04d", months[month - 1], year);
804 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
808 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
811 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
813 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
820 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
821 day, months[month - 1], year,
822 (int) fmod (floor (number / 60. / 60.), 24.),
823 (int) fmod (floor (number / 60.), 60.));
828 if (fp->w >= 22 && fp->d > 0)
830 d = min (fp->d, fp->w - 21);
839 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
849 st_bare_pad_copy (dst, buf, fp->w);
854 convert_time (char *dst, const struct fmt_spec *fp, double number)
862 if (fabs (number) > 1e20)
864 msg (ME, _("Time value %g too large in magnitude to convert to "
865 "alphanumeric time."), number);
873 *cp++ = '-', time = -time;
874 if (fp->type == FMT_DTIME)
876 double days = floor (time / 60. / 60. / 24.);
877 cp = spprintf (temp_buf, "%02.0f ", days);
878 time = time - days * 60. * 60. * 24.;
884 cp = spprintf (cp, "%02.0f:%02.0f",
885 fmod (floor (time / 60. / 60.), 24.),
886 fmod (floor (time / 60.), 60.));
892 if (width >= 10 && fp->d >= 0 && fp->d != 0)
893 d = min (fp->d, width - 9), w = 3 + d;
897 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
899 st_bare_pad_copy (dst, temp_buf, fp->w);
905 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
907 static const char *weekdays[7] =
909 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
910 "THURSDAY", "FRIDAY", "SATURDAY",
913 if (wkday < 1 || wkday > 7)
915 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
919 st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
925 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
927 static const char *months[12] =
929 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
930 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
933 if (month < 1 || month > 12)
935 msg (ME, _("Month index %f does not lie between 1 and 12."),
940 st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
945 /* Helper functions. */
947 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
948 for format spec *FP. */
950 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
952 /* Number of leading spaces in the number. This is the amount of
953 room we have for inserting commas and dollar signs. */
956 /* Number of digits before the decimal point. This is used to
957 determine the Number of commas to insert. */
960 /* Number of commas to insert. */
963 /* Number of items ,%$ to insert. */
966 /* Number of n_items items not to use for commas. */
969 /* Digit iterator. */
972 /* Source pointer. */
975 /* Count spaces and digits. */
977 while (sp < src + fp->w && *sp == ' ')
984 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
986 n_commas = (n_digits - 1) / 3;
987 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
989 /* Check whether we have enough space to do insertions. */
990 if (!n_spaces || !n_items)
992 memcpy (dst, src, fp->w);
995 if (n_items > n_spaces)
1000 memcpy (dst, src, fp->w);
1005 /* Put spaces at the beginning if there's extra room. */
1006 if (n_spaces > n_items)
1008 memset (dst, ' ', n_spaces - n_items);
1009 dst += n_spaces - n_items;
1012 /* Insert $ and reserve space for %. */
1014 if (fp->type == FMT_DOLLAR)
1019 else if (fp->type == FMT_PCT)
1022 /* Copy negative sign and digits, inserting commas. */
1023 if (sp - src > n_spaces)
1025 for (i = n_digits; i; i--)
1027 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
1030 *dst++ = fp->type == FMT_COMMA ? set_grouping : set_decimal;
1035 /* Copy decimal places and insert % if necessary. */
1036 memcpy (dst, sp, fp->w - (sp - src));
1037 if (fp->type == FMT_PCT && n_items > 0)
1038 dst[fp->w - (sp - src)] = '%';
1041 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
1046 if (year >= 1 && year <= 9999)
1048 msg (ME, _("Year %d cannot be represented in four digits for "
1049 "output formatting purposes."), year);
1054 try_CCx (char *dst, const struct fmt_spec *fp, double number)
1056 struct set_cust_currency *cc = &set_cc[fp->type - FMT_CCA];
1064 /* Determine length available, decimal character for number
1066 f.type = cc->decimal == set_decimal ? FMT_COMMA : FMT_DOT;
1067 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
1069 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
1071 /* Convert -0 to +0. */
1072 number = fabs (number);
1078 /* There's room for all that currency crap. Let's do the F
1079 conversion first. */
1080 if (!convert_F (buf, &f, number) || *buf == '*')
1082 insert_commas (buf2, buf, &f);
1084 /* Postprocess back into buf. */
1087 cp = stpcpy (cp, cc->neg_prefix);
1088 cp = stpcpy (cp, cc->prefix);
1094 assert ((number >= 0) ^ (*bp == '-'));
1098 memcpy (cp, bp, f.w - (bp - buf2));
1099 cp += f.w - (bp - buf2);
1101 cp = stpcpy (cp, cc->suffix);
1103 cp = stpcpy (cp, cc->neg_suffix);
1105 /* Copy into dst. */
1106 assert (cp - buf <= fp->w);
1107 if (cp - buf < fp->w)
1109 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1110 memset (dst, ' ', fp->w - (cp - buf));
1113 memcpy (dst, buf, fp->w);
1118 /* This routine relies on the underlying implementation of sprintf:
1120 If the number has a magnitude 1e40 or greater, then we needn't
1121 bother with it, since it's guaranteed to need processing in
1122 scientific notation.
1124 Otherwise, do a binary search for the base-10 magnitude of the
1125 thing. log10() is not accurate enough, and the alternatives are
1126 frightful. Besides, we never need as many as 6 (pairs of)
1127 comparisons. The algorithm used for searching is Knuth's Algorithm
1128 6.2.1C (Uniform binary search).
1130 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1131 LONG TIME! The rest of the program is heavily dependent on
1132 specific properties of this routine's output. LOG ALL CHANGES! */
1134 try_F (char *dst, const struct fmt_spec *fp, double number)
1136 /* This is the DELTA array from Knuth.
1137 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1138 static const int delta[8] =
1140 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1141 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1144 /* The number of digits in floor(number), including sign. This
1145 is `i' from Knuth. */
1146 int n_int = (40 + 1) / 2;
1148 /* Used to step through delta[]. This is `j' from Knuth. */
1151 /* Magnitude of number. This is `K' from Knuth. */
1154 /* Number of characters for the fractional part, including the
1158 /* Pointer into buf used for formatting. */
1161 /* Used to count characters formatted by nsprintf(). */
1164 /* Temporary buffer. */
1167 /* First check for infinities and NaNs. 12/13/96. */
1168 if (!finite (number))
1170 n = nsprintf (buf, "%f", number);
1172 memset (buf, '*', fp->w);
1175 memmove (&buf[fp->w - n], buf, n);
1176 memset (buf, ' ', fp->w - n);
1178 memcpy (dst, buf, fp->w);
1182 /* Then check for radically out-of-range values. */
1183 mag = fabs (number);
1184 if (mag >= power10[fp->w])
1191 /* Avoid printing `-.000'. 7/6/96. */
1192 if (approx_eq (number, 0.0))
1196 /* Now perform a `uniform binary search' based on the tables
1197 power10[] and delta[]. After this step, nint is the number of
1198 digits in floor(number), including any sign. */
1201 if (mag >= power10[n_int]) /* Should this be approx_ge()? */
1204 n_int += delta[j++];
1206 else if (mag < power10[n_int - 1])
1209 n_int -= delta[j++];
1215 /* If we have any decimal places, then there is a decimal point,
1221 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1222 only when fabs(number) < 1.0. */
1223 if (n_int + n_dec == 0)
1226 /* Give space for a minus sign. Moved 1/10/96. */
1230 /* Normally we only go through the loop once; occasionally twice.
1231 Three times or more indicates a very serious bug somewhere. */
1234 /* Check out the total length of the string. */
1236 if (n_int + n_dec > fp->w)
1238 /* The string is too long. Let's see what can be done. */
1240 /* If we can, just reduce the number of decimal places. */
1241 n_dec = fp->w - n_int;
1245 else if (n_int + n_dec < fp->w)
1247 /* The string is too short. Left-pad with spaces. */
1248 int n_spaces = fp->w - n_int - n_dec;
1249 memset (cp, ' ', n_spaces);
1253 /* Finally, format the number. */
1255 n = nsprintf (cp, "%.*f", n_dec - 1, number);
1257 n = nsprintf (cp, "%.0f", number);
1259 /* If number is positive and its magnitude is less than
1265 /* The value rounds to `.###'. */
1266 memmove (cp, &cp[1], n - 1);
1271 /* The value rounds to `1.###'. */
1276 /* Else if number is negative and its magnitude is less
1278 else if (number < 0 && n_int == 1)
1282 /* The value rounds to `-.###'. */
1283 memmove (&cp[1], &cp[2], n - 2);
1288 /* The value rounds to `-1.###'. */
1294 /* Check for a correct number of digits & decimal places & stuff.
1295 This is just a desperation check. Hopefully it won't fail too
1296 often, because then we have to run through the whole loop again:
1297 sprintf() is not a fast operation with floating-points! */
1298 if (n == n_int + n_dec)
1300 /* Convert periods `.' to commas `,' for our foreign friends. */
1301 if ((set_decimal == ',' && fp->type != FMT_DOT)
1302 || (set_decimal == '.' && fp->type == FMT_DOT))
1304 cp = strchr (cp, '.');
1309 memcpy (dst, buf, fp->w);
1313 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */