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., 51 Franklin Street, Fifth Floor, 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 assert (check_output_specifier (fp, 0));
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);
114 ok = convert_IB (s, fp, number);
118 ok = convert_P (s, fp, number);
122 ok = convert_PIB (s, fp, number);
126 ok = convert_PIBHEX (s, fp, number);
130 ok = convert_PK (s, fp, number);
134 ok = convert_RB (s, fp, number);
138 ok = convert_RBHEX (s, fp, number);
141 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
142 ok = convert_CCx (s, fp, number);
145 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
146 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
148 ok = convert_date (s, fp, number);
151 case FMT_TIME: case FMT_DTIME:
152 ok = convert_time (s, fp, number);
156 ok = convert_WKDAY (s, fp, number);
160 ok = convert_MONTH (s, fp, number);
170 /* String formatting. */
171 const char *string = v->s;
176 ok = convert_A (s, fp, string);
180 ok = convert_AHEX (s, fp, string);
189 /* Error handling. */
191 strncpy (s, "ERROR", fp->w);
194 /* Converts V into S in F format with width W and D decimal places,
195 then deletes trailing zeros. S is not null-terminated. */
197 num_to_string (double v, char *s, int w, int d)
199 /* Dummy to pass to convert_F. */
203 /* Pointer to `.' in S. */
206 /* Pointer to `E' in S. */
209 /* Number of characters to delete. */
216 /* Cut out the jokers. */
224 memcpy (temp, "NaN", 3);
229 memcpy (temp, "+Infinity", 9);
236 memcpy (temp, _("Unknown"), 7);
242 memset (s, ' ', pad);
253 decp = memchr (s, set_decimal, w);
257 /* If there's an `E' we can only delete 0s before the E. */
258 expp = memchr (s, 'E', w);
261 while (expp[-n - 1] == '0')
263 if (expp[-n - 1] == set_decimal)
265 memmove (&s[n], s, expp - s - n);
270 /* Otherwise delete all trailing 0s. */
272 while (s[w - n] == '0')
274 if (s[w - n] != set_decimal)
276 /* Avoid stripping `.0' to `'. */
277 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
282 memmove (&s[n], s, w - n);
287 /* Main conversion functions. */
289 static void insert_commas (char *dst, const char *src,
290 const struct fmt_spec *fp);
291 static int year4 (int year);
292 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
295 #error Write your own floating-point output routines.
300 Some of the routines in this file are likely very specific to
301 base-2 representation of floating-point numbers, most notably the
302 routines that use frexp() or ldexp(). These attempt to extract
303 individual digits by setting the base-2 exponent and
304 multiplying/dividing by powers of 2. In base-2 numeration systems,
305 this just nudges the exponent up or down, but in base-10 floating
306 point, such multiplications/division can cause catastrophic loss of
309 The author has never personally used a machine that didn't use
310 binary floating point formats, so he is unwilling, and perhaps
311 unable, to code around this "problem". */
313 /* Converts a number between 0 and 15 inclusive to a `hexit'
315 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
317 /* Table of powers of 10. */
318 static const double power10[] =
321 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
322 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
323 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
324 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
327 /* Handles F format. */
329 convert_F (char *dst, const struct fmt_spec *fp, double number)
331 if (!try_F (dst, fp, number))
332 convert_E (dst, fp, number);
336 /* Handles N format. */
338 convert_N (char *dst, const struct fmt_spec *fp, double number)
340 double d = floor (number);
342 if (d < 0 || d == SYSMIS)
344 msg (ME, _("The N output format cannot be used to output a "
345 "negative number or the system-missing value."));
349 if (d < power10[fp->w])
352 sprintf (buf, "%0*.0f", fp->w, number);
353 memcpy (dst, buf, fp->w);
356 memset (dst, '*', fp->w);
361 /* Handles E format. Also operates as fallback for some other
364 convert_E (char *dst, const struct fmt_spec *fp, double number)
366 /* Temporary buffer. */
369 /* Ranged number of decimal places. */
372 /* Check that the format is width enough.
373 Although PSPP generally checks this, convert_E() can be called as
374 a fallback from other formats which do not check. */
377 memset (dst, '*', fp->w);
381 /* Put decimal places in usable range. */
382 d = min (fp->d, fp->w - 6);
387 sprintf (buf, "%*.*E", fp->w, d, number);
389 /* What we do here is force the exponent part to have four
390 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
391 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
392 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
393 Note that ANSI C guarantees at least two digits in the
395 if (fabs (number) > 1e99)
397 /* Pointer to the `E' in buf. */
400 cp = strchr (buf, 'E');
403 /* Exponent better not be bigger than an int. */
404 int exp = atoi (cp + 1);
406 if (abs (exp) > 99 && abs (exp) < 1000)
408 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
414 else if (abs (exp) >= 1000)
415 memset (buf, '*', fp->w);
419 /* The C locale always uses a period `.' as a decimal point.
420 Translate to comma if necessary. */
421 if ((get_decimal() == ',' && fp->type != FMT_DOT)
422 || (get_decimal() == '.' && fp->type == FMT_DOT))
424 char *cp = strchr (buf, '.');
429 memcpy (dst, buf, fp->w);
433 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
435 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
439 if (try_F (buf, fp, number))
440 insert_commas (dst, buf, fp);
442 convert_E (dst, fp, number);
448 convert_Z (char *dst, const struct fmt_spec *fp, double number)
450 static int warned = 0;
455 _("Quality of zoned decimal (Z) output format code is "
456 "suspect. Check your results. Report bugs to %s."),
461 if (number == SYSMIS)
463 msg (ME, _("The system-missing value cannot be output as a zoned "
473 d = fabs (floor (number));
474 if (d >= power10[fp->w])
476 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
477 number, fp->w, fp->d);
481 sprintf (buf, "%*.0f", fp->w, number);
482 for (i = 0; i < fp->w; i++)
483 dst[i] = (buf[i] - '0') | 0xf0;
485 dst[fp->w - 1] &= 0xdf;
492 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
494 memcpy (dst, string, fp->w);
499 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
503 for (i = 0; i < fp->w / 2; i++)
505 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
506 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
513 convert_IB (char *dst, const struct fmt_spec *fp, double number)
515 /* Strategy: Basically the same as convert_PIBHEX() but with
516 base 256. Then negate the two's-complement result if number
519 /* Used for constructing the two's-complement result. */
522 /* Fraction (mantissa). */
528 /* Difference between exponent and (-8*fp->w-1). */
534 /* Make the exponent (-8*fp->w-1). */
535 frac = frexp (fabs (number), &exp);
536 diff = exp - (-8 * fp->w - 1);
538 frac *= ldexp (1.0, diff);
540 /* Extract each base-256 digit. */
541 for (i = 0; i < fp->w; i++)
545 temp[i] = floor (frac);
548 /* Perform two's-complement negation if number is negative. */
551 /* Perform NOT operation. */
552 for (i = 0; i < fp->w; i++)
554 /* Add 1 to the whole number. */
555 for (i = fp->w - 1; i >= 0; i--)
562 memcpy (dst, temp, fp->w);
563 #ifndef WORDS_BIGENDIAN
564 mm_reverse (dst, fp->w);
571 convert_P (char *dst, const struct fmt_spec *fp, double number)
573 /* Buffer for fp->w*2-1 characters + a decimal point if library is
574 not quite compliant + a null. */
580 /* Main extraction. */
581 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
583 for (i = 0; i < fp->w; i++)
584 ((unsigned char *) dst)[i]
585 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
588 dst[fp->w - 1] &= 0xf0;
590 dst[fp->w - 1] |= 0xf;
592 dst[fp->w - 1] |= 0xd;
598 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
600 /* Strategy: Basically the same as convert_IB(). */
602 /* Fraction (mantissa). */
608 /* Difference between exponent and (-8*fp->w). */
614 /* Make the exponent (-8*fp->w). */
615 frac = frexp (fabs (number), &exp);
616 diff = exp - (-8 * fp->w);
618 frac *= ldexp (1.0, diff);
620 /* Extract each base-256 digit. */
621 for (i = 0; i < fp->w; i++)
625 ((unsigned char *) dst)[i] = floor (frac);
627 #ifndef WORDS_BIGENDIAN
628 mm_reverse (dst, fp->w);
635 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
637 /* Strategy: Use frexp() to create a normalized result (but mostly
638 to find the base-2 exponent), then change the base-2 exponent to
639 (-4*fp->w) using multiplication and division by powers of two.
640 Extract each hexit by multiplying by 16. */
642 /* Fraction (mantissa). */
648 /* Difference between exponent and (-4*fp->w). */
654 /* Make the exponent (-4*fp->w). */
655 frac = frexp (fabs (number), &exp);
656 diff = exp - (-4 * fp->w);
658 frac *= ldexp (1.0, diff);
660 /* Extract each hexit. */
661 for (i = 0; i < fp->w; i++)
665 *dst++ = MAKE_HEXIT ((int) floor (frac));
672 convert_PK (char *dst, const struct fmt_spec *fp, double number)
674 /* Buffer for fp->w*2 characters + a decimal point if library is not
675 quite compliant + a null. */
681 /* Main extraction. */
682 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
684 for (i = 0; i < fp->w; i++)
685 ((unsigned char *) dst)[i]
686 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
692 convert_RB (char *dst, const struct fmt_spec *fp, double number)
702 memcpy (dst, u.c, fp->w);
708 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
720 for (i = 0; i < fp->w / 2; i++)
722 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
723 *dst++ = MAKE_HEXIT (u.c[i] & 15);
730 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
732 if (try_CCx (dst, fp, number))
742 return convert_F_plus (dst, &f, number);
747 convert_date (char *dst, const struct fmt_spec *fp, double number)
749 static const char *months[12] =
751 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
752 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
756 int ofs = number / 86400.;
757 int month, day, year;
762 calendar_offset_to_gregorian (ofs, &year, &month, &day);
767 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
769 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
773 sprintf (buf, "%02d.%02d.%04d", day, month, year);
775 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
779 sprintf (buf, "%04d/%02d/%02d", year, month, day);
781 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
785 sprintf (buf, "%02d/%02d/%04d", month, day, year);
787 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
791 int yday = calendar_offset_to_yday (ofs);
794 sprintf (buf, "%02d%03d", year % 100, yday);
795 else if (year4 (year))
796 sprintf (buf, "%04d%03d", year, yday);
802 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
804 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
808 sprintf (buf, "%s% 04d", months[month - 1], year);
810 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
814 int yday = calendar_offset_to_yday (ofs);
817 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
819 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
826 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
827 day, months[month - 1], year,
828 (int) fmod (floor (number / 60. / 60.), 24.),
829 (int) fmod (floor (number / 60.), 60.));
834 if (fp->w >= 22 && fp->d > 0)
836 d = min (fp->d, fp->w - 21);
845 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
855 st_bare_pad_copy (dst, buf, fp->w);
860 convert_time (char *dst, const struct fmt_spec *fp, double number)
868 if (fabs (number) > 1e20)
870 msg (ME, _("Time value %g too large in magnitude to convert to "
871 "alphanumeric time."), number);
879 *cp++ = '-', time = -time;
880 if (fp->type == FMT_DTIME)
882 double days = floor (time / 60. / 60. / 24.);
883 cp = spprintf (temp_buf, "%02.0f ", days);
884 time = time - days * 60. * 60. * 24.;
890 cp = spprintf (cp, "%02.0f:%02.0f",
891 fmod (floor (time / 60. / 60.), 24.),
892 fmod (floor (time / 60.), 60.));
898 if (width >= 10 && fp->d >= 0 && fp->d != 0)
899 d = min (fp->d, width - 9), w = 3 + d;
903 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
905 st_bare_pad_copy (dst, temp_buf, fp->w);
911 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
913 static const char *weekdays[7] =
915 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
916 "THURSDAY", "FRIDAY", "SATURDAY",
919 if (wkday < 1 || wkday > 7)
921 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
925 st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
931 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
933 static const char *months[12] =
935 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
936 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
939 if (month < 1 || month > 12)
941 msg (ME, _("Month index %f does not lie between 1 and 12."),
946 st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
951 /* Helper functions. */
953 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
954 for format spec *FP. */
956 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
958 /* Number of leading spaces in the number. This is the amount of
959 room we have for inserting commas and dollar signs. */
962 /* Number of digits before the decimal point. This is used to
963 determine the Number of commas to insert. */
966 /* Number of commas to insert. */
969 /* Number of items ,%$ to insert. */
972 /* Number of n_items items not to use for commas. */
975 /* Digit iterator. */
978 /* Source pointer. */
981 /* Count spaces and digits. */
983 while (sp < src + fp->w && *sp == ' ')
990 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
992 n_commas = (n_digits - 1) / 3;
993 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
995 /* Check whether we have enough space to do insertions. */
996 if (!n_spaces || !n_items)
998 memcpy (dst, src, fp->w);
1001 if (n_items > n_spaces)
1003 n_items -= n_commas;
1006 memcpy (dst, src, fp->w);
1011 /* Put spaces at the beginning if there's extra room. */
1012 if (n_spaces > n_items)
1014 memset (dst, ' ', n_spaces - n_items);
1015 dst += n_spaces - n_items;
1018 /* Insert $ and reserve space for %. */
1020 if (fp->type == FMT_DOLLAR)
1025 else if (fp->type == FMT_PCT)
1028 /* Copy negative sign and digits, inserting commas. */
1029 if (sp - src > n_spaces)
1031 for (i = n_digits; i; i--)
1033 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
1036 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
1041 /* Copy decimal places and insert % if necessary. */
1042 memcpy (dst, sp, fp->w - (sp - src));
1043 if (fp->type == FMT_PCT && n_items > 0)
1044 dst[fp->w - (sp - src)] = '%';
1047 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
1052 if (year >= 1 && year <= 9999)
1054 msg (ME, _("Year %d cannot be represented in four digits for "
1055 "output formatting purposes."), year);
1060 try_CCx (char *dst, const struct fmt_spec *fp, double number)
1062 const struct set_cust_currency *cc = get_cc(fp->type - FMT_CCA);
1070 /* Determine length available, decimal character for number
1072 f.type = cc->decimal == get_decimal() ? FMT_COMMA : FMT_DOT;
1073 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
1075 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
1077 /* Convert -0 to +0. */
1078 number = fabs (number);
1084 /* There's room for all that currency crap. Let's do the F
1085 conversion first. */
1086 if (!convert_F (buf, &f, number) || *buf == '*')
1088 insert_commas (buf2, buf, &f);
1090 /* Postprocess back into buf. */
1093 cp = stpcpy (cp, cc->neg_prefix);
1094 cp = stpcpy (cp, cc->prefix);
1100 assert ((number >= 0) ^ (*bp == '-'));
1104 memcpy (cp, bp, f.w - (bp - buf2));
1105 cp += f.w - (bp - buf2);
1107 cp = stpcpy (cp, cc->suffix);
1109 cp = stpcpy (cp, cc->neg_suffix);
1111 /* Copy into dst. */
1112 assert (cp - buf <= fp->w);
1113 if (cp - buf < fp->w)
1115 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1116 memset (dst, ' ', fp->w - (cp - buf));
1119 memcpy (dst, buf, fp->w);
1124 /* This routine relies on the underlying implementation of sprintf:
1126 If the number has a magnitude 1e40 or greater, then we needn't
1127 bother with it, since it's guaranteed to need processing in
1128 scientific notation.
1130 Otherwise, do a binary search for the base-10 magnitude of the
1131 thing. log10() is not accurate enough, and the alternatives are
1132 frightful. Besides, we never need as many as 6 (pairs of)
1133 comparisons. The algorithm used for searching is Knuth's Algorithm
1134 6.2.1C (Uniform binary search).
1136 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1137 LONG TIME! The rest of the program is heavily dependent on
1138 specific properties of this routine's output. LOG ALL CHANGES! */
1140 try_F (char *dst, const struct fmt_spec *fp, double number)
1142 /* This is the DELTA array from Knuth.
1143 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1144 static const int delta[8] =
1146 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1147 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1150 /* The number of digits in floor(number), including sign. This
1151 is `i' from Knuth. */
1152 int n_int = (40 + 1) / 2;
1154 /* Used to step through delta[]. This is `j' from Knuth. */
1157 /* Magnitude of number. This is `K' from Knuth. */
1160 /* Number of characters for the fractional part, including the
1164 /* Pointer into buf used for formatting. */
1167 /* Used to count characters formatted by nsprintf(). */
1170 /* Temporary buffer. */
1173 /* First check for infinities and NaNs. 12/13/96. */
1174 if (!finite (number))
1176 n = nsprintf (buf, "%f", number);
1178 memset (buf, '*', fp->w);
1181 memmove (&buf[fp->w - n], buf, n);
1182 memset (buf, ' ', fp->w - n);
1184 memcpy (dst, buf, fp->w);
1188 /* Then check for radically out-of-range values. */
1189 mag = fabs (number);
1190 if (mag >= power10[fp->w])
1197 /* Avoid printing `-.000'. 7/6/96. */
1202 /* Now perform a `uniform binary search' based on the tables
1203 power10[] and delta[]. After this step, nint is the number of
1204 digits in floor(number), including any sign. */
1207 if (mag >= power10[n_int])
1210 n_int += delta[j++];
1212 else if (mag < power10[n_int - 1])
1215 n_int -= delta[j++];
1221 /* If we have any decimal places, then there is a decimal point,
1227 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1228 only when fabs(number) < 1.0. */
1229 if (n_int + n_dec == 0)
1232 /* Give space for a minus sign. Moved 1/10/96. */
1236 /* Normally we only go through the loop once; occasionally twice.
1237 Three times or more indicates a very serious bug somewhere. */
1240 /* Check out the total length of the string. */
1242 if (n_int + n_dec > fp->w)
1244 /* The string is too long. Let's see what can be done. */
1246 /* If we can, just reduce the number of decimal places. */
1247 n_dec = fp->w - n_int;
1251 else if (n_int + n_dec < fp->w)
1253 /* The string is too short. Left-pad with spaces. */
1254 int n_spaces = fp->w - n_int - n_dec;
1255 memset (cp, ' ', n_spaces);
1259 /* Finally, format the number. */
1261 n = nsprintf (cp, "%.*f", n_dec - 1, number);
1263 n = nsprintf (cp, "%.0f", number);
1265 /* If number is positive and its magnitude is less than
1271 /* The value rounds to `.###'. */
1272 memmove (cp, &cp[1], n - 1);
1277 /* The value rounds to `1.###'. */
1282 /* Else if number is negative and its magnitude is less
1284 else if (number < 0 && n_int == 1)
1288 /* The value rounds to `-.###'. */
1289 memmove (&cp[1], &cp[2], n - 2);
1294 /* The value rounds to `-1.###'. */
1300 /* Check for a correct number of digits & decimal places & stuff.
1301 This is just a desperation check. Hopefully it won't fail too
1302 often, because then we have to run through the whole loop again:
1303 sprintf() is not a fast operation with floating-points! */
1304 if (n == n_int + n_dec)
1306 /* Convert periods `.' to commas `,' for our foreign friends. */
1307 if ((get_decimal() == ',' && fp->type != FMT_DOT)
1308 || (get_decimal() == '.' && fp->type == FMT_DOT))
1310 cp = strchr (cp, '.');
1315 memcpy (dst, buf, fp->w);
1319 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */