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