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