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);
111 ok = convert_IB (s, fp, number);
115 ok = convert_P (s, fp, number);
119 ok = convert_PIB (s, fp, number);
123 ok = convert_PIBHEX (s, fp, number);
127 ok = convert_PK (s, fp, number);
131 ok = convert_RB (s, fp, number);
135 ok = convert_RBHEX (s, fp, number);
138 case FMT_CCA: case FMT_CCB: case FMT_CCC: case FMT_CCD: case FMT_CCE:
139 ok = convert_CCx (s, fp, number);
142 case FMT_DATE: case FMT_EDATE: case FMT_SDATE: case FMT_ADATE:
143 case FMT_JDATE: case FMT_QYR: case FMT_MOYR: case FMT_WKYR:
145 ok = convert_date (s, fp, number);
148 case FMT_TIME: case FMT_DTIME:
149 ok = convert_time (s, fp, number);
153 ok = convert_WKDAY (s, fp, number);
157 ok = convert_MONTH (s, fp, number);
166 /* String formatting. */
167 const char *string = v->s;
172 ok = convert_A (s, fp, string);
176 ok = convert_AHEX (s, fp, string);
184 /* Error handling. */
186 strncpy (s, "ERROR", fp->w);
189 /* Converts V into S in F format with width W and D decimal places,
190 then deletes trailing zeros. S is not null-terminated. */
192 num_to_string (double v, char *s, int w, int d)
194 /* Dummy to pass to convert_F. */
198 /* Pointer to `.' in S. */
201 /* Pointer to `E' in S. */
204 /* Number of characters to delete. */
211 /* Cut out the jokers. */
219 memcpy (temp, "NaN", 3);
224 memcpy (temp, "+Infinity", 9);
231 memcpy (temp, _("Unknown"), 7);
237 memset (s, ' ', pad);
248 decp = memchr (s, set_decimal, w);
252 /* If there's an `E' we can only delete 0s before the E. */
253 expp = memchr (s, 'E', w);
256 while (expp[-n - 1] == '0')
258 if (expp[-n - 1] == set_decimal)
260 memmove (&s[n], s, expp - s - n);
265 /* Otherwise delete all trailing 0s. */
267 while (s[w - n] == '0')
269 if (s[w - n] != set_decimal)
271 /* Avoid stripping `.0' to `'. */
272 if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
277 memmove (&s[n], s, w - n);
282 /* Main conversion functions. */
284 static void insert_commas (char *dst, const char *src,
285 const struct fmt_spec *fp);
286 static int year4 (int year);
287 static int try_CCx (char *s, const struct fmt_spec *fp, double v);
290 #error Write your own floating-point output routines.
295 Some of the routines in this file are likely very specific to
296 base-2 representation of floating-point numbers, most notably the
297 routines that use frexp() or ldexp(). These attempt to extract
298 individual digits by setting the base-2 exponent and
299 multiplying/dividing by powers of 2. In base-2 numeration systems,
300 this just nudges the exponent up or down, but in base-10 floating
301 point, such multiplications/division can cause catastrophic loss of
304 The author has never personally used a machine that didn't use
305 binary floating point formats, so he is unwilling, and perhaps
306 unable, to code around this "problem". */
308 /* Converts a number between 0 and 15 inclusive to a `hexit'
310 #define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
312 /* Table of powers of 10. */
313 static const double power10[] =
316 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10,
317 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20,
318 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30,
319 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 1e40,
322 /* Handles F format. */
324 convert_F (char *dst, const struct fmt_spec *fp, double number)
326 if (!try_F (dst, fp, number))
327 convert_E (dst, fp, number);
331 /* Handles N format. */
333 convert_N (char *dst, const struct fmt_spec *fp, double number)
335 double d = floor (number);
337 if (d < 0 || d == SYSMIS)
339 msg (ME, _("The N output format cannot be used to output a "
340 "negative number or the system-missing value."));
344 if (d < power10[fp->w])
347 sprintf (buf, "%0*.0f", fp->w, number);
348 memcpy (dst, buf, fp->w);
351 memset (dst, '*', fp->w);
356 /* Handles E format. Also operates as fallback for some other
359 convert_E (char *dst, const struct fmt_spec *fp, double number)
361 /* Temporary buffer. */
364 /* Ranged number of decimal places. */
367 /* Check that the format is width enough.
368 Although PSPP generally checks this, convert_E() can be called as
369 a fallback from other formats which do not check. */
372 memset (dst, '*', fp->w);
376 /* Put decimal places in usable range. */
377 d = min (fp->d, fp->w - 6);
382 sprintf (buf, "%*.*E", fp->w, d, number);
384 /* What we do here is force the exponent part to have four
385 characters whenever possible. That is, 1.00E+99 is okay (`E+99')
386 but 1.00E+100 (`E+100') must be coerced to 1.00+100 (`+100'). On
387 the other hand, 1.00E1000 (`E+100') cannot be canonicalized.
388 Note that ANSI C guarantees at least two digits in the
390 if (fabs (number) > 1e99)
392 /* Pointer to the `E' in buf. */
395 cp = strchr (buf, 'E');
398 /* Exponent better not be bigger than an int. */
399 int exp = atoi (cp + 1);
401 if (abs (exp) > 99 && abs (exp) < 1000)
403 /* Shift everything left one place: 1.00e+100 -> 1.00+100. */
409 else if (abs (exp) >= 1000)
410 memset (buf, '*', fp->w);
414 /* The C locale always uses a period `.' as a decimal point.
415 Translate to comma if necessary. */
416 if ((get_decimal() == ',' && fp->type != FMT_DOT)
417 || (get_decimal() == '.' && fp->type == FMT_DOT))
419 char *cp = strchr (buf, '.');
424 memcpy (dst, buf, fp->w);
428 /* Handles COMMA, DOT, DOLLAR, and PCT formats. */
430 convert_F_plus (char *dst, const struct fmt_spec *fp, double number)
434 if (try_F (buf, fp, number))
435 insert_commas (dst, buf, fp);
437 convert_E (dst, fp, number);
443 convert_Z (char *dst, const struct fmt_spec *fp, double number)
445 static int warned = 0;
450 _("Quality of zoned decimal (Z) output format code is "
451 "suspect. Check your results. Report bugs to %s."),
456 if (number == SYSMIS)
458 msg (ME, _("The system-missing value cannot be output as a zoned "
468 d = fabs (floor (number));
469 if (d >= power10[fp->w])
471 msg (ME, _("Number %g too big to fit in field with format Z%d.%d."),
472 number, fp->w, fp->d);
476 sprintf (buf, "%*.0f", fp->w, number);
477 for (i = 0; i < fp->w; i++)
478 dst[i] = (buf[i] - '0') | 0xf0;
480 dst[fp->w - 1] &= 0xdf;
487 convert_A (char *dst, const struct fmt_spec *fp, const char *string)
489 memcpy (dst, string, fp->w);
494 convert_AHEX (char *dst, const struct fmt_spec *fp, const char *string)
498 for (i = 0; i < fp->w / 2; i++)
500 *dst++ = MAKE_HEXIT ((string[i]) >> 4);
501 *dst++ = MAKE_HEXIT ((string[i]) & 0xf);
508 convert_IB (char *dst, const struct fmt_spec *fp, double number)
510 /* Strategy: Basically the same as convert_PIBHEX() but with
511 base 256. Then negate the two's-complement result if number
514 /* Used for constructing the two's-complement result. */
517 /* Fraction (mantissa). */
523 /* Difference between exponent and (-8*fp->w-1). */
529 /* Make the exponent (-8*fp->w-1). */
530 frac = frexp (fabs (number), &exp);
531 diff = exp - (-8 * fp->w - 1);
533 frac *= ldexp (1.0, diff);
535 /* Extract each base-256 digit. */
536 for (i = 0; i < fp->w; i++)
540 temp[i] = floor (frac);
543 /* Perform two's-complement negation if number is negative. */
546 /* Perform NOT operation. */
547 for (i = 0; i < fp->w; i++)
549 /* Add 1 to the whole number. */
550 for (i = fp->w - 1; i >= 0; i--)
557 memcpy (dst, temp, fp->w);
558 #ifndef WORDS_BIGENDIAN
559 mm_reverse (dst, fp->w);
566 convert_P (char *dst, const struct fmt_spec *fp, double number)
568 /* Buffer for fp->w*2-1 characters + a decimal point if library is
569 not quite compliant + a null. */
575 /* Main extraction. */
576 sprintf (buf, "%0*.0f", fp->w * 2 - 1, floor (fabs (number)));
578 for (i = 0; i < fp->w; i++)
579 ((unsigned char *) dst)[i]
580 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
583 dst[fp->w - 1] &= 0xf0;
585 dst[fp->w - 1] |= 0xf;
587 dst[fp->w - 1] |= 0xd;
593 convert_PIB (char *dst, const struct fmt_spec *fp, double number)
595 /* Strategy: Basically the same as convert_IB(). */
597 /* Fraction (mantissa). */
603 /* Difference between exponent and (-8*fp->w). */
609 /* Make the exponent (-8*fp->w). */
610 frac = frexp (fabs (number), &exp);
611 diff = exp - (-8 * fp->w);
613 frac *= ldexp (1.0, diff);
615 /* Extract each base-256 digit. */
616 for (i = 0; i < fp->w; i++)
620 ((unsigned char *) dst)[i] = floor (frac);
622 #ifndef WORDS_BIGENDIAN
623 mm_reverse (dst, fp->w);
630 convert_PIBHEX (char *dst, const struct fmt_spec *fp, double number)
632 /* Strategy: Use frexp() to create a normalized result (but mostly
633 to find the base-2 exponent), then change the base-2 exponent to
634 (-4*fp->w) using multiplication and division by powers of two.
635 Extract each hexit by multiplying by 16. */
637 /* Fraction (mantissa). */
643 /* Difference between exponent and (-4*fp->w). */
649 /* Make the exponent (-4*fp->w). */
650 frac = frexp (fabs (number), &exp);
651 diff = exp - (-4 * fp->w);
653 frac *= ldexp (1.0, diff);
655 /* Extract each hexit. */
656 for (i = 0; i < fp->w; i++)
660 *dst++ = MAKE_HEXIT ((int) floor (frac));
667 convert_PK (char *dst, const struct fmt_spec *fp, double number)
669 /* Buffer for fp->w*2 characters + a decimal point if library is not
670 quite compliant + a null. */
676 /* Main extraction. */
677 sprintf (buf, "%0*.0f", fp->w * 2, floor (fabs (number)));
679 for (i = 0; i < fp->w; i++)
680 ((unsigned char *) dst)[i]
681 = ((buf[i * 2] - '0') << 4) + buf[i * 2 + 1] - '0';
687 convert_RB (char *dst, const struct fmt_spec *fp, double number)
697 memcpy (dst, u.c, fp->w);
703 convert_RBHEX (char *dst, const struct fmt_spec *fp, double number)
715 for (i = 0; i < fp->w / 2; i++)
717 *dst++ = MAKE_HEXIT (u.c[i] >> 4);
718 *dst++ = MAKE_HEXIT (u.c[i] & 15);
725 convert_CCx (char *dst, const struct fmt_spec *fp, double number)
727 if (try_CCx (dst, fp, number))
737 return convert_F_plus (dst, &f, number);
742 convert_date (char *dst, const struct fmt_spec *fp, double number)
744 static const char *months[12] =
746 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
747 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
751 int month, day, year;
753 julian_to_calendar (number / 86400., &year, &month, &day);
758 sprintf (buf, "%02d-%s-%04d", day, months[month - 1], year);
760 sprintf (buf, "%02d-%s-%02d", day, months[month - 1], year % 100);
764 sprintf (buf, "%02d.%02d.%04d", day, month, year);
766 sprintf (buf, "%02d.%02d.%02d", day, month, year % 100);
770 sprintf (buf, "%04d/%02d/%02d", year, month, day);
772 sprintf (buf, "%02d/%02d/%02d", year % 100, month, day);
776 sprintf (buf, "%02d/%02d/%04d", month, day, year);
778 sprintf (buf, "%02d/%02d/%02d", month, day, year % 100);
782 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
787 sprintf (buf, "%04d%03d", year, yday);
790 sprintf (buf, "%02d%03d", year % 100, yday);
795 sprintf (buf, "%d Q% 04d", (month - 1) / 3 + 1, year);
797 sprintf (buf, "%d Q% 02d", (month - 1) / 3 + 1, year % 100);
801 sprintf (buf, "%s% 04d", months[month - 1], year);
803 sprintf (buf, "%s% 02d", months[month - 1], year % 100);
807 int yday = (number / 86400.) - calendar_to_julian (year, 1, 1) + 1;
810 sprintf (buf, "%02d WK% 04d", (yday - 1) / 7 + 1, year);
812 sprintf (buf, "%02d WK% 02d", (yday - 1) / 7 + 1, year % 100);
819 cp = spprintf (buf, "%02d-%s-%04d %02d:%02d",
820 day, months[month - 1], year,
821 (int) fmod (floor (number / 60. / 60.), 24.),
822 (int) fmod (floor (number / 60.), 60.));
827 if (fp->w >= 22 && fp->d > 0)
829 d = min (fp->d, fp->w - 21);
838 cp = spprintf (cp, ":%0*.*f", w, d, fmod (number, 60.));
848 st_bare_pad_copy (dst, buf, fp->w);
853 convert_time (char *dst, const struct fmt_spec *fp, double number)
861 if (fabs (number) > 1e20)
863 msg (ME, _("Time value %g too large in magnitude to convert to "
864 "alphanumeric time."), number);
872 *cp++ = '-', time = -time;
873 if (fp->type == FMT_DTIME)
875 double days = floor (time / 60. / 60. / 24.);
876 cp = spprintf (temp_buf, "%02.0f ", days);
877 time = time - days * 60. * 60. * 24.;
883 cp = spprintf (cp, "%02.0f:%02.0f",
884 fmod (floor (time / 60. / 60.), 24.),
885 fmod (floor (time / 60.), 60.));
891 if (width >= 10 && fp->d >= 0 && fp->d != 0)
892 d = min (fp->d, width - 9), w = 3 + d;
896 cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
898 st_bare_pad_copy (dst, temp_buf, fp->w);
904 convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday)
906 static const char *weekdays[7] =
908 "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
909 "THURSDAY", "FRIDAY", "SATURDAY",
912 if (wkday < 1 || wkday > 7)
914 msg (ME, _("Weekday index %f does not lie between 1 and 7."),
918 st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
924 convert_MONTH (char *dst, const struct fmt_spec *fp, double month)
926 static const char *months[12] =
928 "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
929 "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
932 if (month < 1 || month > 12)
934 msg (ME, _("Month index %f does not lie between 1 and 12."),
939 st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
944 /* Helper functions. */
946 /* Copies SRC to DST, inserting commas and dollar signs as appropriate
947 for format spec *FP. */
949 insert_commas (char *dst, const char *src, const struct fmt_spec *fp)
951 /* Number of leading spaces in the number. This is the amount of
952 room we have for inserting commas and dollar signs. */
955 /* Number of digits before the decimal point. This is used to
956 determine the Number of commas to insert. */
959 /* Number of commas to insert. */
962 /* Number of items ,%$ to insert. */
965 /* Number of n_items items not to use for commas. */
968 /* Digit iterator. */
971 /* Source pointer. */
974 /* Count spaces and digits. */
976 while (sp < src + fp->w && *sp == ' ')
983 while (sp + n_digits < src + fp->w && isdigit ((unsigned char) sp[n_digits]))
985 n_commas = (n_digits - 1) / 3;
986 n_items = n_commas + (fp->type == FMT_DOLLAR || fp->type == FMT_PCT);
988 /* Check whether we have enough space to do insertions. */
989 if (!n_spaces || !n_items)
991 memcpy (dst, src, fp->w);
994 if (n_items > n_spaces)
999 memcpy (dst, src, fp->w);
1004 /* Put spaces at the beginning if there's extra room. */
1005 if (n_spaces > n_items)
1007 memset (dst, ' ', n_spaces - n_items);
1008 dst += n_spaces - n_items;
1011 /* Insert $ and reserve space for %. */
1013 if (fp->type == FMT_DOLLAR)
1018 else if (fp->type == FMT_PCT)
1021 /* Copy negative sign and digits, inserting commas. */
1022 if (sp - src > n_spaces)
1024 for (i = n_digits; i; i--)
1026 if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
1029 *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
1034 /* Copy decimal places and insert % if necessary. */
1035 memcpy (dst, sp, fp->w - (sp - src));
1036 if (fp->type == FMT_PCT && n_items > 0)
1037 dst[fp->w - (sp - src)] = '%';
1040 /* Returns 1 if YEAR (i.e., 1987) can be represented in four digits, 0
1045 if (year >= 1 && year <= 9999)
1047 msg (ME, _("Year %d cannot be represented in four digits for "
1048 "output formatting purposes."), year);
1053 try_CCx (char *dst, const struct fmt_spec *fp, double number)
1055 const struct set_cust_currency *cc = get_cc(fp->type - FMT_CCA);
1063 /* Determine length available, decimal character for number
1065 f.type = cc->decimal == get_decimal() ? FMT_COMMA : FMT_DOT;
1066 f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
1068 f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
1070 /* Convert -0 to +0. */
1071 number = fabs (number);
1077 /* There's room for all that currency crap. Let's do the F
1078 conversion first. */
1079 if (!convert_F (buf, &f, number) || *buf == '*')
1081 insert_commas (buf2, buf, &f);
1083 /* Postprocess back into buf. */
1086 cp = stpcpy (cp, cc->neg_prefix);
1087 cp = stpcpy (cp, cc->prefix);
1093 assert ((number >= 0) ^ (*bp == '-'));
1097 memcpy (cp, bp, f.w - (bp - buf2));
1098 cp += f.w - (bp - buf2);
1100 cp = stpcpy (cp, cc->suffix);
1102 cp = stpcpy (cp, cc->neg_suffix);
1104 /* Copy into dst. */
1105 assert (cp - buf <= fp->w);
1106 if (cp - buf < fp->w)
1108 memcpy (&dst[fp->w - (cp - buf)], buf, cp - buf);
1109 memset (dst, ' ', fp->w - (cp - buf));
1112 memcpy (dst, buf, fp->w);
1117 /* This routine relies on the underlying implementation of sprintf:
1119 If the number has a magnitude 1e40 or greater, then we needn't
1120 bother with it, since it's guaranteed to need processing in
1121 scientific notation.
1123 Otherwise, do a binary search for the base-10 magnitude of the
1124 thing. log10() is not accurate enough, and the alternatives are
1125 frightful. Besides, we never need as many as 6 (pairs of)
1126 comparisons. The algorithm used for searching is Knuth's Algorithm
1127 6.2.1C (Uniform binary search).
1129 DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
1130 LONG TIME! The rest of the program is heavily dependent on
1131 specific properties of this routine's output. LOG ALL CHANGES! */
1133 try_F (char *dst, const struct fmt_spec *fp, double number)
1135 /* This is the DELTA array from Knuth.
1136 DELTA[j] = floor((40+2**(j-1))/(2**j)). */
1137 static const int delta[8] =
1139 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
1140 (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
1143 /* The number of digits in floor(number), including sign. This
1144 is `i' from Knuth. */
1145 int n_int = (40 + 1) / 2;
1147 /* Used to step through delta[]. This is `j' from Knuth. */
1150 /* Magnitude of number. This is `K' from Knuth. */
1153 /* Number of characters for the fractional part, including the
1157 /* Pointer into buf used for formatting. */
1160 /* Used to count characters formatted by nsprintf(). */
1163 /* Temporary buffer. */
1166 /* First check for infinities and NaNs. 12/13/96. */
1167 if (!finite (number))
1169 n = nsprintf (buf, "%f", number);
1171 memset (buf, '*', fp->w);
1174 memmove (&buf[fp->w - n], buf, n);
1175 memset (buf, ' ', fp->w - n);
1177 memcpy (dst, buf, fp->w);
1181 /* Then check for radically out-of-range values. */
1182 mag = fabs (number);
1183 if (mag >= power10[fp->w])
1190 /* Avoid printing `-.000'. 7/6/96. */
1195 /* Now perform a `uniform binary search' based on the tables
1196 power10[] and delta[]. After this step, nint is the number of
1197 digits in floor(number), including any sign. */
1200 if (mag >= power10[n_int])
1203 n_int += delta[j++];
1205 else if (mag < power10[n_int - 1])
1208 n_int -= delta[j++];
1214 /* If we have any decimal places, then there is a decimal point,
1220 /* 1/10/96: If there aren't any digits at all, add one. This occurs
1221 only when fabs(number) < 1.0. */
1222 if (n_int + n_dec == 0)
1225 /* Give space for a minus sign. Moved 1/10/96. */
1229 /* Normally we only go through the loop once; occasionally twice.
1230 Three times or more indicates a very serious bug somewhere. */
1233 /* Check out the total length of the string. */
1235 if (n_int + n_dec > fp->w)
1237 /* The string is too long. Let's see what can be done. */
1239 /* If we can, just reduce the number of decimal places. */
1240 n_dec = fp->w - n_int;
1244 else if (n_int + n_dec < fp->w)
1246 /* The string is too short. Left-pad with spaces. */
1247 int n_spaces = fp->w - n_int - n_dec;
1248 memset (cp, ' ', n_spaces);
1252 /* Finally, format the number. */
1254 n = nsprintf (cp, "%.*f", n_dec - 1, number);
1256 n = nsprintf (cp, "%.0f", number);
1258 /* If number is positive and its magnitude is less than
1264 /* The value rounds to `.###'. */
1265 memmove (cp, &cp[1], n - 1);
1270 /* The value rounds to `1.###'. */
1275 /* Else if number is negative and its magnitude is less
1277 else if (number < 0 && n_int == 1)
1281 /* The value rounds to `-.###'. */
1282 memmove (&cp[1], &cp[2], n - 2);
1287 /* The value rounds to `-1.###'. */
1293 /* Check for a correct number of digits & decimal places & stuff.
1294 This is just a desperation check. Hopefully it won't fail too
1295 often, because then we have to run through the whole loop again:
1296 sprintf() is not a fast operation with floating-points! */
1297 if (n == n_int + n_dec)
1299 /* Convert periods `.' to commas `,' for our foreign friends. */
1300 if ((get_decimal() == ',' && fp->type != FMT_DOT)
1301 || (get_decimal() == '.' && fp->type == FMT_DOT))
1303 cp = strchr (cp, '.');
1308 memcpy (dst, buf, fp->w);
1312 n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */