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
29 #include "julcal/julcal.h"
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 month, day, year;
757 julian_to_calendar (number / 86400., &year, &month, &day);
762 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
764 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
768 sprintf (buf, "%02d.%02d.%04d", day, month, year);
770 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
774 sprintf (buf, "%04d/%02d/%02d", year, month, day);
776 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
780 sprintf (buf, "%02d/%02d/%04d", month, day, year);
782 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
786 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
791 sprintf (buf, "%04d%03d", year, yday);
794 sprintf (buf, "%02d%03d", year % 100, yday);
799 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
801 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
805 sprintf (buf, "%s% 04d", months[month - 1], year);
807 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
811 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
814 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
816 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
823 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
824 day, months[month - 1], year,
825 (int) fmod (floor (number / 60. / 60.), 24.),
826 (int) fmod (floor (number / 60.), 60.));
831 if (fp->w >= 22 && fp->d > 0)
833 d = min (fp->d, fp->w - 21);
842 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
852 st_bare_pad_copy (dst, buf, fp->w);
857 convert_time (char *dst, const struct fmt_spec *fp, double number)
865 if (fabs (number) > 1e20)
867 msg (ME, _("Time value %g too large in magnitude to convert to "
868 "alphanumeric time."), number);
876 *cp++ = '-', time = -time;
877 if (fp->type == FMT_DTIME)
879 double days = floor (time / 60. / 60. / 24.);
880 cp = spprintf (temp_buf, "%02.0f ", days);
881 time = time - days * 60. * 60. * 24.;
887 cp = spprintf (cp, "%02.0f:%02.0f",
888 fmod (floor (time / 60. / 60.), 24.),
889 fmod (floor (time / 60.), 60.));
895 if (width >= 10 && fp->d >= 0 && fp->d != 0)
896 d = min (fp->d, width - 9), w = 3 + d;
900 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
902 st_bare_pad_copy (dst, temp_buf, fp->w);
908 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
910 static const char *weekdays[7] =
912 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
913 "THURSDAY", "FRIDAY", "SATURDAY",
916 if (wkday < 1 || wkday > 7)
918 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
922 st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
928 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
930 static const char *months[12] =
932 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
933 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
936 if (month < 1 || month > 12)
938 msg (ME, _("Month index %f does not lie between 1 and 12."),
943 st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
948 /* Helper functions. */
950 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
951 for format spec *FP. */
953 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
955 /* Number of leading spaces in the number. This is the amount of
956 room we have for inserting commas and dollar signs. */
959 /* Number of digits before the decimal point. This is used to
960 determine the Number of commas to insert. */
963 /* Number of commas to insert. */
966 /* Number of items ,%$ to insert. */
969 /* Number of n_items items not to use for commas. */
972 /* Digit iterator. */
975 /* Source pointer. */
978 /* Count spaces and digits. */
980 while (sp < src + fp->w && *sp == ' ')
987 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
989 n_commas = (n_digits - 1) / 3;
990 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
992 /* Check whether we have enough space to do insertions. */
993 if (!n_spaces || !n_items)
995 memcpy (dst, src, fp->w);
998 if (n_items > n_spaces)
1000 n_items -= n_commas;
1003 memcpy (dst, src, fp->w);
1008 /* Put spaces at the beginning if there's extra room. */
1009 if (n_spaces > n_items)
1011 memset (dst, ' ', n_spaces - n_items);
1012 dst += n_spaces - n_items;
1015 /* Insert $ and reserve space for %. */
1017 if (fp->type == FMT_DOLLAR)
1022 else if (fp->type == FMT_PCT)
1025 /* Copy negative sign and digits, inserting commas. */
1026 if (sp - src > n_spaces)
1028 for (i = n_digits; i; i--)
1030 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
1033 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
1038 /* Copy decimal places and insert % if necessary. */
1039 memcpy (dst, sp, fp->w - (sp - src));
1040 if (fp->type == FMT_PCT && n_items > 0)
1041 dst[fp->w - (sp - src)] = '%';
1044 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
1049 if (year >= 1 && year <= 9999)
1051 msg (ME, _("Year %d cannot be represented in four digits for "
1052 "output formatting purposes."), year);
1057 try_CCx (char *dst, const struct fmt_spec *fp, double number)
1059 const struct set_cust_currency *cc = get_cc(fp->type - FMT_CCA);
1067 /* Determine length available, decimal character for number
1069 f.type = cc->decimal == get_decimal() ? FMT_COMMA : FMT_DOT;
1070 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
1072 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
1074 /* Convert -0 to +0. */
1075 number = fabs (number);
1081 /* There's room for all that currency crap. Let's do the F
1082 conversion first. */
1083 if (!convert_F (buf, &f, number) || *buf == '*')
1085 insert_commas (buf2, buf, &f);
1087 /* Postprocess back into buf. */
1090 cp = stpcpy (cp, cc->neg_prefix);
1091 cp = stpcpy (cp, cc->prefix);
1097 assert ((number >= 0) ^ (*bp == '-'));
1101 memcpy (cp, bp, f.w - (bp - buf2));
1102 cp += f.w - (bp - buf2);
1104 cp = stpcpy (cp, cc->suffix);
1106 cp = stpcpy (cp, cc->neg_suffix);
1108 /* Copy into dst. */
1109 assert (cp - buf <= fp->w);
1110 if (cp - buf < fp->w)
1112 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1113 memset (dst, ' ', fp->w - (cp - buf));
1116 memcpy (dst, buf, fp->w);
1121 /* This routine relies on the underlying implementation of sprintf:
1123 If the number has a magnitude 1e40 or greater, then we needn't
1124 bother with it, since it's guaranteed to need processing in
1125 scientific notation.
1127 Otherwise, do a binary search for the base-10 magnitude of the
1128 thing. log10() is not accurate enough, and the alternatives are
1129 frightful. Besides, we never need as many as 6 (pairs of)
1130 comparisons. The algorithm used for searching is Knuth's Algorithm
1131 6.2.1C (Uniform binary search).
1133 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1134 LONG TIME! The rest of the program is heavily dependent on
1135 specific properties of this routine's output. LOG ALL CHANGES! */
1137 try_F (char *dst, const struct fmt_spec *fp, double number)
1139 /* This is the DELTA array from Knuth.
1140 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1141 static const int delta[8] =
1143 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1144 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1147 /* The number of digits in floor(number), including sign. This
1148 is `i' from Knuth. */
1149 int n_int = (40 + 1) / 2;
1151 /* Used to step through delta[]. This is `j' from Knuth. */
1154 /* Magnitude of number. This is `K' from Knuth. */
1157 /* Number of characters for the fractional part, including the
1161 /* Pointer into buf used for formatting. */
1164 /* Used to count characters formatted by nsprintf(). */
1167 /* Temporary buffer. */
1170 /* First check for infinities and NaNs. 12/13/96. */
1171 if (!finite (number))
1173 n = nsprintf (buf, "%f", number);
1175 memset (buf, '*', fp->w);
1178 memmove (&buf[fp->w - n], buf, n);
1179 memset (buf, ' ', fp->w - n);
1181 memcpy (dst, buf, fp->w);
1185 /* Then check for radically out-of-range values. */
1186 mag = fabs (number);
1187 if (mag >= power10[fp->w])
1194 /* Avoid printing `-.000'. 7/6/96. */
1199 /* Now perform a `uniform binary search' based on the tables
1200 power10[] and delta[]. After this step, nint is the number of
1201 digits in floor(number), including any sign. */
1204 if (mag >= power10[n_int])
1207 n_int += delta[j++];
1209 else if (mag < power10[n_int - 1])
1212 n_int -= delta[j++];
1218 /* If we have any decimal places, then there is a decimal point,
1224 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1225 only when fabs(number) < 1.0. */
1226 if (n_int + n_dec == 0)
1229 /* Give space for a minus sign. Moved 1/10/96. */
1233 /* Normally we only go through the loop once; occasionally twice.
1234 Three times or more indicates a very serious bug somewhere. */
1237 /* Check out the total length of the string. */
1239 if (n_int + n_dec > fp->w)
1241 /* The string is too long. Let's see what can be done. */
1243 /* If we can, just reduce the number of decimal places. */
1244 n_dec = fp->w - n_int;
1248 else if (n_int + n_dec < fp->w)
1250 /* The string is too short. Left-pad with spaces. */
1251 int n_spaces = fp->w - n_int - n_dec;
1252 memset (cp, ' ', n_spaces);
1256 /* Finally, format the number. */
1258 n = nsprintf (cp, "%.*f", n_dec - 1, number);
1260 n = nsprintf (cp, "%.0f", number);
1262 /* If number is positive and its magnitude is less than
1268 /* The value rounds to `.###'. */
1269 memmove (cp, &cp[1], n - 1);
1274 /* The value rounds to `1.###'. */
1279 /* Else if number is negative and its magnitude is less
1281 else if (number < 0 && n_int == 1)
1285 /* The value rounds to `-.###'. */
1286 memmove (&cp[1], &cp[2], n - 2);
1291 /* The value rounds to `-1.###'. */
1297 /* Check for a correct number of digits & decimal places & stuff.
1298 This is just a desperation check. Hopefully it won't fail too
1299 often, because then we have to run through the whole loop again:
1300 sprintf() is not a fast operation with floating-points! */
1301 if (n == n_int + n_dec)
1303 /* Convert periods `.' to commas `,' for our foreign friends. */
1304 if ((get_decimal() == ',' && fp->type != FMT_DOT)
1305 || (get_decimal() == '.' && fp->type == FMT_DOT))
1307 cp = strchr (cp, '.');
1312 memcpy (dst, buf, fp->w);
1316 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */