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