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