github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/gc/mparith1.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include <u.h> 6 #include <libc.h> 7 #include "go.h" 8 9 /// uses arithmetic 10 11 int 12 mpcmpfixflt(Mpint *a, Mpflt *b) 13 { 14 char buf[500]; 15 Mpflt c; 16 17 snprint(buf, sizeof(buf), "%B", a); 18 mpatoflt(&c, buf); 19 return mpcmpfltflt(&c, b); 20 } 21 22 int 23 mpcmpfltfix(Mpflt *a, Mpint *b) 24 { 25 char buf[500]; 26 Mpflt c; 27 28 snprint(buf, sizeof(buf), "%B", b); 29 mpatoflt(&c, buf); 30 return mpcmpfltflt(a, &c); 31 } 32 33 int 34 mpcmpfixfix(Mpint *a, Mpint *b) 35 { 36 Mpint c; 37 38 mpmovefixfix(&c, a); 39 mpsubfixfix(&c, b); 40 return mptestfix(&c); 41 } 42 43 int 44 mpcmpfixc(Mpint *b, vlong c) 45 { 46 Mpint c1; 47 48 mpmovecfix(&c1, c); 49 return mpcmpfixfix(b, &c1); 50 } 51 52 int 53 mpcmpfltflt(Mpflt *a, Mpflt *b) 54 { 55 Mpflt c; 56 57 mpmovefltflt(&c, a); 58 mpsubfltflt(&c, b); 59 return mptestflt(&c); 60 } 61 62 int 63 mpcmpfltc(Mpflt *b, double c) 64 { 65 Mpflt a; 66 67 mpmovecflt(&a, c); 68 return mpcmpfltflt(b, &a); 69 } 70 71 void 72 mpsubfixfix(Mpint *a, Mpint *b) 73 { 74 mpnegfix(a); 75 mpaddfixfix(a, b, 0); 76 mpnegfix(a); 77 } 78 79 void 80 mpsubfltflt(Mpflt *a, Mpflt *b) 81 { 82 mpnegflt(a); 83 mpaddfltflt(a, b); 84 mpnegflt(a); 85 } 86 87 void 88 mpaddcfix(Mpint *a, vlong c) 89 { 90 Mpint b; 91 92 mpmovecfix(&b, c); 93 mpaddfixfix(a, &b, 0); 94 } 95 96 void 97 mpaddcflt(Mpflt *a, double c) 98 { 99 Mpflt b; 100 101 mpmovecflt(&b, c); 102 mpaddfltflt(a, &b); 103 } 104 105 void 106 mpmulcfix(Mpint *a, vlong c) 107 { 108 Mpint b; 109 110 mpmovecfix(&b, c); 111 mpmulfixfix(a, &b); 112 } 113 114 void 115 mpmulcflt(Mpflt *a, double c) 116 { 117 Mpflt b; 118 119 mpmovecflt(&b, c); 120 mpmulfltflt(a, &b); 121 } 122 123 void 124 mpdivfixfix(Mpint *a, Mpint *b) 125 { 126 Mpint q, r; 127 128 mpdivmodfixfix(&q, &r, a, b); 129 mpmovefixfix(a, &q); 130 } 131 132 void 133 mpmodfixfix(Mpint *a, Mpint *b) 134 { 135 Mpint q, r; 136 137 mpdivmodfixfix(&q, &r, a, b); 138 mpmovefixfix(a, &r); 139 } 140 141 void 142 mpcomfix(Mpint *a) 143 { 144 Mpint b; 145 146 mpmovecfix(&b, 1); 147 mpnegfix(a); 148 mpsubfixfix(a, &b); 149 } 150 151 void 152 mpmovefixflt(Mpflt *a, Mpint *b) 153 { 154 a->val = *b; 155 a->exp = 0; 156 mpnorm(a); 157 } 158 159 // convert (truncate) b to a. 160 // return -1 (but still convert) if b was non-integer. 161 static int 162 mpexactfltfix(Mpint *a, Mpflt *b) 163 { 164 Mpflt f; 165 166 *a = b->val; 167 mpshiftfix(a, b->exp); 168 if(b->exp < 0) { 169 f.val = *a; 170 f.exp = 0; 171 mpnorm(&f); 172 if(mpcmpfltflt(b, &f) != 0) 173 return -1; 174 } 175 return 0; 176 } 177 178 int 179 mpmovefltfix(Mpint *a, Mpflt *b) 180 { 181 Mpflt f; 182 int i; 183 184 if(mpexactfltfix(a, b) == 0) 185 return 0; 186 187 // try rounding down a little 188 f = *b; 189 f.val.a[0] = 0; 190 if(mpexactfltfix(a, &f) == 0) 191 return 0; 192 193 // try rounding up a little 194 for(i=1; i<Mpprec; i++) { 195 f.val.a[i]++; 196 if(f.val.a[i] != Mpbase) 197 break; 198 f.val.a[i] = 0; 199 } 200 mpnorm(&f); 201 if(mpexactfltfix(a, &f) == 0) 202 return 0; 203 204 return -1; 205 } 206 207 void 208 mpmovefixfix(Mpint *a, Mpint *b) 209 { 210 *a = *b; 211 } 212 213 void 214 mpmovefltflt(Mpflt *a, Mpflt *b) 215 { 216 *a = *b; 217 } 218 219 static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 }; 220 static void 221 mppow10flt(Mpflt *a, int p) 222 { 223 if(p < 0) 224 abort(); 225 if(p < nelem(tab)) { 226 mpmovecflt(a, tab[p]); 227 return; 228 } 229 mppow10flt(a, p>>1); 230 mpmulfltflt(a, a); 231 if(p & 1) 232 mpmulcflt(a, 10); 233 } 234 235 static void 236 mphextofix(Mpint *a, char *s, int n) 237 { 238 char *hexdigitp, *end, c; 239 long d; 240 int bit; 241 242 while(*s == '0') { 243 s++; 244 n--; 245 } 246 247 // overflow 248 if(4*n > Mpscale*Mpprec) { 249 a->ovf = 1; 250 return; 251 } 252 253 end = s+n-1; 254 for(hexdigitp=end; hexdigitp>=s; hexdigitp--) { 255 c = *hexdigitp; 256 if(c >= '0' && c <= '9') 257 d = c-'0'; 258 else if(c >= 'A' && c <= 'F') 259 d = c-'A'+10; 260 else 261 d = c-'a'+10; 262 263 bit = 4*(end - hexdigitp); 264 while(d > 0) { 265 if(d & 1) 266 a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale); 267 bit++; 268 d = d >> 1; 269 } 270 } 271 } 272 273 // 274 // floating point input 275 // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] 276 // 277 void 278 mpatoflt(Mpflt *a, char *as) 279 { 280 Mpflt b; 281 int dp, c, f, ef, ex, eb, base; 282 char *s, *start; 283 284 while(*as == ' ' || *as == '\t') 285 as++; 286 287 /* determine base */ 288 s = as; 289 base = -1; 290 while(base == -1) { 291 switch(*s++) { 292 case '-': 293 case '+': 294 break; 295 296 case '0': 297 if(*s == 'x') 298 base = 16; 299 else 300 base = 10; 301 break; 302 303 default: 304 base = 10; 305 } 306 } 307 308 s = as; 309 dp = 0; /* digits after decimal point */ 310 f = 0; /* sign */ 311 ex = 0; /* exponent */ 312 eb = 0; /* binary point */ 313 314 mpmovecflt(a, 0.0); 315 if(base == 16) { 316 start = nil; 317 for(;;) { 318 c = *s; 319 if(c == '-') { 320 f = 1; 321 s++; 322 } 323 else if(c == '+') { 324 s++; 325 } 326 else if(c == '0' && s[1] == 'x') { 327 s += 2; 328 start = s; 329 } 330 else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { 331 s++; 332 } 333 else { 334 break; 335 } 336 } 337 if(start == nil) 338 goto bad; 339 340 mphextofix(&a->val, start, s-start); 341 if(a->val.ovf) 342 goto bad; 343 a->exp = 0; 344 mpnorm(a); 345 } 346 for(;;) { 347 switch(c = *s++) { 348 default: 349 goto bad; 350 351 case '-': 352 f = 1; 353 354 case ' ': 355 case '\t': 356 case '+': 357 continue; 358 359 case '.': 360 if(base == 16) 361 goto bad; 362 dp = 1; 363 continue; 364 365 case '1': 366 case '2': 367 case '3': 368 case '4': 369 case '5': 370 case '6': 371 case '7': 372 case '8': 373 case '9': 374 case '0': 375 mpmulcflt(a, 10); 376 mpaddcflt(a, c-'0'); 377 if(dp) 378 dp++; 379 continue; 380 381 case 'P': 382 case 'p': 383 eb = 1; 384 385 case 'E': 386 case 'e': 387 ex = 0; 388 ef = 0; 389 for(;;) { 390 c = *s++; 391 if(c == '+' || c == ' ' || c == '\t') 392 continue; 393 if(c == '-') { 394 ef = 1; 395 continue; 396 } 397 if(c >= '0' && c <= '9') { 398 ex = ex*10 + (c-'0'); 399 if(ex > 1e8) { 400 yyerror("constant exponent out of range: %s", as); 401 errorexit(); 402 } 403 continue; 404 } 405 break; 406 } 407 if(ef) 408 ex = -ex; 409 410 case 0: 411 break; 412 } 413 break; 414 } 415 416 if(eb) { 417 if(dp) 418 goto bad; 419 mpsetexp(a, a->exp+ex); 420 goto out; 421 } 422 423 if(dp) 424 dp--; 425 if(mpcmpfltc(a, 0.0) != 0) { 426 if(ex >= dp) { 427 mppow10flt(&b, ex-dp); 428 mpmulfltflt(a, &b); 429 } else { 430 // 4 approximates least_upper_bound(log2(10)). 431 if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) { 432 mpmovecflt(a, 0.0); 433 } 434 else { 435 mppow10flt(&b, dp-ex); 436 mpdivfltflt(a, &b); 437 } 438 } 439 } 440 441 out: 442 if(f) 443 mpnegflt(a); 444 return; 445 446 bad: 447 yyerror("constant too large: %s", as); 448 mpmovecflt(a, 0.0); 449 } 450 451 // 452 // fixed point input 453 // required syntax is [+-][0[x]]d* 454 // 455 void 456 mpatofix(Mpint *a, char *as) 457 { 458 int c, f; 459 char *s, *s0; 460 461 s = as; 462 f = 0; 463 mpmovecfix(a, 0); 464 465 c = *s++; 466 switch(c) { 467 case '-': 468 f = 1; 469 470 case '+': 471 c = *s++; 472 if(c != '0') 473 break; 474 475 case '0': 476 goto oct; 477 } 478 479 while(c) { 480 if(c >= '0' && c <= '9') { 481 mpmulcfix(a, 10); 482 mpaddcfix(a, c-'0'); 483 c = *s++; 484 continue; 485 } 486 goto bad; 487 } 488 goto out; 489 490 oct: 491 c = *s++; 492 if(c == 'x' || c == 'X') 493 goto hex; 494 while(c) { 495 if(c >= '0' && c <= '7') { 496 mpmulcfix(a, 8); 497 mpaddcfix(a, c-'0'); 498 c = *s++; 499 continue; 500 } 501 goto bad; 502 } 503 goto out; 504 505 hex: 506 s0 = s; 507 c = *s; 508 while(c) { 509 if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { 510 s++; 511 c = *s; 512 continue; 513 } 514 goto bad; 515 } 516 mphextofix(a, s0, s-s0); 517 if(a->ovf) 518 goto bad; 519 520 out: 521 if(f) 522 mpnegfix(a); 523 return; 524 525 bad: 526 yyerror("constant too large: %s", as); 527 mpmovecfix(a, 0); 528 } 529 530 int 531 Bconv(Fmt *fp) 532 { 533 char buf[500], *p; 534 Mpint *xval, q, r, ten, sixteen; 535 int f, digit; 536 537 xval = va_arg(fp->args, Mpint*); 538 mpmovefixfix(&q, xval); 539 f = 0; 540 if(mptestfix(&q) < 0) { 541 f = 1; 542 mpnegfix(&q); 543 } 544 545 p = &buf[sizeof(buf)]; 546 *--p = 0; 547 if(fp->flags & FmtSharp) { 548 // Hexadecimal 549 mpmovecfix(&sixteen, 16); 550 for(;;) { 551 mpdivmodfixfix(&q, &r, &q, &sixteen); 552 digit = mpgetfix(&r); 553 if(digit < 10) 554 *--p = digit + '0'; 555 else 556 *--p = digit - 10 + 'A'; 557 if(mptestfix(&q) <= 0) 558 break; 559 } 560 *--p = 'x'; 561 *--p = '0'; 562 } else { 563 // Decimal 564 mpmovecfix(&ten, 10); 565 for(;;) { 566 mpdivmodfixfix(&q, &r, &q, &ten); 567 *--p = mpgetfix(&r) + '0'; 568 if(mptestfix(&q) <= 0) 569 break; 570 } 571 } 572 if(f) 573 *--p = '-'; 574 return fmtstrcpy(fp, p); 575 } 576 577 int 578 Fconv(Fmt *fp) 579 { 580 char buf[500]; 581 Mpflt *fvp, fv; 582 double d, dexp; 583 int exp; 584 585 fvp = va_arg(fp->args, Mpflt*); 586 if(fp->flags & FmtSharp) { 587 // alternate form - decimal for error messages. 588 // for well in range, convert to double and use print's %g 589 exp = fvp->exp + sigfig(fvp)*Mpscale; 590 if(-900 < exp && exp < 900) { 591 d = mpgetflt(fvp); 592 if(d >= 0 && (fp->flags & FmtSign)) 593 fmtprint(fp, "+"); 594 return fmtprint(fp, "%g", d); 595 } 596 597 // very out of range. compute decimal approximation by hand. 598 // decimal exponent 599 dexp = fvp->exp * 0.301029995663981195; // log_10(2) 600 exp = (int)dexp; 601 // decimal mantissa 602 fv = *fvp; 603 fv.val.neg = 0; 604 fv.exp = 0; 605 d = mpgetflt(&fv); 606 d *= pow(10, dexp-exp); 607 while(d >= 9.99995) { 608 d /= 10; 609 exp++; 610 } 611 if(fvp->val.neg) 612 fmtprint(fp, "-"); 613 else if(fp->flags & FmtSign) 614 fmtprint(fp, "+"); 615 return fmtprint(fp, "%.5fe+%d", d, exp); 616 } 617 618 if(sigfig(fvp) == 0) { 619 snprint(buf, sizeof(buf), "0p+0"); 620 goto out; 621 } 622 fv = *fvp; 623 624 while(fv.val.a[0] == 0) { 625 mpshiftfix(&fv.val, -Mpscale); 626 fv.exp += Mpscale; 627 } 628 while((fv.val.a[0]&1) == 0) { 629 mpshiftfix(&fv.val, -1); 630 fv.exp += 1; 631 } 632 633 if(fv.exp >= 0) { 634 snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp); 635 goto out; 636 } 637 snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp); 638 639 out: 640 return fmtstrcpy(fp, buf); 641 }