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