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