| ---
tfltfmt.c (12809B)
---
1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include "plan9.h"
12 #include "fmt.h"
13 #include "fmtdef.h"
14 #include "nan.h"
15
16 enum
17 {
18 FDIGIT = 30,
19 FDEFLT = 6,
20 NSIGNIF = 17
21 };
22
23 /*
24 * first few powers of 10, enough for about 1/2 of the
25 * total space for doubles.
26 */
27 static double pows10[] =
28 {
29 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
30 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
31 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
32 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
33 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
34 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
35 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
36 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
37 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
38 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
39 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
40 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
41 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
42 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
43 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
44 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
45 };
46 #define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
47 #define pow10(x) fmtpow10(x)
48
49 static double
50 pow10(int n)
51 {
52 double d;
53 int neg;
54
55 neg = 0;
56 if(n < 0){
57 neg = 1;
58 n = -n;
59 }
60
61 if(n < npows10)
62 d = pows10[n];
63 else{
64 d = pows10[npows10-1];
65 for(;;){
66 n -= npows10 - 1;
67 if(n < npows10){
68 d *= pows10[n];
69 break;
70 }
71 d *= pows10[npows10 - 1];
72 }
73 }
74 if(neg)
75 return 1./d;
76 return d;
77 }
78
79 /*
80 * add 1 to the decimal integer string a of length n.
81 * if 99999 overflows into 10000, return 1 to tell caller
82 * to move the virtual decimal point.
83 */
84 static int
85 xadd1(char *a, int n)
86 {
87 char *b;
88 int c;
89
90 if(n < 0 || n > NSIGNIF)
91 return 0;
92 for(b = a+n-1; b >= a; b--) {
93 c = *b + 1;
94 if(c <= '9') {
95 *b = c;
96 return 0;
97 }
98 *b = '0';
99 }
100 /*
101 * need to overflow adding digit.
102 * shift number down and insert 1 at beginning.
103 * decimal is known to be 0s or we wouldn't
104 * have gotten this far. (e.g., 99999+1 => 00000)
105 */
106 a[0] = '1';
107 return 1;
108 }
109
110 /*
111 * subtract 1 from the decimal integer string a.
112 * if 10000 underflows into 09999, make it 99999
113 * and return 1 to tell caller to move the virtual
114 * decimal point. this way, xsub1 is inverse of xadd1.
115 */
116 static int
117 xsub1(char *a, int n)
118 {
119 char *b;
120 int c;
121
122 if(n < 0 || n > NSIGNIF)
123 return 0;
124 for(b = a+n-1; b >= a; b--) {
125 c = *b - 1;
126 if(c >= '0') {
127 if(c == '0' && b == a) {
128 /*
129 * just zeroed the top digit; shift everyone up.
130 * decimal is known to be 9s or we wouldn't
131 * have gotten this far. (e.g., 10000-1 => 09999)
132 */
133 *b = '9';
134 return 1;
135 }
136 *b = c;
137 return 0;
138 }
139 *b = '9';
140 }
141 /*
142 * can't get here. the number a is always normalized
143 * so that it has a nonzero first digit.
144 */
145 abort();
146 }
147
148 /*
149 * format exponent like sprintf(p, "e%+02d", e)
150 */
151 static void
152 xfmtexp(char *p, int e, int ucase)
153 {
154 char se[9];
155 int i;
156
157 *p++ = ucase ? 'E' : 'e';
158 if(e < 0) {
159 *p++ = '-';
160 e = -e;
161 } else
162 *p++ = '+';
163 i = 0;
164 while(e) {
165 se[i++] = e % 10 + '0';
166 e /= 10;
167 }
168 while(i < 2)
169 se[i++] = '0';
170 while(i > 0)
171 *p++ = se[--i];
172 *p++ = '\0';
173 }
174
175 /*
176 * compute decimal integer m, exp such that:
177 * f = m*10^exp
178 * m is as short as possible with losing exactness
179 * assumes special cases (NaN, +Inf, -Inf) have been handled.
180 */
181 static void
182 xdtoa(double f, char *s, int *exp, int *neg, int *ns)
183 {
184 int c, d, e2, e, ee, i, ndigit, oerrno;
185 char tmp[NSIGNIF+10];
186 double g;
187
188 oerrno = errno; /* in case strtod smashes errno */
189
190 /*
191 * make f non-negative.
192 */
193 *neg = 0;
194 if(f < 0) {
195 f = -f;
196 *neg = 1;
197 }
198
199 /*
200 * must handle zero specially.
201 */
202 if(f == 0){
203 *exp = 0;
204 s[0] = '0';
205 s[1] = '\0';
206 *ns = 1;
207 return;
208 }
209
210 /*
211 * find g,e such that f = g*10^e.
212 * guess 10-exponent using 2-exponent, then fine tune.
213 */
214 frexp(f, &e2);
215 e = (int)(e2 * .301029995664);
216 g = f * pow10(-e);
217 while(g < 1) {
218 e--;
219 g = f * pow10(-e);
220 }
221 while(g >= 10) {
222 e++;
223 g = f * pow10(-e);
224 }
225
226 /*
227 * convert NSIGNIF digits as a first approximation.
228 */
229 for(i=0; i g) {
248 if(xadd1(s, NSIGNIF)) {
249 /* gained a digit */
250 e--;
251 xfmtexp(s+NSIGNIF, e, 0);
252 }
253 continue;
254 }
255 if(f < g) {
256 if(xsub1(s, NSIGNIF)) {
257 /* lost a digit */
258 e++;
259 xfmtexp(s+NSIGNIF, e, 0);
260 }
261 continue;
262 }
263 break;
264 }
265
266 /*
267 * play with the decimal to try to simplify.
268 */
269
270 /*
271 * bump last few digits up to 9 if we can
272 */
273 for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
274 c = s[i];
275 if(c != '9') {
276 s[i] = '9';
277 g = fmtstrtod(s, nil);
278 if(g != f) {
279 s[i] = c;
280 break;
281 }
282 }
283 }
284
285 /*
286 * add 1 in hopes of turning 9s to 0s
287 */
288 if(s[NSIGNIF-1] == '9') {
289 strcpy(tmp, s);
290 ee = e;
291 if(xadd1(tmp, NSIGNIF)) {
292 ee--;
293 xfmtexp(tmp+NSIGNIF, ee, 0);
294 }
295 g = fmtstrtod(tmp, nil);
296 if(g == f) {
297 strcpy(s, tmp);
298 e = ee;
299 }
300 }
301
302 /*
303 * bump last few digits down to 0 as we can.
304 */
305 for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
306 c = s[i];
307 if(c != '0') {
308 s[i] = '0';
309 g = fmtstrtod(s, nil);
310 if(g != f) {
311 s[i] = c;
312 break;
313 }
314 }
315 }
316
317 /*
318 * remove trailing zeros.
319 */
320 ndigit = NSIGNIF;
321 while(ndigit > 1 && s[ndigit-1] == '0'){
322 e++;
323 --ndigit;
324 }
325 s[ndigit] = 0;
326 *exp = e;
327 *ns = ndigit;
328 errno = oerrno;
329 }
330
331 #ifdef PLAN9PORT
332 static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
333 #else
334 static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
335 #endif
336
337 int
338 __efgfmt(Fmt *fmt)
339 {
340 char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
341 double f;
342 int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
343 int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
344 Rune r, *rs, *rt;
345
346 if(fmt->flags&FmtLong)
347 f = va_arg(fmt->args, long double);
348 else
349 f = va_arg(fmt->args, double);
350
351 /*
352 * extract formatting flags
353 */
354 fl = fmt->flags;
355 fmt->flags = 0;
356 prec = FDEFLT;
357 if(fl & FmtPrec)
358 prec = fmt->prec;
359 chr = fmt->r;
360 ucase = 0;
361 switch(chr) {
362 case 'A':
363 case 'E':
364 case 'F':
365 case 'G':
366 chr += 'a'-'A';
367 ucase = 1;
368 break;
369 }
370
371 /*
372 * pick off special numbers.
373 */
374 if(__isNaN(f)) {
375 s = special[0+ucase];
376 special:
377 fmt->flags = fl & (FmtWidth|FmtLeft);
378 return __fmtcpy(fmt, s, strlen(s), strlen(s));
379 }
380 if(__isInf(f, 1)) {
381 s = special[2+ucase];
382 goto special;
383 }
384 if(__isInf(f, -1)) {
385 s = special[4+ucase];
386 goto special;
387 }
388
389 /*
390 * get exact representation.
391 */
392 digits = buf;
393 xdtoa(f, digits, &exp, &neg, &ndigits);
394
395 /*
396 * get locale's decimal point.
397 */
398 dot = fmt->decimal;
399 if(dot == nil)
400 dot = ".";
401 dotwid = utflen(dot);
402
403 /*
404 * now the formatting fun begins.
405 * compute parameters for actual fmt:
406 *
407 * pad: number of spaces to insert before/after field.
408 * z1: number of zeros to insert before digits
409 * z2: number of zeros to insert after digits
410 * point: number of digits to print before decimal point
411 * ndigits: number of digits to use from digits[]
412 * suf: trailing suffix, like "e-5"
413 */
414 realchr = chr;
415 switch(chr){
416 case 'g':
417 /*
418 * convert to at most prec significant digits. (prec=0 means 1)
419 */
420 if(prec == 0)
421 prec = 1;
422 if(ndigits > prec) {
423 if(digits[prec] >= '5' && xadd1(digits, prec))
424 exp++;
425 exp += ndigits-prec;
426 ndigits = prec;
427 }
428
429 /*
430 * extra rules for %g (implemented below):
431 * trailing zeros removed after decimal unless FmtSharp.
432 * decimal point only if digit follows.
433 */
434
435 /* fall through to %e */
436 default:
437 case 'e':
438 /*
439 * one significant digit before decimal, no leading zeros.
440 */
441 point = 1;
442 z1 = 0;
443
444 /*
445 * decimal point is after ndigits digits right now.
446 * slide to be after first.
447 */
448 e = exp + (ndigits-1);
449
450 /*
451 * if this is %g, check exponent and convert prec
452 */
453 if(realchr == 'g') {
454 if(-4 <= e && e < prec)
455 goto casef;
456 prec--; /* one digit before decimal; rest after */
457 }
458
459 /*
460 * compute trailing zero padding or truncate digits.
461 */
462 if(1+prec >= ndigits)
463 z2 = 1+prec - ndigits;
464 else {
465 /*
466 * truncate digits
467 */
468 assert(realchr != 'g');
469 newndigits = 1+prec;
470 if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
471 /*
472 * had 999e4, now have 100e5
473 */
474 e++;
475 }
476 ndigits = newndigits;
477 z2 = 0;
478 }
479 xfmtexp(suf, e, ucase);
480 sufwid = strlen(suf);
481 break;
482
483 casef:
484 case 'f':
485 /*
486 * determine where digits go with respect to decimal point
487 */
488 if(ndigits+exp > 0) {
489 point = ndigits+exp;
490 z1 = 0;
491 } else {
492 point = 1;
493 z1 = 1 + -(ndigits+exp);
494 }
495
496 /*
497 * %g specifies prec = number of significant digits
498 * convert to number of digits after decimal point
499 */
500 if(realchr == 'g')
501 prec += z1 - point;
502
503 /*
504 * compute trailing zero padding or truncate digits.
505 */
506 if(point+prec >= z1+ndigits)
507 z2 = point+prec - (z1+ndigits);
508 else {
509 /*
510 * truncate digits
511 */
512 assert(realchr != 'g');
513 newndigits = point+prec - z1;
514 if(newndigits < 0) {
515 z1 += newndigits;
516 newndigits = 0;
517 } else if(newndigits == 0) {
518 /* perhaps round up */
519 if(digits[0] >= '5'){
520 digits[0] = '1';
521 newndigits = 1;
522 goto newdigit;
523 }
524 } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
525 /*
526 * digits was 999, is now 100; make it 1000
527 */
528 digits[newndigits++] = '0';
529 newdigit:
530 /*
531 * account for new digit
532 */
533 if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
534 z1--;
535 else /* 9.99 => 10.00 */
536 point++;
537 }
538 z2 = 0;
539 ndigits = newndigits;
540 }
541 sufwid = 0;
542 break;
543 }
544
545 /*
546 * if %g is given without FmtSharp, remove trailing zeros.
547 * must do after truncation, so that e.g. print %.3g 1.001
548 * produces 1, not 1.00. sorry, but them's the rules.
549 */
550 if(realchr == 'g' && !(fl & FmtSharp)) {
551 if(z1+ndigits+z2 >= point) {
552 if(z1+ndigits < point)
553 z2 = point - (z1+ndigits);
554 else{
555 z2 = 0;
556 while(z1+ndigits > point && digits[ndigits-1] == '0')
557 ndigits--;
558 }
559 }
560 }
561
562 /*
563 * compute width of all digits and decimal point and suffix if any
564 */
565 wid = z1+ndigits+z2;
566 if(wid > point)
567 wid += dotwid;
568 else if(wid == point){
569 if(fl & FmtSharp)
570 wid += dotwid;
571 else
572 point++; /* do not print any decimal point */
573 }
574 wid += sufwid;
575
576 /*
577 * determine sign
578 */
579 sign = 0;
580 if(neg)
581 sign = '-';
582 else if(fl & FmtSign)
583 sign = '+';
584 else if(fl & FmtSpace)
585 sign = ' ';
586 if(sign)
587 wid++;
588
589 /*
590 * compute padding
591 */
592 pad = 0;
593 if((fl & FmtWidth) && fmt->width > wid)
594 pad = fmt->width - wid;
595 if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
596 z1 += pad;
597 point += pad;
598 pad = 0;
599 }
600
601 /*
602 * format the actual field. too bad about doing this twice.
603 */
604 if(fmt->runes){
605 if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
606 return -1;
607 rt = (Rune*)fmt->to;
608 rs = (Rune*)fmt->stop;
609 if(sign)
610 FMTRCHAR(fmt, rt, rs, sign);
611 while(z1>0 || ndigits>0 || z2>0) {
612 if(z1 > 0){
613 z1--;
614 c = '0';
615 }else if(ndigits > 0){
616 ndigits--;
617 c = *digits++;
618 }else{
619 z2--;
620 c = '0';
621 }
622 FMTRCHAR(fmt, rt, rs, c);
623 if(--point == 0) {
624 for(p = dot; *p; ){
625 p += chartorune(&r, p);
626 FMTRCHAR(fmt, rt, rs, r);
627 }
628 }
629 }
630 fmt->nfmt += rt - (Rune*)fmt->to;
631 fmt->to = rt;
632 if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
633 return -1;
634 if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
635 return -1;
636 }else{
637 if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
638 return -1;
639 t = (char*)fmt->to;
640 s = (char*)fmt->stop;
641 if(sign)
642 FMTCHAR(fmt, t, s, sign);
643 while(z1>0 || ndigits>0 || z2>0) {
644 if(z1 > 0){
645 z1--;
646 c = '0';
647 }else if(ndigits > 0){
648 ndigits--;
649 c = *digits++;
650 }else{
651 z2--;
652 c = '0';
653 }
654 FMTCHAR(fmt, t, s, c);
655 if(--point == 0)
656 for(p=dot; *p; p++)
657 FMTCHAR(fmt, t, s, *p);
658 }
659 fmt->nfmt += t - (char*)fmt->to;
660 fmt->to = t;
661 if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
662 return -1;
663 if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
664 return -1;
665 }
666 return 0;
667 } |