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