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