|
|
1.1 root 1: /*
2: * libc/stdio/_dtefg.c
3: * ANSI-compliant C standard i/o library internals.
4: * _dtefg(), _dtoa()
5: * ANSI 4.9.6.1.
6: * Floating point output conversion routines for 'printf'.
7: * Conditionalized #if _IEEE to do 8087 conversion.
8: */
9:
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <float.h>
13: #include <math.h>
14: #include "stdio.int.h"
15:
16: #if 0
17: #include <locale.h>
18: #else
19: #define _decimal_point '.'
20: #endif
21:
22: extern char *_dtof();
23:
24: #if _IEEE
25: #include <stddef.h>
26: #include <string.h>
27:
28: /*
29: * This table is indexed by the return value of the "_fxam" routine.
30: * The number is converted if the entry is NULL,
31: * otherwise the entry gives the string to print.
32: */
33: static char *fxamsg[] = {
34: "{+ Unnormal}",
35: "{+ NAN}",
36: "{- Unnormal}",
37: "{- NAN}",
38: NULL, /* + Normal */
39: "{+ Infinity}",
40: NULL, /* - Normal */
41: "{- Infinity}",
42: NULL, /* +0 */
43: NULL, /* Empty */
44: NULL, /* -0 */
45: NULL, /* Empty */
46: "{+ Denormal}",
47: NULL, /* Empty */
48: "{- Denormal}",
49: NULL /* Empty */
50: };
51: #endif
52:
53: /*
54: * Convert a floating point number 'd' from binary
55: * into 'e', 'E', 'f', 'g', or 'G' format ASCII in the buffer 'cp'.
56: * 'fmt' is the conversion type.
57: * 'prec' is the precision.
58: * 'aflag' is the '#' flag from the conversion specication.
59: * 'signp' points to the returned sign (-1 negative, 1 nonnegative).
60: * Return a pointer past the last character.
61: *
62: * Called from printf() for fp conversions and from gcvt().
63: */
64: char *
65: _dtefg(cp, dp, fmt, prec, aflag, signp)
66: register char *cp; double *dp; int fmt, prec, aflag; int *signp;
67: {
68: int eflag, decexp;
69: char tbuf[DBL_DIG+1];
70: double d;
71:
72: d = *dp;
73: #if _IEEE
74: {
75: register char *cp2;
76:
77: /* Print given string if 8087 format is special. */
78: if ((cp2=fxamsg[_fxam(d)]) != NULL) {
79: strcpy(cp, cp2);
80: return cp + strlen(cp);
81: }
82: }
83: #endif
84:
85: if (prec == 0 && (fmt == 'g' || fmt == 'G'))
86: prec = 1;
87: else if (prec == -1)
88: prec = 6; /* Default precision */
89:
90: if (d < 0.0) {
91: d = -d; /* Force d nonnegative */
92: *signp = -1;
93: } else
94: *signp = 1;
95: _dtoa(fmt, &d, prec, &decexp, tbuf);
96: eflag = (fmt=='e' || fmt=='E'
97: || ((fmt=='g' || fmt=='G') && (decexp < -4 || decexp >= prec)));
98: cp = _dtof(cp, tbuf, prec, eflag ? 0 : decexp, fmt, aflag);
99: if (eflag) {
100: *cp++ = (fmt == 'E' || fmt == 'G') ? 'E' : 'e';
101: cp += sprintf(cp, "%+03d", decexp);
102: }
103: return cp;
104: }
105:
106: /*
107: * Copy ASCII number from 'cp' to 'buf' in %f format
108: * with precision 'prec' and decimal exponent 'decexp'.
109: * The 'fmt' determines whether trailing zeros are suppressed.
110: * Return a pointer past the last character.
111: */
112: static
113: char *
114: _dtof(buf, cp, prec, decexp, fmt, aflag)
115: register char *buf, *cp; register int prec, decexp, fmt, aflag;
116: {
117: if (decexp < 0)
118: *buf++ = '0'; /* Units digit '0' */
119: else
120: do
121: *buf++ = *cp ? *cp++ : '0'; /* integral part */
122: while (decexp--);
123: if (!aflag && (prec == 0 || ((fmt=='g'|| fmt=='G') && *cp == '\0')))
124: return buf;
125: *buf++ = _decimal_point; /* '.' */
126: while (prec-- > 0) {
127: if ((fmt=='g' || fmt=='G') && *cp == '\0' && !aflag)
128: break; /* suppress trailing zeros */
129: if (++decexp < 0)
130: *buf++ = '0'; /* put leading zero */
131: else
132: *buf++ = *cp ? *cp++ : '0';
133: }
134: return buf;
135: }
136:
137: /*
138: * Convert the mantissa of nonnegative double 'd' to a string of ASCII digits
139: * in the supplied buffer 'buf'.
140: * Store the decimal exponent indirectly through 'decexpp'.
141: * The first digit of the mantissa is implicitly followed by '.'
142: * The result has no leading zeros (unless d=0.0) and no trailing zeros.
143: * The precision 'prec' and format 'fmt' determine the digit count.
144: * The maximum length of the result is DBL_DIG+1 (for the NUL).
145: * For example, if *dp==123.456789 and prec==3:
146: * fmt=='e' "1234" decexp==2 1.234e+02
147: * fmt=='f' "123456" decexp==2 123.456
148: * fmt=='g' "123" decexp==2 123
149: * This is called directly by ecvt() and fcvt(), as well as from _dtefg().
150: */
151: void
152: _dtoa(fmt, dp, prec, decexpp, buf) int fmt; double *dp; int prec; int *decexpp; char *buf;
153: {
154: register char * cp;
155: register int digit;
156: register int decexp;
157: int ndigits;
158: int binexp;
159: double d;
160: double dexp;
161:
162: /* Handle 0.0 as a special case. */
163: cp = buf;
164: if ((d = *dp) == 0.0) {
165: ret0:
166: *decexpp = 0;
167: *cp++ = '0';
168: *cp ='\0';
169: return;
170: }
171:
172: /* Reduce d to range [1., 10) and set decexp accordingly. */
173: /* Approximate the decimal exponent from the binary exponent. */
174: /* Obscure but it makes floating output much more efficient. */
175: frexp(d, &binexp); /* Find binary exponent */
176: if (modf((--binexp)/LOG10B2, &dexp) < 0.0)
177: dexp -= 1.0; /* Scale, take integer part */
178: decexp = dexp; /* Convert to integer */
179: d *= _pow10(-decexp); /* Reduce d by power of 10 */
180: if (d >= 10.) { /* May be off by 1 place */
181: ++decexp;
182: d *= 0.10;
183: }
184: *decexpp = decexp; /* Store the decimal exponent */
185:
186: /* Compute the desired number of result digits. */
187: if (fmt == 'e' || fmt == 'E')
188: ndigits = prec + 1; /* For 'e' or 'E' format */
189: else if (fmt == 'f')
190: ndigits = prec + decexp + 1; /* For 'f' format */
191: else
192: ndigits = prec; /* For 'g' or 'G' format */
193: if (ndigits <= 0) { /* No significant digits */
194: if (ndigits == 0 && d > 5.0) /* Round up to one digit */
195: goto ret1; /* and return "1" */
196: else
197: goto ret0; /* return "0" */
198: } else if (ndigits > DBL_DIG)
199: ndigits = DBL_DIG; /* Maximum precision */
200:
201: /* Compute the result digits. */
202: for ( ; cp < &buf[ndigits] && d != 0.0; ) {
203: digit = (int) d;
204: *cp++ = digit + '0'; /* Store next digit */
205: d = 10.0 * (d-digit); /* and reduce d accordingly */
206: }
207: *cp = '\0'; /* NUL-terminate result */
208:
209: /* Round up the result if appropriate. */
210: if (d <= 5.0) { /* Do not round up */
211: while (--cp != buf && *cp == '0')
212: *cp = '\0'; /* Strip a trailing '0' */
213: return;
214: }
215: while (cp-- != buf) { /* Round up */
216: if (++*cp <= '9') /* Bump last digit */
217: return;
218: *cp = '\0'; /* Strip a trailing '0' */
219: }
220: ++cp; /* Point to buf again */
221: ret1:
222: ++*decexpp; /* and return "1" */
223: *cp++ = '1';
224: *cp = '\0';
225: }
226:
227: /* end of libc/stdio/_dtefg.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.