a58c5196f233c8f950e7c0226e5710908f23d4f8
[oweals/cde.git] / cde / programs / dtcalc / functions.c
1 /* $XConsortium: functions.c /main/6 1996/09/25 09:36:28 mustafa $ */
2 /*                                                                      *
3  *  functions.c                                                         *
4  *   Contains the many of the functions (i.e. do_*) which actually do   *
5  *   (at least start) the calculations.                                 *
6  *                                                                      *
7  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
8  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
9  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
10  * (c) Copyright 1993, 1994 Novell, Inc.                                *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <math.h>
18 #include "calctool.h"
19
20 extern char *base_str[] ;       /* Strings for each base value. */
21 extern char *dtype_str[] ;      /* Strings for each display mode value. */
22 extern char *mode_str[] ;       /* Strings for each mode value. */
23 extern char *ttype_str[] ;      /* Strings for each trig type value. */
24 extern char *vstrs[] ;          /* Various strings. */
25
26 extern struct button buttons[] ;           /* Calculator button values. */
27 extern struct button mode_buttons[] ;      /* Special "mode" buttons. */
28 extern struct menu_entry menu_entries[] ;  /* All the menu strings. */
29
30 extern Vars v ;                 /* Calctool variables and options. */
31
32 double mods[] = { 1.0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4,
33                   1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9,
34                   1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14,
35                   1.0e-15, 1.0e-16, 1.0e-17, 1.0e-18, 1.0e-19 };
36
37
38 void
39 do_accuracy()     /* Set display accuracy. */
40 {
41   int i ;
42
43   for (i = ACC_START; i <= ACC_END; i++)
44     if (v->current == menu_entries[i].val)
45       {
46         v->accuracy = char_val(v->current) ;
47         make_registers(MEM) ;
48         make_registers(FIN) ;
49         return ;
50       }
51 }
52
53
54 void
55 do_ascii()        /* Convert ASCII value. */
56 {
57   int val ;
58
59   show_ascii_frame() ;
60 }
61
62
63 void
64 do_base()    /* Change the current base setting. */
65 {
66        if (v->current == BASE_BIN) v->base = BIN ;
67   else if (v->current == BASE_OCT) v->base = OCT ;
68   else if (v->current == BASE_DEC) v->base = DEC ;
69   else if (v->current == BASE_HEX) v->base = HEX ;
70   else return ;
71
72   set_base(v->base) ;
73 }
74
75 void
76 set_base(base)
77 enum base_type base ;
78 {
79   grey_buttons(v->base) ;
80   show_display(v->MPdisp_val) ;
81   set_option_menu((int) BASEITEM, (int)v->base);
82   v->pending = 0 ;
83   if (v->rstate) make_registers(MEM) ;
84   if (v->frstate) make_registers(FIN) ;
85 }
86
87 void
88 do_business()     /* Perform special business mode calculations. */
89 {
90   Boolean need_show = TRUE;
91   char *display_number = NULL;
92   int MPbv[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MP3[MP_SIZE], MP4[MP_SIZE] ;
93   int MP5[MP_SIZE];
94   int i, len, val, val2, accSav ;
95   double result, w;
96
97   if (IS_KEY(v->current, KEY_CTRM))
98     {
99 /*  Cterm - FMEM1 = int (periodic interest rate).
100  *          FMEM2 = Pv  (present value).
101  *          FMEM4 = Fv  (future value).
102  *
103  *          RESULT = log(FMEM4 / FMEM2) / log(1 + FMEM1)
104  */
105       if(v->MPfvals[1] == 0.0 || v->MPfvals[2] == 0.0 || v->MPfvals[4] == 0.0)
106       {
107            char *errorMsg, *tmp;
108
109            /* want to undraw the button first */
110            draw_button(19, 0, 4, 3, FALSE);
111            errorMsg = GETMESSAGE(5, 7, "Can't calculate 'Compound Term'\nwithout a non zero interest rate,\na non zero Present value, and\na non zero Future value.\n");
112            tmp = XtNewString(errorMsg);
113            ErrorDialog(tmp);
114            XtFree(tmp);
115       }
116       else
117       {
118          v->error = False;
119          result = log(v->MPfvals[4] / v->MPfvals[2]) / log(1.0 + (v->MPfvals[1] / 1200));
120          if(!v->error)
121          {
122             mpcdm(&result, v->MPdisp_val) ;
123             make_registers(FIN) ;
124             v->funstate = 1;
125          }
126       }
127     }
128   else if (IS_KEY(v->current, KEY_DDB))
129     {
130
131 /*  Ddb   - MEM0 = cost    (amount paid for asset).
132  *          MEM1 = salvage (value of asset at end of its life).
133  *          MEM2 = life    (useful life of the asset).
134  *          MEM3 = period  (time period for depreciation allowance).
135  *
136  *          bv = 0.0 ;
137  *          for (i = 0; i < MEM3; i++)
138  *            {
139  *              VAL = ((MEM0 - bv) * 2) / MEM2
140  *              bv += VAL
141  *            }
142  *          RESULT = VAL
143  */
144
145       i = 0 ;
146       mpcim(&i, MPbv) ;
147       mpcmi(v->MPmvals[3], &len) ;
148       for (i = 0; i < len; i++)
149         {
150           mpsub(v->MPmvals[0], MPbv, MP1) ;
151           val = 2 ;
152           mpmuli(MP1, &val, MP2) ;
153           mpdiv(MP2, v->MPmvals[2], v->MPdisp_val) ;
154           mpstr(MPbv, MP1) ;
155           mpadd(MP1, v->MPdisp_val, MPbv) ;
156         }
157     }
158   else if (IS_KEY(v->current, KEY_FV))
159     {
160
161 /*  Fv    - FMEM3 = pmt (periodic payment).
162  *          FMEM1 = int (periodic interest rate).
163  *          FMEM2 = Pv  (present value).
164  *          FMEM0 = n   (number of periods).
165  *
166  */
167       if(v->MPfvals[0] == 0.0 || v->MPfvals[1] == 0.0 ||
168              (v->MPfvals[2] == 0.0 && v->MPfvals[3] == 0.0) || v->funstate == 0)
169       {
170           if(v->funstate == 1)
171           {
172              v->funstate = 0;
173              doerr(GETMESSAGE(5, 2, "ERROR: No Solution"));
174              return;
175           }
176           else
177              /* set FV register */
178              mpcmd(v->MPdisp_val, &(v->MPfvals[4]));
179       }
180       else
181       {
182          if ((w = 1.0 + v->MPfvals[1] / (v->MPfvals[5] * 100.0)) == 1.0)
183              result = -(v->MPfvals[2] + v->MPfvals[0] * v->MPfvals[3]);
184          else
185              result =  -(v->MPfvals[2] * pow(w, v->MPfvals[0]) +
186                        v->MPfvals[3] * (pow(w, v->MPfvals[0]) - 1.0) *
187                        pow(w, 0.0) / (w - 1.0));
188          mpcdm(&result, v->MPdisp_val) ;
189       }
190       if(strcmp(v->display, GETMESSAGE(3, 364, "Error")) != 0)
191          mpcmd(v->MPdisp_val, &(v->MPfvals[4]));
192       make_registers(FIN) ;
193       v->funstate = 1;
194     }
195   else if (IS_KEY(v->current, KEY_PMT))
196     {
197
198 /*  Pmt   - FMEM0 = prin (principal).
199  *          FMEM1 = int  (periodic interest rate).
200  *          FMEM2 = n    (term).
201  *
202  *          RESULT = FMEM0 * (FMEM1 / (1 - pow(FMEM1 + 1, -1 * FMEM2)))
203  */
204
205       if(v->MPfvals[0] == 0.0 || v->MPfvals[1] == 0.0 ||
206            (v->MPfvals[2] == 0.0 && v->MPfvals[4] == 0.0) || v->funstate == 0)
207       {
208           if(v->funstate == 1)
209           {
210              v->funstate = 0;
211              doerr(GETMESSAGE(5, 2, "ERROR: No Solution"));
212              return;
213           }
214           else
215              /* set Payment register */
216              mpcmd(v->MPdisp_val, &(v->MPfvals[3]));
217       }
218       else
219       {
220
221          if ((w = 1.0 + v->MPfvals[1] / (v->MPfvals[5] * 100.0)) == 1.0)
222              result = -(v->MPfvals[4] + v->MPfvals[2]) / v->MPfvals[0];
223          else
224              result = -(v->MPfvals[2] * pow(w, v->MPfvals[0]) +
225                         v->MPfvals[4]) * (w - 1.0) /
226                         ((pow(w, v->MPfvals[0]) - 1.0) * pow(w, 0.0));
227          mpcdm(&result, v->MPdisp_val) ;
228       }
229       if(strcmp(v->display, GETMESSAGE(3, 364, "Error")) != 0)
230          mpcmd(v->MPdisp_val, &(v->MPfvals[3]));
231       make_registers(FIN) ;
232       v->funstate = 1;
233     }
234   else if (IS_KEY(v->current, KEY_PV))
235     {
236
237 /*  Pv    - FMEM0 = pmt (periodic payment).
238  *          FMEM1 = int (periodic interest rate).
239  *          FMEM2 = n   (term).
240  *
241  *          RESULT = FMEM0 * (1 - pow(1 + FMEM1, -1 * FMEM2)) / FMEM1
242  */
243
244       if(v->MPfvals[0] == 0.0 || v->MPfvals[1] == 0.0 || v->MPfvals[3] == 0.0 ||                v->funstate == 0)
245       {
246           if(v->funstate == 1)
247           {
248              v->funstate = 0;
249              doerr(GETMESSAGE(5, 2, "ERROR: No Solution"));
250              return;
251           }
252           else
253              /* set PV register */
254              mpcmd(v->MPdisp_val, &(v->MPfvals[2]));
255       }
256       else
257       {
258          if ((w = 1.0 + v->MPfvals[1] / (v->MPfvals[5] * 100.0)) == 1.0)
259              result = -(v->MPfvals[4] + v->MPfvals[0] * v->MPfvals[3]);
260          else
261              result =  -(v->MPfvals[4] / pow(w, v->MPfvals[0]) +
262                          v->MPfvals[3] * (pow(w, v->MPfvals[0]) - 1.0) *
263                          pow(w, 0.0 - v->MPfvals[0]) / (w - 1.0));
264          mpcdm(&result, v->MPdisp_val) ;
265       }
266       if(strcmp(v->display, GETMESSAGE(3, 364, "Error")) != 0)
267          mpcmd(v->MPdisp_val, &(v->MPfvals[2]));
268       make_registers(FIN) ;
269       v->funstate = 1;
270     }
271   else if (IS_KEY(v->current, KEY_RATE))
272     {
273 /*  Rate  - MEM0 = fv (future value).
274  *          MEM1 = pv (present value).
275  *          MEM2 = n  (term).
276  *
277  *          RESULT = pow(MEM0 / MEM1, 1 / MEM2) - 1
278  */
279       if(v->MPfvals[0] == 0.0 || (v->MPfvals[2] == 0.0 && v->MPfvals[3] == 0.0)
280                               || (v->MPfvals[3] == 0.0 && v->MPfvals[4] == 0.0)
281                               || v->funstate == 0)
282       {
283           if(v->funstate == 1)
284           {
285              v->funstate = 0;
286              doerr(GETMESSAGE(5, 2, "ERROR: No Solution"));
287              return;
288           }
289           else
290           {
291              accSav = v->accuracy;
292              v->accuracy = 2;
293              display_number = make_number(v->MPdisp_val, FALSE);
294              MPstr_to_num(display_number, DEC, v->MPdisp_val);
295              /* set RATE register */
296              mpcmd(v->MPdisp_val, &(v->MPfvals[1]));
297              v->accuracy = accSav;
298           }
299       }
300       else
301       {
302           compute_i(&(v->MPfvals[1]));
303           mpcdm(&(v->MPfvals[1]), v->MPdisp_val);
304           accSav = v->accuracy;
305           v->accuracy = 2;
306           display_number = make_number(v->MPdisp_val, FALSE);
307           MPstr_to_num(display_number, DEC, v->MPdisp_val);
308           v->accuracy = accSav;
309       }
310
311       if(!v->error)
312           make_registers(FIN) ;
313       v->funstate = 1;
314
315       STRCPY(v->display, display_number);
316       set_item(DISPLAYITEM, v->display);
317       need_show = FALSE;
318     }
319   else if (IS_KEY(v->current, KEY_SLN))
320     {
321
322 /*  Sln   - MEM0 = cost    (cost of the asset).
323  *          MEM1 = salvage (salvage value of the asset).
324  *          MEM2 = life    (useful life of the asset).
325  *
326  *          RESULT = (MEM0 - MEM1) / MEM2
327  */
328
329       mpsub(v->MPmvals[0], v->MPmvals[1], MP1) ;
330       mpdiv(MP1, v->MPmvals[2], v->MPdisp_val) ;
331     }
332   else if (IS_KEY(v->current, KEY_SYD))
333     {
334
335 /*  Syd   - MEM0 = cost    (cost of the asset).
336  *          MEM1 = salvage (salvage value of the asset).
337  *          MEM2 = life    (useful life of the asset).
338  *          MEM3 = period  (period for which depreciation is computed).
339  *
340  *          RESULT = ((MEM0 - MEM1) * (MEM2 - MEM3 + 1)) /
341  *                   (MEM2 * (MEM2 + 1) / 2)
342  */
343
344       mpsub(v->MPmvals[2], v->MPmvals[3], MP2) ;
345       val = 1 ;
346       mpaddi(MP2, &val, MP3) ;
347       mpaddi(v->MPmvals[2], &val, MP2) ;
348       mpmul(v->MPmvals[2], MP2, MP4) ;
349       val = 2 ;
350       mpcim(&val, MP2) ;
351       mpdiv(MP4, MP2, MP1) ;
352       mpdiv(MP3, MP1, MP2) ;
353       mpsub(v->MPmvals[0], v->MPmvals[1], MP1) ;
354       mpmul(MP1, MP2, v->MPdisp_val) ;
355     }
356   else if (IS_KEY(v->current, KEY_TERM))
357     {
358
359 /*  Term  - FMEM0 = pmt (periodic payment).
360  *          FMEM1 = fv  (future value).
361  *          FMEM2 = int (periodic interest rate).
362  *
363  *          RESULT = log(1 + (FMEM1 * FMEM2 / FMEM0)) / log(1 + FMEM2)
364  */
365
366       if(v->MPfvals[1] == 0.0 || (v->MPfvals[2] == 0.0 && v->MPfvals[4] == 0)
367                               || v->MPfvals[3] == 0.0 || v->funstate == 0)
368       {
369           if(v->funstate == 1)
370           {
371              v->funstate = 0;
372              doerr(GETMESSAGE(5, 2, "ERROR: No Solution"));
373              return;
374           }
375           else
376              /* set Term register */
377              mpcmd(v->MPdisp_val, &(v->MPfvals[0]));
378       }
379       else
380       {
381          if ((w = 1.0 + v->MPfvals[1] / (v->MPfvals[5] * 100.0)) == 1.0)
382              result = -(v->MPfvals[4] + v->MPfvals[2]) / v->MPfvals[3];
383          else
384          {
385              double wdb = pow(w, 0.0);
386
387              result = log((v->MPfvals[3] * wdb / (w - 1.0) - v->MPfvals[4]) /
388                           (v->MPfvals[2] * pow(w, 0.0) + v->MPfvals[3] * wdb /
389                           (w - 1.0))) / log(w);
390          }
391
392          if(strcmp(v->display, GETMESSAGE(3, 364, "Error")) != 0)
393             mpcdm(&result, v->MPdisp_val) ;
394       }
395       if(strcmp(v->display, GETMESSAGE(3, 364, "Error")) != 0)
396          mpcmd(v->MPdisp_val, &(v->MPfvals[0]));
397       make_registers(FIN) ;
398       v->funstate = 1;
399     }
400   else if (IS_KEY(v->current, KEY_PYR))
401     {
402       mpcmd(v->MPdisp_val, &(v->MPfvals[5]));
403       result = do_round(v->MPfvals[5], 0);
404       if (result < 1.0)
405          v->MPfvals[5] = 1.0;
406       else
407          v->MPfvals[5] = result;
408       make_registers(FIN) ;
409       v->funstate = 1;
410     }
411   else if (IS_KEY(v->current, KEY_FCLR))
412     {
413        int zero = 0;
414
415        mpcim(&zero, MP1) ;
416
417        /* clear Term register */
418        mpcmd(MP1, &(v->MPfvals[0])) ;
419
420        /* clear %/YR register */
421        mpcmd(MP1, &(v->MPfvals[1])) ;
422
423        /* clear PV register */
424        mpcmd(MP1, &(v->MPfvals[2])) ;
425
426        /* clear Payment register */
427        mpcmd(MP1, &(v->MPfvals[3])) ;
428
429        /* clear FV register */
430        mpcmd(MP1, &(v->MPfvals[4])) ;
431
432        zero = 12;
433        mpcim(&zero, MP1) ;
434        mpcmd(MP1, &(v->MPfvals[5])) ;
435
436        make_registers(FIN);
437     }
438
439   if (need_show == TRUE)
440       show_display(v->MPdisp_val) ;
441
442   return;
443 }
444
445
446 void
447 do_calc()      /* Perform arithmetic calculation and display result. */
448 {
449   double dval, dres ;
450   int MP1[MP_SIZE] ;
451
452   /* the financial state is false - last key was not a fin. key */
453   v->funstate = 0;
454
455   if (!(v->opsptr && !v->show_paren))   /* Don't do if processing parens. */
456     if (IS_KEY(v->current, KEY_EQ) && IS_KEY(v->old_cal_value, KEY_EQ))
457       if (v->new_input)
458          mpstr(v->MPdisp_val, v->MPresult) ;
459       else
460          mpstr(v->MPlast_input, v->MPdisp_val) ;
461
462   if (!IS_KEY(v->current, KEY_EQ) && IS_KEY(v->old_cal_value, KEY_EQ))
463     v->cur_op = '?' ;
464
465   if (IS_KEY(v->cur_op, KEY_COS) ||                           /* Cos */
466       IS_KEY(v->cur_op, KEY_SIN) ||                           /* Sin */
467       IS_KEY(v->cur_op, KEY_TAN) ||                           /* Tan */
468       v->cur_op == '?')                                 /* Undefined */
469     mpstr(v->MPdisp_val, v->MPresult) ;
470
471   else if (IS_KEY(v->cur_op, KEY_ADD))                  /* Addition */
472     mpadd(v->MPresult, v->MPdisp_val, v->MPresult) ;
473
474   else if (IS_KEY(v->cur_op, KEY_SUB))                  /* Subtraction. */
475     mpsub(v->MPresult, v->MPdisp_val, v->MPresult) ;
476
477   else if (v->cur_op == '*' ||
478            IS_KEY(v->cur_op, KEY_MUL))                  /* Multiplication */
479     mpmul(v->MPresult, v->MPdisp_val, v->MPresult) ;
480
481   else if (IS_KEY(v->cur_op, KEY_DIV))                  /* Division. */
482     mpdiv(v->MPresult, v->MPdisp_val, v->MPresult) ;
483
484   else if (IS_KEY(v->cur_op, KEY_PER))                  /* % */
485     {
486       mpmul(v->MPresult, v->MPdisp_val, v->MPresult) ;
487       MPstr_to_num("0.01", DEC, MP1) ;
488       mpmul(v->MPresult, MP1, v->MPresult) ;
489     }
490
491   else if (IS_KEY(v->cur_op, KEY_YTOX))                 /* y^x */
492     mppwr2(v->MPresult, v->MPdisp_val, v->MPresult) ;
493
494   else if (IS_KEY(v->cur_op, KEY_AND))                  /* And */
495     {
496       mpcmd(v->MPresult, &dres) ;
497       mpcmd(v->MPdisp_val, &dval) ;
498       dres = setbool((BOOLEAN)(ibool(dres) & ibool(dval))) ;
499       mpcdm(&dres, v->MPresult) ;
500     }
501
502   else if (IS_KEY(v->cur_op, KEY_OR))                   /* Or */
503     {
504       mpcmd(v->MPresult, &dres) ;
505       mpcmd(v->MPdisp_val, &dval) ;
506       dres = setbool((BOOLEAN)(ibool(dres) | ibool(dval))) ;
507       mpcdm(&dres, v->MPresult) ;
508     }
509
510   else if (IS_KEY(v->cur_op, KEY_XOR))                  /* Xor */
511     {
512       mpcmd(v->MPresult, &dres) ;
513       mpcmd(v->MPdisp_val, &dval) ;
514       dres = setbool((BOOLEAN)(ibool(dres) ^ ibool(dval))) ;
515       mpcdm(&dres, v->MPresult) ;
516     }
517
518   else if (IS_KEY(v->cur_op, KEY_XNOR))                 /* Xnor */
519     {
520       mpcmd(v->MPresult, &dres) ;
521       mpcmd(v->MPdisp_val, &dval) ;
522       dres = setbool((BOOLEAN)(~ibool(dres) ^ ibool(dval))) ;
523       mpcdm(&dres, v->MPresult) ;
524     }
525
526   else if (IS_KEY(v->cur_op, KEY_EQ)) /* do nothing. */ ;   /* Equals */
527
528   show_display(v->MPresult) ;
529
530   if (!(IS_KEY(v->current, KEY_EQ) && IS_KEY(v->old_cal_value, KEY_EQ)))
531     mpstr(v->MPdisp_val, v->MPlast_input) ;
532
533   mpstr(v->MPresult, v->MPdisp_val) ;
534
535   v->cur_op = v->current ;
536
537   v->old_cal_value = v->current ;
538   v->new_input     = v->key_exp = 0 ;
539 }
540
541
542 void
543 do_clear()       /* Clear the calculator display and re-initialise. */
544 {
545   clear_display() ;
546   if (v->error) set_item(DISPLAYITEM, "") ;
547   initialise() ;
548 }
549
550
551 void
552 do_constant()
553 {
554   if (v->current >= '0' && v->current <= '9')
555     {
556       mpstr(v->MPcon_vals[char_val(v->current)], v->MPdisp_val) ;
557       show_display(v->MPdisp_val) ;
558     }
559 }
560
561
562 void
563 do_delete()     /* Remove the last numeric character typed. */
564 {
565   if (strlen(v->display))
566     v->display[strlen(v->display)-1] = '\0' ;
567
568    /*  If we were entering a scientific number, and we have backspaced over
569     *  the exponent sign, then this reverts to entering a fixed point number.
570     */
571
572   if (v->key_exp && !(strchr(v->display, '+')))
573     {
574       v->key_exp = 0 ;
575       v->display[strlen(v->display)-1] = '\0' ;
576       set_item(OPITEM, "") ;
577     }
578
579    /* If we've backspaced over the numeric point, clear the pointed flag. */
580
581   if (v->pointed && !(strchr(v->display, '.'))) v->pointed = 0 ;
582
583   if(strcmp(v->display, "") == 0)
584      do_clear();
585
586   set_item(DISPLAYITEM, v->display) ;
587   MPstr_to_num(v->display, v->base, v->MPdisp_val) ;
588 }
589
590
591 void
592 do_exchange()         /* Exchange display with memory register. */
593 {
594   int i, MPtemp[MP_SIZE] ;
595
596   for (i = MEM_START; i <= MEM_END; i++)
597     if (v->current == menu_entries[i].val)
598       {
599         mpstr(v->MPdisp_val, MPtemp) ;
600         mpstr(v->MPmvals[char_val(v->current)], v->MPdisp_val) ;
601         mpstr(MPtemp, v->MPmvals[char_val(v->current)]) ;
602         make_registers(MEM) ;
603         return ;
604       }
605 }
606
607
608 void
609 do_expno()           /* Get exponential number. */
610 {
611   /* the financial state is false - last key was not a fin. key */
612   v->funstate = 0;
613
614   v->pointed = (strchr(v->display, '.') != NULL) ;
615   if (!v->new_input)
616     {
617       STRCPY(v->display, "1.0 +") ;
618       v->new_input = v->pointed = 1 ;
619     }
620   else if (!v->pointed)
621     {
622       STRNCAT(v->display, ". +", 3) ;
623       v->pointed = 1 ;
624     }
625   else if (!v->key_exp) STRNCAT(v->display, " +", 2) ;
626   v->toclear = 0 ;
627   v->key_exp = 1 ;
628   v->exp_posn = strchr(v->display, '+') ;
629   set_item(DISPLAYITEM, v->display) ;
630   MPstr_to_num(v->display, v->base, v->MPdisp_val) ;
631 }
632
633
634 void
635 do_factorial(MPval, MPres)             /* Calculate the factorial of MPval. */
636 int *MPval, *MPres ;
637 {
638   double val ;
639   int i, MPa[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE] ;
640
641 /*  NOTE: do_factorial, on each iteration of the loop, will attempt to
642  *        convert the current result to a double. If v->error is set,
643  *        then we've overflowed. This is to provide the same look&feel
644  *        as V3.
645  *
646  *  XXX:  Needs to be improved. Shouldn't need to convert to a double in
647  *        order to check this.
648  */
649
650   mpstr(MPval, MPa) ;
651   mpcmim(MPval, MP1) ;
652   i = 0 ;
653   mpcim(&i, MP2) ;
654   if (mpeq(MPval, MP1) &&  mpge(MPval, MP2))  /* Only positive integers. */
655     {
656       i = 1 ;
657       if (mpeq(MP1, MP2))                     /* Special case for 0! */
658         {
659           mpcim(&i, MPres) ;
660           return ;
661         }
662       mpcim(&i, MPa) ;
663       mpcmi(MP1, &i) ;
664       if (!i) matherr((struct exception *) NULL) ;
665       else
666         while (i > 0)
667           {
668             mpmuli(MPa, &i, MPa) ;
669             mpcmd(MPa, &val) ;
670             if (v->error) break ;
671             i-- ;
672           }
673     }
674   else matherr((struct exception *) NULL) ;
675   mpstr(MPa, MPres) ;
676 }
677
678
679 void
680 do_frame()    /* Exit dtcalc. */
681 {
682   exit(0) ;
683 }
684
685 void
686 do_function()      /* Perform a user defined function. */
687 {
688   enum fcp_type scurwin ;
689   int fno, scolumn, srow ;
690
691   srow = v->row ;
692   scolumn = v->column ;
693   scurwin = v->curwin ;
694   v->pending = 0 ;
695   if (v->current >= '0' && v->current <= '9')
696     {
697       fno = char_val(v->current) ;
698       if(strcmp(v->fun_vals[fno], "") != 0)
699          process_str(v->fun_vals[fno], M_FUN) ;
700     }
701   v->curwin = scurwin ;
702   v->row = srow ;
703   v->column = scolumn ;
704 }
705
706
707 void
708 do_immed()
709 {
710   double dval, dval2 ;
711   int i, MP1[MP_SIZE], MP2[MP_SIZE] ;
712
713   /* the financial state is false - last key was not a fin. key */
714   v->funstate = 0;
715
716  if (IS_KEY(v->current, KEY_HYP))          /* Hyp */
717     {
718       v->hyperbolic = !v->hyperbolic ;
719       set_item(HYPITEM, (v->hyperbolic) ? vstrs[(int) V_HYP]
720                                         : "    ") ;
721     }
722
723   else if (IS_KEY(v->current, KEY_INV))          /* Inv */
724     {
725       v->inverse = !v->inverse ;
726       set_item(INVITEM, (v->inverse) ? vstrs[(int) V_INV]
727                                      : "    ") ;
728     }
729
730   else if (IS_KEY(v->current, KEY_32))           /* &32 */
731     {
732       mpcmd(v->MPdisp_val, &dval) ;
733       dval2 = ibool2(dval);
734       if(dval2 == 0)
735          doerr(GETMESSAGE(5, 6, "ERR:Num too large for operation"));
736       else
737       {
738          dval = setbool((BOOLEAN)dval2) ;
739          mpcdm(&dval, v->MPdisp_val) ;
740       }
741     }
742
743   else if (IS_KEY(v->current, KEY_16))           /* &16 */
744     {
745       mpcmd(v->MPdisp_val, &dval) ;
746       dval2 = ibool2(dval);
747       if(dval2 == 0)
748          doerr(GETMESSAGE(5, 6, "ERR:Num too large for operation"));
749       else
750       {
751          dval = setbool((BOOLEAN)(ibool(dval2) & 0xffff)) ;
752          mpcdm(&dval, v->MPdisp_val) ;
753       }
754     }
755
756   else if (IS_KEY(v->current, KEY_ETOX))         /* e^x */
757     {
758       mpstr(v->MPdisp_val, MP1) ;
759       mpexp(MP1, v->MPdisp_val) ;
760     }
761
762   else if (IS_KEY(v->current, KEY_TTOX))         /* 10^x */
763     {
764       i = 10 ;
765       mpcim(&i, MP1) ;
766       mppwr2(MP1, v->MPdisp_val, v->MPdisp_val) ;
767     }
768
769   else if (IS_KEY(v->current, KEY_LN))           /* Ln */
770     {
771       mpstr(v->MPdisp_val, MP1) ;
772       mpln(MP1, v->MPdisp_val) ;
773     }
774
775   else if (IS_KEY(v->current, KEY_LOG))          /* Log */
776     {
777       mplog10(v->MPdisp_val, v->MPdisp_val) ;
778     }
779
780   else if (IS_KEY(v->current, KEY_RAND))         /* Rand */
781     {
782       dval = drand48() ;
783       mpcdm(&dval, v->MPdisp_val) ;
784     }
785
786   else if (IS_KEY(v->current, KEY_SQRT))         /* Sqrt */
787     {
788       mpstr(v->MPdisp_val, MP1) ;
789       mpsqrt(MP1, v->MPdisp_val) ;
790     }
791
792   else if (IS_KEY(v->current, KEY_NOT))          /* Not */
793     {
794       mpcmd(v->MPdisp_val, &dval) ;
795       dval = setbool((BOOLEAN)~ibool(dval)) ;
796       mpcdm(&dval, v->MPdisp_val) ;
797     }
798
799   else if (IS_KEY(v->current, KEY_REC))          /* 1/x */
800     {
801       i = 1 ;
802       mpcim(&i, MP1) ;
803       mpstr(v->MPdisp_val, MP2) ;
804       mpdiv(MP1, MP2, v->MPdisp_val) ;
805     }
806   else if (IS_KEY(v->current, KEY_FACT))         /* x! */
807     {
808       do_factorial(v->MPdisp_val, MP1) ;
809       mpstr(MP1, v->MPdisp_val) ;
810     }
811   else if (IS_KEY(v->current, KEY_SQR))          /* x^2 */
812     {
813       mpstr(v->MPdisp_val, MP1) ;
814       mpmul(MP1, MP1, v->MPdisp_val) ;
815     }
816
817   else if (IS_KEY(v->current, KEY_CHS))          /* +/- */
818     {
819       if (v->key_exp)
820         {
821           if (*v->exp_posn == '+') *v->exp_posn = '-' ;
822           else                     *v->exp_posn = '+' ;
823           set_item(DISPLAYITEM, v->display) ;
824           MPstr_to_num(v->display, v->base, v->MPdisp_val) ;
825           v->key_exp = 0 ;
826         }
827       else
828       {
829          mpneg(v->MPdisp_val, v->MPdisp_val) ;
830          mpstr(v->MPdisp_val, v->MPlast_input) ;
831       }
832     }
833   show_display(v->MPdisp_val) ;
834 }
835
836
837 void
838 do_keys()      /* Display/undisplay the dtcalc key values. */
839 {
840   v->tstate = !v->tstate ;
841   redraw_buttons() ;
842 }
843
844 void
845 do_mode()                  /* Set special calculator mode. */
846 {
847        if (v->current == MODE_FIN) v->modetype = FINANCIAL ;
848   else if (v->current == MODE_LOG) v->modetype = LOGICAL ;
849   else if (v->current == MODE_SCI) v->modetype = SCIENTIFIC ;
850
851   make_modewin() ;
852   v->curwin = FCP_KEY ;
853 }
854
855
856 void
857 do_none()       /* Null routine for empty buttons. */
858 {
859 }
860
861
862 void
863 do_number()
864 {
865   char nextchar ;
866   int len, n ;
867   static int maxvals[4] = { 1, 7, 9, 15 } ;
868
869   /* the financial state is false - last key was not a fin. key */
870   v->funstate = 0;
871
872   nextchar = v->current ;
873   n = v->current - '0' ;
874   if (v->base == HEX && v->current >= 'a' && v->current <= 'f')
875     {
876       nextchar -= 32 ;             /* Convert to uppercase hex digit. */
877       n = v->current - 'a' + 10 ;
878     }
879   if (n > maxvals[(int) v->base])
880     {
881       beep() ;
882       return ;
883     }
884
885   if (v->toclear)
886     {
887       SPRINTF(v->display, "%c", nextchar) ;
888       v->toclear = 0 ;
889     }
890   else
891     {
892       len = strlen(v->display) ;
893       if (len < MAX_DIGITS)
894         {
895           v->display[len] = nextchar ;
896           v->display[len+1] = '\0' ;
897         }
898       else
899         beep() ;
900     }
901   set_item(DISPLAYITEM, v->display) ;
902   MPstr_to_num(v->display, v->base, v->MPdisp_val) ;
903   v->new_input = 1 ;
904 }
905
906
907 void
908 do_numtype()    /* Set number type (engineering, fixed or scientific). */
909 {
910        if (v->current == DISP_ENG) v->dtype = ENG ;
911   else if (v->current == DISP_FIX) v->dtype = FIX ;
912   else if (v->current == DISP_SCI) v->dtype = SCI ;
913   else return ;
914
915   set_numtype(v->dtype);
916 }
917
918 set_numtype( dtype )
919 enum num_type dtype ;
920 {
921   v->pending = 0 ;
922   show_display(v->MPdisp_val) ;
923   set_option_menu((int) NUMITEM, (int)v->dtype);
924   if (v->rstate) make_registers(MEM) ;
925   if (v->frstate) make_registers(FIN) ;
926 }
927
928 void
929 do_paren()
930 {
931   char *ptr ;
932   double tmpdb;
933
934   /* the financial state is false - last key was not a fin. key */
935   v->funstate = 0;
936
937 /*  Check to see if this is the first outstanding parenthesis. If so, and
938  *  their is a current operation already defined, then add the current
939  *  operation to the parenthesis expression being displayed.
940  *  Increment parentheses count, and add the open paren to the expression.
941  */
942
943   if (IS_KEY(v->current, KEY_LPAR))
944     {
945       if (v->noparens == 0)
946       {
947           /* if not in default state, put the operand between the display
948              value and the paren, else just put the paren */
949           if(!v->defState)
950           {
951             /* there is no paren, and there is no current operand ... Let's
952                make the current operand into a "x" */
953             if(v->cur_op == '?')
954             {
955                v->current = 'x';
956                do_calc();
957             }
958  
959              /* if the current op is an '=' and the result in the display is 
960                 zero, we want to ignore the display */
961              if(v->cur_op == '=')
962              {
963                 mpcmd(v->MPdisp_val, &tmpdb);
964                 if(tmpdb == 0.0)
965                 {
966                    v->cur_op = '?';
967                    STRCPY(v->display, "") ;
968                    set_item(DISPLAYITEM, v->display) ;
969                 }
970                 else
971                 {
972                    v->current = 'x';
973                    do_calc();
974                    v->current = '(';
975                    paren_disp(v->cur_op) ;
976                 }
977              }
978              else
979              {
980                 v->current = '(';
981                 paren_disp(v->cur_op) ;
982              }
983           }
984           else
985           {
986              STRCPY(v->display, "") ;
987              set_item(DISPLAYITEM, v->display) ;
988          }
989       }
990       else
991       {
992          int len = strlen(v->display);
993
994          if(v->display[len - 1] >= '0' && v->display[len - 1] <= '9')
995             paren_disp(v->cur_op) ;
996       }
997
998       v->pending = v->current ;
999       v->noparens++ ;
1000     }
1001
1002 /*  If we haven't had any left brackets yet, and this is a right bracket,
1003  *  then just ignore it.
1004  *  Decrement the bracket count. If the count is zero, then process the
1005  *  parenthesis expression.
1006  */
1007
1008   else if (IS_KEY(v->current, KEY_RPAR))
1009     {
1010       if (!v->noparens) return ;
1011       v->noparens-- ;
1012       if (!v->noparens)
1013         {
1014           v->toclear = 1;
1015           paren_disp(v->current) ;
1016           ptr = v->display ;
1017           while (*ptr != '(') ptr++ ;
1018           while (*ptr != '\0') process_parens(*ptr++) ;
1019           return ;
1020         }
1021     }
1022   paren_disp(v->current) ;
1023 }
1024
1025 void
1026 do_pending()
1027 {
1028
1029   /* the financial state is false - last key was not a fin. key */
1030   v->funstate = 0;
1031
1032 /*  Certain pending operations which are half completed, force the numeric
1033  *  keypad to be reshown (assuming they already aren't).
1034  *
1035  *  Con, Exch, Fun, Sto, Rcl and Acc    show buttons 0 - 9.
1036  *  < and >                             show buttons 0 - f.
1037  */
1038
1039   if (!v->ismenu)
1040     {
1041       if (IS_KEY(v->current, KEY_CON)  ||      /* Con. */
1042           IS_KEY(v->current, KEY_EXCH) ||      /* Exch. */
1043           IS_KEY(v->current, KEY_FUN)  ||      /* Fun. */
1044           IS_KEY(v->current, KEY_STO)  ||      /* Sto. */
1045           IS_KEY(v->current, KEY_RCL)  ||      /* Rcl. */
1046           IS_KEY(v->current, KEY_ACC))         /* Acc. */
1047         grey_buttons(DEC) ;
1048       if (IS_KEY(v->current, KEY_LSFT) ||
1049           IS_KEY(v->current, KEY_RSFT))
1050         grey_buttons(HEX) ;
1051      }
1052
1053        if (IS_KEY(v->pending, KEY_BASE)) do_base() ;         /* Base */
1054   else if (IS_KEY(v->pending, KEY_DISP)) do_numtype() ;      /* Disp */
1055   else if (IS_KEY(v->pending, KEY_TRIG)) do_trigtype() ;     /* Trig */
1056   else if (IS_KEY(v->pending, KEY_CON))  do_constant() ;     /* Con */
1057   else if (IS_KEY(v->pending, KEY_EXCH)) do_exchange() ;     /* Exch */
1058   else if (IS_KEY(v->pending, KEY_FUN))  do_function() ;     /* Fun */
1059   else if (IS_KEY(v->pending, KEY_STO) ||                    /* Sto */
1060            IS_KEY(v->pending, KEY_RCL))                      /* Rcl */
1061     {
1062       do_sto_rcl() ;
1063       if (IS_KEY(v->pending_op, KEY_ADD) ||
1064           IS_KEY(v->pending_op, KEY_SUB) ||
1065           IS_KEY(v->pending_op, KEY_MUL) ||
1066           IS_KEY(v->pending_op, KEY_DIV)) return ;
1067     }
1068   else if (IS_KEY(v->pending, KEY_LSFT) ||                   /* < */
1069            IS_KEY(v->pending, KEY_RSFT)) do_shift() ;        /* > */
1070   else if (IS_KEY(v->pending, KEY_ACC))  do_accuracy() ;     /* Acc */
1071   else if (IS_KEY(v->pending, KEY_MODE)) do_mode() ;         /* Mode */
1072   else if (IS_KEY(v->pending, KEY_LPAR))                     /* ( */
1073     {
1074       do_paren() ;
1075       return ;
1076     }
1077   else if (!v->pending)
1078     {
1079       save_pending_values(v->current) ;
1080       v->pending_op = KEY_EQ ;
1081       return ;
1082     }
1083
1084   show_display(v->MPdisp_val) ;
1085   if (v->error) set_item(OPITEM, vstrs[(int) V_CLR]) ;
1086   else set_item(OPITEM, "") ;         /* Redisplay pending op. (if any). */
1087
1088   v->pending = 0 ;
1089   if (!v->ismenu)
1090     grey_buttons(v->base) ;  /* Just show numeric keys for current base. */
1091 }
1092
1093
1094 void
1095 do_point()                   /* Handle numeric point. */
1096 {
1097   /* the financial state is false - last key was not a fin. key */
1098   v->funstate = 0;
1099
1100   if (!v->pointed)
1101     {
1102       if (v->toclear)
1103         {
1104           STRCPY(v->display, ".") ;
1105           v->toclear = 0 ;
1106         }
1107       else STRNCAT(v->display, ".", 1) ;
1108       v->pointed = 1 ;
1109     }
1110   else
1111     beep() ;
1112   set_item(DISPLAYITEM, v->display) ;
1113   MPstr_to_num(v->display, v->base, v->MPdisp_val) ;
1114 }
1115
1116
1117 void
1118 do_portion()
1119 {
1120   int MP1[MP_SIZE] ;
1121
1122   /* the financial state is false - last key was not a fin. key */
1123   v->funstate = 0;
1124
1125        if (IS_KEY(v->current, KEY_ABS))                      /* Abs */
1126     {
1127       mpstr(v->MPdisp_val, MP1) ;
1128       mpabs(MP1, v->MPdisp_val) ;
1129     }
1130   else if (IS_KEY(v->current, KEY_FRAC))                     /* Frac */
1131     {
1132       mpstr(v->MPdisp_val, MP1) ;
1133       mpcmf(MP1, v->MPdisp_val) ;
1134     }
1135   else if (IS_KEY(v->current, KEY_INT))                      /* Int */
1136     {
1137       mpstr(v->MPdisp_val, MP1) ;
1138       mpcmim(MP1, v->MPdisp_val) ;
1139     }
1140   show_display(v->MPdisp_val) ;
1141 }
1142
1143
1144 void
1145 do_shift()     /* Perform bitwise shift on display value. */
1146 {
1147   int i, MPtemp[MP_SIZE], shift ;
1148   BOOLEAN temp ;
1149   double dval ;
1150
1151   shift = char_val(v->current) ;
1152   if(strcmp(v->snum, v->display) != 0)
1153   {
1154      MPstr_to_num(v->display, v->base, MPtemp) ;
1155      mpcmd(MPtemp, &dval) ;
1156   }
1157   else
1158      mpcmd(v->MPdisp_val, &dval) ;
1159   temp = ibool(dval) ;
1160
1161        if (IS_KEY(v->pending, KEY_LSFT)) temp = temp << shift ;
1162   else if (IS_KEY(v->pending, KEY_RSFT)) temp = temp >> shift ;
1163
1164   dval = setbool((BOOLEAN)temp) ;
1165   mpcdm(&dval, v->MPdisp_val) ;
1166   show_display(v->MPdisp_val) ;
1167   mpstr(v->MPdisp_val, v->MPlast_input) ;
1168   return ;
1169 }
1170
1171
1172 void
1173 do_sto_rcl()     /* Save/restore value to/from memory register. */
1174 {
1175   int i, MPn[MP_SIZE], n ;
1176
1177   for (i = MEM_START; i <= MEM_END; i++)
1178     if (v->current == menu_entries[i].val)
1179       {
1180         if (IS_KEY(v->pending, KEY_RCL))                        /* Rcl */
1181           {
1182             mpstr(v->MPmvals[char_val(v->current)], v->MPdisp_val) ;
1183             v->new_input = 1 ;
1184           }
1185         else if (IS_KEY(v->pending, KEY_STO))                   /* Sto */
1186           {
1187             n = char_val(v->current) ;
1188
1189                  if (IS_KEY(v->pending_op, KEY_ADD))            /* + */
1190               {
1191                 mpstr(v->MPmvals[n], MPn) ;
1192                 mpadd(MPn, v->MPdisp_val, v->MPmvals[n]) ;
1193               }
1194             else if (IS_KEY(v->pending_op, KEY_SUB))            /* - */
1195               {
1196                 mpstr(v->MPmvals[n], MPn) ;
1197                 mpsub(MPn, v->MPdisp_val, v->MPmvals[n]) ;
1198               }
1199             else if (IS_KEY(v->pending_op, KEY_MUL))            /* x */
1200               {
1201                 mpstr(v->MPmvals[n], MPn) ;
1202                 mpmul(MPn, v->MPdisp_val, v->MPmvals[n]) ;
1203               }
1204             else if (IS_KEY(v->pending_op, KEY_DIV))            /* / */
1205               {
1206                 mpstr(v->MPmvals[n], MPn) ;
1207                 mpdiv(MPn, v->MPdisp_val, v->MPmvals[n]) ;
1208               }
1209             else mpstr(v->MPdisp_val, v->MPmvals[n]) ;
1210
1211             v->pending_op = 0 ;
1212             make_registers(MEM) ;
1213           }
1214         return ;
1215       }
1216
1217   if (IS_KEY(v->current, KEY_ADD) || IS_KEY(v->current, KEY_SUB) ||
1218       IS_KEY(v->current, KEY_MUL) || IS_KEY(v->current, KEY_DIV))
1219     v->pending_op = v->current ;
1220 }
1221
1222
1223 void
1224 do_trig()         /* Perform all trigonometric functions. */
1225 {
1226   int i, MPtemp[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE] ;
1227   double cval ;
1228   int MPcos[MP_SIZE], MPsin[MP_SIZE] ;
1229
1230   if (!v->inverse)
1231     {
1232       if (!v->hyperbolic)
1233         {
1234                if (v->ttype == DEG)
1235             {
1236               mppi(MP1) ;
1237               mpmul(v->MPdisp_val, MP1, MP2) ;
1238               i = 180 ;
1239               mpcim(&i, MP1) ;
1240               mpdiv(MP2, MP1, MPtemp) ;
1241             }
1242           else if (v->ttype == GRAD)
1243             {
1244               mppi(MP1) ;
1245               mpmul(v->MPdisp_val, MP1, MP2) ;
1246               i = 200 ;
1247               mpcim(&i, MP1) ;
1248               mpdiv(MP2, MP1, MPtemp) ;
1249             }
1250           else mpstr(v->MPdisp_val, MPtemp) ;
1251         }
1252       else mpstr(v->MPdisp_val, MPtemp) ;
1253
1254       if (!v->hyperbolic)
1255         {
1256                if (IS_KEY(v->current, KEY_COS))                  /* Cos */
1257             mpcos(MPtemp, v->MPtresults[(int) RAD]) ;
1258           else if (IS_KEY(v->current, KEY_SIN))                  /* Sin */
1259             mpsin(MPtemp, v->MPtresults[(int) RAD]) ;
1260           else if (IS_KEY(v->current, KEY_TAN))                  /* Tan */
1261             {
1262               mpsin(MPtemp, MPsin) ;
1263               mpcos(MPtemp, MPcos) ;
1264               mpcmd(MPcos, &cval) ;
1265               if (cval == 0.0) doerr(vstrs[(int) V_ERROR]) ;
1266               mpdiv(MPsin, MPcos, v->MPtresults[(int) RAD]) ;
1267             }
1268         }
1269       else
1270         {
1271                if (IS_KEY(v->current, KEY_COS))                  /* Cosh */
1272             mpcosh(MPtemp, v->MPtresults[(int) RAD]) ;
1273           else if (IS_KEY(v->current, KEY_SIN))                  /* Sinh */
1274             mpsinh(MPtemp, v->MPtresults[(int) RAD]) ;
1275           else if (IS_KEY(v->current, KEY_TAN))                  /* Tanh */
1276             mptanh(MPtemp, v->MPtresults[(int) RAD]) ;
1277         }
1278
1279       mpstr(v->MPtresults[(int) RAD], v->MPtresults[(int) DEG]) ;
1280       mpstr(v->MPtresults[(int) RAD], v->MPtresults[(int) GRAD]) ;
1281     }
1282   else
1283     {
1284       if (!v->hyperbolic)
1285         {
1286                  if (IS_KEY(v->current, KEY_COS))                /* Acos */
1287               mpacos(v->MPdisp_val, v->MPdisp_val) ;
1288             else if (IS_KEY(v->current, KEY_SIN))                /* Asin */
1289               mpasin(v->MPdisp_val, v->MPdisp_val) ;
1290             else if (IS_KEY(v->current, KEY_TAN))                /* Atan */
1291               mpatan(v->MPdisp_val, v->MPdisp_val) ;
1292         }
1293       else
1294         {
1295                  if (IS_KEY(v->current, KEY_COS))                /* Acosh */
1296               mpacosh(v->MPdisp_val, v->MPdisp_val) ;
1297             else if (IS_KEY(v->current, KEY_SIN))                /* Asinh */
1298               mpasinh(v->MPdisp_val, v->MPdisp_val) ;
1299             else if (IS_KEY(v->current, KEY_TAN))                /* Atanh */
1300               mpatanh(v->MPdisp_val, v->MPdisp_val) ;
1301         }
1302
1303       if (!v->hyperbolic)
1304         {
1305           i = 180 ;
1306           mpcim(&i, MP1) ;
1307           mpmul(v->MPdisp_val, MP1, MP2) ;
1308           mppi(MP1) ;
1309           mpdiv(MP2, MP1, v->MPtresults[(int) DEG]) ;
1310
1311           i = 200 ;
1312           mpcim(&i, MP1) ;
1313           mpmul(v->MPdisp_val, MP1, MP2) ;
1314           mppi(MP1) ;
1315           mpdiv(MP2, MP1, v->MPtresults[(int) GRAD]) ;
1316         }
1317       else
1318         {
1319           mpstr(v->MPdisp_val, v->MPtresults[(int) DEG]) ;
1320           mpstr(v->MPdisp_val, v->MPtresults[(int) GRAD]) ;
1321         }
1322
1323       mpstr(v->MPdisp_val, v->MPtresults[(int) RAD]) ;
1324     }
1325
1326   show_display(v->MPtresults[(int) v->ttype]) ;
1327   mpstr(v->MPtresults[(int) v->ttype], v->MPdisp_val) ;
1328   v->cur_op = '?';
1329 }
1330
1331
1332 void
1333 do_trigtype()          /* Change the current trigonometric type. */
1334 {
1335        if (v->current == TRIG_DEG) v->ttype = DEG ;
1336   else if (v->current == TRIG_GRA) v->ttype = GRAD ;
1337   else if (v->current == TRIG_RAD) v->ttype = RAD ;
1338   else return ;
1339
1340   if (IS_KEY(v->cur_op, KEY_COS) ||
1341       IS_KEY(v->cur_op, KEY_SIN) ||
1342       IS_KEY(v->cur_op, KEY_TAN))
1343     {
1344       mpstr(v->MPtresults[(int) v->ttype], v->MPdisp_val) ;
1345       show_display(v->MPtresults[(int) v->ttype]) ;
1346     }
1347   set_option_menu((int) TTYPEITEM, (int)v->ttype);
1348   v->pending = 0 ;
1349 }
1350
1351
1352 BOOLEAN
1353 ibool(x)
1354 double x ;
1355 {
1356   BOOLEAN p ;
1357
1358        if (x >  68719476736.00) return(0) ;
1359   else if (x < -68719476736.00) return(0) ;
1360   else
1361     {
1362       while (x <  0.0)           x += 4294967296.00 ;
1363       while (x >= 4294967296.00) x -= 4294967296.00 ;
1364       p = x ;
1365       return(p) ;
1366     }
1367 }
1368
1369 BOOLEAN
1370 ibool2(x)
1371 double x ;
1372 {
1373   BOOLEAN p ;
1374
1375   if (x >  9007199254740991.00 || x < -9007199254740991.00)
1376   {
1377      return(0) ;
1378   }
1379   else
1380     {
1381       while (x <  0.0)           x += 4294967296.00 ;
1382       while (x >= 4294967296.00) x -= 4294967296.00 ;
1383       p = x ;
1384       return(p) ;
1385     }
1386 }
1387
1388
1389 /*  The following MP routines were not in the Brent FORTRAN package. They are
1390  *  derived here, in terms of the existing routines.
1391  */
1392
1393 /*  MP precision arc cosine.
1394  *
1395  *  1. If (x < -1.0  or x > 1.0) then report DOMAIN error and return 0.0.
1396  *
1397  *  2. If (x = 0.0) then acos(x) = PI/2.
1398  *
1399  *  3. If (x = 1.0) then acos(x) = 0.0
1400  *
1401  *  4. If (x = -1.0) then acos(x) = PI.
1402  *
1403  *  5. If (0.0 < x < 1.0) then  acos(x) = atan(sqrt(1-(x**2)) / x)
1404  *
1405  *  6. If (-1.0 < x < 0.0) then acos(x) = atan(sqrt(1-(x**2)) / x) + PI
1406  */
1407
1408 void
1409 mpacos(MPx, MPretval)
1410 int *MPx, *MPretval ;
1411 {
1412   int MP0[MP_SIZE],  MP1[MP_SIZE],  MP2[MP_SIZE] ;
1413   int MPn1[MP_SIZE], MPpi[MP_SIZE], MPy[MP_SIZE], val ;
1414
1415   mppi(MPpi) ;
1416   val = 0 ;
1417   mpcim(&val, MP0) ;
1418   val = 1 ;
1419   mpcim(&val, MP1) ;
1420   val = -1 ;
1421   mpcim(&val, MPn1) ;
1422
1423   if (mpgt(MPx, MP1) || mplt(MPx, MPn1))
1424     {
1425       doerr("acos DOMAIN error") ;
1426       mpstr(MP0, MPretval) ;
1427     }
1428   else if (mpeq(MPx, MP0))
1429     {
1430       val = 2 ;
1431       mpdivi(MPpi, &val, MPretval) ;
1432     }
1433   else if (mpeq(MPx, MP1))  mpstr(MP0, MPretval) ;
1434   else if (mpeq(MPx, MPn1)) mpstr(MPpi, MPretval) ;
1435   else
1436     {
1437       mpmul(MPx, MPx, MP2) ;
1438       mpsub(MP1, MP2, MP2) ;
1439       mpsqrt(MP2, MP2) ;
1440       mpdiv(MP2, MPx, MP2) ;
1441       mpatan(MP2, MPy) ;
1442       if (mpgt(MPx, MP0)) mpstr(MPy, MPretval) ;
1443       else                 mpadd(MPy, MPpi, MPretval) ;
1444     }
1445 }
1446
1447
1448 /*  MP precision hyperbolic arc cosine.
1449  *
1450  *  1. If (x < 1.0) then report DOMAIN error and return 0.0.
1451  *
1452  *  2. acosh(x) = log(x + sqrt(x**2 - 1))
1453  */
1454
1455 void
1456 mpacosh(MPx, MPretval)
1457 int *MPx, *MPretval ;
1458 {
1459   int MP1[MP_SIZE], val ;
1460
1461   val = 1 ;
1462   mpcim(&val, MP1) ;
1463   if (mplt(MPx, MP1))
1464     {
1465       doerr("acosh DOMAIN error") ;
1466       val = 0 ;
1467       mpcim(&val, MPretval) ;
1468     }
1469   else
1470     {
1471       mpmul(MPx, MPx, MP1) ;
1472       val = -1 ;
1473       mpaddi(MP1, &val, MP1) ;
1474       mpsqrt(MP1, MP1) ;
1475       mpadd(MPx, MP1, MP1) ;
1476       mpln(MP1, MPretval) ;
1477     }
1478 }
1479
1480
1481 /*  MP precision hyperbolic arc sine.
1482  *
1483  *  1. asinh(x) = log(x + sqrt(x**2 + 1))
1484  */
1485
1486 void
1487 mpasinh(MPx, MPretval)
1488 int *MPx, *MPretval ;
1489 {
1490   int MP1[MP_SIZE], val ;
1491
1492   mpmul(MPx, MPx, MP1) ;
1493   val = 1 ;
1494   mpaddi(MP1, &val, MP1) ;
1495   mpsqrt(MP1, MP1) ;
1496   mpadd(MPx, MP1, MP1) ;
1497   mpln(MP1, MPretval) ;
1498 }
1499
1500
1501 /*  MP precision hyperbolic arc tangent.
1502  *
1503  *  1. If (x <= -1.0 or x >= 1.0) then report a DOMAIn error and return 0.0.
1504  *
1505  *  2. atanh(x) = 0.5 * log((1 + x) / (1 - x))
1506  */
1507
1508 void
1509 mpatanh(MPx, MPretval)
1510 int *MPx, *MPretval ;
1511 {
1512   int MP0[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE] ;
1513   int MP3[MP_SIZE], MPn1[MP_SIZE], val ;
1514
1515   val = 0 ;
1516   mpcim(&val, MP0) ;
1517   val = 1 ;
1518   mpcim(&val, MP1) ;
1519   val = -1 ;
1520   mpcim(&val, MPn1) ;
1521
1522   if (mpge(MPx, MP1) || mple(MPx, MPn1))
1523     {
1524       doerr("atanh DOMAIN error") ;
1525       mpstr(MP0, MPretval) ;
1526     }
1527   else
1528     {
1529       mpadd(MP1, MPx, MP2) ;
1530       mpsub(MP1, MPx, MP3) ;
1531       mpdiv(MP2, MP3, MP3) ;
1532       mpln(MP3, MP3) ;
1533       MPstr_to_num("0.5", DEC, MP1) ;
1534       mpmul(MP1, MP3, MPretval) ;
1535     }
1536 }
1537
1538
1539 /*  MP precision common log.
1540  *
1541  *  1. log10(x) = log10(e) * log(x)
1542  */
1543
1544 void
1545 mplog10(MPx, MPretval)
1546 int *MPx, *MPretval ;
1547 {
1548   int MP1[MP_SIZE], MP2[MP_SIZE], n ;
1549
1550   n = 10 ;
1551   mpcim(&n, MP1) ;
1552   mpln(MP1, MP1) ;
1553   mpln(MPx, MP2) ;
1554   mpdiv(MP2, MP1, MPretval) ;
1555 }
1556
1557
1558 void
1559 process_parens(current)
1560 char current ;
1561 {
1562   int i ;
1563   int last_lpar ;     /* Position in stack of last left paren. */
1564   int last_num ;      /* Position is numeric stack to start processing. */
1565
1566 /*  Check to see if this is the first outstanding parenthesis. If so, and
1567  *  their is a current operation already defined, then push the current
1568  *  result on the numeric stack, and note it on the op stack, with a -1,
1569  *  which has this special significance.
1570  *  Zeroise current display value (in case of invalid operands inside the
1571  *  parentheses.
1572  *  Add the current pending operation to the opstack.
1573  *  Increment parentheses count.
1574  */
1575
1576   if (IS_KEY(current, KEY_LPAR))
1577     {
1578       if (!v->noparens && v->cur_op != '?')
1579         {
1580           push_num(v->MPresult) ;
1581           push_op(-1) ;
1582           i = 0 ;
1583           mpcim(&i, v->MPdisp_val) ;
1584           push_op(v->cur_op) ;
1585         }
1586       v->noparens++ ;     /* Count of left brackets outstanding. */
1587       save_pending_values(current) ;
1588     }
1589
1590 /*  If we haven't had any left brackets yet, and this is a right bracket,
1591  *  then just ignore it.
1592  *  Decrement the bracket count.
1593  *  Add a equals to the op stack, to force a calculation to be performed
1594  *  for two op operands. This is ignored if the preceding element of the
1595  *  op stack was an immediate operation.
1596  *  Work out where the preceding left bracket is in the stack, and then
1597  *  process the stack from that point until this end, pushing the result
1598  *  on the numeric stack, and setting the new op stack pointer appropriately.
1599  *  If there are no brackets left unmatched, then clear the pending flag,
1600  *  clear the stack pointers and current operation, and show the display.
1601  */
1602
1603   else if (IS_KEY(current, KEY_RPAR))
1604     {
1605       v->noparens-- ;
1606       push_op('=') ;
1607       last_lpar = v->opsptr - 1 ;
1608       last_num = v->numsptr ;
1609       while (!IS_KEY(v->opstack[last_lpar], KEY_LPAR))
1610         {
1611           if (v->opstack[last_lpar] == -1) last_num-- ;
1612           last_lpar-- ;
1613         }
1614       process_stack(last_lpar + 1, last_num, v->opsptr - last_lpar - 1) ;
1615       if (!v->noparens)
1616         {
1617           if (v->opsptr > 1)
1618             {
1619               push_op(KEY_EQ) ;
1620               process_stack(0, 0, v->opsptr) ;
1621             }
1622           v->pending = v->opsptr = v->numsptr = 0 ;
1623           v->cur_op = '?' ;
1624           set_item(OPITEM, "") ;
1625           if (v->error)
1626             {
1627               set_item(DISPLAYITEM, vstrs[(int) V_ERROR]) ;
1628               set_item(OPITEM,      vstrs[(int) V_CLR]) ;
1629               STRCPY(v->display,    vstrs[(int) V_ERROR]) ;
1630             }
1631           else
1632             {
1633               show_display(v->MPdisp_val) ;
1634               mpstr(v->MPdisp_val, v->MPlast_input) ;
1635             }
1636         }
1637       return ;
1638     }
1639   push_op(current) ;
1640 }
1641
1642
1643 void
1644 push_num(MPval)            /* Try to push value onto the numeric stack. */
1645 int *MPval ;
1646 {
1647   if (v->numsptr < 0) return ;
1648   if (v->numsptr >= MAXSTACK)
1649     {
1650       STRCPY(v->display, vstrs[(int) V_NUMSTACK]) ;
1651       set_item(DISPLAYITEM, v->display) ;
1652       v->error = 1 ;
1653       beep() ;
1654       set_item(OPITEM, vstrs[(int) V_CLR]) ;
1655     }
1656   else
1657     {
1658       if (v->MPnumstack[v->numsptr] == NULL)
1659         v->MPnumstack[v->numsptr] =
1660                         (int *) LINT_CAST(calloc(1, sizeof(int) * MP_SIZE)) ;
1661       mpstr(MPval, v->MPnumstack[v->numsptr++]) ;
1662     }
1663 }
1664
1665
1666 void
1667 push_op(val)     /* Try to push value onto the operand stack. */
1668 int val ;
1669 {
1670   if (v->opsptr < 0) return ;
1671   if (v->opsptr >= MAXSTACK)
1672     {
1673       STRCPY(v->display, vstrs[(int) V_OPSTACK]) ;
1674       set_item(DISPLAYITEM, v->display) ;
1675       v->error = 1 ;
1676       set_item(OPITEM, vstrs[(int) V_CLR]) ;
1677     }
1678   else v->opstack[v->opsptr++] = val ;
1679 }
1680
1681
1682 void
1683 save_pending_values(val)
1684 int val ;
1685 {
1686   int n ;
1687
1688   v->pending = val ;
1689   for (n = 0; n < TITEMS; n++)
1690   {
1691     if (val == buttons[n].value)
1692        v->pending_n = n ;
1693   }
1694   v->pending_win = v->curwin ;
1695   if (v->pending_win == FCP_MODE)
1696      v->pending_mode = v->modetype ;
1697 }
1698
1699
1700 double
1701 setbool(p)
1702 BOOLEAN p ;
1703 {
1704   BOOLEAN q ;
1705   double val ;
1706
1707   q = p & 0x80000000 ;
1708   p &= 0x7fffffff ;
1709   val = p ;
1710   if (q) val += 2147483648.0 ;
1711   return(val) ;
1712 }
1713
1714 double
1715 do_round(result, ndigits)
1716 double result;
1717 int ndigits;
1718 {
1719     char buf2[40], buffer[100];
1720     int temp;
1721
1722     if (isnan(result)) return result;
1723 #if defined(_AIX) || defined(__aix) || defined(__osf__)
1724     temp = finite(result);
1725     if (!temp)
1726        return (temp > 0) ? HUGE : -HUGE;
1727 #else
1728 #if defined(USL) || defined(__uxp__)
1729     temp = finite(result);
1730     if (!temp)
1731        return (temp > 0) ? HUGE : -HUGE;
1732 #else
1733     if (temp = isinf(result)) return (temp > 0) ? HUGE : -HUGE;
1734 #endif /* USL or __uxp__ */
1735 #endif /* _AIX or __osf__ */
1736
1737     if (ndigits >= 0 && ndigits < MAX_DIGITS)
1738     {
1739         result += 0.5 * (result > 0 ? mods[ndigits] : -mods[ndigits]);
1740         result -= fmod(result, mods[ndigits]);
1741     }
1742
1743     sprintf(buf2, "%%.%dlg", MAX_DIGITS);
1744     sprintf(buffer, buf2, result);
1745     return atof(buffer);
1746 }
1747
1748 BOOLEAN
1749 try_compute_i(guess, result, method)
1750 double guess;
1751 double *result;
1752 int method;
1753 {
1754     double sum_pos, sum_pos_prime, sum_neg, sum_neg_prime, w = guess;
1755     double new_w;
1756     int niter = 0;
1757
1758     for (;;)
1759     {
1760         double term, term_prime, f, f_prime, lsp, lsn;
1761
1762         sum_pos = sum_pos_prime = sum_neg = sum_neg_prime = 0;
1763
1764         if (v->MPfvals[2] != 0.0)
1765         {
1766             if (w == 1)
1767             {
1768                 term = 1;
1769                 term_prime = v->MPfvals[0];
1770             }
1771             else
1772             {
1773                 term = pow(w, v->MPfvals[0]);
1774                 term_prime = (v->MPfvals[0]) * pow(w, v->MPfvals[0] - 1.0);
1775             }
1776             if (v->MPfvals[2] > 0.0)
1777             {
1778                 sum_pos += v->MPfvals[2] * term;
1779                 sum_pos_prime += v->MPfvals[2] * term_prime;
1780             }
1781             else
1782             {
1783                 sum_neg -= v->MPfvals[2] * term;
1784                 sum_neg_prime -= v->MPfvals[2] * term_prime;
1785             }
1786         }
1787         if (v->MPfvals[3] != 0.0)
1788         {
1789             if (w == 1.0)
1790             {
1791                 term = v->MPfvals[0];
1792
1793                 term_prime = v->MPfvals[0] * (v->MPfvals[0] - 1) / 2.0 +
1794                              v->MPfvals[0] * (0.0);
1795             }
1796             else
1797             {
1798                 double wn = pow(w, v->MPfvals[0]);
1799                 double wdb = pow(w, 0.0);
1800
1801                 term = (wn - 1.0) * wdb / (w - 1.0);
1802
1803                 term_prime = (v->MPfvals[0] * pow(w,(0.0 + v->MPfvals[0] - .01))
1804                               + (wn - 1.0) * (0.0) * pow(w, (0.0 - 1.0))) /
1805                               (w - 1.0) - (wn - 1.0) * wdb /
1806                               ((w - 1.0) * (w - 1.0));
1807
1808             }
1809             if (v->MPfvals[3] > 0.0)
1810             {
1811                 sum_pos += v->MPfvals[3] * term;
1812                 sum_pos_prime += v->MPfvals[3] * term_prime;
1813             }
1814             else
1815             {
1816                 sum_neg -= v->MPfvals[3] * term;
1817                 sum_neg_prime -= v->MPfvals[3] * term_prime;
1818             }
1819         }
1820         if (v->MPfvals[4] != 0.0)
1821         {
1822             if (v->MPfvals[4] > 0.0) sum_pos += v->MPfvals[4];
1823             else sum_neg -= v->MPfvals[4];
1824         }
1825
1826         lsp = log(sum_pos);
1827         lsn = log(sum_neg);
1828
1829         switch (method)
1830         {
1831             case 1:
1832                 f = lsp - lsn;
1833                 f_prime = sum_pos_prime / sum_pos - sum_neg_prime / sum_neg;
1834                 break;
1835             case 2:
1836                 f = lsp / lsn - 1.0;
1837                 f_prime = (lsn * sum_pos_prime / sum_pos -
1838                            lsp * sum_neg_prime / sum_neg) /
1839                           (lsn * lsn);
1840                 break;
1841         }
1842
1843         new_w = w - f / f_prime;
1844
1845 #if defined(_AIX) || defined(__aix) || defined (__osf__)
1846         if (!(!isnan(new_w) && finite(new_w)))
1847             return FALSE;
1848 #else
1849 #if defined(USL) || defined(__uxp__)
1850         if (!(!isnan(new_w) && finite(new_w)))
1851             return FALSE;
1852 #else
1853         if (!(!isnan(new_w) && !isinf(new_w)))
1854             return FALSE;
1855 #endif
1856 #endif /* _AIX or __osf__ */
1857
1858         if (new_w == w || w != 0.0 && fabs((new_w - w) / w) < FIN_EPSILON)
1859            break;
1860
1861         w = new_w;
1862
1863         if (niter++ >= MAX_FIN_ITER)
1864             return FALSE;
1865     }
1866
1867     *result = do_round((new_w - 1.0) * 100.0 * v->MPfvals[5], -1);
1868     return TRUE;
1869 }
1870
1871 compute_i(target)
1872 double *target;
1873 {
1874     double p[3];
1875     double first_period, last_period;
1876     int nsc;
1877     BOOLEAN success;
1878
1879     first_period = 1.0;
1880     last_period = 0.0;
1881
1882     if (first_period < 0.0 || last_period < 0.0)
1883     {
1884         doerr(GETMESSAGE(5, 5, "ERROR:Invalid odd period values"));
1885         return;
1886     }
1887
1888     p[0] = v->MPfvals[2] + (first_period == 0.0 ? v->MPfvals[3] : 0);
1889     p[1] = v->MPfvals[3];
1890     p[2] = v->MPfvals[4] + (last_period == 0.0 ? v->MPfvals[3] : 0);
1891
1892     nsc = count_sign_changes(p, 3);
1893
1894     if (nsc == 0)
1895     {
1896         int MP1[MP_SIZE], MP2[MP_SIZE], MP3[MP_SIZE], MP4[MP_SIZE];
1897         int MP5[MP_SIZE] ;
1898         int val;
1899         double temp;
1900
1901         temp = v->MPfvals[4]/v->MPfvals[2];
1902         mpcdm(&temp, MP1);
1903         val = 1 ;
1904         mpcim(&val, MP2) ;
1905         mpcdm(&(v->MPfvals[0]), MP4);
1906         mpdiv(MP2, MP4, MP3) ;
1907         mppwr2(MP1, MP3, MP5) ;
1908         val = -1 ;
1909         mpaddi(MP5, &val, MP1) ;
1910         val = 1200 ;
1911         mpmuli(MP1, &val, v->MPdisp_val) ;
1912         mpcmd(v->MPdisp_val, target);
1913         return;
1914     }
1915     else if (nsc > 1)
1916     {
1917         doerr(GETMESSAGE(5, 3, "ERROR: Multiple Solutions"));
1918         return;
1919     }
1920     else if (v->MPfvals[0] <= 0)
1921     {
1922         doerr(GETMESSAGE(5, 4, "ERROR: Term <= 0"));
1923         return;
1924     }
1925
1926     success = try_compute_i((double)1.0, target, 1);
1927     success = success || try_compute_i((double)1.0e-12, target, 1);
1928     success = success || try_compute_i((double)1.0, target, 2);
1929     success = success || try_compute_i((double)1.0e-12, target, 2);
1930
1931     if (!success)
1932         doerr(GETMESSAGE(5, 1, "ERROR: Computation Failed"));
1933 }
1934
1935 int
1936 count_sign_changes(cf, count)
1937 double *cf;
1938 int count;
1939 {
1940     int i, curr_sign = 0, result = 0;
1941
1942     for (i = 0; i < count; i++)
1943     {
1944         if (cf[i] == 0.0) continue;
1945
1946         if (curr_sign == 1)
1947         {
1948             if (cf[i] > 0.0) continue;
1949             curr_sign = -1;
1950             result++;
1951         }
1952         else if (curr_sign == -1)
1953         {
1954             if (cf[i] < 0.0) continue;
1955             curr_sign = 1;
1956             result++;
1957         }
1958         else
1959         {
1960             if (cf[i] > 0.0) curr_sign = 1;
1961             else curr_sign = -1;
1962         }
1963     }
1964
1965     return result;
1966 }
1967