Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/ape/lib/fmt/fltfmt.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * The authors of this software are Rob Pike and Ken Thompson.
3
 *              Copyright (c) 2002 by Lucent Technologies.
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose without fee is hereby granted, provided that this entire notice
6
 * is included in all copies of any software which is or includes a copy
7
 * or modification of this software and in all copies of the supporting
8
 * documentation for such software.
9
 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10
 * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
11
 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12
 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13
 */
14
#include <stdio.h>
15
#include <math.h>
16
#include <float.h>
17
#include <string.h>
18
#include <stdlib.h>
19
#include <errno.h>
20
#include <stdarg.h>
21
#include "fmt.h"
22
#include "fmtdef.h"
23
#include "nan.h"
24
 
25
enum
26
{
27
	FDEFLT	= 6,
28
	NSIGNIF	= 17
29
};
30
 
31
/*
32
 * first few powers of 10, enough for about 1/2 of the
33
 * total space for doubles.
34
 */
35
static double pows10[] =
36
{
37
	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,  
38
	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,  
39
	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,  
40
	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,  
41
	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,  
42
	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,  
43
	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,  
44
	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,  
45
	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,  
46
	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,  
47
	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 
48
	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 
49
	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 
50
	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 
51
	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 
52
	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 
53
};
54
 
55
static double
56
pow10(int n)
57
{
58
	double d;
59
	int neg;
60
 
61
	neg = 0;
62
	if(n < 0){
63
		if(n < DBL_MIN_10_EXP){
64
			return 0.;
65
		}
66
		neg = 1;
67
		n = -n;
68
	}else if(n > DBL_MAX_10_EXP){
69
		return HUGE_VAL;
70
	}
71
	if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
72
		d = pows10[n];
73
	else{
74
		d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
75
		for(;;){
76
			n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
77
			if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
78
				d *= pows10[n];
79
				break;
80
			}
81
			d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
82
		}
83
	}
84
	if(neg){
85
		return 1./d;
86
	}
87
	return d;
88
}
89
 
90
static int
91
xadd(char *a, int n, int v)
92
{
93
	char *b;
94
	int c;
95
 
96
	if(n < 0 || n >= NSIGNIF)
97
		return 0;
98
	for(b = a+n; b >= a; b--) {
99
		c = *b + v;
100
		if(c <= '9') {
101
			*b = c;
102
			return 0;
103
		}
104
		*b = '0';
105
		v = 1;
106
	}
107
	*a = '1';	/* overflow adding */
108
	return 1;
109
}
110
 
111
static int
112
xsub(char *a, int n, int v)
113
{
114
	char *b;
115
	int c;
116
 
117
	for(b = a+n; b >= a; b--) {
118
		c = *b - v;
119
		if(c >= '0') {
120
			*b = c;
121
			return 0;
122
		}
123
		*b = '9';
124
		v = 1;
125
	}
126
	*a = '9';	/* underflow subtracting */
127
	return 1;
128
}
129
 
130
static void
131
xaddexp(char *p, int e)
132
{
133
	char se[9];
134
	int i;
135
 
136
	*p++ = 'e';
137
	if(e < 0) {
138
		*p++ = '-';
139
		e = -e;
140
	}
141
	i = 0;
142
	while(e) {
143
		se[i++] = e % 10 + '0';
144
		e /= 10;
145
	}
146
	if(i == 0) {
147
		*p++ = '0';
148
	} else {
149
		while(i > 0)
150
			*p++ = se[--i];
151
	}
152
	*p = '\0';
153
}
154
 
155
static char*
156
xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
157
{
158
	char s2[NSIGNIF+10];
159
	double g, h;
160
	int e, d, i;
161
	int c2, sign, oerr;
162
 
163
	if(chr == 'F')
164
		chr = 'f';
165
	if(prec > NSIGNIF)
166
		prec = NSIGNIF;
167
	if(prec < 0)
168
		prec = 0;
169
	if(__isNaN(f)) {
170
		*decpt = 9999;
171
		*rsign = 0;
172
		strcpy(s1, "nan");
173
		return &s1[3];
174
	}
175
	sign = 0;
176
	if(f < 0) {
177
		f = -f;
178
		sign++;
179
	}
180
	*rsign = sign;
181
	if(__isInf(f, 1) || __isInf(f, -1)) {
182
		*decpt = 9999;
183
		strcpy(s1, "inf");
184
		return &s1[3];
185
	}
186
 
187
	e = 0;
188
	g = f;
189
	if(g != 0) {
190
		frexp(f, &e);
191
		e = (int)(e * .301029995664);
192
		if(e >= -150 && e <= +150) {
193
			d = 0;
194
			h = f;
195
		} else {
196
			d = e/2;
197
			h = f * pow10(-d);
198
		}
199
		g = h * pow10(d-e);
200
		while(g < 1) {
201
			e--;
202
			g = h * pow10(d-e);
203
		}
204
		while(g >= 10) {
205
			e++;
206
			g = h * pow10(d-e);
207
		}
208
	}
209
 
210
	/*
211
	 * convert NSIGNIF digits and convert
212
	 * back to get accuracy.
213
	 */
214
	for(i=0; i<NSIGNIF; i++) {
215
		d = (int)g;
216
		s1[i] = d + '0';
217
		g = (g - d) * 10;
218
	}
219
	s1[i] = 0;
220
 
221
	/*
222
	 * try decimal rounding to eliminate 9s
223
	 */
224
	c2 = prec + 1;
225
	if(chr == 'f')
226
		c2 += e;
227
	oerr = errno;
228
	if(c2 >= NSIGNIF-2) {
229
		strcpy(s2, s1);
230
		d = e;
231
		s1[NSIGNIF-2] = '0';
232
		s1[NSIGNIF-1] = '0';
233
		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
234
		g = fmtstrtod(s1, nil);
235
		if(g == f)
236
			goto found;
237
		if(xadd(s1, NSIGNIF-3, 1)) {
238
			e++;
239
			xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
240
		}
241
		g = fmtstrtod(s1, nil);
242
		if(g == f)
243
			goto found;
244
		strcpy(s1, s2);
245
		e = d;
246
	}
247
 
248
	/*
249
	 * convert back so s1 gets exact answer
250
	 */
251
	for(d = 0; d < 10; d++) {
252
		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
253
		g = fmtstrtod(s1, nil);
254
		if(f > g) {
255
			if(xadd(s1, NSIGNIF-1, 1))
256
				e--;
257
			continue;
258
		}
259
		if(f < g) {
260
			if(xsub(s1, NSIGNIF-1, 1))
261
				e++;
262
			continue;
263
		}
264
		break;
265
	}
266
 
267
found:
268
	errno = oerr;
269
 
270
	/*
271
	 * round & adjust 'f' digits
272
	 */
273
	c2 = prec + 1;
274
	if(chr == 'f'){
275
		if(xadd(s1, c2+e, 5))
276
			e++;
277
		c2 += e;
278
		if(c2 < 0){
279
			c2 = 0;
280
			e = -prec - 1;
281
		}
282
	}else{
283
		if(xadd(s1, c2, 5))
284
			e++;
285
	}
286
	if(c2 > NSIGNIF){
287
		c2 = NSIGNIF;
288
	}
289
 
290
	*decpt = e + 1;
291
 
292
	/*
293
	 * terminate the converted digits
294
	 */
295
	s1[c2] = '\0';
296
	return &s1[c2];
297
}
298
 
299
/*
300
 * this function works like the standard dtoa, if you want it.
301
 */
302
#if 0
303
static char*
304
__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
305
{
306
	static char s2[NSIGNIF + 10];
307
	char *es;
308
	int chr, prec;
309
 
310
	switch(mode) {
311
	/* like 'e' */
312
	case 2:
313
	case 4:
314
	case 6:
315
	case 8:
316
		chr = 'e';
317
		break;
318
	/* like 'g' */
319
	case 0:
320
	case 1:
321
	default:
322
		chr = 'g';
323
		break;
324
	/* like 'f' */
325
	case 3:
326
	case 5:
327
	case 7:
328
	case 9:
329
		chr = 'f';
330
		break;
331
	}
332
 
333
	if(chr != 'f' && ndigits){
334
		ndigits--;
335
	}
336
	prec = ndigits;
337
	if(prec > NSIGNIF)
338
		prec = NSIGNIF;
339
	if(ndigits == 0)
340
		prec = NSIGNIF;
341
	es = xdodtoa(s2, f, chr, prec, decpt, rsign);
342
 
343
	/*
344
	 * strip trailing 0
345
	 */
346
	for(; es > s2 + 1; es--){
347
		if(es[-1] != '0'){
348
			break;
349
		}
350
	}
351
	*es = '\0';
352
	if(rve != NULL)
353
		*rve = es;
354
	return s2;
355
}
356
#endif
357
 
358
static int
359
fmtzdotpad(Fmt *f, int n, int pt)
360
{
361
	char *t, *s;
362
	int i;
363
	Rune *rt, *rs;
364
 
365
	if(f->runes){
366
		rt = (Rune*)f->to;
367
		rs = (Rune*)f->stop;
368
		for(i = 0; i < n; i++){
369
			if(i == pt){
370
				FMTRCHAR(f, rt, rs, '.');
371
			}
372
			FMTRCHAR(f, rt, rs, '0');
373
		}
374
		f->nfmt += rt - (Rune*)f->to;
375
		f->to = rt;
376
	}else{
377
		t = (char*)f->to;
378
		s = (char*)f->stop;
379
		for(i = 0; i < n; i++){
380
			if(i == pt){
381
				FMTCHAR(f, t, s, '.');
382
			}
383
			FMTCHAR(f, t, s, '0');
384
		}
385
		f->nfmt += t - (char *)f->to;
386
		f->to = t;
387
	}
388
	return 0;
389
}
390
 
391
int
392
__efgfmt(Fmt *fmt)
393
{
394
	double f;
395
	char s1[NSIGNIF+10];
396
	int e, d, n;
397
	int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
398
 
399
	f = va_arg(fmt->args, double);
400
	prec = FDEFLT;
401
	fl = fmt->flags;
402
	fmt->flags = 0;
403
	if(fl & FmtPrec)
404
		prec = fmt->prec;
405
	chr = fmt->r;
406
	ucase = 0;
407
	if(chr == 'E'){
408
		chr = 'e';
409
		ucase = 1;
410
	}else if(chr == 'F'){
411
		chr = 'f';
412
		ucase = 1;
413
	}else if(chr == 'G'){
414
		chr = 'g';
415
		ucase = 1;
416
	}
417
	if(prec > 0 && chr == 'g')
418
		prec--;
419
	if(prec < 0)
420
		prec = 0;
421
 
422
	xdodtoa(s1, f, chr, prec, &e, &sign);
423
	e--;
424
	if(*s1 == 'i' || *s1 == 'n'){
425
		if(ucase){
426
			if(*s1 == 'i'){
427
				strcpy(s1, "INF");
428
			}else{
429
				strcpy(s1, "NAN");
430
			}
431
		}
432
		fmt->flags = fl & (FmtWidth|FmtLeft);
433
		return __fmtcpy(fmt, (const void*)s1, 3, 3);
434
	}
435
 
436
	/*
437
	 * copy into final place
438
	 * c1 digits of leading '0'
439
	 * c2 digits from conversion
440
	 * c3 digits of trailing '0'
441
	 * c4 digits after '.'
442
	 */
443
	c1 = 0;
444
	c2 = prec + 1;
445
	c3 = 0;
446
	c4 = prec;
447
	switch(chr) {
448
	default:
449
		chr = 'e';
450
		break;
451
	case 'g':
452
		/*
453
		 * decide on 'e' of 'f' style convers
454
		 */
455
		if(e >= -4 && e <= prec) {
456
			c1 = -e;
457
			c4 = prec - e;
458
			chr = 'h';	/* flag for 'f' style */
459
		}
460
		break;
461
	case 'f':
462
		c1 = -e;
463
		if(c1 > prec)
464
			c1 = prec + 1;
465
		c2 += e;
466
		break;
467
	}
468
 
469
	/*
470
	 * clean up c1 c2 and c3
471
	 */
472
	if(c1 < 0)
473
		c1 = 0;
474
	if(c2 < 0)
475
		c2 = 0;
476
	if(c2 > NSIGNIF) {
477
		c3 = c2-NSIGNIF;
478
		c2 = NSIGNIF;
479
	}
480
 
481
	/*
482
	 * trim trailing zeros for %g
483
	 */
484
	if(!(fl & FmtSharp)
485
	&& (chr == 'g' || chr == 'h')){
486
		if(c4 >= c3){
487
			c4 -= c3;
488
			c3 = 0;
489
		}else{
490
			c3 -= c4;
491
			c4 = 0;
492
		}
493
		while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
494
			c4--;
495
			c2--;
496
		}
497
	}
498
 
499
	/*
500
	 * calculate the total length
501
	 */
502
	n = c1 + c2 + c3;
503
	if(sign || (fl & (FmtSign|FmtSpace)))
504
		n++;
505
	if(c4 || (fl & FmtSharp)){
506
		n++;
507
	}
508
	if(chr == 'e' || chr == 'g'){
509
		n += 4;
510
		if(e >= 100)
511
			n++;
512
	}
513
 
514
	/*
515
	 * pad to width if right justified
516
	 */
517
	if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
518
		if(fl & FmtZero){
519
			c1 += fmt->width - n;
520
		}else{
521
			if(__fmtpad(fmt, fmt->width - n) < 0){
522
				return -1;
523
			}
524
		}
525
	}
526
 
527
	/*
528
	 * sign
529
	 */
530
	d = 0;
531
	if(sign)
532
		d = '-';
533
	else if(fl & FmtSign)
534
		d = '+';
535
	else if(fl & FmtSpace)
536
		d = ' ';
537
	if(d && fmtrune(fmt, d) < 0){
538
		return -1;
539
	}
540
 
541
	/*
542
	 * copy digits
543
	 */
544
	c4 = c1 + c2 + c3 - c4;
545
	if(c1 > 0){
546
		if(fmtzdotpad(fmt, c1, c4) < 0){
547
			return -1;
548
		}
549
		c4 -= c1;
550
	}
551
	d = 0;
552
	if(c4 >= 0 && c4 < c2){
553
		if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
554
			return -1;
555
		d = c4;
556
		c2 -= c4;
557
		c4 = -1;
558
	}
559
	if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
560
		return -1;
561
	}
562
	c4 -= c2;
563
	if(c3 > 0){
564
		if(fmtzdotpad(fmt, c3, c4) < 0){
565
			return -1;
566
		}
567
		c4 -= c3;
568
	}
569
 
570
	/*
571
	 * strip trailing '0' on g conv
572
	 */
573
	if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
574
		return -1;
575
	}
576
	if(chr == 'e' || chr == 'g') {
577
		d = 0;
578
		if(ucase)
579
			s1[d++] = 'E';
580
		else
581
			s1[d++] = 'e';
582
		c1 = e;
583
		if(c1 < 0) {
584
			s1[d++] = '-';
585
			c1 = -c1;
586
		} else
587
			s1[d++] = '+';
588
		if(c1 >= 100) {
589
			s1[d++] = c1/100 + '0';
590
			c1 = c1%100;
591
		}
592
		s1[d++] = c1/10 + '0';
593
		s1[d++] = c1%10 + '0';
594
		if(__fmtcpy(fmt, s1, d, d) < 0){
595
			return -1;
596
		}
597
	}
598
	if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
599
		if(__fmtpad(fmt, fmt->width - n) < 0){
600
			return -1;
601
		}
602
	}
603
	return 0;
604
}