4 * Copyright (c) 1987-2007 Sun Microsystems, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30 #include "functions.h"
33 static char digits
[] = "0123456789ABCDEF";
35 static double max_fix
[MAXBASES
] = {
36 1.298074214e+33, /* Binary. */
37 2.037035976e+90, /* Octal. */
38 1.000000000e+100, /* Decimal */
39 2.582249878e+120 /* Hexadecimal. */
42 static char *make_eng_sci(int *, int);
44 /* Add in the thousand separators characters if required and if we are
45 * currently in the decimal numeric base, use the "right" radix character.
49 localize_number(char *dest
, const char *src
)
51 char tnum
[MAX_LOCALIZED
], *dstp
;
53 if (!v
->error
&& v
->show_tsep
&& v
->base
== DEC
) {
54 const char *radixp
, *srcp
;
58 /* Process the fractional part (if any). */
59 srcp
= src
+ strlen(src
) - 1;
61 if ((radixp
= strchr(src
, '.')) != NULL
) {
62 while (srcp
!= radixp
) {
68 /* Process the integer part, add in thousand separators. */
69 tsep_len
= strlen(v
->tsep
);
74 if (n
== 3 && srcp
>= src
&& *srcp
!= '-') {
75 for (i
= tsep_len
- 1; i
>= 0; i
--) {
83 /* Move from scratch pad to fnum, reversing the character order. */
84 srcp
= tnum
+ strlen(tnum
) - 1;
86 while (srcp
>= tnum
) {
93 dstp
= strchr(dest
, '.');
97 radix_len
= strlen(v
->radix
);
99 memmove(dstp
+ radix_len
, dstp
+ 1, strlen (dstp
+ 1) + 1);
101 MEMCPY(dstp
, v
->radix
, radix_len
);
109 if (chr
>= '0' && chr
<= '9') {
111 } else if (chr
>= 'a' && chr
<= 'f') {
112 return(chr
- 'a' + 10);
113 } else if (chr
>= 'A' && chr
<= 'F') {
114 return(chr
- 'A' + 10);
122 clear_display(int initialise
)
129 mpcim(&i
, v
->MPdisp_val
);
130 STRNCPY(v
->display
, make_number(v
->MPdisp_val
, v
->base
, FALSE
),
132 ui_set_display(v
->display
, FALSE
);
135 if (initialise
== TRUE
) {
139 ui_set_hyperbolic_state(FALSE
); /* Also clears v->hyperbolic. */
140 ui_set_inverse_state(FALSE
); /* Also clears v->inverse. */
148 /* TODO: perhaps this function should be renamed to reset. */
151 struct exprm_state
*e
;
153 v
->error
= 0; /* Currently no display error. */
154 v
->cur_op
= -1; /* No arithmetic operator defined yet. */
155 v
->old_cal_value
= -1;
157 mpcim(&i
, v
->MPresult
); /* No previous result yet. */
158 mpcim(&i
, v
->MPdisp_val
);
159 mpcim(&i
, v
->MPlast_input
);
161 v
->new_input
= 1; /* Value zero is on calculator display */
165 e
->expression
= NULL
;
169 /* Convert MP number to fixed number string in the given base to the
170 * maximum number of digits specified.
174 make_fixed(int *MPnumber
, char *str
, int base
, int cmax
, int toclear
)
177 int MP1base
[MP_SIZE
], MP1
[MP_SIZE
], MP2
[MP_SIZE
], MPval
[MP_SIZE
];
178 int ndig
; /* Total number of digits to generate. */
179 int ddig
; /* Number of digits to left of decimal sep. */
183 mpabs(MPnumber
, MPval
);
186 if (mplt(MPnumber
, MP1
)) {
190 mpcim(&basevals
[base
], MP1base
);
192 mppwr(MP1base
, &v
->accuracy
, MP1
);
193 /* FIXME: string const. if MPstr_to_num can get it */
194 SPRINTF(half
, "0.5");
195 MPstr_to_num(half
, DEC
, MP2
);
196 mpdiv(MP2
, MP1
, MP1
);
197 mpadd(MPval
, MP1
, MPval
);
201 if (mplt(MPval
, MP2
)) {
206 for (ddig
= 0; mpge(MPval
, MP2
); ddig
++) {
207 mpdiv(MPval
, MP1base
, MPval
);
211 ndig
= MIN(ddig
+ v
->accuracy
, --cmax
);
217 mpmul(MPval
, MP1base
, MPval
);
220 if (dval
> basevals
[base
]-1) {
221 dval
= basevals
[base
]-1;
224 *optr
++ = digits
[dval
];
226 mpaddi(MPval
, &dval
, MPval
);
229 if (toclear
== TRUE
) {
234 if (!v
->show_zeroes
&& v
->accuracy
!= 0) {
235 optr
= str
+ strlen(str
) - 1;
236 while (*optr
== '0') {
239 if (optr
< str
|| *optr
!= '.') {
249 /* Convert MP number to character string in the given base. */
252 make_number(int *MPnumber
, int base
, int ignoreError
)
256 /* NOTE: make_number can currently set v->error when converting to a double.
257 * This is to provide the same look&feel as V3 even though gcalctool
258 * now does internal arithmetic to "infinite" precision.
260 * XXX: Needs to be improved. Shouldn't need to convert to a double in
261 * order to do these tests.
264 mpcmd(MPnumber
, &number
);
266 if (v
->error
&& !ignoreError
) {
269 if ((v
->dtype
== ENG
) ||
271 (v
->dtype
== FIX
&& val
!= 0.0 && (val
> max_fix
[base
]))) {
272 return(make_eng_sci(MPnumber
, base
));
274 return(make_fixed(MPnumber
, v
->fnum
, base
, MAX_DIGITS
, TRUE
));
279 /* Convert engineering or scientific number in the given base. */
282 make_eng_sci(int *MPnumber
, int base
)
284 char half
[4], fixed
[MAX_DIGITS
], *optr
;
285 int MP1
[MP_SIZE
], MPatmp
[MP_SIZE
], MPval
[MP_SIZE
];
286 int MP1base
[MP_SIZE
], MP3base
[MP_SIZE
], MP10base
[MP_SIZE
];
288 int MPmant
[MP_SIZE
]; /* Mantissa. */
289 int ddig
; /* Number of digits in exponent. */
290 int eng
= 0; /* Set if this is an engineering number. */
291 int exp
= 0; /* Exponent */
293 if (v
->dtype
== ENG
) {
297 mpabs(MPnumber
, MPval
);
300 if (mplt(MPnumber
, MP1
)) {
303 mpstr(MPval
, MPmant
);
305 mpcim(&basevals
[base
], MP1base
);
307 mppwr(MP1base
, &n
, MP3base
);
310 mppwr(MP1base
, &n
, MP10base
);
314 mpdiv(MP1
, MP10base
, MPatmp
);
318 if (!mpeq(MPmant
, MP1
)) {
319 while (!eng
&& mpge(MPmant
, MP10base
)) {
321 mpmul(MPmant
, MPatmp
, MPmant
);
324 while ((!eng
&& mpge(MPmant
, MP1base
)) ||
325 (eng
&& (mpge(MPmant
, MP3base
) || exp
% 3 != 0))) {
327 mpdiv(MPmant
, MP1base
, MPmant
);
330 while (!eng
&& mplt(MPmant
, MPatmp
)) {
332 mpmul(MPmant
, MP10base
, MPmant
);
337 while (mplt(MPmant
, MP1
) || (eng
&& exp
% 3 != 0)) {
339 mpmul(MPmant
, MP1base
, MPmant
);
343 STRCPY(fixed
, make_fixed(MPmant
, v
->fnum
, base
, MAX_DIGITS
-6, TRUE
));
345 for (i
= 0; i
< len
; i
++) {
358 SPRINTF(half
, "0.5");
359 MPstr_to_num(half
, DEC
, MP1
);
360 mpaddi(MP1
, &exp
, MPval
);
363 for (ddig
= 0; mpge(MPval
, MP1
); ddig
++) {
364 mpdiv(MPval
, MP1base
, MPval
);
372 mpmul(MPval
, MP1base
, MPval
);
374 *optr
++ = digits
[dval
];
376 mpaddi(MPval
, &dval
, MPval
);
386 /* Convert string into an MP number, in the given base
390 MPstr_to_num(char *str
, enum base_type base
, int *MPval
)
393 int MP1
[MP_SIZE
], MP2
[MP_SIZE
], MPbase
[MP_SIZE
];
398 char *lnp
= ui_get_localized_numeric_point();
403 mpcim(&basevals
[(int) base
], MPbase
);
407 /* Remove any initial spaces or tabs. */
408 while (*optr
== ' ' || *optr
== '\t') {
412 /* Check if this is a negative number. */
418 while ((inum
= char_val(*optr
)) >= 0) {
419 mpmul(MPval
, MPbase
, MPval
);
420 mpaddi(MPval
, &inum
, MPval
);
424 if (*optr
== '.' || *optr
== *lnp
) {
426 for (i
= 1; (inum
= char_val(*optr
)) >= 0; i
++) {
427 mppwr(MPbase
, &i
, MP1
);
429 mpdiv(MP2
, MP1
, MP1
);
430 mpadd(MPval
, MP1
, MPval
);
435 while (*optr
== ' ') {
444 while ((inum
= char_val(*++optr
)) >= 0) {
445 exp
= exp
* basevals
[(int) base
] + inum
;
451 mppwr(MPbase
, &exp
, MP1
);
452 mpmul(MPval
, MP1
, MPval
);
461 /* Append the latest parenthesis char to the display item. */
469 /* If the character is a Delete, clear the whole line, and exit parenthesis
472 * If the character is a Back Space, remove the last character. If the last
473 * character was a left parenthesis, decrement the parentheses count. If
474 * the parentheses count is zero, exit parenthesis processing.
476 * Otherwise just append the character.
479 n
= strlen(v
->display
);
480 text
= buttons
[key
].symname
;
484 v
->noparens
= v
->numsptr
= 0;
487 mpcim(&i
, v
->MPdisp_val
);
488 show_display(v
->MPdisp_val
);
495 if (v
->display
[n
-1] == ')') {
497 } else if (v
->display
[n
-1] == '(') {
502 show_display(v
->MPdisp_val
);
505 } else if (v
->display
[n
-1] == ')') v
->noparens
++;
506 v
->display
[n
-1] = '\0';
509 case KEY_START_BLOCK
:
511 /* If this is the first left parenthesis being displayed and there is no
512 * current arithmetic operand, then the current display is initially cleared
513 * to avoid the confusion of showing something like "0(".
516 if (v
->noparens
== 1 && v
->cur_op
== -1) {
518 v
->display
[0] = '\0';
529 SNPRINTF(v
->display
+n
, MAXLINE
-n
, "%s", text
);
532 n
= (n
< MAX_DIGITS
) ? 0 : n
- MAX_DIGITS
;
533 v
->show_paren
= 1; /* Hack to get ui_set_display to really display it. */
534 ui_set_display(&v
->display
[n
], FALSE
);
540 process_item(struct button
*button
, int arg
)
542 v
->current
= button
->id
;
545 /* Must press a valid key first. */
546 if (v
->current
!= KEY_CLEAR
) {
549 ui_set_error_state(FALSE
);
552 if (v
->noparens
> 0) {
557 (*button
->func
)(arg
);
562 show_display(int *MPval
)
565 STRNCPY(v
->display
, make_number(MPval
, v
->base
, FALSE
), MAXLINE
- 1);
566 ui_set_display(v
->display
, FALSE
);
571 /* In arithmetic precedence mode this routine should be called to redraw
578 char localized
[MAX_LOCALIZED
];
579 struct exprm_state
*e
;
583 show_display(v
->MPdisp_val
);
589 if (e
->expression
&& strlen(e
->expression
)) {
590 char *str
= gc_strdup(e
->expression
);
591 char *ans
= make_number(e
->ans
, v
->base
, TRUE
);
593 localize_number(localized
, ans
);
594 str_replace(&str
, "Ans", localized
);
596 { /* Replace registers with values. */
601 for (i
= 0; i
< 10; i
++) {
605 SNPRINTF(reg
, 3, "R%c", n
+i
);
606 do_rcl_reg(i
, MP_reg
);
607 reg_val
= make_number(MP_reg
, v
->base
, FALSE
);
608 str_replace(&str
, reg
, reg_val
);
611 ui_set_display(str
, FALSE
);