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