Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <float.h>
4
#include <ctype.h>
5
#include "fmtdef.h"
6
 
7
enum
8
{
9
	FDIGIT	= 30,
10
	FDEFLT	= 6,
11
	NSIGNIF	= 17
12
};
13
 
14
/*
15
 * first few powers of 10, enough for about 1/2 of the
16
 * total space for doubles.
17
 */
18
static double pows10[] =
19
{
20
	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,  
21
	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,  
22
	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,  
23
	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,  
24
	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,  
25
	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,  
26
	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,  
27
	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,  
28
	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,  
29
	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,  
30
	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 
31
	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 
32
	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 
33
	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 
34
	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 
35
	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 
36
};
37
 
38
#undef pow10
39
#define  pow10(x)  fmtpow10(x)
40
 
41
static double
42
pow10(int n)
43
{
44
	double d;
45
	int neg;
46
 
47
	neg = 0;
48
	if(n < 0){
49
		if(n < DBL_MIN_10_EXP){
50
			return 0.;
51
		}
52
		neg = 1;
53
		n = -n;
54
	}else if(n > DBL_MAX_10_EXP){
55
		return HUGE_VAL;
56
	}
57
	if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
58
		d = pows10[n];
59
	else{
60
		d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
61
		for(;;){
62
			n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
63
			if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
64
				d *= pows10[n];
65
				break;
66
			}
67
			d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
68
		}
69
	}
70
	if(neg){
71
		return 1./d;
72
	}
73
	return d;
74
}
75
 
76
static int
77
xadd(char *a, int n, int v)
78
{
79
	char *b;
80
	int c;
81
 
82
	if(n < 0 || n >= NSIGNIF)
83
		return 0;
84
	for(b = a+n; b >= a; b--) {
85
		c = *b + v;
86
		if(c <= '9') {
87
			*b = c;
88
			return 0;
89
		}
90
		*b = '0';
91
		v = 1;
92
	}
93
	*a = '1';	/* overflow adding */
94
	return 1;
95
}
96
 
97
static int
98
xsub(char *a, int n, int v)
99
{
100
	char *b;
101
	int c;
102
 
103
	for(b = a+n; b >= a; b--) {
104
		c = *b - v;
105
		if(c >= '0') {
106
			*b = c;
107
			return 0;
108
		}
109
		*b = '9';
110
		v = 1;
111
	}
112
	*a = '9';	/* underflow subtracting */
113
	return 1;
114
}
115
 
116
static void
117
xdtoa(Fmt *fmt, char *s2, double f)
118
{
119
	char s1[NSIGNIF+10];
120
	double g, h;
121
	int e, d, i, n;
122
	int c1, c2, c3, c4, ucase, sign, chr, prec;
123
 
124
	prec = FDEFLT;
125
	if(fmt->flags & FmtPrec)
126
		prec = fmt->prec;
127
	if(prec > FDIGIT)
128
		prec = FDIGIT;
129
	if(__isNaN(f)) {
130
		strcpy(s2, "NaN");
131
		return;
132
	}
133
	if(__isInf(f, 1)) {
134
		strcpy(s2, "+Inf");
135
		return;
136
	}
137
	if(__isInf(f, -1)) {
138
		strcpy(s2, "-Inf");
139
		return;
140
	}
141
	sign = 0;
142
	if(f < 0) {
143
		f = -f;
144
		sign++;
145
	}
146
	ucase = 0;
147
	chr = fmt->r;
148
	if(isupper(chr)) {
149
		ucase = 1;
150
		chr = tolower(chr);
151
	}
152
 
153
	e = 0;
154
	g = f;
155
	if(g != 0) {
156
		frexp(f, &e);
157
		e = e * .301029995664;
158
		if(e >= -150 && e <= +150) {
159
			d = 0;
160
			h = f;
161
		} else {
162
			d = e/2;
163
			h = f * pow10(-d);
164
		}
165
		g = h * pow10(d-e);
166
		while(g < 1) {
167
			e--;
168
			g = h * pow10(d-e);
169
		}
170
		while(g >= 10) {
171
			e++;
172
			g = h * pow10(d-e);
173
		}
174
	}
175
 
176
	/*
177
	 * convert NSIGNIF digits and convert
178
	 * back to get accuracy.
179
	 */
180
	for(i=0; i<NSIGNIF; i++) {
181
		d = g;
182
		s1[i] = d + '0';
183
		g = (g - d) * 10;
184
	}
185
	s1[i] = 0;
186
 
187
	/*
188
	 * try decimal rounding to eliminate 9s
189
	 */
190
	c2 = prec + 1;
191
	if(chr == 'f')
192
		c2 += e;
193
	if(c2 >= NSIGNIF-2) {
194
		strcpy(s2, s1);
195
		d = e;
196
		s1[NSIGNIF-2] = '0';
197
		s1[NSIGNIF-1] = '0';
198
		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
199
		g = strtod(s1, nil);
200
		if(g == f)
201
			goto found;
202
		if(xadd(s1, NSIGNIF-3, 1)) {
203
			e++;
204
			sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
205
		}
206
		g = strtod(s1, nil);
207
		if(g == f)
208
			goto found;
209
		strcpy(s1, s2);
210
		e = d;
211
	}
212
 
213
	/*
214
	 * convert back so s1 gets exact answer
215
	 */
216
	for(;;) {
217
		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
218
		g = strtod(s1, nil);
219
		if(f > g) {
220
			if(xadd(s1, NSIGNIF-1, 1))
221
				e--;
222
			continue;
223
		}
224
		if(f < g) {
225
			if(xsub(s1, NSIGNIF-1, 1))
226
				e++;
227
			continue;
228
		}
229
		break;
230
	}
231
 
232
found:
233
	/*
234
	 * sign
235
	 */
236
	d = 0;
237
	i = 0;
238
	if(sign)
239
		s2[d++] = '-';
240
	else if(fmt->flags & FmtSign)
241
		s2[d++] = '+';
242
	else if(fmt->flags & FmtSpace)
243
		s2[d++] = ' ';
244
 
245
	/*
246
	 * copy into final place
247
	 * c1 digits of leading '0'
248
	 * c2 digits from conversion
249
	 * c3 digits of trailing '0'
250
	 * c4 digits after '.'
251
	 */
252
	c1 = 0;
253
	c2 = prec + 1;
254
	c3 = 0;
255
	c4 = prec;
256
	switch(chr) {
257
	default:
258
		if(xadd(s1, c2, 5))
259
			e++;
260
		break;
261
	case 'g':
262
		/*
263
		 * decide on 'e' of 'f' style convers
264
		 */
265
		if(xadd(s1, c2, 5))
266
			e++;
267
		if(e >= -5 && e <= prec) {
268
			c1 = -e - 1;
269
			c4 = prec - e;
270
			chr = 'h';	// flag for 'f' style
271
		}
272
		break;
273
	case 'f':
274
		if(xadd(s1, c2+e, 5))
275
			e++;
276
		c1 = -e;
277
		if(c1 > prec)
278
			c1 = c2;
279
		c2 += e;
280
		break;
281
	}
282
 
283
	/*
284
	 * clean up c1 c2 and c3
285
	 */
286
	if(c1 < 0)
287
		c1 = 0;
288
	if(c2 < 0)
289
		c2 = 0;
290
	if(c2 > NSIGNIF) {
291
		c3 = c2-NSIGNIF;
292
		c2 = NSIGNIF;
293
	}
294
 
295
	/*
296
	 * copy digits
297
	 */
298
	while(c1 > 0) {
299
		if(c1+c2+c3 == c4)
300
			s2[d++] = '.';
301
		s2[d++] = '0';
302
		c1--;
303
	}
304
	while(c2 > 0) {
305
		if(c2+c3 == c4)
306
			s2[d++] = '.';
307
		s2[d++] = s1[i++];
308
		c2--;
309
	}
310
	while(c3 > 0) {
311
		if(c3 == c4)
312
			s2[d++] = '.';
313
		s2[d++] = '0';
314
		c3--;
315
	}
316
 
317
	/*
318
	 * strip trailing '0' on g conv
319
	 */
320
	if(fmt->flags & FmtSharp) {
321
		if(0 == c4)
322
			s2[d++] = '.';
323
	} else
324
	if(chr == 'g' || chr == 'h') {
325
		for(n=d-1; n>=0; n--)
326
			if(s2[n] != '0')
327
				break;
328
		for(i=n; i>=0; i--)
329
			if(s2[i] == '.') {
330
				d = n;
331
				if(i != n)
332
					d++;
333
				break;
334
			}
335
	}
336
	if(chr == 'e' || chr == 'g') {
337
		if(ucase)
338
			s2[d++] = 'E';
339
		else
340
			s2[d++] = 'e';
341
		c1 = e;
342
		if(c1 < 0) {
343
			s2[d++] = '-';
344
			c1 = -c1;
345
		} else
346
			s2[d++] = '+';
347
		if(c1 >= 100) {
348
			s2[d++] = c1/100 + '0';
349
			c1 = c1%100;
350
		}
351
		s2[d++] = c1/10 + '0';
352
		s2[d++] = c1%10 + '0';
353
	}
354
	s2[d] = 0;
355
}
356
 
357
static int
358
floatfmt(Fmt *fmt, double f)
359
{
360
	char s[341];		/* precision+exponent+sign+'.'+null */
361
 
362
	xdtoa(fmt, s, f);
363
	fmt->flags &= FmtWidth|FmtLeft;
364
	__fmtcpy(fmt, s, strlen(s), strlen(s));
365
	return 0;
366
}
367
 
368
int
369
__efgfmt(Fmt *f)
370
{
371
	double d;
372
 
373
	d = va_arg(f->args, double);
374
	return floatfmt(f, d);
375
}