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