math.c revision 0df20633
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 215 flagINV=0; 216 217 if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) { 218 int cell = 0; 219 220 switch (keynum) { 221 case kONE: cell = 1; break; 222 case kTWO: cell = 2; break; 223 case kTHREE: cell = 3; break; 224 case kFOUR: cell = 4; break; 225 case kFIVE: cell = 5; break; 226 case kSIX: cell = 6; break; 227 case kSEVEN: cell = 7; break; 228 case kEIGHT: cell = 8; break; 229 case kNINE: cell = 9; break; 230 case kZERO: cell = 0; break; 231 } 232 switch (memop) { 233 case kSTO: 234 mem[cell] = dnum; 235 lift_enabled = 1; 236 entered = 2; 237 clrdisp++; 238 break; 239 case kRCL: 240 PushNum(dnum); 241 dnum = mem[cell]; 242 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 243 lift_enabled = 1; 244 entered = 1; 245 clrdisp++; 246 break; 247 case kSUM: 248 mem[cell] += dnum; 249 lift_enabled = 1; 250 entered = 2; 251 clrdisp++; 252 break; 253 } 254 memop = kCLR; 255 DrawDisplay(); 256 return; 257 } 258 259 if (clrdisp) { 260 dispstr[0]='\0'; 261 exponent=Dpoint=0; 262/* if (rpn && entered==2) 263 PushNum(dnum); 264 */ 265 if (rpn & lift_enabled) 266 PushNum(dnum); 267 } 268 if ((int) strlen(dispstr) >= MAXDISP) 269 return; 270 271 switch (keynum){ 272 case kONE: st[0] = '1'; break; 273 case kTWO: st[0] = '2'; break; 274 case kTHREE: st[0] = '3'; break; 275 case kFOUR: st[0] = '4'; break; 276 case kFIVE: st[0] = '5'; break; 277 case kSIX: st[0] = '6'; break; 278 case kSEVEN: st[0] = '7'; break; 279 case kEIGHT: st[0] = '8'; break; 280 case kNINE: st[0] = '9'; break; 281 case kZERO: st[0] = '0'; break; 282 } 283 st[1] = '\0'; 284 strcat(dispstr,st); 285 286 DrawDisplay(); 287 if (clrdisp && keynum != kZERO) 288 clrdisp=0; /*no leading 0s*/ 289 memop = keynum; 290 entered=1; 291 lift_enabled = 0; 292} 293 294void 295bkspf(void) 296{ 297 298 lift_enabled = 0; 299 300 if (! flagINV) 301 { 302 if (entered!=1) { 303 clearf(); 304 return; 305 } 306 if (clrdisp) 307 return; 308 if ((int) strlen(dispstr) > 0) { 309#ifndef X_LOCALE 310 const char *dp = localeconv()->decimal_point; 311 size_t dp_len = strlen(dp); 312 size_t ds_len = strlen(dispstr); 313 if (ds_len >= dp_len && strcmp(dispstr + ds_len - dp_len, dp) == 0) 314 Dpoint=0; 315#else 316 if (dispstr[strlen(dispstr)-1] == '.') 317 Dpoint=0; 318#endif 319 dispstr[strlen(dispstr)-1] = 0; 320 } 321 if (strlen(dispstr) == 0) { 322 strcat(dispstr, "0"); 323 clrdisp++; 324 } 325 } 326 else 327 { 328 strlcpy(dispstr, "0", sizeof(dispstr)); 329 dnum = 0.0; 330 clrdisp++; 331 flagINV = 0; 332 } 333 DrawDisplay(); 334} 335 336void 337decf(void) 338{ 339 flagINV=0; 340 if (clrdisp) { 341 if (rpn && lift_enabled) 342 PushNum(dnum); 343 strlcpy(dispstr, "0", sizeof(dispstr)); 344 } 345 if (!Dpoint) { 346#ifndef X_LOCALE 347 strcat(dispstr, localeconv()->decimal_point); 348#else 349 strcat(dispstr, "."); 350#endif 351 DrawDisplay(); 352 Dpoint++; 353 } 354 clrdisp=0; 355 entered=1; 356} 357 358void 359eef(void) 360{ 361 flagINV=0; 362 if (clrdisp) { 363 if (rpn && lift_enabled) 364 PushNum(dnum); 365 strlcpy(dispstr, rpn ? "1" : "0", sizeof(dispstr)); 366 } 367 if (!exponent) { 368 strcat(dispstr,"E+"); 369 DrawDisplay(); 370 exponent=strlen(dispstr)-1; /* where the '-' goes */ 371 } 372 clrdisp=0; 373 entered=1; 374} 375 376void 377clearf(void) 378{ 379 flagINV=0; 380 if (CLR && !rpn) { /* clear all */ 381 ClearStacks(); 382 flagPAREN=0; 383 } 384 CLR++; 385 exponent=Dpoint=0; 386 clrdisp=1; 387 entered=1; 388 strlcpy(dispstr, "0", sizeof(dispstr)); 389 DrawDisplay(); 390} 391 392void 393negf(void) 394{ 395 flagINV=0; 396 if (exponent) { /* neg the exponent */ 397 if (dispstr[exponent]=='-') 398 dispstr[exponent]='+'; 399 else 400 dispstr[exponent]='-'; 401 DrawDisplay(); 402 return; 403 } 404 405 if (strcmp("0",dispstr)==0) 406 return; /* don't neg a zero */ 407 if (dispstr[0]=='-') /* already neg-ed */ 408 strcpy(dispstr,dispstr+1); /* move str left once */ 409 else { /* not neg-ed. add a '-' */ 410 char tmp[32]; 411 snprintf(tmp, sizeof(tmp), "-%s", dispstr); 412 strlcpy(dispstr, tmp, sizeof(dispstr)); 413 } 414 if (entered==2) 415 dnum = -1.0 * dnum; 416 DrawDisplay(); 417} 418 419/* Two operand functions for infix calc */ 420void 421twoop(int keynum) 422{ 423 if (flagINV) { 424 flagINV=0; 425 DrawDisplay(); 426 } 427 428 if (!entered) { /* something like "5+*" */ 429 if (!isopempty()) 430 (void) PopOp(); /* replace the prev op */ 431 PushOp(keynum); /* with the new one */ 432 return; 433 } 434 435 if (entered==1) 436 parse_double(dispstr,"%lf",&dnum); 437 438 clrdisp=CLR=1; 439 entered=Dpoint=exponent=0; 440 441 if (!isopempty()) { /* there was a previous op */ 442 lastop=PopOp(); /* get it */ 443 444 if (lastop==kLPAR) { /* put it back */ 445 PushOp(kLPAR); 446 PushOp(keynum); 447 PushNum(dnum); 448 return; 449 } 450 451 /* now, if the current op (keynum) is of 452 higher priority than the lastop, the current 453 op and number are just pushed on top 454 Priorities: (Y^X) > *,/ > +,- */ 455 456 if (priority(keynum) > priority(lastop)) { 457 PushNum(dnum); 458 PushOp(lastop); 459 PushOp(keynum); 460 } else { /* execute lastop on lastnum and dnum, push 461 result and current op on stack */ 462 acc=PopNum(); 463 switch (lastop) { /* perform the operation */ 464 case kADD: acc += dnum; break; 465 case kSUB: acc -= dnum; break; 466 case kMUL: acc *= dnum; break; 467 case kDIV: acc /= dnum; break; 468 case kPOW: acc = pow(acc,dnum); break; 469 } 470 PushNum(acc); 471 PushOp(keynum); 472 snprintf(dispstr, sizeof(dispstr), "%.8g", acc); 473 DrawDisplay(); 474 dnum=acc; 475 } 476 } 477 else { /* op stack is empty, push op and num */ 478 PushOp(keynum); 479 PushNum(dnum); 480 } 481} 482 483/* Two operand functions for rpn calc */ 484void 485twof(int keynum) 486{ 487 if (flagINV) { 488 flagINV=0; 489 DrawDisplay(); 490 } 491 if (!entered) 492 return; 493 if (entered==1) 494 parse_double(dispstr, "%lf", &dnum); 495 acc = PopNum(); 496 switch(keynum) { 497 case kADD: acc += dnum; break; 498 case kSUB: acc -= dnum; break; 499 case kMUL: acc *= dnum; break; 500 case kDIV: acc /= dnum; break; 501 case kPOW: acc = pow(acc,dnum); break; 502 case kXXY: PushNum(dnum); 503 } 504 snprintf(dispstr, sizeof(dispstr), "%.8g", acc); 505 DrawDisplay(); 506 clrdisp++; 507 Dpoint = exponent = 0; 508 entered = 2; 509 lift_enabled = 1; 510 dnum = acc; 511} 512 513void 514entrf(void) 515{ 516 flagINV=0; 517 if (!entered) 518 return; 519 520 clrdisp=CLR=1; 521 Dpoint=exponent=0; 522 523 if (entered==1) 524 parse_double(dispstr,"%lf",&dnum); 525 entered=2; 526 memop = kENTR; 527 PushNum(dnum); 528 lift_enabled = 0; 529} 530 531void 532equf(void) 533{ 534 flagINV=0; 535 if (!entered) 536 return; 537 538 clrdisp=CLR=1; 539 Dpoint=exponent=0; 540 541 if (entered==1) 542 parse_double(dispstr,"%lf",&dnum); 543 entered=2; 544 545 PushNum(dnum); 546 547 while (!isopempty()) { /* do all pending ops */ 548 dnum=PopNum(); 549 acc=PopNum(); 550 lastop=PopOp(); 551 switch (lastop) { 552 case kADD: acc += dnum; 553 break; 554 case kSUB: acc -= dnum; 555 break; 556 case kMUL: acc *= dnum; 557 break; 558 case kDIV: acc /= dnum; 559 break; 560 case kPOW: acc = pow(acc,dnum); 561 break; 562 case kLPAR: flagPAREN--; 563 PushNum(acc); 564 break; 565 } 566 dnum=acc; 567 PushNum(dnum); 568 } 569 570 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 571 DrawDisplay(); 572} 573 574void 575lparf(void) 576{ 577 flagINV=0; 578 PushOp(kLPAR); 579 flagPAREN++; 580 DrawDisplay(); 581} 582 583void 584rollf(void) 585{ 586 if (!entered) 587 return; 588 if (entered==1) 589 parse_double(dispstr, "%lf", &dnum); 590 entered = 2; 591 lift_enabled = 1; 592 RollNum(flagINV); 593 flagINV=0; 594 clrdisp++; 595 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 596 DrawDisplay(); 597} 598 599void 600rparf(void) 601{ 602 flagINV=0; 603 if (!entered) 604 return; 605 606 if (!flagPAREN) 607 return; 608 609 clrdisp++; 610 Dpoint=exponent=0; 611 612 if (entered==1) 613 parse_double(dispstr,"%lf",&dnum); 614 entered=2; 615 616 PushNum(dnum); 617 while (!isopempty() && (lastop=PopOp())!=kLPAR) { 618 /* do all pending ops, back to left paren */ 619 dnum=PopNum(); 620 acc=PopNum(); 621 switch (lastop) { 622 case kADD: acc += dnum; 623 break; 624 case kSUB: acc -= dnum; 625 break; 626 case kMUL: acc *= dnum; 627 break; 628 case kDIV: acc /= dnum; 629 break; 630 case kPOW: acc = pow(acc,dnum); 631 break; 632 } 633 dnum=acc; 634 PushNum(dnum); 635 } 636 (void) PopNum(); 637 flagPAREN--; 638 entered=2; 639 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 640 DrawDisplay(); 641} 642 643void 644drgf(void) 645{ 646 if (flagINV) { 647 if (entered==1) 648 parse_double(dispstr,"%lf",&dnum); 649 switch (drgmode) { 650 case DEG: dnum=dnum*M_PI/180.0; break; 651 case RAD: dnum=dnum*200.0/M_PI; break; 652 case GRAD: dnum=dnum*90.0/100.0; break; 653 } 654 entered=2; 655 clrdisp=1; 656 flagINV=0; 657 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 658 } 659 660 flagINV=0; 661 drgmode = (drgmode + 1) % 3; 662 switch (drgmode) { 663 case DEG: drg2rad=M_PI / 180.0; 664 rad2drg=180.0 / M_PI; 665 break; 666 case RAD: drg2rad=1.0; 667 rad2drg=1.0; 668 break; 669 case GRAD: drg2rad=M_PI / 200.0; 670 rad2drg=200.0 / M_PI; 671 break; 672 } 673 DrawDisplay(); 674} 675 676void 677invf(void) 678{ 679 flagINV = ~flagINV; 680 DrawDisplay(); 681} 682 683void 684memf(int keynum) 685{ 686 memop = keynum; 687 if (entered==1) 688 parse_double(dispstr,"%lf",&dnum); 689 entered = 2; 690 clrdisp++; 691 lift_enabled = 0; 692} 693 694void 695oneop(int keynum) 696{ 697 int i,j; 698 double dtmp; 699 700 if (entered==1) 701 parse_double(dispstr,"%lf",&dnum); 702 entered = 2; 703 704 switch (keynum) { /* do the actual math fn. */ 705 case kE: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_E; break; 706 case kPI: if (rpn && memop != kENTR) PushNum(dnum); dnum=M_PI; break; 707 case kRECIP: dnum=1.0/dnum; break; 708 case kSQR: flagINV = !flagINV; /* fall through */ 709 case kSQRT: if (flagINV) dnum=dnum*dnum; 710 else dnum=sqrt(dnum); 711 break; 712 case k10X: flagINV = !flagINV; /* fall through */ 713 case kLOG: if (flagINV) dnum=pow(10.0,dnum); 714 else dnum=log10(dnum); 715 break; 716 case kEXP: flagINV = !flagINV; /* fall through */ 717 case kLN: if (flagINV) dnum=exp(dnum); 718 else dnum=log(dnum); 719 break; 720 case kSIN: if (flagINV) dnum=asin(dnum)*rad2drg; 721 else dnum=sin(dnum*drg2rad); 722 break; 723 case kCOS: if (flagINV) dnum=acos(dnum)*rad2drg; 724 else dnum=cos(dnum*drg2rad); 725 break; 726 case kTAN: if (flagINV) dnum=atan(dnum)*rad2drg; 727 else dnum=tan(dnum*drg2rad); 728 break; 729 case kSTO: mem[0]=dnum; flagM=!(mem[0]==0.0); break; 730 case kRCL: if (rpn && lift_enabled) PushNum(dnum); 731 dnum=mem[0]; flagM=!(mem[0]==0.0); break; 732 case kSUM: mem[0]+=dnum; flagM=!(mem[0]==0.0); break; 733 case kEXC: dtmp=dnum; dnum=mem[0]; mem[0]=dtmp; 734 flagM=!(mem[0]==0.0); break; 735 case kFACT: if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) { 736 strlcpy(dispstr, "error", sizeof(dispstr)); 737 entered=3; 738 break; 739 } 740 dtmp = floor(dnum); i = dtmp; 741 for (j=1,dnum=1.0; j<=i; j++) 742 dnum*=(float) j; 743 break; 744 } 745 746 if (entered==3) { /* error */ 747 DrawDisplay(); 748 return; 749 } 750 751 memop = keynum; 752 entered=2; 753 clrdisp=1; 754 flagINV=0; 755 lift_enabled = 1; 756 snprintf(dispstr, sizeof(dispstr), "%.8g", dnum); 757 DrawDisplay(); 758} 759 760void 761offf(void) 762{ 763 /* full reset */ 764 ResetCalc(); 765 entered=clrdisp=1; 766 lift_enabled = 0; 767 dnum=mem[0]=0.0; 768 if (rpn) 769 for (int 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