xref: /reactos/base/applications/calc/rpn_mpfr.c (revision 7115d7ba)
1 /*
2  * ReactOS Calc (RPN encoder/decoder for GMP/MPFR engine)
3  *
4  * Copyright 2007-2017, Carlo Bramini
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "calc.h"
22 
23 typedef struct {
24     calc_node_t     node;
25     void           *next;
26 } stack_node_t;
27 
28 typedef void (*operator_call)(calc_number_t *, calc_number_t *, calc_number_t *);
29 
30 typedef struct {
31     unsigned int prec;
32     operator_call op_f;
33     operator_call op_i;
34     operator_call op_p;
35 } calc_operator_t;
36 
37 static stack_node_t *stack;
38 static calc_node_t   temp;
39 static BOOL          percent_mode;
40 
41 static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
42 static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
43 static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
44 static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
45 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
46 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
47 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
48 static void rpn_or_f (calc_number_t *r, calc_number_t *a, calc_number_t *b);
49 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
50 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
51 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
52 
53 /* Integer mode calculations */
54 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
55 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
56 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
57 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
58 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
59 
60 /* Percentage mode calculations */
61 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
62 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
63 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
64 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
65 
66 static const calc_operator_t operator_list[] = {
67     { 0, NULL,      NULL,      NULL,      }, // RPN_OPERATOR_PARENT
68     { 0, NULL,      NULL,      NULL,      }, // RPN_OPERATOR_PERCENT
69     { 0, NULL,      NULL,      NULL,      }, // RPN_OPERATOR_EQUAL
70     { 1, rpn_or_f,  rpn_or_f,  NULL,      }, // RPN_OPERATOR_OR
71     { 2, rpn_xor_f, rpn_xor_f, NULL,      }, // RPN_OPERATOR_XOR
72     { 3, rpn_and_f, rpn_and_f, NULL,      }, // RPN_OPERATOR_AND
73     { 4, rpn_shl_f, rpn_shl_f, NULL,      }, // RPN_OPERATOR_LSH
74     { 4, rpn_shr_f, rpn_shr_f, NULL,      }, // RPN_OPERATOR_RSH
75     { 5, rpn_add_f, rpn_add_i, rpn_add_p, }, // RPN_OPERATOR_ADD
76     { 5, rpn_sub_f, rpn_sub_i, rpn_sub_p, }, // RPN_OPERATOR_SUB
77     { 6, rpn_mul_f, rpn_mul_i, rpn_mul_p, }, // RPN_OPERATOR_MULT
78     { 6, rpn_div_f, rpn_div_i, rpn_div_p, }, // RPN_OPERATOR_DIV
79     { 6, rpn_mod_i, rpn_mod_i, NULL,      }, // RPN_OPERATOR_MOD
80     { 7, rpn_pow_f, NULL,      NULL,      }, // RPN_OPERATOR_POW
81     { 7, rpn_sqr_f, NULL,      NULL,      }, // RPN_OPERATOR_SQR
82 };
83 
84 static void node_copy(calc_node_t *dst, calc_node_t *src)
85 {
86     mpfr_set(dst->number.mf, src->number.mf, MPFR_DEFAULT_RND);
87     dst->operation = src->operation;
88 }
89 
90 static calc_node_t *pop(void)
91 {
92     void *next;
93 
94     if (stack == NULL)
95         return NULL;
96 
97     /* copy the node */
98     node_copy(&temp, &stack->node);
99     next = stack->next;
100 
101     /* free the node */
102     mpfr_clear(stack->node.number.mf);
103     free(stack);
104     stack = next;
105 
106     return &temp;
107 }
108 
109 static int is_stack_empty(void)
110 {
111     return (stack == NULL);
112 }
113 
114 static void push(calc_node_t *op)
115 {
116     stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
117 
118     mpfr_init_set(z->node.number.mf, op->number.mf, MPFR_DEFAULT_RND);
119     z->node.operation = op->operation;
120     z->next = stack;
121     stack = z;
122 }
123 /*
124 static unsigned int get_prec(unsigned int opc)
125 {
126     unsigned int x;
127 
128     for (x=0; x<SIZEOF(operator_list); x++)
129         if (operator_list[x].opc == opc) break;
130     return operator_list[x].prec;
131 }
132 */
133 
134 typedef void (*exec_call_t)
135 __GMP_PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr));
136 
137 static void rpn_exec_int(calc_number_t *r, calc_number_t *a, calc_number_t *b, exec_call_t cb)
138 {
139     mpz_t ai, bi;
140 
141     mpz_init(ai);
142     mpz_init(bi);
143     mpfr_get_z(ai, a->mf, MPFR_DEFAULT_RND);
144     mpfr_get_z(bi, b->mf, MPFR_DEFAULT_RND);
145     cb(ai, ai, bi);
146     mpfr_set_z(r->mf, ai, MPFR_DEFAULT_RND);
147     mpz_clear(ai);
148     mpz_clear(bi);
149 }
150 
151 
152 /* Real mode calculations */
153 static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
154 {
155     mpfr_add(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
156 }
157 
158 static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
159 {
160     mpfr_sub(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
161 }
162 
163 static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
164 {
165     mpfr_mul(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
166 }
167 
168 static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
169 {
170     if (mpfr_sgn(b->mf) == 0)
171         calc.is_nan = TRUE;
172     else
173         mpfr_div(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
174 }
175 
176 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
177 {
178     rpn_exec_int(r, a, b, mpz_and);
179 }
180 
181 static void rpn_or_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
182 {
183     rpn_exec_int(r, a, b, mpz_ior);
184 }
185 
186 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
187 {
188     rpn_exec_int(r, a, b, mpz_xor);
189 }
190 
191 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
192 {
193     unsigned long e;
194 
195     mpfr_trunc(r->mf, b->mf);
196     if (mpfr_fits_ulong_p(r->mf, MPFR_DEFAULT_RND) == 0)
197         calc.is_nan = TRUE;
198     else {
199         e = mpfr_get_ui(r->mf, MPFR_DEFAULT_RND);
200         mpfr_mul_2exp(r->mf, a->mf, e, MPFR_DEFAULT_RND);
201     }
202 }
203 
204 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
205 {
206     unsigned long e;
207 
208     mpfr_trunc(r->mf, b->mf);
209     if (mpfr_fits_ulong_p(r->mf, MPFR_DEFAULT_RND) == 0)
210         calc.is_nan = TRUE;
211     else {
212         e = mpfr_get_ui(r->mf, MPFR_DEFAULT_RND);
213         mpfr_div_2exp(r->mf, a->mf, e, MPFR_DEFAULT_RND);
214     }
215 }
216 
217 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
218 {
219     mpfr_pow(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
220 }
221 
222 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
223 {
224     if (mpfr_sgn(b->mf) == 0)
225         calc.is_nan = TRUE;
226     else {
227         mpfr_t tmp;
228 
229         mpfr_init(tmp);
230         mpfr_set(tmp, b->mf, MPFR_DEFAULT_RND);
231         mpfr_ui_div(tmp, 1, tmp, MPFR_DEFAULT_RND);
232         mpfr_pow(r->mf, a->mf, tmp, MPFR_DEFAULT_RND);
233         mpfr_clear(tmp);
234     }
235 }
236 
237 /* Integer mode calculations */
238 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
239 {
240     rpn_exec_int(r, a, b, mpz_add);
241 }
242 
243 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
244 {
245     rpn_exec_int(r, a, b, mpz_sub);
246 }
247 
248 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
249 {
250     rpn_exec_int(r, a, b, mpz_mul);
251 }
252 
253 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
254 {
255     if (mpfr_sgn(b->mf) == 0)
256         calc.is_nan = TRUE;
257     else
258         rpn_exec_int(r, a, b, mpz_tdiv_q);
259 }
260 
261 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
262 {
263     if (mpfr_sgn(b->mf) == 0)
264         calc.is_nan = TRUE;
265     else
266         rpn_exec_int(r, a, b, mpz_tdiv_r);
267 }
268 
269 /* Percent mode calculations */
270 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
271 {
272     mpfr_t tmp;
273 
274     mpfr_init(tmp);
275     mpfr_set(tmp, b->mf, MPFR_DEFAULT_RND);
276     mpfr_div_ui(tmp, tmp, 100, MPFR_DEFAULT_RND);
277     mpfr_add_ui(tmp, tmp, 1, MPFR_DEFAULT_RND);
278     mpfr_mul(r->mf, a->mf, tmp, MPFR_DEFAULT_RND);
279     mpfr_clear(tmp);
280 }
281 
282 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
283 {
284     mpfr_t tmp;
285 
286     mpfr_init(tmp);
287     mpfr_set(tmp, b->mf, MPFR_DEFAULT_RND);
288     mpfr_div_ui(tmp, tmp, 100, MPFR_DEFAULT_RND);
289     mpfr_sub_ui(tmp, tmp, 1, MPFR_DEFAULT_RND);
290     mpfr_mul(r->mf, a->mf, tmp, MPFR_DEFAULT_RND);
291     mpfr_clear(tmp);
292 }
293 
294 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
295 {
296     mpfr_mul(r->mf, a->mf, b->mf, MPFR_DEFAULT_RND);
297     mpfr_div_ui(r->mf, r->mf, 100, MPFR_DEFAULT_RND);
298 }
299 
300 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
301 {
302     if (mpfr_sgn(b->mf) == 0)
303         calc.is_nan = TRUE;
304     else {
305         mpfr_mul_ui(r->mf, a->mf, 100, MPFR_DEFAULT_RND);
306         mpfr_div(r->mf, r->mf, b->mf, MPFR_DEFAULT_RND);
307     }
308 }
309 
310 void run_operator(calc_node_t *result,
311                   calc_node_t *a,
312                   calc_node_t *b,
313                   unsigned int operation)
314 {
315     if (calc.base == IDC_RADIO_DEC) {
316         if (percent_mode) {
317             percent_mode = FALSE;
318             operator_list[operation].op_p(&result->number, &a->number, &b->number);
319         } else
320             operator_list[operation].op_f(&result->number, &a->number, &b->number);
321     } else {
322         operator_list[operation].op_i(&result->number, &a->number, &b->number);
323         /* apply final limiter to result */
324         apply_int_mask(&result->number);
325     }
326 }
327 
328 static void evalStack(calc_number_t *number)
329 {
330     calc_node_t *op, ip;
331     unsigned int prec;
332 
333     mpfr_init(ip.number.mf);
334     op = pop();
335     node_copy(&ip, op);
336     prec = operator_list[ip.operation].prec;
337     while (!is_stack_empty()) {
338         op = pop();
339 
340         if (prec <= operator_list[op->operation].prec) {
341             if (op->operation == RPN_OPERATOR_PARENT) continue;
342 
343             rpn_copy(&calc.prev, &ip.number);
344             run_operator(&ip, op, &ip, op->operation);
345             if (calc.is_nan) {
346                 flush_postfix();
347                 mpfr_clear(ip.number.mf);
348                 return;
349             }
350         } else {
351             push(op);
352             break;
353         }
354     }
355 
356     if (ip.operation != RPN_OPERATOR_EQUAL && ip.operation != RPN_OPERATOR_PERCENT)
357         push(&ip);
358 
359     calc.prev_operator = op->operation;
360 
361     rpn_copy(number, &ip.number);
362     mpfr_clear(ip.number.mf);
363 }
364 
365 int exec_infix2postfix(calc_number_t *number, unsigned int func)
366 {
367     calc_node_t tmp;
368 
369     if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
370         /* if a number has been entered with exponential */
371         /* notation, I may update it with normal mode */
372         if (calc.sci_in)
373             return 1;
374         return 0;
375     }
376 
377     if (func == RPN_OPERATOR_PERCENT)
378         percent_mode = TRUE;
379 
380     mpfr_init(tmp.number.mf);
381     rpn_copy(&tmp.number, number);
382     tmp.operation = func;
383 
384     push(&tmp);
385     mpfr_clear(tmp.number.mf);
386 
387     if (func == RPN_OPERATOR_NONE)
388         return 0;
389 
390     if (func != RPN_OPERATOR_PARENT) {
391         calc.last_operator = func;
392         evalStack(number);
393     }
394     return 1;
395 }
396 
397 void exec_change_infix(void)
398 {
399     stack_node_t *op = stack;
400 
401     if (op == NULL)
402         return;
403     if (op->node.operation == RPN_OPERATOR_PARENT ||
404         op->node.operation == RPN_OPERATOR_PERCENT ||
405         op->node.operation == RPN_OPERATOR_EQUAL)
406         return;
407     /* remove the head, it will be re-inserted with new operator */
408     pop();
409 }
410 
411 void exec_closeparent(calc_number_t *number)
412 {
413     calc_node_t *op, ip;
414 
415     rpn_alloc(&ip.number);
416     rpn_copy(&ip.number, number);
417     while (!is_stack_empty()) {
418         op = pop();
419 
420         if (op->operation == RPN_OPERATOR_PARENT)
421             break;
422 
423         run_operator(&ip, op, &ip, op->operation);
424         if (calc.is_nan) {
425             flush_postfix();
426             return;
427         }
428     }
429     rpn_copy(number, &ip.number);
430     rpn_free(&ip.number);
431 }
432 
433 int eval_parent_count(void)
434 {
435     stack_node_t *s = stack;
436     int           n = 0;
437 
438     while (s != NULL) {
439         if (s->node.operation == RPN_OPERATOR_PARENT)
440             n++;
441         s = (stack_node_t *)(s->next);
442     }
443     return n;
444 }
445 
446 void flush_postfix(void)
447 {
448     while (!is_stack_empty())
449         pop();
450     /* clear prev and last typed operators */
451     calc.prev_operator =
452     calc.last_operator = 0;
453 }
454 
455 void start_rpn_engine(void)
456 {
457     mpf_set_default_prec(512);
458     mpfr_set_default_prec(512);
459     stack = NULL;
460     mpfr_init(calc.code.mf);
461     mpfr_init(calc.prev.mf);
462     mpfr_init(calc.memory.number.mf);
463     mpfr_init(temp.number.mf);
464     rpn_zero(&calc.memory.number);
465 }
466 
467 void stop_rpn_engine(void)
468 {
469     mpfr_clear(calc.code.mf);
470     mpfr_clear(calc.prev.mf);
471     mpfr_clear(calc.memory.number.mf);
472     mpfr_clear(temp.number.mf);
473 }
474