Sync up with trunk r61578.
[reactos.git] / base / applications / calc / function.c
1 #include "calc.h"
2
3 #include <limits.h>
4
5 void apply_int_mask(calc_number_t *r)
6 {
7 unsigned __int64 mask;
8
9 switch (calc.size) {
10 case IDC_RADIO_QWORD:
11 mask = _UI64_MAX;
12 break;
13 case IDC_RADIO_DWORD:
14 mask = ULONG_MAX;
15 break;
16 case IDC_RADIO_WORD:
17 mask = USHRT_MAX;
18 break;
19 case IDC_RADIO_BYTE:
20 mask = UCHAR_MAX;
21 break;
22 default:
23 mask = (unsigned __int64)-1;
24 }
25 r->i &= mask;
26 }
27
28 double asinh(double x)
29 {
30 return log(x+sqrt(x*x+1));
31 }
32
33 double acosh(double x)
34 {
35 // must be x>=1, if not return Nan (Not a Number)
36 if(!(x>=1.0)) return sqrt(-1.0);
37
38 // return only the positive result (as sqrt does).
39 return log(x+sqrt(x*x-1.0));
40 }
41
42 double atanh(double x)
43 {
44 // must be x>-1, x<1, if not return Nan (Not a Number)
45 if(!(x>-1.0 && x<1.0)) return sqrt(-1.0);
46
47 return log((1.0+x)/(1.0-x))/2.0;
48 }
49
50 double validate_rad2angle(double a)
51 {
52 switch (calc.degr) {
53 case IDC_RADIO_DEG:
54 a = a * (180.0/CALC_PI);
55 break;
56 case IDC_RADIO_RAD:
57 break;
58 case IDC_RADIO_GRAD:
59 a = a * (200.0/CALC_PI);
60 break;
61 }
62 return a;
63 }
64
65 double validate_angle2rad(calc_number_t *c)
66 {
67 switch (calc.degr) {
68 case IDC_RADIO_DEG:
69 c->f = c->f * (CALC_PI/180.0);
70 break;
71 case IDC_RADIO_RAD:
72 break;
73 case IDC_RADIO_GRAD:
74 c->f = c->f * (CALC_PI/200.0);
75 break;
76 }
77 return c->f;
78 }
79
80 void rpn_sin(calc_number_t *c)
81 {
82 double angle = validate_angle2rad(c);
83
84 if (angle == 0 || angle == CALC_PI)
85 c->f = 0;
86 else
87 if (angle == CALC_3_PI_2)
88 c->f = -1;
89 else
90 if (angle == CALC_2_PI)
91 c->f = 1;
92 else
93 c->f = sin(angle);
94 }
95 void rpn_cos(calc_number_t *c)
96 {
97 double angle = validate_angle2rad(c);
98
99 if (angle == CALC_PI_2 || angle == CALC_3_PI_2)
100 c->f = 0;
101 else
102 if (angle == CALC_PI)
103 c->f = -1;
104 else
105 if (angle == CALC_2_PI)
106 c->f = 1;
107 else
108 c->f = cos(angle);
109 }
110 void rpn_tan(calc_number_t *c)
111 {
112 double angle = validate_angle2rad(c);
113
114 if (angle == CALC_PI_2 || angle == CALC_3_PI_2)
115 calc.is_nan = TRUE;
116 else
117 if (angle == CALC_PI || angle == CALC_2_PI)
118 c->f = 0;
119 else
120 c->f = tan(angle);
121 }
122
123 void rpn_asin(calc_number_t *c)
124 {
125 c->f = validate_rad2angle(asin(c->f));
126 if (_isnan(c->f))
127 calc.is_nan = TRUE;
128 }
129 void rpn_acos(calc_number_t *c)
130 {
131 c->f = validate_rad2angle(acos(c->f));
132 if (_isnan(c->f))
133 calc.is_nan = TRUE;
134 }
135 void rpn_atan(calc_number_t *c)
136 {
137 c->f = validate_rad2angle(atan(c->f));
138 if (_isnan(c->f))
139 calc.is_nan = TRUE;
140 }
141
142 void rpn_sinh(calc_number_t *c)
143 {
144 c->f = sinh(c->f);
145 if (_isnan(c->f))
146 calc.is_nan = TRUE;
147 }
148 void rpn_cosh(calc_number_t *c)
149 {
150 c->f = cosh(c->f);
151 if (_isnan(c->f))
152 calc.is_nan = TRUE;
153 }
154 void rpn_tanh(calc_number_t *c)
155 {
156 c->f = tanh(c->f);
157 if (_isnan(c->f))
158 calc.is_nan = TRUE;
159 }
160
161 void rpn_asinh(calc_number_t *c)
162 {
163 c->f = asinh(c->f);
164 if (_isnan(c->f))
165 calc.is_nan = TRUE;
166 }
167 void rpn_acosh(calc_number_t *c)
168 {
169 c->f = acosh(c->f);
170 if (_isnan(c->f))
171 calc.is_nan = TRUE;
172 }
173 void rpn_atanh(calc_number_t *c)
174 {
175 c->f = atanh(c->f);
176 if (_isnan(c->f))
177 calc.is_nan = TRUE;
178 }
179
180 void rpn_int(calc_number_t *c)
181 {
182 double int_part;
183
184 modf(calc.code.f, &int_part);
185 c->f = int_part;
186 }
187
188 void rpn_frac(calc_number_t *c)
189 {
190 double int_part;
191
192 c->f = modf(calc.code.f, &int_part);
193 }
194
195 void rpn_reci(calc_number_t *c)
196 {
197 if (c->f == 0)
198 calc.is_nan = TRUE;
199 else
200 c->f = 1./c->f;
201 }
202
203 void rpn_fact(calc_number_t *c)
204 {
205 double fact, mult, num;
206
207 if (calc.base == IDC_RADIO_DEC)
208 num = c->f;
209 else
210 num = (double)c->i;
211 if (num > 1000) {
212 calc.is_nan = TRUE;
213 return;
214 }
215 if (num < 0) {
216 calc.is_nan = TRUE;
217 return;
218 } else
219 if (num == 0)
220 fact = 1;
221 else {
222 rpn_int(c);
223 fact = 1;
224 mult = 2;
225 while (mult <= num) {
226 fact *= mult;
227 mult++;
228 }
229 c->f = fact;
230 }
231 if (_finite(fact) == 0)
232 calc.is_nan = TRUE;
233 else
234 if (calc.base == IDC_RADIO_DEC)
235 c->f = fact;
236 else
237 c->i = (__int64)fact;
238 }
239
240 __int64 logic_dbl2int(calc_number_t *a)
241 {
242 double int_part;
243 int width;
244
245 modf(a->f, &int_part);
246 width = (int_part==0) ? 1 : (int)log10(fabs(int_part))+1;
247 if (width > 63) {
248 calc.is_nan = TRUE;
249 return 0;
250 }
251 return (__int64)int_part;
252 }
253 double logic_int2dbl(calc_number_t *a)
254 {
255 return (double)a->i;
256 }
257
258 void rpn_not(calc_number_t *c)
259 {
260 if (calc.base == IDC_RADIO_DEC) {
261 calc_number_t n;
262 n.i = logic_dbl2int(c);
263 c->f = (long double)(~n.i);
264 } else
265 c->i = ~c->i;
266 }
267
268 void rpn_pi(calc_number_t *c)
269 {
270 c->f = CALC_PI;
271 }
272
273 void rpn_2pi(calc_number_t *c)
274 {
275 c->f = CALC_PI*2;
276 }
277
278 void rpn_sign(calc_number_t *c)
279 {
280 if (calc.base == IDC_RADIO_DEC)
281 c->f = 0-c->f;
282 else
283 c->i = 0-c->i;
284 }
285
286 void rpn_exp2(calc_number_t *c)
287 {
288 if (calc.base == IDC_RADIO_DEC) {
289 c->f *= c->f;
290 if (_finite(c->f) == 0)
291 calc.is_nan = TRUE;
292 } else
293 c->i *= c->i;
294 }
295
296 void rpn_exp3(calc_number_t *c)
297 {
298 if (calc.base == IDC_RADIO_DEC) {
299 c->f = pow(c->f, 3.);
300 if (_finite(c->f) == 0)
301 calc.is_nan = TRUE;
302 } else
303 c->i *= (c->i*c->i);
304 }
305
306 static __int64 myabs64(__int64 number)
307 {
308 return (number < 0) ? 0-number : number;
309 }
310
311 static unsigned __int64 sqrti(unsigned __int64 number)
312 {
313 /* modified form of Newton's method for approximating roots */
314 #define NEXT(n, i) (((n) + (i)/(n)) >> 1)
315 unsigned __int64 n, n1;
316
317 #ifdef __GNUC__
318 if (number == 0xffffffffffffffffLL)
319 #else
320 if (number == 0xffffffffffffffff)
321 #endif
322 return 0xffffffff;
323
324 n = 1;
325 n1 = NEXT(n, number);
326 while (myabs64(n1 - n) > 1) {
327 n = n1;
328 n1 = NEXT(n, number);
329 }
330 while((n1*n1) > number)
331 n1--;
332 return n1;
333 #undef NEXT
334 }
335
336 void rpn_sqrt(calc_number_t *c)
337 {
338 if (calc.base == IDC_RADIO_DEC) {
339 if (c->f < 0)
340 calc.is_nan = TRUE;
341 else
342 c->f = sqrt(c->f);
343 } else {
344 c->i = sqrti(c->i);
345 }
346 }
347
348 static __int64 cbrti(__int64 x) {
349 __int64 s, y, b;
350
351 s = 60;
352 y = 0;
353 while(s >= 0) {
354 y = 2*y;
355 b = (3*y*(y + 1) + 1) << s;
356 s = s - 3;
357 if (x >= b) {
358 x = x - b;
359 y = y + 1;
360 }
361 }
362 return y;
363 }
364
365 void rpn_cbrt(calc_number_t *c)
366 {
367 if (calc.base == IDC_RADIO_DEC)
368 #if defined(__GNUC__) && !defined(__REACTOS__)
369 c->f = cbrt(c->f);
370 #else
371 c->f = pow(c->f,1./3.);
372 #endif
373 else {
374 c->i = cbrti(c->i);
375 }
376 }
377
378 void rpn_exp(calc_number_t *c)
379 {
380 c->f = exp(c->f);
381 if (_finite(c->f) == 0)
382 calc.is_nan = TRUE;
383 }
384
385 void rpn_exp10(calc_number_t *c)
386 {
387 double int_part;
388
389 modf(c->f, &int_part);
390 if (fmod(int_part, 2.) == 0.)
391 calc.is_nan = TRUE;
392 else {
393 c->f = pow(10., c->f);
394 if (_finite(c->f) == 0)
395 calc.is_nan = TRUE;
396 }
397 }
398
399 void rpn_ln(calc_number_t *c)
400 {
401 if (c->f <= 0)
402 calc.is_nan = TRUE;
403 else
404 c->f = log(c->f);
405 }
406
407 void rpn_log(calc_number_t *c)
408 {
409 if (c->f <= 0)
410 calc.is_nan = TRUE;
411 else
412 c->f = log10(c->f);
413 }
414
415 static double stat_sum(void)
416 {
417 double sum = 0;
418 statistic_t *p = calc.stat;
419
420 while (p != NULL) {
421 if (p->base == IDC_RADIO_DEC)
422 sum += p->num.f;
423 else
424 sum += p->num.i;
425 p = (statistic_t *)(p->next);
426 }
427 return sum;
428 }
429
430 void rpn_ave(calc_number_t *c)
431 {
432 double ave = 0;
433 int n;
434
435 ave = stat_sum();
436 n = SendDlgItemMessage(calc.hStatWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
437
438 if (n)
439 ave = ave / (double)n;
440 if (calc.base == IDC_RADIO_DEC)
441 c->f = ave;
442 else
443 c->i = (__int64)ave;
444 }
445
446 void rpn_sum(calc_number_t *c)
447 {
448 double sum = stat_sum();
449
450 if (calc.base == IDC_RADIO_DEC)
451 c->f = sum;
452 else
453 c->i = (__int64)sum;
454 }
455
456 static void rpn_s_ex(calc_number_t *c, int pop_type)
457 {
458 double ave = 0;
459 double n = 0;
460 double dev = 0;
461 double num = 0;
462 statistic_t *p = calc.stat;
463
464 ave = stat_sum();
465 n = (double)SendDlgItemMessage(calc.hStatWnd, IDC_LIST_STAT, LB_GETCOUNT, 0, 0);
466
467 if (n == 0) {
468 c->f = 0;
469 return;
470 }
471 ave = ave / n;
472
473 dev = 0;
474 p = calc.stat;
475 while (p != NULL) {
476 if (p->base == IDC_RADIO_DEC)
477 num = p->num.f;
478 else
479 num = (double)p->num.i;
480 dev += pow(num-ave, 2.);
481 p = (statistic_t *)(p->next);
482 }
483 dev = sqrt(dev/(pop_type ? n-1 : n));
484 if (calc.base == IDC_RADIO_DEC)
485 c->f = dev;
486 else
487 c->i = (__int64)dev;
488 }
489
490 void rpn_s(calc_number_t *c)
491 {
492 rpn_s_ex(c, 0);
493 }
494
495 void rpn_s_m1(calc_number_t *c)
496 {
497 rpn_s_ex(c, 1);
498 }
499
500 void rpn_dms2dec(calc_number_t *c)
501 {
502 double d, m, s;
503
504 m = modf(c->f, &d) * 100;
505 s = (modf(m, &m) * 100)+.5;
506 modf(s, &s);
507
508 m = m/60;
509 s = s/3600;
510
511 c->f = d + m + s;
512 }
513
514 void rpn_dec2dms(calc_number_t *c)
515 {
516 double d, m, s;
517
518 m = modf(c->f, &d) * 60;
519 s = ceil(modf(m, &m) * 60);
520 c->f = d + m/100. + s/10000.;
521 }
522
523 void rpn_zero(calc_number_t *c)
524 {
525 c->f = 0;
526 }
527
528 void rpn_copy(calc_number_t *dst, calc_number_t *src)
529 {
530 *dst = *src;
531 }
532
533 int rpn_is_zero(calc_number_t *c)
534 {
535 return (c->f == 0);
536 }
537
538 void rpn_alloc(calc_number_t *c)
539 {
540 }
541
542 void rpn_free(calc_number_t *c)
543 {
544 }