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