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