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