[CALC] Improve multi-precision support, and powers/roots. CORE-8486
[reactos.git] / base / applications / calc / rpn_ieee.c
1 /*
2 * ReactOS Calc (RPN encoder/decoder for IEEE-754 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_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
46 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
47 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
48 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
49 static void rpn_or_f (calc_number_t *r, calc_number_t *a, calc_number_t *b);
50 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
51 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
52 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
53
54 /* Integer mode calculations */
55 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
56 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
57 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
58 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
59 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
60 static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
61 static void rpn_or_i (calc_number_t *r, calc_number_t *a, calc_number_t *b);
62 static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
63 static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
64 static void rpn_shr_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
65
66 /* Percentage mode calculations */
67 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
68 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
69 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
70 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
71
72 static const calc_operator_t operator_list[] = {
73 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PARENT
74 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PERCENT
75 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_EQUAL
76 { 1, rpn_or_f, rpn_or_i, NULL, }, // RPN_OPERATOR_OR
77 { 2, rpn_xor_f, rpn_xor_i, NULL, }, // RPN_OPERATOR_XOR
78 { 3, rpn_and_f, rpn_and_i, NULL, }, // RPN_OPERATOR_AND
79 { 4, rpn_shl_f, rpn_shl_i, NULL, }, // RPN_OPERATOR_LSH
80 { 4, rpn_shr_f, rpn_shr_i, NULL, }, // RPN_OPERATOR_RSH
81 { 5, rpn_add_f, rpn_add_i, rpn_add_p, }, // RPN_OPERATOR_ADD
82 { 5, rpn_sub_f, rpn_sub_i, rpn_sub_p, }, // RPN_OPERATOR_SUB
83 { 6, rpn_mul_f, rpn_mul_i, rpn_mul_p, }, // RPN_OPERATOR_MULT
84 { 6, rpn_div_f, rpn_div_i, rpn_div_p, }, // RPN_OPERATOR_DIV
85 { 6, rpn_mod_f, rpn_mod_i, NULL, }, // RPN_OPERATOR_MOD
86 { 7, rpn_pow_f, NULL, NULL, }, // RPN_OPERATOR_POW
87 { 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR
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 temp = stack->node;
99 next = stack->next;
100
101 /* free the node */
102 free(stack);
103 stack = next;
104
105 return &temp;
106 }
107
108 static int is_stack_empty(void)
109 {
110 return (stack == NULL);
111 }
112
113 static void push(calc_node_t *op)
114 {
115 stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
116
117 z->node = *op;
118 z->next = stack;
119 stack = z;
120 }
121 /*
122 static unsigned int get_prec(unsigned int opc)
123 {
124 unsigned int x;
125
126 for (x=0; x<SIZEOF(operator_list); x++)
127 if (operator_list[x].opc == opc) break;
128 return operator_list[x].prec;
129 }
130 */
131 /* Real mode calculations */
132 static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
133 {
134 r->f = a->f + b->f;
135 }
136
137 static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
138 {
139 r->f = a->f - b->f;
140 }
141
142 static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
143 {
144 r->f = a->f * b->f;
145 }
146
147 static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
148 {
149 if (b->f == 0)
150 calc.is_nan = TRUE;
151 else
152 r->f = a->f / b->f;
153 }
154
155 static void rpn_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
156 {
157 double t;
158
159 if (b->f == 0)
160 calc.is_nan = TRUE;
161 else {
162 modf(a->f/b->f, &t);
163 r->f = a->f - (t * b->f);
164 }
165 }
166
167 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
168 {
169 calc_number_t ai, bi;
170
171 ai.i = logic_dbl2int(a);
172 bi.i = logic_dbl2int(b);
173
174 r->f = (long double)(ai.i & bi.i);
175 }
176
177 static void rpn_or_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
178 {
179 calc_number_t ai, bi;
180
181 ai.i = logic_dbl2int(a);
182 bi.i = logic_dbl2int(b);
183
184 r->f = (long double)(ai.i | bi.i);
185 }
186
187 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
188 {
189 calc_number_t ai, bi;
190
191 ai.i = logic_dbl2int(a);
192 bi.i = logic_dbl2int(b);
193
194 r->f = (long double)(ai.i ^ bi.i);
195 }
196
197 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
198 {
199 calc_number_t n;
200
201 modf(b->f, &n.f);
202
203 r->f = a->f * pow(2., n.f);
204 }
205
206 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
207 {
208 calc_number_t n;
209
210 modf(b->f, &n.f);
211
212 r->f = a->f / pow(2., n.f);
213 }
214
215 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
216 {
217 r->f = pow(a->f, b->f);
218 if (_finite(r->f) == 0 || _isnan(r->f))
219 calc.is_nan = TRUE;
220 }
221
222 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
223 {
224 if (b->f == 0)
225 calc.is_nan = TRUE;
226 else {
227 r->f = pow(a->f, 1./b->f);
228 if (_finite(r->f) == 0 || _isnan(r->f))
229 calc.is_nan = TRUE;
230 }
231 }
232
233 /* Integer mode calculations */
234 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
235 {
236 r->i = a->i + b->i;
237 }
238
239 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
240 {
241 r->i = a->i - b->i;
242 }
243
244 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
245 {
246 r->i = a->i * b->i;
247 }
248
249 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
250 {
251 if (b->i == 0)
252 calc.is_nan = TRUE;
253 else
254 r->i = a->i / b->i;
255 }
256
257 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
258 {
259 if (b->i == 0)
260 calc.is_nan = TRUE;
261 else
262 r->i = a->i % b->i;
263 }
264
265 static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
266 {
267 r->i = a->i & b->i;
268 }
269
270 static void rpn_or_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
271 {
272 r->i = a->i | b->i;
273 }
274
275 static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
276 {
277 r->i = a->i ^ b->i;
278 }
279
280 static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
281 {
282 r->i = a->i << b->i;
283 }
284
285 static void rpn_shr_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
286 {
287 r->i = a->i >> b->i;
288 }
289
290 /* Percent mode calculations */
291 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
292 {
293 r->f = a->f * (1. + b->f/100.);
294 }
295
296 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
297 {
298 r->f = a->f * (1. - b->f/100.);
299 }
300
301 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
302 {
303 r->f = a->f * b->f / 100.;
304 }
305
306 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
307 {
308 if (b->f == 0)
309 calc.is_nan = TRUE;
310 else
311 r->f = a->f * 100. / b->f;
312 }
313
314 void run_operator(calc_node_t *result,
315 calc_node_t *a,
316 calc_node_t *b,
317 unsigned int operation)
318 {
319 calc_number_t da, db, dc;
320 DWORD base = calc.base;
321
322 da = a->number;
323 db = b->number;
324 if (a->base == IDC_RADIO_DEC && b->base != IDC_RADIO_DEC) {
325 db.f = logic_int2dbl(&b->number);
326 base = IDC_RADIO_DEC;
327 } else
328 if (a->base != IDC_RADIO_DEC && b->base == IDC_RADIO_DEC) {
329 da.f = logic_int2dbl(&a->number);
330 base = IDC_RADIO_DEC;
331 }
332
333 if (base == IDC_RADIO_DEC) {
334 if (percent_mode) {
335 percent_mode = FALSE;
336 operator_list[operation].op_p(&dc, &da, &db);
337 } else
338 operator_list[operation].op_f(&dc, &da, &db);
339 if (_finite(dc.f) == 0)
340 calc.is_nan = TRUE;
341 } else {
342 operator_list[operation].op_i(&dc, &da, &db);
343 /* apply final limiter to result */
344 apply_int_mask(&dc);
345 }
346
347 if (a->base == IDC_RADIO_DEC && b->base != IDC_RADIO_DEC) {
348 result->number.i = logic_dbl2int(&dc);
349 apply_int_mask(&result->number);
350 } else
351 if (a->base != IDC_RADIO_DEC && b->base == IDC_RADIO_DEC)
352 result->number.f = dc.f;
353 else
354 result->number = dc;
355 }
356
357 static void evalStack(calc_number_t *number)
358 {
359 calc_node_t *op, ip;
360 unsigned int prec;
361
362 op = pop();
363 ip = *op;
364 prec = operator_list[ip.operation].prec;
365 while (!is_stack_empty()) {
366 op = pop();
367
368 if (prec <= operator_list[op->operation].prec) {
369 if (op->operation == RPN_OPERATOR_PARENT) continue;
370
371 calc.prev = ip.number;
372 run_operator(&ip, op, &ip, op->operation);
373 if (calc.is_nan) {
374 flush_postfix();
375 return;
376 }
377 } else {
378 push(op);
379 break;
380 }
381 }
382
383 if (ip.operation != RPN_OPERATOR_EQUAL && ip.operation != RPN_OPERATOR_PERCENT)
384 push(&ip);
385
386 calc.prev_operator = op->operation;
387
388 *number = ip.number;
389 }
390
391 int exec_infix2postfix(calc_number_t *number, unsigned int func)
392 {
393 calc_node_t tmp;
394
395 if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
396 /* if a number has been entered with exponential */
397 /* notation, I may update it with normal mode */
398 if (calc.sci_in)
399 return 1;
400 return 0;
401 }
402
403 if (func == RPN_OPERATOR_PERCENT)
404 percent_mode = TRUE;
405
406 tmp.number = *number;
407 tmp.base = calc.base;
408 tmp.operation = func;
409
410 push(&tmp);
411
412 if (func == RPN_OPERATOR_NONE)
413 return 0;
414
415 if (func != RPN_OPERATOR_PARENT) {
416 calc.last_operator = func;
417 evalStack(number);
418 }
419 return 1;
420 }
421
422 void exec_change_infix(void)
423 {
424 stack_node_t *op = stack;
425
426 if (op == NULL)
427 return;
428 if (op->node.operation == RPN_OPERATOR_PARENT ||
429 op->node.operation == RPN_OPERATOR_PERCENT ||
430 op->node.operation == RPN_OPERATOR_EQUAL)
431 return;
432 /* remove the head, it will be re-inserted with new operator */
433 pop();
434 }
435
436 void exec_closeparent(calc_number_t *number)
437 {
438 calc_node_t *op, ip;
439
440 ip.number = *number;
441 ip.base = calc.base;
442 while (!is_stack_empty()) {
443 op = pop();
444
445 if (op->operation == RPN_OPERATOR_PARENT)
446 break;
447
448 run_operator(&ip, op, &ip, op->operation);
449 if (calc.is_nan) {
450 flush_postfix();
451 return;
452 }
453 }
454 *number = ip.number;
455 }
456
457 int eval_parent_count(void)
458 {
459 stack_node_t *s = stack;
460 int n = 0;
461
462 while (s != NULL) {
463 if (s->node.operation == RPN_OPERATOR_PARENT)
464 n++;
465 s = (stack_node_t *)(s->next);
466 }
467 return n;
468 }
469
470 void flush_postfix(void)
471 {
472 while (!is_stack_empty())
473 pop();
474 /* clear prev and last typed operators */
475 calc.prev_operator =
476 calc.last_operator = 0;
477 }
478
479 void start_rpn_engine(void)
480 {
481 stack = NULL;
482 }
483
484 void stop_rpn_engine(void)
485 {
486 }