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
) {
137 v
->opsptr
= 0; /* Clear parentheses stacks. */
140 ui_set_hyperbolic_state(FALSE
); /* Also clears v->hyperbolic. */
141 ui_set_inverse_state(FALSE
); /* Also clears v->inverse. */
149 /* TODO: perhaps this function should be renamed to reset. */
152 struct exprm_state
*e
;
154 v
->error
= 0; /* Currently no display error. */
155 v
->cur_op
= -1; /* No arithmetic operator defined yet. */
156 v
->old_cal_value
= -1;
158 mpcim(&i
, v
->MPresult
); /* No previous result yet. */
159 mpcim(&i
, v
->MPdisp_val
);
160 mpcim(&i
, v
->MPlast_input
);
162 v
->new_input
= 1; /* Value zero is on calculator display */
166 e
->expression
= NULL
;
170 /* Convert MP number to fixed number string in the given base to the
171 * maximum number of digits specified.
175 make_fixed(int *MPnumber
, char *str
, int base
, int cmax
, int toclear
)
178 int MP1base
[MP_SIZE
], MP1
[MP_SIZE
], MP2
[MP_SIZE
], MPval
[MP_SIZE
];
179 int ndig
; /* Total number of digits to generate. */
180 int ddig
; /* Number of digits to left of decimal sep. */
184 mpabs(MPnumber
, MPval
);
187 if (mplt(MPnumber
, MP1
)) {
191 mpcim(&basevals
[base
], MP1base
);
193 mppwr(MP1base
, &v
->accuracy
, MP1
);
194 /* FIXME: string const. if MPstr_to_num can get it */
195 SPRINTF(half
, "0.5");
196 MPstr_to_num(half
, DEC
, MP2
);
197 mpdiv(MP2
, MP1
, MP1
);
198 mpadd(MPval
, MP1
, MPval
);
202 if (mplt(MPval
, MP2
)) {
207 for (ddig
= 0; mpge(MPval
, MP2
); ddig
++) {
208 mpdiv(MPval
, MP1base
, MPval
);
212 ndig
= MIN(ddig
+ v
->accuracy
, --cmax
);
218 mpmul(MPval
, MP1base
, MPval
);
221 if (dval
> basevals
[base
]-1) {
222 dval
= basevals
[base
]-1;
225 *optr
++ = digits
[dval
];
227 mpaddi(MPval
, &dval
, MPval
);
230 if (toclear
== TRUE
) {
235 if (!v
->show_zeroes
&& v
->accuracy
!= 0) {
236 optr
= str
+ strlen(str
) - 1;
237 while (*optr
== '0') {
240 if (optr
< str
|| *optr
!= '.') {
250 /* Convert MP number to character string in the given base. */
253 make_number(int *MPnumber
, int base
, int ignoreError
)
257 /* NOTE: make_number can currently set v->error when converting to a double.
258 * This is to provide the same look&feel as V3 even though gcalctool
259 * now does internal arithmetic to "infinite" precision.
261 * XXX: Needs to be improved. Shouldn't need to convert to a double in
262 * order to do these tests.
265 mpcmd(MPnumber
, &number
);
267 if (v
->error
&& !ignoreError
) {
270 if ((v
->dtype
== ENG
) ||
272 (v
->dtype
== FIX
&& val
!= 0.0 && (val
> max_fix
[base
]))) {
273 return(make_eng_sci(MPnumber
, base
));
275 return(make_fixed(MPnumber
, v
->fnum
, base
, MAX_DIGITS
, TRUE
));
280 /* Convert engineering or scientific number in the given base. */
283 make_eng_sci(int *MPnumber
, int base
)
285 char half
[4], fixed
[MAX_DIGITS
], *optr
;
286 int MP1
[MP_SIZE
], MPatmp
[MP_SIZE
], MPval
[MP_SIZE
];
287 int MP1base
[MP_SIZE
], MP3base
[MP_SIZE
], MP10base
[MP_SIZE
];
289 int MPmant
[MP_SIZE
]; /* Mantissa. */
290 int ddig
; /* Number of digits in exponent. */
291 int eng
= 0; /* Set if this is an engineering number. */
292 int exp
= 0; /* Exponent */
294 if (v
->dtype
== ENG
) {
298 mpabs(MPnumber
, MPval
);
301 if (mplt(MPnumber
, MP1
)) {
304 mpstr(MPval
, MPmant
);
306 mpcim(&basevals
[base
], MP1base
);
308 mppwr(MP1base
, &n
, MP3base
);
311 mppwr(MP1base
, &n
, MP10base
);
315 mpdiv(MP1
, MP10base
, MPatmp
);
319 if (!mpeq(MPmant
, MP1
)) {
320 while (!eng
&& mpge(MPmant
, MP10base
)) {
322 mpmul(MPmant
, MPatmp
, MPmant
);
325 while ((!eng
&& mpge(MPmant
, MP1base
)) ||
326 (eng
&& (mpge(MPmant
, MP3base
) || exp
% 3 != 0))) {
328 mpdiv(MPmant
, MP1base
, MPmant
);
331 while (!eng
&& mplt(MPmant
, MPatmp
)) {
333 mpmul(MPmant
, MP10base
, MPmant
);
338 while (mplt(MPmant
, MP1
) || (eng
&& exp
% 3 != 0)) {
340 mpmul(MPmant
, MP1base
, MPmant
);
344 STRCPY(fixed
, make_fixed(MPmant
, v
->fnum
, base
, MAX_DIGITS
-6, TRUE
));
346 for (i
= 0; i
< len
; i
++) {
359 SPRINTF(half
, "0.5");
360 MPstr_to_num(half
, DEC
, MP1
);
361 mpaddi(MP1
, &exp
, MPval
);
364 for (ddig
= 0; mpge(MPval
, MP1
); ddig
++) {
365 mpdiv(MPval
, MP1base
, MPval
);
373 mpmul(MPval
, MP1base
, MPval
);
375 *optr
++ = digits
[dval
];
377 mpaddi(MPval
, &dval
, MPval
);
387 /* Convert string into an MP number, in the given base
391 MPstr_to_num(char *str
, enum base_type base
, int *MPval
)
394 int MP1
[MP_SIZE
], MP2
[MP_SIZE
], MPbase
[MP_SIZE
];
399 char *lnp
= ui_get_localized_numeric_point();
404 mpcim(&basevals
[(int) base
], MPbase
);
408 /* Remove any initial spaces or tabs. */
409 while (*optr
== ' ' || *optr
== '\t') {
413 /* Check if this is a negative number. */
419 while ((inum
= char_val(*optr
)) >= 0) {
420 mpmul(MPval
, MPbase
, MPval
);
421 mpaddi(MPval
, &inum
, MPval
);
425 if (*optr
== '.' || *optr
== *lnp
) {
427 for (i
= 1; (inum
= char_val(*optr
)) >= 0; i
++) {
428 mppwr(MPbase
, &i
, MP1
);
430 mpdiv(MP2
, MP1
, MP1
);
431 mpadd(MPval
, MP1
, MPval
);
436 while (*optr
== ' ') {
445 while ((inum
= char_val(*++optr
)) >= 0) {
446 exp
= exp
* basevals
[(int) base
] + inum
;
452 mppwr(MPbase
, &exp
, MP1
);
453 mpmul(MPval
, MP1
, MPval
);
462 /* Append the latest parenthesis char to the display item. */
470 /* If the character is a Delete, clear the whole line, and exit parenthesis
473 * If the character is a Back Space, remove the last character. If the last
474 * character was a left parenthesis, decrement the parentheses count. If
475 * the parentheses count is zero, exit parenthesis processing.
477 * Otherwise just append the character.
480 n
= strlen(v
->display
);
481 text
= buttons
[key
].symname
;
485 v
->noparens
= v
->opsptr
= v
->numsptr
= 0;
488 mpcim(&i
, v
->MPdisp_val
);
489 show_display(v
->MPdisp_val
);
496 if (v
->display
[n
-1] == ')') {
498 } else if (v
->display
[n
-1] == '(') {
501 v
->opsptr
= v
->numsptr
= 0;
503 show_display(v
->MPdisp_val
);
506 } else if (v
->display
[n
-1] == ')') v
->noparens
++;
507 v
->display
[n
-1] = '\0';
510 case KEY_START_BLOCK
:
512 /* If this is the first left parenthesis being displayed and there is no
513 * current arithmetic operand, then the current display is initially cleared
514 * to avoid the confusion of showing something like "0(".
517 if (v
->noparens
== 1 && v
->cur_op
== -1) {
519 v
->display
[0] = '\0';
530 SNPRINTF(v
->display
+n
, MAXLINE
-n
, "%s", text
);
533 n
= (n
< MAX_DIGITS
) ? 0 : n
- MAX_DIGITS
;
534 v
->show_paren
= 1; /* Hack to get ui_set_display to really display it. */
535 ui_set_display(&v
->display
[n
], FALSE
);
541 process_item(struct button
*button
, int arg
)
543 v
->current
= button
->id
;
546 /* Must press a valid key first. */
547 if (v
->current
!= KEY_CLEAR
) {
550 ui_set_error_state(FALSE
);
553 if (v
->noparens
> 0) {
558 STRCPY(v
->opstr
, v
->op_item_text
);
560 (*button
->func
)(arg
);
565 show_display(int *MPval
)
568 STRNCPY(v
->display
, make_number(MPval
, v
->base
, FALSE
), MAXLINE
- 1);
569 ui_set_display(v
->display
, FALSE
);
574 /* In arithmetic precedence mode this routine should be called to redraw
581 char localized
[MAX_LOCALIZED
];
582 struct exprm_state
*e
;
586 show_display(v
->MPdisp_val
);
592 if (e
->expression
&& strlen(e
->expression
)) {
593 char *str
= gc_strdup(e
->expression
);
594 char *ans
= make_number(e
->ans
, v
->base
, TRUE
);
596 localize_number(localized
, ans
);
597 str_replace(&str
, "Ans", localized
);
599 { /* Replace registers with values. */
604 for (i
= 0; i
< 10; i
++) {
608 SNPRINTF(reg
, 3, "R%c", n
+i
);
609 do_rcl_reg(i
, MP_reg
);
610 reg_val
= make_number(MP_reg
, v
->base
, FALSE
);
611 str_replace(&str
, reg
, reg_val
);
614 ui_write_display(str
);