math.c revision 19d64aee
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; /* 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 */ 97 98static void 99parse_double (const char *src, const char *fmt, double *dp) 100{ 101 int olderrno = errno; 102 103 (void) sscanf (src, fmt, dp); 104 errno = olderrno; 105 return; 106} 107 108 109/*********************************/ 110int pre_op(int keynum) 111{ 112 if (keynum==-1) return(0); 113 114 errno = 0; /* for non-IEEE machines */ 115 116 if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) { 117 if (rpn) { 118 clrdisp++; 119 } else { 120 ringbell(); 121 return(1); /* the intent was probably not to do the operation */ 122 } 123 } 124 125 if (keynum != kCLR) CLR=0; 126 return(0); 127} 128 129#ifndef IEEE 130 131/* cannot assign result of setjmp under ANSI C, use global instead */ 132static volatile int SignalKind; 133 134void fail_op(void) 135{ 136 if (SignalKind == SIGFPE) 137 strlcpy(dispstr, "math error", sizeof(dispstr)); 138 else if (SignalKind == SIGILL) 139 strlcpy(dispstr, "illegal operand", sizeof(dispstr)); 140 141 entered=3; 142 DrawDisplay(); 143 return; 144} 145 146/*ARGSUSED*/ 147void fperr(int sig) 148{ 149#if defined(SYSV) || defined(SVR4) || defined(linux) 150 signal(SIGFPE, fperr); 151#endif 152 SignalKind = sig; 153 longjmp(env,1); 154} 155 156/* for VAX BSD4.3 */ 157/*ARGSUSED*/ 158void illerr(int sig) 159{ 160 /* not reset when caught? */ 161 signal(SIGILL, illerr); 162 163 SignalKind = sig; 164 longjmp(env,1); 165} 166 167#endif /* not IEEE */ 168 169 170void post_op(void) 171{ 172#ifdef DEBUG 173 showstack("\0"); 174#endif 175#ifndef IEEE 176 if (errno) { 177 strlcpy(dispstr, "error", sizeof(dispstr)); 178 DrawDisplay(); 179 entered=3; 180 errno=0; 181 } 182#endif 183} 184/*-------------------------------------------------------------------------*/ 185static void 186DrawDisplay(void) 187{ 188 if (strlen(dispstr) > 12) { /* strip out some decimal digits */ 189 char *estr = strchr(dispstr,'e'); /* search for exponent part */ 190 if (!estr) dispstr[12]='\0'; /* no exp, just trunc. */ 191 else { 192 char tmp[32]; 193 if (strlen(estr) <= 4) /* leftmost 8 chars plus exponent */ 194 snprintf(tmp, sizeof(tmp), "%.8s%s", dispstr, estr); 195 else /* leftmost 7 chars plus exponent */ 196 snprintf(tmp, sizeof(tmp), "%.7s%s", dispstr, estr); 197 strlcpy(dispstr, tmp, sizeof(dispstr)); 198 } 199 } 200 draw(dispstr); 201 setflag(XCalc_MEMORY, (flagM)); 202 setflag(XCalc_INVERSE, (flagINV)); 203 setflag(XCalc_DEGREE, (drgmode==DEG)); 204 setflag(XCalc_RADIAN, (drgmode==RAD)); 205 setflag(XCalc_GRADAM, (drgmode==GRAD)); 206 setflag(XCalc_PAREN, (flagPAREN)); 207} 208 209/*-------------------------------------------------------------------------*/ 210void 211numeric(int keynum) 212{ 213 char st[2]; 214 int cell = 0; 215 216 flagINV=0; 217 218 if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) { 219 switch (keynum) { 220 case kONE: cell = 1; break; 221 case kTWO: cell = 2; break; 222 case kTHREE: cell = 3; break; 223 case kFOUR: cell = 4; break; 224 case kFIVE: cell = 5; break; 225 case kSIX: cell = 6; break; 226 case kSEVEN: cell = 7; break; 227 case kEIGHT: cell = 8; break; 228 case kNINE: cell = 9; break; 229 case kZERO: cell = 0; break; 230 } 231 switch (memop) { 232 case kSTO: 233 mem[cell] = dnum; 234 lift_enabled = 1; 235 entered = 2; 236 clrdisp++; 237 break; 238 case kRCL: 239 PushNum(dnum); 240 dnum = mem[cell]; 241 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 242 lift_enabled = 1; 243 entered = 1; 244 clrdisp++; 245 break; 246 case kSUM: 247 mem[cell] += dnum; 248 lift_enabled = 1; 249 entered = 2; 250 clrdisp++; 251 break; 252 } 253 memop = kCLR; 254 DrawDisplay(); 255 return; 256 } 257 258 if (clrdisp) { 259 dispstr[0]='\0'; 260 exponent=Dpoint=0; 261/* if (rpn && entered==2) 262 PushNum(dnum); 263 */ 264 if (rpn & lift_enabled) 265 PushNum(dnum); 266 } 267 if ((int) strlen(dispstr) >= MAXDISP) 268 return; 269 270 switch (keynum){ 271 case kONE: st[0] = '1'; break; 272 case kTWO: st[0] = '2'; break; 273 case kTHREE: st[0] = '3'; break; 274 case kFOUR: st[0] = '4'; break; 275 case kFIVE: st[0] = '5'; break; 276 case kSIX: st[0] = '6'; break; 277 case kSEVEN: st[0] = '7'; break; 278 case kEIGHT: st[0] = '8'; break; 279 case kNINE: st[0] = '9'; break; 280 case kZERO: st[0] = '0'; break; 281 } 282 st[1] = '\0'; 283 strcat(dispstr,st); 284 285 DrawDisplay(); 286 if (clrdisp && keynum != kZERO) 287 clrdisp=0; /*no leading 0s*/ 288 memop = keynum; 289 entered=1; 290 lift_enabled = 0; 291} 292 293void 294bkspf(void) 295{ 296 297 lift_enabled = 0; 298 299 if (! flagINV) 300 { 301 if (entered!=1) { 302 clearf(); 303 return; 304 } 305 if (clrdisp) 306 return; 307 if ((int) strlen(dispstr) > 0) { 308#ifndef X_LOCALE 309 const char *dp = localeconv()->decimal_point; 310 size_t dp_len = strlen(dp); 311 size_t ds_len = strlen(dispstr); 312 if (ds_len >= dp_len && strcmp(dispstr + ds_len - dp_len, dp) == 0) 313 Dpoint=0; 314#else 315 if (dispstr[strlen(dispstr)-1] == '.') 316 Dpoint=0; 317#endif 318 dispstr[strlen(dispstr)-1] = 0; 319 } 320 if (strlen(dispstr) == 0) { 321 strcat(dispstr, "0"); 322 clrdisp++; 323 } 324 } 325 else 326 { 327 strlcpy(dispstr, "0", sizeof(dispstr)); 328 dnum = 0.0; 329 clrdisp++; 330 flagINV = 0; 331 } 332 DrawDisplay(); 333} 334 335void 336decf(void) 337{ 338 flagINV=0; 339 if (clrdisp) { 340 if (rpn && lift_enabled) 341 PushNum(dnum); 342 strlcpy(dispstr, "0", sizeof(dispstr)); 343 } 344 if (!Dpoint) { 345#ifndef X_LOCALE 346 strcat(dispstr, localeconv()->decimal_point); 347#else 348 strcat(dispstr, "."); 349#endif 350 DrawDisplay(); 351 Dpoint++; 352 } 353 clrdisp=0; 354 entered=1; 355} 356 357void 358eef(void) 359{ 360 flagINV=0; 361 if (clrdisp) { 362 if (rpn && lift_enabled) 363 PushNum(dnum); 364 strlcpy(dispstr, rpn ? "1" : "0", sizeof(dispstr)); 365 } 366 if (!exponent) { 367 strcat(dispstr,"E+"); 368 DrawDisplay(); 369 exponent=strlen(dispstr)-1; /* where the '-' goes */ 370 } 371 clrdisp=0; 372 entered=1; 373} 374 375void 376clearf(void) 377{ 378 flagINV=0; 379 if (CLR && !rpn) { /* clear all */ 380 ClearStacks(); 381 flagPAREN=0; 382 } 383 CLR++; 384 exponent=Dpoint=0; 385 clrdisp=1; 386 entered=1; 387 strlcpy(dispstr, "0", sizeof(dispstr)); 388 DrawDisplay(); 389} 390 391void 392negf(void) 393{ 394 flagINV=0; 395 if (exponent) { /* neg the exponent */ 396 if (dispstr[exponent]=='-') 397 dispstr[exponent]='+'; 398 else 399 dispstr[exponent]='-'; 400 DrawDisplay(); 401 return; 402 } 403 404 if (strcmp("0",dispstr)==0) 405 return; /* don't neg a zero */ 406 if (dispstr[0]=='-') /* already neg-ed */ 407 strcpy(dispstr,dispstr+1); /* move str left once */ 408 else { /* not neg-ed. add a '-' */ 409 char tmp[32]; 410 snprintf(tmp, sizeof(tmp), "-%s", dispstr); 411 strlcpy(dispstr, tmp, sizeof(dispstr)); 412 } 413 if (entered==2) 414 dnum = -1.0 * dnum; 415 DrawDisplay(); 416} 417 418/* Two operand functions for infix calc */ 419void 420twoop(int keynum) 421{ 422 if (flagINV) { 423 flagINV=0; 424 DrawDisplay(); 425 } 426 427 if (!entered) { /* something like "5+*" */ 428 if (!isopempty()) 429 (void) PopOp(); /* replace the prev op */ 430 PushOp(keynum); /* with the new one */ 431 return; 432 } 433 434 if (entered==1) 435 parse_double(dispstr,"%lf",&dnum); 436 437 clrdisp=CLR=1; 438 entered=Dpoint=exponent=0; 439 440 if (!isopempty()) { /* there was a previous op */ 441 lastop=PopOp(); /* get it */ 442 443 if (lastop==kLPAR) { /* put it back */ 444 PushOp(kLPAR); 445 PushOp(keynum); 446 PushNum(dnum); 447 return; 448 } 449 450 /* now, if the current op (keynum) is of 451 higher priority than the lastop, the current 452 op and number are just pushed on top 453 Priorities: (Y^X) > *,/ > +,- */ 454 455 if (priority(keynum) > priority(lastop)) { 456 PushNum(dnum); 457 PushOp(lastop); 458 PushOp(keynum); 459 } else { /* execute lastop on lastnum and dnum, push 460 result and current op on stack */ 461 acc=PopNum(); 462 switch (lastop) { /* perform the operation */ 463 case kADD: acc += dnum; break; 464 case kSUB: acc -= dnum; break; 465 case kMUL: acc *= dnum; break; 466 case kDIV: acc /= dnum; break; 467 case kPOW: acc = pow(acc,dnum); break; 468 } 469 PushNum(acc); 470 PushOp(keynum); 471 snprintf(dispstr, sizeof(dispstr), "%.8g", acc); 472 DrawDisplay(); 473 dnum=acc; 474 } 475 } 476 else { /* op stack is empty, push op and num */ 477 PushOp(keynum); 478 PushNum(dnum); 479 } 480} 481 482/* Two operand functions for rpn calc */ 483void 484twof(int keynum) 485{ 486 if (flagINV) { 487 flagINV=0; 488 DrawDisplay(); 489 } 490 if (!entered) 491 return; 492 if (entered==1) 493 parse_double(dispstr, "%lf", &dnum); 494 acc = PopNum(); 495 switch(keynum) { 496 case kADD: acc += dnum; break; 497 case kSUB: acc -= dnum; break; 498 case kMUL: acc *= dnum; break; 499 case kDIV: acc /= dnum; break; 500 case kPOW: acc = pow(acc,dnum); break; 501 case kXXY: PushNum(dnum); 502 } 503 snprintf(dispstr, sizeof(dispstr), "%.8g", acc); 504 DrawDisplay(); 505 clrdisp++; 506 Dpoint = exponent = 0; 507 entered = 2; 508 lift_enabled = 1; 509 dnum = acc; 510} 511 512void 513entrf(void) 514{ 515 flagINV=0; 516 if (!entered) 517 return; 518 519 clrdisp=CLR=1; 520 Dpoint=exponent=0; 521 522 if (entered==1) 523 parse_double(dispstr,"%lf",&dnum); 524 entered=2; 525 memop = kENTR; 526 PushNum(dnum); 527 lift_enabled = 0; 528} 529 530void 531equf(void) 532{ 533 flagINV=0; 534 if (!entered) 535 return; 536 537 clrdisp=CLR=1; 538 Dpoint=exponent=0; 539 540 if (entered==1) 541 parse_double(dispstr,"%lf",&dnum); 542 entered=2; 543 544 PushNum(dnum); 545 546 while (!isopempty()) { /* do all pending ops */ 547 dnum=PopNum(); 548 acc=PopNum(); 549 lastop=PopOp(); 550 switch (lastop) { 551 case kADD: acc += dnum; 552 break; 553 case kSUB: acc -= dnum; 554 break; 555 case kMUL: acc *= dnum; 556 break; 557 case kDIV: acc /= dnum; 558 break; 559 case kPOW: acc = pow(acc,dnum); 560 break; 561 case kLPAR: flagPAREN--; 562 PushNum(acc); 563 break; 564 } 565 dnum=acc; 566 PushNum(dnum); 567 } 568 569 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 570 DrawDisplay(); 571} 572 573void 574lparf(void) 575{ 576 flagINV=0; 577 PushOp(kLPAR); 578 flagPAREN++; 579 DrawDisplay(); 580} 581 582void 583rollf(void) 584{ 585 if (!entered) 586 return; 587 if (entered==1) 588 parse_double(dispstr, "%lf", &dnum); 589 entered = 2; 590 lift_enabled = 1; 591 RollNum(flagINV); 592 flagINV=0; 593 clrdisp++; 594 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 595 DrawDisplay(); 596} 597 598void 599rparf(void) 600{ 601 flagINV=0; 602 if (!entered) 603 return; 604 605 if (!flagPAREN) 606 return; 607 608 clrdisp++; 609 Dpoint=exponent=0; 610 611 if (entered==1) 612 parse_double(dispstr,"%lf",&dnum); 613 entered=2; 614 615 PushNum(dnum); 616 while (!isopempty() && (lastop=PopOp())!=kLPAR) { 617 /* do all pending ops, back to left paren */ 618 dnum=PopNum(); 619 acc=PopNum(); 620 switch (lastop) { 621 case kADD: acc += dnum; 622 break; 623 case kSUB: acc -= dnum; 624 break; 625 case kMUL: acc *= dnum; 626 break; 627 case kDIV: acc /= dnum; 628 break; 629 case kPOW: acc = pow(acc,dnum); 630 break; 631 } 632 dnum=acc; 633 PushNum(dnum); 634 } 635 (void) PopNum(); 636 flagPAREN--; 637 entered=2; 638 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 639 DrawDisplay(); 640} 641 642void 643drgf(void) 644{ 645 if (flagINV) { 646 if (entered==1) 647 parse_double(dispstr,"%lf",&dnum); 648 switch (drgmode) { 649 case DEG: dnum=dnum*M_PI/180.0; break; 650 case RAD: dnum=dnum*200.0/M_PI; break; 651 case GRAD: dnum=dnum*90.0/100.0; break; 652 } 653 entered=2; 654 clrdisp=1; 655 flagINV=0; 656 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 657 } 658 659 flagINV=0; 660 drgmode = (drgmode + 1) % 3; 661 switch (drgmode) { 662 case DEG: drg2rad=M_PI / 180.0; 663 rad2drg=180.0 / M_PI; 664 break; 665 case RAD: drg2rad=1.0; 666 rad2drg=1.0; 667 break; 668 case GRAD: drg2rad=M_PI / 200.0; 669 rad2drg=200.0 / M_PI; 670 break; 671 } 672 DrawDisplay(); 673} 674 675void 676invf(void) 677{ 678 flagINV = ~flagINV; 679 DrawDisplay(); 680} 681 682void 683memf(int keynum) 684{ 685 memop = keynum; 686 if (entered==1) 687 parse_double(dispstr,"%lf",&dnum); 688 entered = 2; 689 clrdisp++; 690 lift_enabled = 0; 691} 692 693void 694oneop(int keynum) 695{ 696 int i,j; 697 double dtmp; 698 699 if (entered==1) 700 parse_double(dispstr,"%lf",&dnum); 701 entered = 2; 702 703 switch (keynum) { /* do the actual math fn. */ 704 case kE: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_E; break; 705 case kPI: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_PI; break; 706 case kRECIP: dnum=1.0/dnum; break; 707 case kSQR: flagINV = !flagINV; /* fall through to */ 708 case kSQRT: if (flagINV) dnum=dnum*dnum; 709 else dnum=sqrt(dnum); 710 break; 711 case k10X: flagINV = !flagINV; /* fall through to */ 712 case kLOG: if (flagINV) dnum=pow(10.0,dnum); 713 else dnum=log10(dnum); 714 break; 715 case kEXP: flagINV = !flagINV; /* fall through to */ 716 case kLN: if (flagINV) dnum=exp(dnum); 717 else dnum=log(dnum); 718 break; 719 case kSIN: if (flagINV) dnum=asin(dnum)*rad2drg; 720 else dnum=sin(dnum*drg2rad); 721 break; 722 case kCOS: if (flagINV) dnum=acos(dnum)*rad2drg; 723 else dnum=cos(dnum*drg2rad); 724 break; 725 case kTAN: if (flagINV) dnum=atan(dnum)*rad2drg; 726 else dnum=tan(dnum*drg2rad); 727 break; 728 case kSTO: mem[0]=dnum; flagM=!(mem[0]==0.0); break; 729 case kRCL: if (rpn && lift_enabled) PushNum(dnum); 730 dnum=mem[0]; flagM=!(mem[0]==0.0); break; 731 case kSUM: mem[0]+=dnum; flagM=!(mem[0]==0.0); break; 732 case kEXC: dtmp=dnum; dnum=mem[0]; mem[0]=dtmp; 733 flagM=!(mem[0]==0.0); break; 734 case kFACT: if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) { 735 strlcpy(dispstr, "error", sizeof(dispstr)); 736 entered=3; 737 break; 738 } 739 dtmp = floor(dnum); i = dtmp; 740 for (j=1,dnum=1.0; j<=i; j++) 741 dnum*=(float) j; 742 break; 743 } 744 745 if (entered==3) { /* error */ 746 DrawDisplay(); 747 return; 748 } 749 750 memop = keynum; 751 entered=2; 752 clrdisp=1; 753 flagINV=0; 754 lift_enabled = 1; 755 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 756 DrawDisplay(); 757} 758 759void 760offf(void) 761{ 762 /* full reset */ 763 int i; 764 ResetCalc(); 765 entered=clrdisp=1; 766 lift_enabled = 0; 767 dnum=mem[0]=0.0; 768 if (rpn) 769 for (i=1; i < XCALC_MEMORY; i++) 770 mem[i]=0.0; 771 exponent=Dpoint=0; 772 DrawDisplay(); 773} 774 775 776#define STACKMAX 32 777static int opstack[STACKMAX]; 778static int opsp; 779static double numstack[STACKMAX]; 780static int numsp; 781 782 783/*******/ 784static void 785PushOp(int op) 786/*******/ 787{ 788 if (opsp==STACKMAX) { 789 strlcpy(dispstr, "stack error", sizeof(dispstr)); 790 entered=3; 791 } else 792 opstack[opsp++]=op; 793} 794 795/*******/ 796static int 797PopOp(void) 798/*******/ 799{ 800 if (opsp==0) { 801 strlcpy(dispstr, "stack error", sizeof(dispstr)); 802 entered=3; 803 return(kNOP); 804 } else 805 return(opstack[--opsp]); 806} 807 808/*******/ 809static int 810isopempty(void) 811/*******/ 812{ 813 return( opsp ? 0 : 1 ); 814} 815 816#ifdef DEBUG 817static void 818showstack(char *string) 819{ 820 fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1], 821 numstack[2]); 822} 823#endif 824 825/*******/ 826static void 827PushNum(double num) 828/*******/ 829{ 830 if (rpn) { 831 numstack[2] = numstack[1]; 832 numstack[1] = numstack[0]; 833 numstack[0] = num; 834 return; 835 } 836 if (numsp==STACKMAX) { 837 strlcpy(dispstr, "stack error", sizeof(dispstr)); 838 entered=3; 839 } else 840 numstack[numsp++]=num; 841} 842 843/*******/ 844static double 845PopNum(void) 846/*******/ 847{ 848 if (rpn) { 849 double tmp = numstack[0]; 850 numstack[0] = numstack[1]; 851 numstack[1] = numstack[2]; 852 return(tmp); 853 } 854 if (numsp==0) { 855 strlcpy(dispstr, "stack error", sizeof(dispstr)); 856 entered=3; 857 return 0.0; 858 } else 859 return(numstack[--numsp]); 860} 861 862/*******/ 863static void 864RollNum(int dir) 865/*******/ 866{ 867 double tmp; 868 869 if (dir) { /* roll up */ 870 tmp = dnum; 871 dnum = numstack[2]; 872 numstack[2] = numstack[1]; 873 numstack[1] = numstack[0]; 874 numstack[0] = tmp; 875 } else { /* roll down */ 876 tmp = dnum; 877 dnum = numstack[0]; 878 numstack[0] = numstack[1]; 879 numstack[1] = numstack[2]; 880 numstack[2] = tmp; 881 } 882} 883 884 885/*******/ 886static void 887ClearStacks(void) 888/*******/ 889{ 890 if (rpn) 891 numstack[0] = numstack[1] = numstack[2] = 0.; 892 opsp=numsp=0; 893} 894 895 896/*******/ 897static int 898priority(int op) 899/*******/ 900{ 901 switch (op) { 902 case kPOW: return(2); 903 case kMUL: 904 case kDIV: return(1); 905 case kADD: 906 case kSUB: return(0); 907 } 908 return 0; 909} 910 911 912/********/ 913void 914ResetCalc(void) 915/********/ 916{ 917 flagM=flagINV=flagPAREN=0; drgmode=DEG; 918 setflag(XCalc_MEMORY, False); 919 setflag(XCalc_INVERSE, False); 920 setflag(XCalc_PAREN, False); 921 setflag(XCalc_RADIAN, False); 922 setflag(XCalc_GRADAM, False); 923 setflag(XCalc_DEGREE, True); 924 strlcpy(dispstr, "0", sizeof(dispstr)); 925 draw(dispstr); 926 ClearStacks(); 927 drg2rad=M_PI/180.0; 928 rad2drg=180.0/M_PI; 929} 930