1/* 2 * math.c - mathematics functions for a hand calculator under X 3 * 4 * Author: John H. Bradley, University of Pennsylvania 5 * (bradley@cis.upenn.edu) 6 * March, 1987 7 * 8 * RPN mode added and port to X11 by Mark Rosenstein, MIT Project Athena 9 * 10 * Modified to be a client of the Xt toolkit and the Athena widget set by 11 * Donna Converse, MIT X Consortium. This is all that remains of the 12 * original calculator, and it still needs to be rewritten. The HP 13 * functionality should be separated from the TI functionality. 14 * Beware the HP functions: there are still errors here. 15 * 16 * Geoffrey Coram fixed most of the HP mode bugs. 17 */ 18 19#include "xcalc.h" 20 21#ifndef M_PI /* sometimes defined in math.h */ 22#define M_PI 3.14159265358979323846 23#endif 24 25#ifndef M_E /* sometimes defined in math.h */ 26#define M_E 2.7182818284590452354 27#endif 28 29#define MAXDISP 11 30#define DEG 0 /* DRG mode. used for trig calculations */ 31#define RAD 1 32#define GRAD 2 33 34#define True 1 35#define False 0 36 37#ifndef IEEE 38jmp_buf env; 39#endif 40 41 42/* This section is all of the state machine that implements the calculator 43 * functions. Much of it is shared between the infix and rpn modes. 44 */ 45 46static int flagINV, flagPAREN, flagM, drgmode, numbase; /* display flags */ 47 48static double drg2rad=M_PI/180.0; /* Conversion factors for trig funcs */ 49static double rad2drg=180.0/M_PI; 50static int entered=1; /* true if display contains a valid number. 51 if==2, then use 'dnum', rather than the string 52 stored in the display. (for accuracy) 53 if==3, then error occurred, only CLR & AC work */ 54/* entered seems to be overloaded - dmc */ 55static int lift_enabled = 0; /* for rpn mode only */ 56 57static int CLR =0; /* CLR clears display. if 1, clears acc, also */ 58static int Dpoint=0; /* to prevent using decimal pt twice in a # */ 59static int clrdisp=1; /* if true clears display before entering # */ 60static int lastop =kCLR; 61static int memop =kCLR; 62static int exponent=0; 63static double acc =0.0; 64static double dnum=0.0; 65#define XCALC_MEMORY 10 66static double mem[XCALC_MEMORY] = { 0.0 }; 67 68static void DrawDisplay(void); 69static void PushOp(int op); 70static int PopOp(void); 71static int isopempty(void); 72#ifdef DEBUG 73static void showstack(char *string); 74#endif 75static void PushNum(double num); 76static double PopNum(void); 77static void RollNum(int dir); 78static void ClearStacks(void); 79static int priority(int op); 80 81#ifndef HAVE_STRLCPY 82/* Close enough for the short strings copied in xcalc */ 83static inline size_t 84strlcpy(char *dst, const char *src, size_t size) 85{ 86 strncpy(dst, src, size); 87 dst[size - 1] = '\0'; 88 return strlen(src); 89} 90#endif 91 92/* 93 * The following is to deal with the unfortunate assumption that if errno 94 * is non-zero then an error has occurred. On some systems (e.g. Ultrix), 95 * sscanf will call lower level routines that will set errno. 96 */ 97static void 98parse_double(double *dp) 99{ 100 unsigned long n = 0; 101 int olderrno = errno; 102 103 switch (numbase) { 104 case 8: 105 sscanf(dispstr, "%lo", &n); 106 *dp = (double)n; 107 break; 108 case 16: 109 sscanf(dispstr, "%lX", &n); 110 *dp = (double)n; 111 break; 112 default: 113 sscanf(dispstr, "%lf", dp); 114 } 115 116 errno = olderrno; 117 return; 118} 119 120/** 121 * Format the given double according to the 122 * selected number base. 123 */ 124static void 125format_double(double n) 126{ 127 switch (numbase) { 128 case 8: 129 snprintf(dispstr, sizeof(dispstr), "%lo", (long)n); 130 break; 131 case 16: 132 snprintf(dispstr, sizeof(dispstr), "%lX", (long)n); 133 break; 134 default: 135 snprintf(dispstr, sizeof(dispstr), "%.8g", n); 136 } 137} 138 139/*********************************/ 140int pre_op(int keynum) 141{ 142 if (keynum==-1) return(0); 143 144 errno = 0; /* for non-IEEE machines */ 145 146 if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) { 147 if (rpn) { 148 clrdisp++; 149 } else { 150 ringbell(); 151 return(1); /* the intent was probably not to do the operation */ 152 } 153 } 154 155 if (keynum != kCLR) CLR=0; 156 return(0); 157} 158 159#ifndef IEEE 160 161/* cannot assign result of setjmp under ANSI C, use global instead */ 162static volatile int SignalKind; 163 164void fail_op(void) 165{ 166 if (SignalKind == SIGFPE) 167 strlcpy(dispstr, "math error", sizeof(dispstr)); 168 else if (SignalKind == SIGILL) 169 strlcpy(dispstr, "illegal operand", sizeof(dispstr)); 170 171 entered=3; 172 DrawDisplay(); 173 return; 174} 175 176/*ARGSUSED*/ 177void fperr(int sig) 178{ 179#if defined(SYSV) || defined(SVR4) || defined(linux) 180 signal(SIGFPE, fperr); 181#endif 182 SignalKind = sig; 183 longjmp(env,1); 184} 185 186/* for VAX BSD4.3 */ 187/*ARGSUSED*/ 188void illerr(int sig) 189{ 190 /* not reset when caught? */ 191 signal(SIGILL, illerr); 192 193 SignalKind = sig; 194 longjmp(env,1); 195} 196 197#endif /* not IEEE */ 198 199 200void post_op(void) 201{ 202#ifdef DEBUG 203 showstack("\0"); 204#endif 205#ifndef IEEE 206 if (errno) { 207 strlcpy(dispstr, "error", sizeof(dispstr)); 208 DrawDisplay(); 209 entered=3; 210 errno=0; 211 } 212#endif 213} 214 215/*-------------------------------------------------------------------------*/ 216static void 217DrawDisplay(void) 218{ 219 if (strlen(dispstr) >= MAXDISP) { /* strip out some decimal digits */ 220 char *estr = index(dispstr,'e'); /* search for exponent part */ 221 if (!estr) dispstr[12]='\0'; /* no exp, just trunc. */ 222 else { 223 char tmp[32]; 224 if (strlen(estr) <= 4) /* leftmost 8 chars plus exponent */ 225 snprintf(tmp, sizeof(tmp), "%.8s%s", dispstr, estr); 226 else /* leftmost 7 chars plus exponent */ 227 snprintf(tmp, sizeof(tmp), "%.7s%s", dispstr, estr); 228 strlcpy(dispstr, tmp, sizeof(dispstr)); 229 } 230 } 231 draw(dispstr); 232 setflag(XCalc_MEMORY, (flagM)); 233 setflag(XCalc_INVERSE, (flagINV)); 234 setflag(XCalc_DEGREE, (drgmode==DEG)); 235 setflag(XCalc_RADIAN, (drgmode==RAD)); 236 setflag(XCalc_GRADAM, (drgmode==GRAD)); 237 setflag(XCalc_PAREN, (flagPAREN)); 238 setflag(XCalc_HEX, (numbase==16)); 239 setflag(XCalc_DEC, (numbase==10)); 240 setflag(XCalc_OCT, (numbase==8)); 241} 242 243/*-------------------------------------------------------------------------*/ 244void 245change_base(void) 246{ 247 parse_double(&dnum); 248 249 if (dnum >= 0) { 250 switch (numbase) { 251 case 8: numbase = 10; break; 252 case 10: numbase = 16; break; 253 case 16: numbase = 8; break; 254 } 255 256 format_double(dnum); 257 } else strlcpy(dispstr, "error", sizeof(dispstr)); 258 259 DrawDisplay(); 260} 261 262/*-------------------------------------------------------------------------*/ 263void 264numeric(int keynum) 265{ 266 char st[2]; 267 268 flagINV=0; 269 270 if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) { 271 int cell = 0; 272 273 switch (keynum) { 274 case kONE: cell = 1; break; 275 case kTWO: cell = 2; break; 276 case kTHREE: cell = 3; break; 277 case kFOUR: cell = 4; break; 278 case kFIVE: cell = 5; break; 279 case kSIX: cell = 6; break; 280 case kSEVEN: cell = 7; break; 281 case kEIGHT: cell = 8; break; 282 case kNINE: cell = 9; break; 283 case kZERO: cell = 0; break; 284 } 285 switch (memop) { 286 case kSTO: 287 mem[cell] = dnum; 288 lift_enabled = 1; 289 entered = 2; 290 clrdisp++; 291 break; 292 case kRCL: 293 PushNum(dnum); 294 dnum = mem[cell]; 295 format_double(dnum); 296 lift_enabled = 1; 297 entered = 1; 298 clrdisp++; 299 break; 300 case kSUM: 301 mem[cell] += dnum; 302 lift_enabled = 1; 303 entered = 2; 304 clrdisp++; 305 break; 306 } 307 memop = kCLR; 308 DrawDisplay(); 309 return; 310 } 311 312 if (clrdisp) { 313 dispstr[0]='\0'; 314 exponent=Dpoint=0; 315/* if (rpn && entered==2) 316 PushNum(dnum); 317 */ 318 if (rpn & lift_enabled) 319 PushNum(dnum); 320 } 321 if ((int) strlen(dispstr) >= MAXDISP) 322 return; 323 324 st[0] = '\0'; 325 switch (keynum){ 326 case kZERO: st[0] = '0'; break; 327 case kONE: st[0] = '1'; break; 328 case kTWO: st[0] = '2'; break; 329 case kTHREE: st[0] = '3'; break; 330 case kFOUR: st[0] = '4'; break; 331 case kFIVE: st[0] = '5'; break; 332 case kSIX: st[0] = '6'; break; 333 case kSEVEN: st[0] = '7'; break; 334 case kEIGHT: if (numbase > 8) st[0] = '8'; break; 335 case kNINE: if (numbase > 8) st[0] = '9'; break; 336 case kxA: if (numbase > 10) st[0] = 'A'; break; 337 case kxB: if (numbase > 10) st[0] = 'B'; break; 338 case kxC: if (numbase > 10) st[0] = 'C'; break; 339 case kxD: if (numbase > 10) st[0] = 'D'; break; 340 case kxE: if (numbase > 10) st[0] = 'E'; break; 341 case kxF: if (numbase > 10) st[0] = 'F'; break; 342 } 343 344 if (st[0] == '\0') 345 return; 346 st[1] = '\0'; 347 strcat(dispstr,st); 348 349 DrawDisplay(); 350 if (clrdisp && keynum != kZERO) 351 clrdisp=0; /*no leading 0s*/ 352 memop = keynum; 353 entered=1; 354 lift_enabled = 0; 355} 356 357void 358bkspf(void) 359{ 360 361 lift_enabled = 0; 362 363 if (! flagINV) 364 { 365 if (entered!=1) { 366 clearf(); 367 return; 368 } 369 if (clrdisp) 370 return; 371 if ((int) strlen(dispstr) > 0) { 372#ifndef X_LOCALE 373 const char *dp = localeconv()->decimal_point; 374 size_t dp_len = strlen(dp); 375 size_t ds_len = strlen(dispstr); 376 if (ds_len >= dp_len && strcmp(dispstr + ds_len - dp_len, dp) == 0) 377 Dpoint=0; 378#else 379 if (dispstr[strlen(dispstr)-1] == '.') 380 Dpoint=0; 381#endif 382 dispstr[strlen(dispstr)-1] = 0; 383 } 384 if (strlen(dispstr) == 0) { 385 strcat(dispstr, "0"); 386 clrdisp++; 387 } 388 } 389 else 390 { 391 strlcpy(dispstr, "0", sizeof(dispstr)); 392 dnum = 0.0; 393 clrdisp++; 394 flagINV = 0; 395 } 396 DrawDisplay(); 397} 398 399void 400decf(void) 401{ 402 flagINV=0; 403 if (clrdisp) { 404 if (rpn && lift_enabled) 405 PushNum(dnum); 406 strlcpy(dispstr, "0", sizeof(dispstr)); 407 } 408 if (!Dpoint) { 409#ifndef X_LOCALE 410 strcat(dispstr, localeconv()->decimal_point); 411#else 412 strcat(dispstr, "."); 413#endif 414 DrawDisplay(); 415 Dpoint++; 416 } 417 clrdisp=0; 418 entered=1; 419} 420 421void 422eef(void) 423{ 424 flagINV=0; 425 if (clrdisp) { 426 if (rpn && lift_enabled) 427 PushNum(dnum); 428 strlcpy(dispstr, rpn ? "1" : "0", sizeof(dispstr)); 429 } 430 if (!exponent) { 431 strcat(dispstr,"E+"); 432 DrawDisplay(); 433 exponent=strlen(dispstr)-1; /* where the '-' goes */ 434 } 435 clrdisp=0; 436 entered=1; 437} 438 439void 440clearf(void) 441{ 442 flagINV=0; 443 if (CLR && !rpn) { /* clear all */ 444 ClearStacks(); 445 flagPAREN=0; 446 } 447 CLR++; 448 exponent=Dpoint=0; 449 clrdisp=1; 450 entered=1; 451 strlcpy(dispstr, "0", sizeof(dispstr)); 452 DrawDisplay(); 453} 454 455void 456negf(void) 457{ 458 flagINV=0; 459 if (exponent) { /* neg the exponent */ 460 if (dispstr[exponent]=='-') 461 dispstr[exponent]='+'; 462 else 463 dispstr[exponent]='-'; 464 DrawDisplay(); 465 return; 466 } 467 468 if (strcmp("0",dispstr)==0) 469 return; /* don't neg a zero */ 470 if (dispstr[0]=='-') /* already neg-ed */ 471 strcpy(dispstr,dispstr+1); /* move str left once */ 472 else { /* not neg-ed. add a '-' */ 473 char tmp[32]; 474 snprintf(tmp, sizeof(tmp), "-%s", dispstr); 475 strlcpy(dispstr, tmp, sizeof(dispstr)); 476 } 477 if (entered==2) 478 dnum = -1.0 * dnum; 479 DrawDisplay(); 480} 481 482/* Two operand functions for infix calc */ 483void 484twoop(int keynum) 485{ 486 if (flagINV) { 487 flagINV=0; 488 DrawDisplay(); 489 } 490 491 if (!entered) { /* something like "5+*" */ 492 if (!isopempty()) 493 PopOp(); /* replace the prev op */ 494 PushOp(keynum); /* with the new one */ 495 return; 496 } 497 498 if (entered==1) 499 parse_double(&dnum); 500 501 clrdisp=CLR=1; 502 entered=Dpoint=exponent=0; 503 504 if (!isopempty()) { /* there was a previous op */ 505 lastop=PopOp(); /* get it */ 506 507 if (lastop==kLPAR) { /* put it back */ 508 PushOp(kLPAR); 509 PushOp(keynum); 510 PushNum(dnum); 511 return; 512 } 513 514 /* now, if the current op (keynum) is of 515 higher priority than the lastop, the current 516 op and number are just pushed on top 517 Priorities: (Y^X) > *,/ > +,- > >>,<< > & > ^ > ~ */ 518 519 if (priority(keynum) > priority(lastop)) { 520 PushNum(dnum); 521 PushOp(lastop); 522 PushOp(keynum); 523 } else { /* execute lastop on lastnum and dnum, push 524 result and current op on stack */ 525 acc=PopNum(); 526 switch (lastop) { /* perform the operation */ 527 case kADD: acc += dnum; break; 528 case kSUB: acc -= dnum; break; 529 case kMUL: acc *= dnum; break; 530 case kDIV: acc /= dnum; break; 531 case kPOW: acc = pow(acc,dnum); break; 532 case kMOD: acc = (long)acc % (long)dnum; break; 533 case kAND: acc = (long)acc & (long)dnum; break; 534 case kOR: acc = (long)acc | (long)dnum; break; 535 case kXOR: acc = (long)acc ^ (long)dnum; break; 536 case kSHL: acc = (long)acc << (long)dnum; break; 537 case kSHR: acc = (long)acc >> (long)dnum; break; 538 } 539 540 PushNum(acc); 541 PushOp(keynum); 542 format_double(acc); 543 DrawDisplay(); 544 dnum=acc; 545 } 546 } 547 else { /* op stack is empty, push op and num */ 548 PushOp(keynum); 549 PushNum(dnum); 550 } 551} 552 553/* Two operand functions for rpn calc */ 554void 555twof(int keynum) 556{ 557 if (flagINV) { 558 flagINV=0; 559 DrawDisplay(); 560 } 561 if (!entered) 562 return; 563 if (entered==1) 564 parse_double(&dnum); 565 acc = PopNum(); 566 switch(keynum) { 567 case kADD: acc += dnum; break; 568 case kSUB: acc -= dnum; break; 569 case kMUL: acc *= dnum; break; 570 case kDIV: acc /= dnum; break; 571 case kPOW: acc = pow(acc,dnum); break; 572 case kXXY: PushNum(dnum); break; 573 case kMOD: acc = (long)acc % (long)dnum; break; 574 case kAND: acc = (long)acc & (long)dnum; break; 575 case kOR: acc = (long)acc | (long)dnum; break; 576 case kXOR: acc = (long)acc ^ (long)dnum; break; 577 case kSHL: acc = (long)acc << (long)dnum; break; 578 case kSHR: acc = (long)acc >> (long)dnum; break; 579 } 580 581 format_double(acc); 582 DrawDisplay(); 583 clrdisp++; 584 Dpoint = exponent = 0; 585 entered = 2; 586 lift_enabled = 1; 587 dnum = acc; 588} 589 590void 591entrf(void) 592{ 593 flagINV=0; 594 if (!entered) 595 return; 596 597 clrdisp=CLR=1; 598 Dpoint=exponent=0; 599 600 if (entered==1) 601 parse_double(&dnum); 602 entered=2; 603 memop = kENTR; 604 PushNum(dnum); 605 lift_enabled = 0; 606} 607 608void 609equf(void) 610{ 611 flagINV=0; 612 if (!entered) 613 return; 614 615 clrdisp=CLR=1; 616 Dpoint=exponent=0; 617 618 if (entered==1) 619 parse_double(&dnum); 620 entered=2; 621 622 PushNum(dnum); 623 624 while (!isopempty()) { /* do all pending ops */ 625 dnum=PopNum(); 626 acc=PopNum(); 627 lastop=PopOp(); 628 switch (lastop) { 629 case kADD: acc += dnum; 630 break; 631 case kSUB: acc -= dnum; 632 break; 633 case kMUL: acc *= dnum; 634 break; 635 case kDIV: acc /= dnum; 636 break; 637 case kPOW: acc = pow(acc,dnum); 638 break; 639 case kLPAR: flagPAREN--; 640 PushNum(acc); 641 break; 642 case kMOD: acc = (long)acc % (long)dnum; 643 break; 644 case kAND: acc = (long)acc & (long)dnum; 645 break; 646 case kOR: acc = (long)acc | (long)dnum; 647 break; 648 case kXOR: acc = (long)acc ^ (long)dnum; 649 break; 650 case kSHL: acc = (long)acc << (long)dnum; 651 break; 652 case kSHR: acc = (long)acc >> (long)dnum; 653 break; 654 } 655 dnum=acc; 656 PushNum(dnum); 657 } 658 659 format_double(dnum); 660 DrawDisplay(); 661} 662 663void 664lparf(void) 665{ 666 flagINV=0; 667 PushOp(kLPAR); 668 flagPAREN++; 669 DrawDisplay(); 670} 671 672void 673rollf(void) 674{ 675 if (!entered) 676 return; 677 if (entered==1) 678 parse_double(&dnum); 679 entered = 2; 680 lift_enabled = 1; 681 RollNum(flagINV); 682 flagINV=0; 683 clrdisp++; 684 format_double(dnum); 685 DrawDisplay(); 686} 687 688void 689rparf(void) 690{ 691 flagINV=0; 692 if (!entered) 693 return; 694 695 if (!flagPAREN) 696 return; 697 698 clrdisp++; 699 Dpoint=exponent=0; 700 701 if (entered==1) 702 parse_double(&dnum); 703 entered=2; 704 705 PushNum(dnum); 706 while (!isopempty() && (lastop=PopOp())!=kLPAR) { 707 /* do all pending ops, back to left paren */ 708 dnum=PopNum(); 709 acc=PopNum(); 710 switch (lastop) { 711 case kADD: acc += dnum; 712 break; 713 case kSUB: acc -= dnum; 714 break; 715 case kMUL: acc *= dnum; 716 break; 717 case kDIV: acc /= dnum; 718 break; 719 case kPOW: acc = pow(acc,dnum); 720 break; 721 case kMOD: acc = (long)acc % (long)dnum; 722 break; 723 case kAND: acc = (long)acc & (long)dnum; 724 break; 725 case kOR: acc = (long)acc | (long)dnum; 726 break; 727 case kXOR: acc = (long)acc ^ (long)dnum; 728 break; 729 case kSHL: acc = (long)acc << (long)dnum; 730 break; 731 case kSHR: acc = (long)acc >> (long)dnum; 732 break; 733 } 734 dnum=acc; 735 PushNum(dnum); 736 } 737 PopNum(); 738 flagPAREN--; 739 entered=2; 740 format_double(dnum); 741 DrawDisplay(); 742} 743 744void 745drgf(void) 746{ 747 if (flagINV) { 748 if (entered==1) 749 parse_double(&dnum); 750 switch (drgmode) { 751 case DEG: dnum=dnum*M_PI/180.0; break; 752 case RAD: dnum=dnum*200.0/M_PI; break; 753 case GRAD: dnum=dnum*90.0/100.0; break; 754 } 755 entered=2; 756 clrdisp=1; 757 flagINV=0; 758 format_double(dnum); 759 } 760 761 flagINV=0; 762 drgmode = (drgmode + 1) % 3; 763 switch (drgmode) { 764 case DEG: drg2rad=M_PI / 180.0; 765 rad2drg=180.0 / M_PI; 766 break; 767 case RAD: drg2rad=1.0; 768 rad2drg=1.0; 769 break; 770 case GRAD: drg2rad=M_PI / 200.0; 771 rad2drg=200.0 / M_PI; 772 break; 773 } 774 DrawDisplay(); 775} 776 777void 778invf(void) 779{ 780 flagINV = ~flagINV; 781 DrawDisplay(); 782} 783 784void 785memf(int keynum) 786{ 787 memop = keynum; 788 if (entered==1) 789 parse_double(&dnum); 790 entered = 2; 791 clrdisp++; 792 lift_enabled = 0; 793} 794 795void 796oneop(int keynum) 797{ 798 int i,j; 799 double dtmp; 800 801 if (entered==1) 802 parse_double(&dnum); 803 entered = 2; 804 805 switch (keynum) { /* do the actual math fn. */ 806 case kE: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_E; break; 807 case kPI: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_PI; break; 808 case kRECIP: dnum=1.0/dnum; break; 809 case kSQR: flagINV = !flagINV; /* fall through */ 810 case kSQRT: if (flagINV) dnum=dnum*dnum; 811 else dnum=sqrt(dnum); 812 break; 813 case k10X: flagINV = !flagINV; /* fall through */ 814 case kLOG: if (flagINV) dnum=pow(10.0,dnum); 815 else dnum=log10(dnum); 816 break; 817 case kEXP: flagINV = !flagINV; /* fall through */ 818 case kLN: if (flagINV) dnum=exp(dnum); 819 else dnum=log(dnum); 820 break; 821 case kSIN: if (flagINV) dnum=asin(dnum)*rad2drg; 822 else dnum=sin(dnum*drg2rad); 823 break; 824 case kCOS: if (flagINV) dnum=acos(dnum)*rad2drg; 825 else dnum=cos(dnum*drg2rad); 826 break; 827 case kTAN: if (flagINV) dnum=atan(dnum)*rad2drg; 828 else dnum=tan(dnum*drg2rad); 829 break; 830 case kSTO: mem[0]=dnum; flagM=!(mem[0]==0.0); break; 831 case kRCL: if (rpn && lift_enabled) PushNum(dnum); 832 dnum=mem[0]; flagM=!(mem[0]==0.0); break; 833 case kSUM: mem[0]+=dnum; flagM=!(mem[0]==0.0); break; 834 case kEXC: dtmp=dnum; dnum=mem[0]; mem[0]=dtmp; 835 flagM=!(mem[0]==0.0); break; 836 case kFACT: if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) { 837 strlcpy(dispstr, "error", sizeof(dispstr)); 838 entered=3; 839 break; 840 } 841 dtmp = floor(dnum); i = dtmp; 842 for (j=1,dnum=1.0; j<=i; j++) 843 dnum*=(float) j; 844 break; 845 case kNOT: dnum = ~(long)dnum; break; 846 case kTRUNC: dnum = trunc(dnum); break; 847 } 848 849 if (entered==3) { /* error */ 850 DrawDisplay(); 851 return; 852 } 853 854 memop = keynum; 855 entered=2; 856 clrdisp=1; 857 flagINV=0; 858 lift_enabled = 1; 859 format_double(dnum); 860 DrawDisplay(); 861} 862 863void 864offf(void) 865{ 866 /* full reset */ 867 ResetCalc(); 868 entered=clrdisp=1; 869 lift_enabled = 0; 870 dnum=mem[0]=0.0; 871 if (rpn) 872 for (int i=1; i < XCALC_MEMORY; i++) 873 mem[i]=0.0; 874 exponent=Dpoint=0; 875 DrawDisplay(); 876} 877 878 879#define STACKMAX 32 880static int opstack[STACKMAX]; 881static int opsp; 882static double numstack[STACKMAX]; 883static int numsp; 884 885 886/*******/ 887static void 888PushOp(int op) 889/*******/ 890{ 891 if (opsp==STACKMAX) { 892 strlcpy(dispstr, "stack error", sizeof(dispstr)); 893 entered=3; 894 } else 895 opstack[opsp++]=op; 896} 897 898/*******/ 899static int 900PopOp(void) 901/*******/ 902{ 903 if (opsp==0) { 904 strlcpy(dispstr, "stack error", sizeof(dispstr)); 905 entered=3; 906 return(kNOP); 907 } else 908 return(opstack[--opsp]); 909} 910 911/*******/ 912static int 913isopempty(void) 914/*******/ 915{ 916 return( opsp ? 0 : 1 ); 917} 918 919#ifdef DEBUG 920static void 921showstack(char *string) 922{ 923 fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1], 924 numstack[2]); 925} 926#endif 927 928/*******/ 929static void 930PushNum(double num) 931/*******/ 932{ 933 if (rpn) { 934 numstack[2] = numstack[1]; 935 numstack[1] = numstack[0]; 936 numstack[0] = num; 937 return; 938 } 939 if (numsp==STACKMAX) { 940 strlcpy(dispstr, "stack error", sizeof(dispstr)); 941 entered=3; 942 } else 943 numstack[numsp++]=num; 944} 945 946/*******/ 947static double 948PopNum(void) 949/*******/ 950{ 951 if (rpn) { 952 double tmp = numstack[0]; 953 numstack[0] = numstack[1]; 954 numstack[1] = numstack[2]; 955 return(tmp); 956 } 957 if (numsp==0) { 958 strlcpy(dispstr, "stack error", sizeof(dispstr)); 959 entered=3; 960 return 0.0; 961 } else 962 return(numstack[--numsp]); 963} 964 965/*******/ 966static void 967RollNum(int dir) 968/*******/ 969{ 970 double tmp; 971 972 if (dir) { /* roll up */ 973 tmp = dnum; 974 dnum = numstack[2]; 975 numstack[2] = numstack[1]; 976 numstack[1] = numstack[0]; 977 numstack[0] = tmp; 978 } else { /* roll down */ 979 tmp = dnum; 980 dnum = numstack[0]; 981 numstack[0] = numstack[1]; 982 numstack[1] = numstack[2]; 983 numstack[2] = tmp; 984 } 985} 986 987 988/*******/ 989static void 990ClearStacks(void) 991/*******/ 992{ 993 if (rpn) 994 numstack[0] = numstack[1] = numstack[2] = 0.; 995 opsp=numsp=0; 996} 997 998 999/*******/ 1000static int 1001priority(int op) 1002/*******/ 1003{ 1004 switch (op) { 1005 case kPOW: return(6); 1006 case kMUL: 1007 case kDIV: 1008 case kMOD: return(5); 1009 case kADD: 1010 case kSUB: return(4); 1011 case kSHL: 1012 case kSHR: return(3); 1013 case kAND: return(2); 1014 case kXOR: return(1); 1015 case kOR: return(0); 1016 } 1017 return 0; 1018} 1019 1020 1021/********/ 1022void 1023ResetCalc(void) 1024/********/ 1025{ 1026 flagM=flagINV=flagPAREN=0; drgmode=DEG; 1027 numbase=(!numbase ? 10 : numbase); 1028 setflag(XCalc_MEMORY, False); 1029 setflag(XCalc_INVERSE, False); 1030 setflag(XCalc_PAREN, False); 1031 setflag(XCalc_RADIAN, False); 1032 setflag(XCalc_GRADAM, False); 1033 setflag(XCalc_DEGREE, True); 1034 setflag(XCalc_HEX, False); 1035 setflag(XCalc_DEC, True); 1036 setflag(XCalc_OCT, False); 1037 strlcpy(dispstr, "0", sizeof(dispstr)); 1038 draw(dispstr); 1039 ClearStacks(); 1040 drg2rad=M_PI/180.0; 1041 rad2drg=180.0/M_PI; 1042} 1043