kspread

valuecalc.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "valuecalc.h"
21
22#include "valueconverter.h"
23
24#include <kdebug.h>
25#include <errno.h>
26#include <float.h>
27#include <math.h>
28#include <stdlib.h>
29#include <time.h>
30
31using namespace KSpread;
32
33
34// Array-walk functions registered on ValueCalc object
35
36void awSum (ValueCalc *c, Value &res, Value val, Value)
37{
38 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
39 res = c->add (res, val);
40}
41
42void awSumA (ValueCalc *c, Value &res, Value val, Value)
43{
44 if (!val.isEmpty())
45 res = c->add (res, val);
46}
47
48void awSumSq (ValueCalc *c, Value &res, Value val, Value)
49{
50 if (!val.isEmpty())
51 res = c->add (res, c->sqr (val));
52}
53
54void awSumSqA (ValueCalc *c, Value &res, Value val, Value)
55{
56 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
57 res = c->add (res, c->sqr (val));
58}
59
60void awCount (ValueCalc *c, Value &res, Value val, Value)
61{
62 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
63 res = c->add (res, 1);
64}
65
66void awCountA (ValueCalc *c, Value &res, Value val, Value)
67{
68 if (!val.isEmpty())
69 res = c->add (res, 1);
70}
71
72void awMax (ValueCalc *c, Value &res, Value val, Value)
73{
74 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
75 if (res.isEmpty())
76 res = val;
77 else
78 if (c->greater (val, res)) res = val;
79}
80
81void awMaxA (ValueCalc *c, Value &res, Value val, Value)
82{
83 if (!val.isEmpty())
84 if (res.isEmpty())
85 // convert to number, so that we don't return string/bool
86 res = c->conv()->asNumeric (val);
87 else
88 if (c->greater (val, res))
89 // convert to number, so that we don't return string/bool
90 res = c->conv()->asNumeric (val);
91}
92
93void awMin (ValueCalc *c, Value &res, Value val, Value)
94{
95 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
96 if (res.isEmpty())
97 res = val;
98 else
99 if (c->lower (val, res)) res = val;
100}
101
102void awMinA (ValueCalc *c, Value &res, Value val, Value)
103{
104 if (!val.isEmpty())
105 if (res.isEmpty())
106 // convert to number, so that we don't return string/bool
107 res = c->conv()->asNumeric (val);
108 else
109 if (c->lower (val, res))
110 // convert to number, so that we don't return string/bool
111 res = c->conv()->asNumeric (val);
112}
113
114void awProd (ValueCalc *c, Value &res, Value val, Value)
115{
116 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
117 res = c->mul (res, val);
118}
119
120void awProdA (ValueCalc *c, Value &res, Value val, Value)
121{
122 if (!val.isEmpty())
123 res = c->mul (res, val);
124}
125
126// sum of squares of deviations, used to compute standard deviation
127void awDevSq (ValueCalc *c, Value &res, Value val,
128 Value avg)
129{
130 if (!val.isEmpty())
131 res = c->add (res, c->sqr (c->sub (val, avg)));
132}
133
134// sum of squares of deviations, used to compute standard deviation
135void awDevSqA (ValueCalc *c, Value &res, Value val,
136 Value avg)
137{
138 if ((!val.isEmpty()) && (!val.isBoolean()) && (!val.isString()))
139 res = c->add (res, c->sqr (c->sub (val, avg)));
140}
141
142
143bool isDate (Value val) {
144 Value::Format fmt = val.format();
145 if ((fmt == Value::fmt_Date) || (fmt == Value::fmt_DateTime))
146 return true;
147 return false;
148}
149
150// ***********************
151// ****** ValueCalc ******
152// ***********************
153
154ValueCalc::ValueCalc (ValueConverter* c): converter( c )
155{
156 // initialize the random number generator
157 srand (time (0));
158
159 // register array-walk functions
160 registerAwFunc ("sum", awSum);
161 registerAwFunc ("suma", awSumA);
162 registerAwFunc ("sumsq", awSumSq);
163 registerAwFunc ("sumsqa", awSumSqA);
164 registerAwFunc ("count", awCount);
165 registerAwFunc ("counta", awCountA);
166 registerAwFunc ("max", awMax);
167 registerAwFunc ("maxa", awMaxA);
168 registerAwFunc ("min", awMin);
169 registerAwFunc ("mina", awMinA);
170 registerAwFunc ("prod", awProd);
171 registerAwFunc ("proda", awProdA);
172 registerAwFunc ("devsq", awDevSq);
173 registerAwFunc ("devsqa", awDevSq);
174}
175
176Value ValueCalc::add (const Value &a, const Value &b)
177{
178 if (a.isError()) return a;
179 if (b.isError()) return b;
180 Value res;
181 if (a.isInteger() && b.isEmpty() || a.isEmpty() && b.isInteger()
182 || a.isInteger() && b.isInteger())
183 {
184 int aa, bb;
185 aa = converter->asInteger (a).asInteger();
186 bb = converter->asInteger (b).asInteger();
187 res = Value (aa + bb);
188 }
189 else
190 {
191 double aa, bb;
192 aa = converter->asFloat (a).asFloat();
193 bb = converter->asFloat (b).asFloat();
194 res = Value (aa + bb);
195 }
196
197 if (a.isNumber() || a.isEmpty())
198 res.setFormat (format (a.format(), b.format()));
199 // operation on two dates should produce a number
200 if (isDate(a) && isDate(b))
201 res.setFormat (Value::fmt_Number);
202
203 return res;
204}
205
206Value ValueCalc::sub (const Value &a, const Value &b)
207{
208 if (a.isError()) return a;
209 if (b.isError()) return b;
210 double aa, bb;
211 aa = converter->asFloat (a).asFloat();
212 bb = converter->asFloat (b).asFloat();
213 Value res = Value (aa - bb);
214
215 if (a.isNumber() || a.isEmpty())
216 res.setFormat (format (a.format(), b.format()));
217 // operation on two dates should produce a number
218 if (isDate(a) && isDate(b))
219 res.setFormat (Value::fmt_Number);
220
221 return res;
222}
223
224Value ValueCalc::mul (const Value &a, const Value &b)
225{
226 if (a.isError()) return a;
227 if (b.isError()) return b;
228 double aa, bb;
229 aa = converter->asFloat (a).asFloat();
230 bb = converter->asFloat (b).asFloat();
231 Value res = Value (aa * bb);
232
233 if (a.isNumber() || a.isEmpty())
234 res.setFormat (format (a.format(), b.format()));
235 // operation on two dates should produce a number
236 if (isDate(a) && isDate(b))
237 res.setFormat (Value::fmt_Number);
238
239 return res;
240}
241
242Value ValueCalc::div (const Value &a, const Value &b)
243{
244 if (a.isError()) return a;
245 if (b.isError()) return b;
246 double aa, bb;
247 aa = converter->asFloat (a).asFloat();
248 bb = converter->asFloat (b).asFloat();
249 Value res;
250 if (bb == 0.0)
251 return Value::errorDIV0();
252 else
253 res = Value (aa / bb);
254
255 if (a.isNumber() || a.isEmpty())
256 res.setFormat (format (a.format(), b.format()));
257 // operation on two dates should produce a number
258 if (isDate(a) && isDate(b))
259 res.setFormat (Value::fmt_Number);
260
261 return res;
262}
263
264Value ValueCalc::mod (const Value &a, const Value &b)
265{
266 if (a.isError()) return a;
267 if (b.isError()) return b;
268 double aa, bb;
269 aa = converter->asFloat (a).asFloat();
270 bb = converter->asFloat (b).asFloat();
271 Value res;
272 if (bb == 0.0)
273 return Value::errorDIV0();
274 else
275 {
276 double m = fmod (aa, bb);
277 // the following adjustments are needed by OpenFormula:
278 // can't simply use fixed increases/decreases, because the implementation
279 // of fmod may differ on various platforms, and we should always return
280 // the same results ...
281 if ((bb > 0) && (aa < 0)) // result must be positive here
282 while (m < 0) m += bb;
283 if (bb < 0) // result must be negative here, but not lower than bb
284 {
285 // bb is negative, hence the following two are correct
286 while (m < bb) m -= bb; // same as m+=fabs(bb)
287 while (m > 0) m += bb; // same as m-=fabs(bb)
288 }
289
290 res = Value (m);
291 }
292
293 if (a.isNumber() || a.isEmpty())
294 res.setFormat (format (a.format(), b.format()));
295 if (isDate(a) && isDate(b))
296 res.setFormat (Value::fmt_Number);
297
298 return res;
299}
300
301Value ValueCalc::pow (const Value &a, const Value &b)
302{
303 if (a.isError()) return a;
304 if (b.isError()) return b;
305 double aa, bb;
306 aa = converter->asFloat (a).asFloat();
307 bb = converter->asFloat (b).asFloat();
308 Value res = Value (::pow (aa, bb));
309
310 if (a.isNumber() || a.isEmpty())
311 res.setFormat (format (a.format(), b.format()));
312 // operation on date(s) should produce a number
313 if (isDate(a) || isDate(b))
314 res.setFormat (Value::fmt_Number);
315
316 return res;
317}
318
319Value ValueCalc::sqr (const Value &a)
320{
321 if (a.isError()) return a;
322 return mul (a, a);
323}
324
325Value ValueCalc::sqrt (const Value &a)
326{
327 if (a.isError()) return a;
328 Value res = Value (::sqrt (converter->asFloat(a).asFloat()));
329 if (a.isNumber() || a.isEmpty())
330 res.setFormat (a.format());
331 // operation on date(s) should produce a number
332 if (isDate(a))
333 res.setFormat (Value::fmt_Number);
334
335 return res;
336}
337
338Value ValueCalc::add (const Value &a, double b)
339{
340 if (a.isError()) return a;
341 Value res = Value (converter->asFloat(a).asFloat() + b);
342
343 if (a.isNumber() || a.isEmpty())
344 res.setFormat (a.format());
345
346 return res;
347}
348
349Value ValueCalc::sub (const Value &a, double b)
350{
351 if (a.isError()) return a;
352 Value res = Value (converter->asFloat(a).asFloat() - b);
353
354 if (a.isNumber() || a.isEmpty())
355 res.setFormat (a.format());
356
357 return res;
358}
359
360Value ValueCalc::mul (const Value &a, double b)
361{
362 if (a.isError()) return a;
363 Value res = Value (converter->asFloat(a).asFloat() * b);
364
365 if (a.isNumber() || a.isEmpty())
366 res.setFormat (a.format());
367
368 return res;
369}
370
371Value ValueCalc::div (const Value &a, double b)
372{
373 if (a.isError()) return a;
374 Value res;
375 if (b == 0.0)
376 return Value::errorDIV0();
377
378 res = Value (converter->asFloat(a).asFloat() / b);
379
380 if (a.isNumber() || a.isEmpty())
381 res.setFormat (a.format());
382
383 return res;
384}
385
386Value ValueCalc::pow (const Value &a, double b)
387{
388 if (a.isError()) return a;
389 Value res = Value (::pow (converter->asFloat(a).asFloat(), b));
390
391 if (a.isNumber() || a.isEmpty())
392 res.setFormat (a.format());
393
394 return res;
395}
396
397Value ValueCalc::abs (const Value &a)
398{
399 if (a.isError()) return a;
400 return Value (fabs (converter->asFloat (a).asFloat()));
401}
402
404{
405 if (a.isError()) return false;
406 return (converter->asFloat (a).asFloat() == 0.0);
407}
408
409bool ValueCalc::isEven (const Value &a)
410{
411 if (a.isError()) return false;
412 return ((converter->asInteger (a).asInteger() % 2) == 0);
413}
414
415bool ValueCalc::equal (const Value &a, const Value &b)
416{
417 return (converter->asFloat (a).asFloat() == converter->asFloat (b).asFloat());
418}
419
420/*********************************************************************
421 *
422 * Helper function to avoid problems with rounding floating point
423 * values. Idea for this kind of solution taken from Openoffice.
424 *
425 *********************************************************************/
426bool ValueCalc::approxEqual (const Value &a, const Value &b)
427{
428 double aa = converter->asFloat (a).asFloat();
429 double bb = converter->asFloat (b).asFloat();
430 if (aa == bb)
431 return true;
432 double x = aa - bb;
433 return (x < 0.0 ? -x : x) < ((aa < 0.0 ? -aa : aa) * DBL_EPSILON);
434}
435
436bool ValueCalc::strEqual (const Value &a, const Value &b, bool CS)
437{
438 TQString aa = converter->asString(a).asString();
439 TQString bb = converter->asString(b).asString();
440 if (!CS) {
441 aa = aa.lower();
442 bb = bb.lower();
443 }
444 return (aa == bb);
445}
446
447bool ValueCalc::strGreater (const Value &a, const Value &b, bool CS)
448{
449 TQString aa = converter->asString(a).asString();
450 TQString bb = converter->asString(b).asString();
451 if (!CS) {
452 aa = aa.lower();
453 bb = bb.lower();
454 }
455 return (aa > bb);
456}
457
458bool ValueCalc::strGequal (const Value &a, const Value &b, bool CS)
459{
460 TQString aa = converter->asString(a).asString();
461 TQString bb = converter->asString(b).asString();
462 if (!CS) {
463 aa = aa.lower();
464 bb = bb.lower();
465 }
466 return (aa >= bb);
467}
468
469bool ValueCalc::strLower (const Value &a, const Value &b, bool CS)
470{
471 return strGreater (b, a, CS);
472}
473
474bool ValueCalc::naturalEqual (const Value &a, const Value &b, bool CS)
475{
476 if (a.isNumber() && b.isNumber())
477 return approxEqual(a, b);
478 if (a.allowComparison(b))
479 return a.equal(b);
480 return strEqual(a, b, CS);
481}
482
483bool ValueCalc::naturalGreater (const Value &a, const Value &b, bool CS)
484{
485 if (a.isNumber() && b.isNumber())
486 return greater(a, b);
487 if (a.allowComparison(b))
488 return a.greater(b);
489 return strGreater(a, b, CS);
490}
491
492bool ValueCalc::naturalGequal (const Value &a, const Value &b, bool CS)
493{
494 return naturalGreater(a, b, CS) || naturalEqual(a, b, CS);
495}
496
497bool ValueCalc::naturalLower (const Value &a, const Value &b, bool CS)
498{
499 return naturalGreater(b, a, CS);
500}
501
502bool ValueCalc::greater (const Value &a, const Value &b)
503{
504 double aa = converter->asFloat (a).asFloat();
505 double bb = converter->asFloat (b).asFloat();
506 return (aa > bb);
507}
508
509bool ValueCalc::gequal (const Value &a, const Value &b)
510{
511 return (greater (a,b) || approxEqual (a,b));
512}
513
514bool ValueCalc::lower (const Value &a, const Value &b)
515{
516 return greater (b, a);
517}
518
520 const Value &digits) {
521 return roundDown (a, converter->asInteger (digits).asInteger());
522}
523
524Value ValueCalc::roundUp (const Value &a,
525 const Value &digits) {
526 return roundUp (a, converter->asInteger (digits).asInteger());
527}
528
529Value ValueCalc::round (const Value &a,
530 const Value &digits) {
531 return round (a, converter->asInteger (digits).asInteger());
532}
533
534Value ValueCalc::roundDown (const Value &a, int digits)
535{
536 // shift in one direction, round, shift back
537 Value val = a;
538 if (digits > 0)
539 for (int i = 0; i < digits; ++i)
540 val = mul (val, 10);
541 if (digits < 0)
542 for (int i = 0; i < digits; ++i)
543 val = div (val, 10);
544
545 val = Value (floor (converter->asFloat (val).asFloat()));
546
547 if (digits > 0)
548 for (int i = 0; i < digits; ++i)
549 val = div (val, 10);
550 if (digits < 0)
551 for (int i = 0; i < digits; ++i)
552 val = mul (val, 10);
553 return val;
554}
555
556Value ValueCalc::roundUp (const Value &a, int digits)
557{
558 // shift in one direction, round, shift back
559 Value val = a;
560 if (digits > 0)
561 for (int i = 0; i < digits; ++i)
562 val = mul (val, 10);
563 if (digits < 0)
564 for (int i = 0; i < digits; ++i)
565 val = div (val, 10);
566
567 val = Value (ceil (converter->asFloat (val).asFloat()));
568
569 if (digits > 0)
570 for (int i = 0; i < digits; ++i)
571 val = div (val, 10);
572 if (digits < 0)
573 for (int i = 0; i < digits; ++i)
574 val = mul (val, 10);
575 return val;
576}
577
578Value ValueCalc::round (const Value &a, int digits)
579{
580 // shift in one direction, round, shift back
581 Value val = a;
582 if (digits > 0)
583 for (int i = 0; i < digits; ++i)
584 val = mul (val, 10);
585 if (digits < 0)
586 for (int i = 0; i < digits; ++i)
587 val = div (val, 10);
588
589 val = Value (int(converter->asFloat (val).asFloat()+0.5));
590
591 if (digits > 0)
592 for (int i = 0; i < digits; ++i)
593 val = div (val, 10);
594 if (digits < 0)
595 for (int i = 0; i < digits; ++i)
596 val = mul (val, 10);
597 return val;
598}
599
600int ValueCalc::sign (const Value &a)
601{
602 double val = converter->asFloat (a).asFloat ();
603 if (val == 0) return 0;
604 if (val > 0) return 1;
605 return -1;
606}
607
608
610 const Value &base)
611{
612 double logbase = converter->asFloat (base).asFloat();
613 if (logbase == 1.0)
614 return Value::errorDIV0();
615 if (logbase <= 0.0)
616 return Value::errorNA();
617
618 logbase = log10 (logbase);
619 Value res = Value (log10 (converter->asFloat (number).asFloat()) / logbase);
620
621 if (number.isNumber() || number.isEmpty())
622 res.setFormat (number.format());
623
624 return res;
625}
626
627Value ValueCalc::ln (const Value &number)
628{
629 Value res = Value (::log (converter->asFloat (number).asFloat()));
630
631 if (number.isNumber() || number.isEmpty())
632 res.setFormat (number.format());
633
634 return res;
635}
636
637Value ValueCalc::log (const Value &number, double base)
638{
639 if (base <= 0.0)
640 return Value::errorNA();
641 if (base == 1.0)
642 return Value::errorDIV0();
643
644 double num = converter->asFloat (number).asFloat();
645 Value res = Value (log10 (num) / log10 (base));
646
647 if (number.isNumber() || number.isEmpty())
648 res.setFormat (number.format());
649
650 return res;
651}
652
653Value ValueCalc::exp (const Value &number)
654{
655 return Value (::exp (converter->asFloat (number).asFloat()));
656}
657
659{
660 // retun PI in double-precision
661 // if arbitrary precision gets in, this should be extended to return
662 // more if need be
663 return Value (M_PI);
664}
665
666Value ValueCalc::eps ()
667{
668 // #### This should adjust according to the actual number system used
669 // (float, double, long double, ...)
670 return Value (DBL_EPSILON);
671}
672
674{
675 return Value (range * (double) rand() / (RAND_MAX + 1.0));
676}
677
679{
680 return random (converter->asFloat (range).asFloat());
681}
682
684{
685 // we can simply use integers - no one is going to compute factorial of
686 // anything bigger than 2^32
687 return fact (converter->asInteger (which).asInteger());
688}
689
690Value ValueCalc::fact (const Value &which,
691 const Value &end)
692{
693 // we can simply use integers - no one is going to compute factorial of
694 // anything bigger than 2^32
695 return fact (converter->asInteger (which).asInteger(),
696 converter->asInteger (end).asInteger ());
697}
698
699Value ValueCalc::fact (int which, int end) {
700 if (which < 0)
701 return Value (-1);
702 if (which == 0)
703 return Value (1);
704 // no multiplication if val==end
705 if (which == end)
706 return Value (1);
707
708 return (mul (fact (which-1, end), which));
709}
710
712{
713 if (which < 0)
714 return Value (-1);
715 if ((which == 0) || (which == 1))
716 return Value (1);
717
718 return (mul (factDouble (which-2), which));
719}
720
722{
723 return factDouble (converter->asInteger (which).asInteger());
724}
725
727{
728 if (n >= 15)
729 {
730 double result = ::exp(lgamma (n + 1) - lgamma (k + 1) - lgamma (n-k+1));
731 return Value (floor(result + 0.5));
732 }
733 else
734 return div (div (fact (n), fact (k)), fact (n - k));
735}
736
738{
739 int nn = converter->asInteger (n).asInteger();
740 int kk = converter->asInteger (k).asInteger();
741 return combin (nn, kk);
742}
743
744Value ValueCalc::gcd (const Value &a, const Value &b)
745{
746 // Euler's GCD algorithm
747 Value aa = round (a);
748 Value bb = round (b);
749
750 if (approxEqual (aa, bb)) return aa;
751
752 if (aa.isZero()) return bb;
753 if (bb.isZero()) return aa;
754
755
756 if (greater (aa, bb))
757 return gcd (bb, mod (aa, bb));
758 else
759 return gcd (aa, mod (bb, aa));
760}
761
762Value ValueCalc::lcm (const Value &a, const Value &b)
763{
764 Value aa = round (a);
765 Value bb = round (b);
766
767 if (approxEqual (aa, bb)) return aa;
768
769 if (aa.isZero()) return bb;
770 if (bb.isZero()) return aa;
771
772 Value g = gcd (aa, bb);
773 if (g.isZero()) // GCD is zero for some weird reason
774 return mul (aa, bb);
775
776 return div (mul (aa, bb), g);
777}
778
779Value ValueCalc::base (const Value &val, int base, int prec)
780{
781 if (base == 10) return round (val, prec);
782 if (prec < 0) prec = 2;
783 if ((base < 2) || (base > 36))
784 return Value::errorVALUE();
785
786 double value = converter->asFloat (val).asFloat();
787 TQString result = TQString::number ((int)value, base);
788
789 if (prec > 0)
790 {
791 result += "."; value = value - (int)value;
792
793 int ix;
794 for( int i = 0; i < prec; i++ )
795 {
796 ix = (int) value * base;
797 result += "0123456789abcdefghijklmnopqrstuvwxyz"[ix];
798 value = base * (value - (double)ix/base);
799 }
800 }
801
802 return Value (result.upper());
803}
804
805Value ValueCalc::fromBase (const Value &val, int base)
806{
807 TQString str = converter->asString (val).asString();
808 bool ok;
809 double num = str.toLong (&ok, base);
810 if (ok)
811 return Value (num);
812 return Value::errorVALUE();
813}
814
815
817{
818 Value res = Value (::sin (converter->asFloat (number).asFloat()));
819
820 if (number.isNumber() || number.isEmpty())
821 res.setFormat (number.format());
822
823 return res;
824}
825
826Value ValueCalc::cos (const Value &number)
827{
828 Value res = Value (::cos (converter->asFloat (number).asFloat()));
829
830 if (number.isNumber() || number.isEmpty())
831 res.setFormat (number.format());
832
833 return res;
834}
835
836Value ValueCalc::tg (const Value &number)
837{
838 Value res = Value (::tan (converter->asFloat (number).asFloat()));
839
840 if (number.isNumber() || number.isEmpty())
841 res.setFormat (number.format());
842
843 return res;
844}
845
846Value ValueCalc::cotg (const Value &number)
847{
848 Value res = Value (div (1, ::tan (converter->asFloat (number).asFloat())));
849
850 if (number.isNumber() || number.isEmpty())
851 res.setFormat (number.format());
852
853 return res;
854}
855
856Value ValueCalc::asin (const Value &number)
857{
858 errno = 0;
859 Value res = Value (::asin (converter->asFloat (number).asFloat()));
860 if (errno)
861 return Value::errorVALUE();
862
863 if (number.isNumber() || number.isEmpty())
864 res.setFormat (number.format());
865
866 return res;
867}
868
869Value ValueCalc::acos (const Value &number)
870{
871 errno = 0;
872 Value res = Value (::acos (converter->asFloat (number).asFloat()));
873 if (errno)
874 return Value::errorVALUE();
875
876 if (number.isNumber() || number.isEmpty())
877 res.setFormat (number.format());
878
879 return res;
880}
881
882Value ValueCalc::atg (const Value &number)
883{
884 errno = 0;
885 Value res = Value (::atan (converter->asFloat (number).asFloat()));
886 if (errno)
887 return Value::errorVALUE();
888
889 if (number.isNumber() || number.isEmpty())
890 res.setFormat (number.format());
891
892 return res;
893}
894
895Value ValueCalc::atan2 (const Value &y, const Value &x)
896{
897 double yy = converter->asFloat (y).asFloat();
898 double xx = converter->asFloat (x).asFloat();
899 return Value (::atan2 (yy, xx));
900}
901
903{
904 Value res = Value (::sinh (converter->asFloat (number).asFloat()));
905
906 if (number.isNumber() || number.isEmpty())
907 res.setFormat (number.format());
908
909 return res;
910}
911
912Value ValueCalc::cosh (const Value &number)
913{
914 Value res = Value (::cosh (converter->asFloat (number).asFloat()));
915
916 if (number.isNumber() || number.isEmpty())
917 res.setFormat (number.format());
918
919 return res;
920}
921
922Value ValueCalc::tgh (const Value &number)
923{
924 Value res = Value (::tanh (converter->asFloat (number).asFloat()));
925
926 if (number.isNumber() || number.isEmpty())
927 res.setFormat (number.format());
928
929 return res;
930}
931
932Value ValueCalc::asinh (const Value &number)
933{
934 errno = 0;
935 Value res = Value (::asinh (converter->asFloat (number).asFloat()));
936 if (errno)
937 return Value::errorVALUE();
938
939 if (number.isNumber() || number.isEmpty())
940 res.setFormat (number.format());
941
942 return res;
943}
944
945Value ValueCalc::acosh (const Value &number)
946{
947 errno = 0;
948 Value res = Value (::acosh (converter->asFloat (number).asFloat()));
949 if (errno)
950 return Value::errorVALUE();
951
952 if (number.isNumber() || number.isEmpty())
953 res.setFormat (number.format());
954
955 return res;
956}
957
958Value ValueCalc::atgh (const Value &number)
959{
960 errno = 0;
961 Value res = Value (::atanh (converter->asFloat (number).asFloat()));
962 if (errno)
963 return Value::errorVALUE();
964
965 if (number.isNumber() || number.isEmpty())
966 res.setFormat (number.format());
967
968 return res;
969}
970
972{
973 Value constant (0.39894228040143268);
974
975 // constant * exp(-(x * x) / 2.0);
976 Value x2neg = mul (sqr (x), -1);
977 return mul (constant, exp (div (x2neg, 2.0)));
978}
979
980static double taylor_helper (double* pPolynom, uint nMax, double x)
981{
982 double nVal = pPolynom[nMax];
983 for (int i = nMax-1; i >= 0; i--) {
984 nVal = pPolynom[i] + (nVal * x);
985 }
986 return nVal;
987}
988
989Value ValueCalc::gauss (Value xx)
990// this is a weird function
991{
992 double x = converter->asFloat (xx).asFloat();
993
994 double t0[] =
995 { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
996 -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
997 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
998 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
999 double t2[] =
1000 { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
1001 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
1002 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
1003 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
1004 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
1005 -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
1006 -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
1007 -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
1008 double t4[] =
1009 { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
1010 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
1011 -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
1012 -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
1013 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
1014 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
1015 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
1016 double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
1017
1018 double xAbs = fabs(x);
1019 uint xShort = static_cast<uint>(floor(xAbs));
1020 double nVal = 0.0;
1021 if (xShort == 0)
1022 nVal = taylor_helper(t0, 11, (xAbs * xAbs)) * xAbs;
1023 else if ((xShort >= 1) && (xShort <= 2))
1024 nVal = taylor_helper(t2, 23, (xAbs - 2.0));
1025 else if ((xShort >= 3) && (xShort <= 4))
1026 nVal = taylor_helper(t4, 20, (xAbs - 4.0));
1027 else
1028 {
1029 double phiAbs = converter->asFloat (phi (xAbs)).asFloat();
1030 nVal = 0.5 + phiAbs * taylor_helper(asympt, 4, 1.0 / (xAbs * xAbs)) / xAbs;
1031 }
1032
1033 if (x < 0.0)
1034 return Value (-nVal);
1035 else
1036 return Value (nVal);
1037}
1038
1039Value ValueCalc::gaussinv (Value xx)
1040// this is a weird function
1041{
1042 double x = converter->asFloat (xx).asFloat();
1043
1044 double q,t,z;
1045
1046 q=x-0.5;
1047
1048 if(fabs(q)<=.425)
1049 {
1050 t=0.180625-q*q;
1051
1052 z=
1053 q*
1054 (
1055 (
1056 (
1057 (
1058 (
1059 (
1060 (
1061 t*2509.0809287301226727+33430.575583588128105
1062 )
1063 *t+67265.770927008700853
1064 )
1065 *t+45921.953931549871457
1066 )
1067 *t+13731.693765509461125
1068 )
1069 *t+1971.5909503065514427
1070 )
1071 *t+133.14166789178437745
1072 )
1073 *t+3.387132872796366608
1074 )
1075 /
1076 (
1077 (
1078 (
1079 (
1080 (
1081 (
1082 (
1083 t*5226.495278852854561+28729.085735721942674
1084 )
1085 *t+39307.89580009271061
1086 )
1087 *t+21213.794301586595867
1088 )
1089 *t+5394.1960214247511077
1090 )
1091 *t+687.1870074920579083
1092 )
1093 *t+42.313330701600911252
1094 )
1095 *t+1.0
1096 );
1097
1098 }
1099 else
1100 {
1101 if(q>0) t=1-x;
1102 else t=x;
1103
1104 t=::sqrt(-::log(t));
1105
1106 if(t<=5.0)
1107 {
1108 t+=-1.6;
1109
1110 z=
1111 (
1112 (
1113 (
1114 (
1115 (
1116 (
1117 (
1118 t*7.7454501427834140764e-4+0.0227238449892691845833
1119 )
1120 *t+0.24178072517745061177
1121 )
1122 *t+1.27045825245236838258
1123 )
1124 *t+3.64784832476320460504
1125 )
1126 *t+5.7694972214606914055
1127 )
1128 *t+4.6303378461565452959
1129 )
1130 *t+1.42343711074968357734
1131 )
1132 /
1133 (
1134 (
1135 (
1136 (
1137 (
1138 (
1139 (
1140 t*1.05075007164441684324e-9+5.475938084995344946e-4
1141 )
1142 *t+0.0151986665636164571966
1143 )
1144 *t+0.14810397642748007459
1145 )
1146 *t+0.68976733498510000455
1147 )
1148 *t+1.6763848301838038494
1149 )
1150 *t+2.05319162663775882187
1151 )
1152 *t+1.0
1153 );
1154
1155 }
1156 else
1157 {
1158 t+=-5.0;
1159
1160 z=
1161 (
1162 (
1163 (
1164 (
1165 (
1166 (
1167 (
1168 t*2.01033439929228813265e-7+2.71155556874348757815e-5
1169 )
1170 *t+0.0012426609473880784386
1171 )
1172 *t+0.026532189526576123093
1173 )
1174 *t+0.29656057182850489123
1175 )
1176 *t+1.7848265399172913358
1177 )
1178 *t+5.4637849111641143699
1179 )
1180 *t+6.6579046435011037772
1181 )
1182 /
1183 (
1184 (
1185 (
1186 (
1187 (
1188 (
1189 (
1190 t*2.04426310338993978564e-15+1.4215117583164458887e-7
1191 )
1192 *t+1.8463183175100546818e-5
1193 )
1194 *t+7.868691311456132591e-4
1195 )
1196 *t+0.0148753612908506148525
1197 )
1198 *t+0.13692988092273580531
1199 )
1200 *t+0.59983220655588793769
1201 )
1202 *t+1.0
1203 );
1204
1205 }
1206
1207 if(q<0.0) z=-z;
1208 }
1209
1210 return Value (z);
1211}
1212
1213//helper for GetGamma and GetLogGamma
1214static double GammaHelp(double& x, bool& bReflect)
1215{
1216 double c[6] = {76.18009173, -86.50532033, 24.01409822,
1217 -1.231739516, 0.120858003E-2, -0.536382E-5};
1218 if (x >= 1.0)
1219 {
1220 bReflect = false;
1221 x -= 1.0;
1222 }
1223 else
1224 {
1225 bReflect = true;
1226 x = 1.0 - x;
1227 }
1228 double s, anum;
1229 s = 1.0;
1230 anum = x;
1231 for (uint i = 0; i < 6; i++)
1232 {
1233 anum += 1.0;
1234 s += c[i]/anum;
1235 }
1236 s *= 2.506628275; // sqrt(2*PI)
1237 return s;
1238}
1239
1240Value ValueCalc::GetGamma (Value _x)
1241{
1242 double x = converter->asFloat (_x).asFloat();
1243
1244 bool bReflect;
1245 double G = GammaHelp(x, bReflect);
1246 G = ::pow(x+5.5,x+0.5)*G/::exp(x+5.5);
1247 if (bReflect)
1248 G = M_PI*x/(G*::sin(M_PI*x));
1249 return Value (G);
1250}
1251
1252Value ValueCalc::GetLogGamma (Value _x)
1253{
1254 double x = converter->asFloat (_x).asFloat();
1255
1256 bool bReflect;
1257 double G = GammaHelp(x, bReflect);
1258 G = (x+0.5)*::log(x+5.5)+::log(G)-(x+5.5);
1259 if (bReflect)
1260 G = ::log(M_PI*x)-G-::log(::sin(M_PI*x));
1261 return Value (G);
1262}
1263
1264Value ValueCalc::GetGammaDist (Value _x, Value _alpha,
1265 Value _beta)
1266{
1267 double x = converter->asFloat (_x).asFloat();
1268 double alpha = converter->asFloat (_alpha).asFloat();
1269 double beta = converter->asFloat (_beta).asFloat();
1270
1271 if (x == 0.0)
1272 return Value (0.0);
1273
1274 x /= beta;
1275 double gamma = alpha;
1276
1277 double c = 0.918938533204672741;
1278 double d[10] = {
1279 0.833333333333333333E-1,
1280 -0.277777777777777778E-2,
1281 0.793650793650793651E-3,
1282 -0.595238095238095238E-3,
1283 0.841750841750841751E-3,
1284 -0.191752691752691753E-2,
1285 0.641025641025641025E-2,
1286 -0.295506535947712418E-1,
1287 0.179644372368830573,
1288 -0.139243221690590111E1
1289 };
1290
1291 double dx = x;
1292 double dgamma = gamma;
1293 int maxit = 10000;
1294
1295 double z = dgamma;
1296 double den = 1.0;
1297 while ( z < 10.0 ) {
1298 den *= z;
1299 z += 1.0;
1300 }
1301
1302 double z2 = z*z;
1303 double z3 = z*z2;
1304 double z4 = z2*z2;
1305 double z5 = z2*z3;
1306 double a = ( z - 0.5 ) * ::log(z) - z + c;
1307 double b = d[0]/z + d[1]/z3 + d[2]/z5 + d[3]/(z2*z5) + d[4]/(z4*z5) +
1308 d[5]/(z*z5*z5) + d[6]/(z3*z5*z5) + d[7]/(z5*z5*z5) + d[8]/(z2*z5*z5*z5);
1309 // double g = exp(a+b) / den;
1310
1311 double sum = 1.0 / dgamma;
1312 double term = 1.0 / dgamma;
1313 double cut1 = dx - dgamma;
1314 double cut2 = dx * 10000000000.0;
1315
1316 for ( int i=1; i<=maxit; i++ ) {
1317 double ai = i;
1318 term = dx * term / ( dgamma + ai );
1319 sum += term;
1320 double cutoff = cut1 + ( cut2 * term / sum );
1321 if ( ai > cutoff ) {
1322 double t = sum;
1323 // return pow( dx, dgamma ) * exp( -dx ) * t / g;
1324 return Value (::exp( dgamma * ::log(dx) - dx - a - b ) * t * den);
1325 }
1326 }
1327
1328 return Value (1.0); // should not happen ...
1329}
1330
1331Value ValueCalc::GetBeta (Value _x, Value _alpha,
1332 Value _beta)
1333{
1334 if (equal (_beta, 1.0))
1335 return pow (_x, _alpha);
1336 else if (equal (_alpha, 1.0))
1337 // 1.0 - pow (1.0-_x, _beta)
1338 return sub (1.0, pow (sub (1.0, _x), _beta));
1339
1340 double x = converter->asFloat (_x).asFloat();
1341 double alpha = converter->asFloat (_alpha).asFloat();
1342 double beta = converter->asFloat (_beta).asFloat();
1343
1344 double fEps = 1.0E-8;
1345 bool bReflect;
1346 double cf, fA, fB;
1347
1348 if (x < (alpha+1.0)/(alpha+beta+1.0)) {
1349 bReflect = false;
1350 fA = alpha;
1351 fB = beta;
1352 }
1353 else {
1354 bReflect = true;
1355 fA = beta;
1356 fB = alpha;
1357 x = 1.0 - x;
1358 }
1359 if (x < fEps)
1360 cf = 0.0;
1361 else {
1362 double a1, b1, a2, b2, fnorm, rm, apl2m, d2m, d2m1, cfnew;
1363 a1 = 1.0; b1 = 1.0;
1364 b2 = 1.0 - (fA+fB)*x/(fA+1.0);
1365 if (b2 == 0.0) {
1366 a2 = b2;
1367 fnorm = 1.0;
1368 cf = 1.0;
1369 }
1370 else {
1371 a2 = 1.0;
1372 fnorm = 1.0/b2;
1373 cf = a2*fnorm;
1374 }
1375 cfnew = 1.0;
1376 for (uint j = 1; j <= 100; j++) {
1377 rm = (double) j;
1378 apl2m = fA + 2.0*rm;
1379 d2m = rm*(fB-rm)*x/((apl2m-1.0)*apl2m);
1380 d2m1 = -(fA+rm)*(fA+fB+rm)*x/(apl2m*(apl2m+1.0));
1381 a1 = (a2+d2m*a1)*fnorm;
1382 b1 = (b2+d2m*b1)*fnorm;
1383 a2 = a1 + d2m1*a2*fnorm;
1384 b2 = b1 + d2m1*b2*fnorm;
1385 if (b2 != 0.0) {
1386 fnorm = 1.0/b2;
1387 cfnew = a2*fnorm;
1388 if (fabs(cf-cfnew)/cf < fEps)
1389 j = 101;
1390 else
1391 cf = cfnew;
1392 }
1393 }
1394 if (fB < fEps)
1395 b1 = 1.0E30;
1396 else
1397 b1 = ::exp(GetLogGamma(fA).asFloat()+GetLogGamma(fB).asFloat()-
1398 GetLogGamma(fA+fB).asFloat());
1399
1400 cf *= ::pow(x, fA)*::pow(1.0-x,fB)/(fA*b1);
1401 }
1402 if (bReflect)
1403 return Value (1.0-cf);
1404 else
1405 return Value (cf);
1406}
1407
1408// ------------------------------------------------------
1409
1410
1411/*
1412 *
1413 * The code for calculating Bessel functions is taken
1414 * from CCMATH, a mathematics library source.code.
1415 *
1416 * Original copyright follows:
1417 *
1418 * Copyright (C) 2000 Daniel A. Atkinson All rights reserved.
1419 * This code may be redistributed under the terms of the GNU library
1420 * public license (LGPL).
1421 */
1422
1423static double ccmath_gaml(double x)
1424{ double g,h;
1425 for(g=1.; x<30. ;g*=x,x+=1.); h=x*x;
1426 g=(x-.5)*log(x)-x+.918938533204672-log(g);
1427 g+=(1.-(1./6.-(1./3.-1./(4.*h))/(7.*h))/(5.*h))/(12.*x);
1428 return g;
1429}
1430
1431static double ccmath_psi(int m)
1432{ double s= -.577215664901533; int k;
1433 for(k=1; k<m ;++k) s+=1./k;
1434 return s;
1435}
1436
1437static double ccmath_ibes(double v,double x)
1438{ double y,s,t,tp; int p,m;
1439 y=x-9.; if(y>0.) y*=y; tp=v*v*.2+25.;
1440 if(y<tp){ x/=2.; m=(int)x;
1441 if(x>0.) s=t=exp(v*log(x)-ccmath_gaml(v+1.));
1442 else{ if(v>0.) return 0.; else if(v==0.) return 1.;}
1443 for(p=1,x*=x;;++p){ t*=x/(p*(v+=1.)); s+=t;
1444 if(p>m && t<1.e-13*s) break;
1445 }
1446 }
1447 else{ double u,a0=1.57079632679490;
1448 s=t=1./sqrt(x*a0); x*=2.; u=0.;
1449 for(p=1,y=.5; (tp=fabs(t))>1.e-14 ;++p,y+=1.){
1450 t*=(v+y)*(v-y)/(p*x); if(y>v && fabs(t)>=tp) break;
1451 if(!(p&1)) s+=t; else u-=t;
1452 }
1453 x/=2.; s=cosh(x)*s+sinh(x)*u;
1454 }
1455 return s;
1456}
1457
1458static double ccmath_kbes(double v,double x)
1459{ double y,s,t,tp,f,a0=1.57079632679490;
1460 int p,k,m;
1461 if(x==0.) return HUGE_VAL;
1462 y=x-10.5; if(y>0.) y*=y; tp=25.+.185*v*v;
1463 if(y<tp && modf(v+.5,&t)!=0.){ y=1.5+.5*v;
1464 if(x<y){ x/=2.; m=(int)x; tp=t=exp(v*log(x)-ccmath_gaml(v+1.));
1465 if(modf(v,&y)==0.){ k=(int)y; tp*=v;
1466 f=2.*log(x)-ccmath_psi(1)-ccmath_psi(k+1);
1467 t/=2.; if(!(k&1)) t= -t; s=f*t;
1468 for(p=1,x*=x;;++p){ f-=1./p+1./(v+=1.);
1469 t*=x/(p*v); s+=(y=t*f);
1470 if(p>m && fabs(y)<1.e-14) break; }
1471 if(k>0){ x= -x; s+=(t=1./(tp*2.));
1472 for(p=1,--k; k>0 ;++p,--k) s+=(t*=x/(p*k)); }
1473 }
1474 else{ f=1./(t*v*2.); t*=a0/sin(2.*a0*v); s=f-t;
1475 for(p=1,x*=x,tp=v;;++p){
1476 t*=x/(p*(v+=1.)); f*= -x/(p*(tp-=1.));
1477 s+=(y=f-t); if(p>m && fabs(y)<1.e-14) break; }
1478 }
1479 }
1480 else{ double tq,h,w,z,r;
1481 t=12./pow(x,.333); k=(int)(t*t); y=2.*(x+k);
1482 m=(int)v; v-=m; tp=v*v-.25; v+=1.; tq=v*v-.25;
1483 for(s=h=1.,r=f=z=w=0.; k>0 ;--k,y-=2.){
1484 t=(y*h-(k+1)*z)/(k-1-tp/k); z=h; f+=(h=t);
1485 t=(y*s-(k+1)*w)/(k-1-tq/k); w=s; r+=(s=t); }
1486 t=sqrt(a0/x)*exp(-x); s*=t/r; h*=t/f; x/=2.; if(m==0) s=h;
1487 for(k=1; k<m ;++k){ t=v*s/x+h; h=s; s=t; v+=1.;}
1488 }
1489 }
1490 else{ s=t=sqrt(a0/x); x*=2.;
1491 for(p=1,y=.5; (tp=fabs(t))>1.e-14 ;++p,y+=1.){
1492 t*=(v+y)*(v-y)/(p*x); if(y>v && fabs(t)>=tp) break; s+=t; }
1493 s*=exp(-x/2.);
1494 }
1495 return s;
1496}
1497
1498static double ccmath_jbes(double v,double x)
1499{ double y,s,t,tp; int p,m;
1500 y=x-8.5; if(y>0.) y*=y; tp=v*v/4.+13.69;
1501 if(y<tp){ x/=2.; m=(int)x;
1502 if(x>0.) s=t=exp(v*log(x)-ccmath_gaml(v+1.));
1503 else{ if(v>0.) return 0.; else if(v==0.) return 1.;}
1504 for(p=1,x*= -x;;++p){ t*=x/(p*(v+=1.)); s+=t;
1505 if(p>m && fabs(t)<1.e-13) break;
1506 }
1507 }
1508 else{ double u,a0=1.57079632679490;
1509 s=t=1./sqrt(x*a0); x*=2.; u=0.;
1510 for(p=1,y=.5; (tp=fabs(t))>1.e-14 ;++p,y+=1.){
1511 t*=(v+y)*(v-y)/(p*x); if(y>v && fabs(t)>=tp) break;
1512 if(!(p&1)){ t= -t; s+=t;} else u-=t;
1513 }
1514 y=x/2.-(v+.5)*a0; s=cos(y)*s+sin(y)*u;
1515 }
1516 return s;
1517}
1518
1519static double ccmath_nbes(double v,double x)
1520{ double y,s,t,tp,u,f,a0=3.14159265358979;
1521 int p,k,m;
1522 y=x-8.5; if(y>0.) y*=y; tp=v*v/4.+13.69;
1523 if(y<tp){ if(x==0.) return HUGE_VAL;
1524 x/=2.; m=(int)x; u=t=exp(v*log(x)-ccmath_gaml(v+1.));
1525 if(modf(v,&y)==0.){ k=(int)y; u*=v;
1526 f=2.*log(x)-ccmath_psi(1)-ccmath_psi(k+1);
1527 t/=a0; x*= -x; s=f*t;
1528 for(p=1;;++p){ f-=1./p+1./(v+=1.);
1529 t*=x/(p*v); s+=(y=t*f); if(p>m && fabs(y)<1.e-13) break; }
1530 if(k>0){ x= -x; s-=(t=1./(u*a0));
1531 for(p=1,--k; k>0 ;++p,--k) s-=(t*=x/(p*k)); }
1532 }
1533 else{ f=1./(t*v*a0); t/=tan(a0*v); s=t-f;
1534 for(p=1,x*=x,u=v;;++p){
1535 t*= -x/(p*(v+=1.)); f*=x/(p*(u-=1.));
1536 s+=(y=t-f); if(p>m && fabs(y)<1.e-13) break; }
1537 }
1538 }
1539 else{ x*=2.; s=t=2./sqrt(x*a0); u=0.;
1540 for(p=1,y=.5; (tp=fabs(t))>1.e-14 ;++p,y+=1.){
1541 t*=(v+y)*(v-y)/(p*x); if(y>v && fabs(t)>tp) break;
1542 if(!(p&1)){ t= -t; s+=t;} else u+=t;
1543 }
1544 y=(x-(v+.5)*a0)/2.; s=sin(y)*s+cos(y)*u;
1545 }
1546 return s;
1547}
1548
1549
1550/* ---------- end of CCMATH code ---------- */
1551
1552
1554{
1555 double vv = converter->asFloat (v).asFloat ();
1556 double xx = converter->asFloat (x).asFloat ();
1557 return Value (ccmath_ibes (vv, xx));
1558}
1559
1560Value ValueCalc::besselj (Value v, Value x)
1561{
1562 double vv = converter->asFloat (v).asFloat ();
1563 double xx = converter->asFloat (x).asFloat ();
1564 return Value (ccmath_jbes (vv, xx));
1565}
1566
1567Value ValueCalc::besselk (Value v, Value x)
1568{
1569 double vv = converter->asFloat (v).asFloat ();
1570 double xx = converter->asFloat (x).asFloat ();
1571 return Value (ccmath_kbes (vv, xx));
1572}
1573
1574Value ValueCalc::besseln (Value v, Value x)
1575{
1576 double vv = converter->asFloat (v).asFloat ();
1577 double xx = converter->asFloat (x).asFloat ();
1578 return Value (ccmath_nbes (vv, xx));
1579}
1580
1581// ------------------------------------------------------
1582
1584{
1585 return Value (::erf (converter->asFloat (x).asFloat()));
1586}
1587
1588Value ValueCalc::erfc (Value x)
1589{
1590 return Value (::erfc (converter->asFloat (x).asFloat()));
1591}
1592
1593// ------------------------------------------------------
1594
1595void ValueCalc::arrayWalk (const Value &range,
1596 Value &res, arrayWalkFunc func, Value param)
1597{
1598 if (res.isError()) return;
1599 if (!range.isArray ())
1600 {
1601 func (this, res, range, param);
1602 return;
1603 }
1604
1605 int rows = range.rows ();
1606 int cols = range.columns ();
1607 for (int r = 0; r < rows; r++)
1608 for (int c = 0; c < cols; c++)
1609 {
1610 Value v = range.element (c, r);
1611 if (v.isArray())
1612 arrayWalk (v, res, func, param);
1613 else {
1614 func (this, res, v, param);
1615 if (res.format() == Value::fmt_None)
1616 res.setFormat (v.format());
1617 }
1618 }
1619}
1620
1621void ValueCalc::arrayWalk (TQValueVector<Value> &range,
1622 Value &res, arrayWalkFunc func, Value param)
1623{
1624 if (res.isError()) return;
1625 for (unsigned int i = 0; i < range.count(); ++i)
1626 arrayWalk (range[i], res, func, param);
1627}
1628
1629void ValueCalc::twoArrayWalk (const Value &a1, const Value &a2,
1630 Value &res, arrayWalkFunc func)
1631{
1632 if (res.isError()) return;
1633 if (!a1.isArray ())
1634 {
1635 func (this, res, a1, a2);
1636 return;
1637 }
1638
1639 int rows = a1.rows ();
1640 int cols = a1.columns ();
1641 int rows2 = a2.rows ();
1642 int cols2 = a2.columns ();
1643 if ((rows != rows2) || (cols != cols2)) {
1644 res = Value::errorVALUE();
1645 return;
1646 }
1647 for (int r = 0; r < rows; r++)
1648 for (int c = 0; c < cols; c++)
1649 {
1650 Value v1 = a1.element (c, r);
1651 Value v2 = a2.element (c, r);
1652 if (v1.isArray() && v2.isArray())
1653 twoArrayWalk (v1, v2, res, func);
1654 else {
1655 func (this, res, v1, v2);
1656 if (res.format() == Value::fmt_None)
1657 res.setFormat (format (v1.format(), v2.format()));
1658 }
1659 }
1660}
1661
1662void ValueCalc::twoArrayWalk (TQValueVector<Value> &a1,
1663 TQValueVector<Value> &a2, Value &res, arrayWalkFunc func)
1664{
1665 if (res.isError()) return;
1666 if (a1.count() != a2.count()) {
1667 res = Value::errorVALUE();
1668 return;
1669 }
1670 for (unsigned int i = 0; i < a1.count(); ++i)
1671 twoArrayWalk (a1[i], a2[i], res, func);
1672}
1673
1674arrayWalkFunc ValueCalc::awFunc (const TQString &name)
1675{
1676 if (awFuncs.count(name))
1677 return awFuncs[name];
1678 return 0;
1679}
1680
1681void ValueCalc::registerAwFunc (const TQString &name, arrayWalkFunc func)
1682{
1683 awFuncs[name] = func;
1684}
1685
1686// ------------------------------------------------------
1687
1688Value ValueCalc::sum (const Value &range, bool full)
1689{
1690 Value res;
1691 arrayWalk (range, res, awFunc (full ? "suma" : "sum"), 0);
1692 return res;
1693}
1694
1695Value ValueCalc::sum (TQValueVector<Value> range, bool full)
1696{
1697 Value res;
1698 arrayWalk (range, res, awFunc (full ? "suma" : "sum"), 0);
1699 return res;
1700}
1701
1702// sum of squares
1703Value ValueCalc::sumsq (const Value &range, bool full)
1704{
1705 Value res;
1706 arrayWalk (range, res, awFunc (full ? "sumsqa" : "sumsq"), 0);
1707 return res;
1708}
1709
1710Value ValueCalc::sumIf (const Value &range,
1711 const Value &checkRange, const Condition &cond)
1712{
1713 if (!range.isArray())
1714 {
1715 if (matches (cond, checkRange.element (0, 0)))
1716 return converter->asNumeric (range);
1717 return Value (0.0);
1718 }
1719
1720 //if we are here, we have an array
1721 Value res;
1722
1723 unsigned int rows = range.rows ();
1724 unsigned int cols = range.columns ();
1725 for (unsigned int r = 0; r < rows; r++)
1726 for (unsigned int c = 0; c < cols; c++)
1727 {
1728 Value v = range.element (c, r);
1729 Value newcheck = v;
1730 if ((c < checkRange.columns()) && (r < checkRange.rows()))
1731 newcheck = checkRange.element (c, r);
1732
1733 if (v.isArray())
1734 res = add (res, sumIf (v, newcheck, cond));
1735 else
1736 if (matches (cond, newcheck))
1737 res = add (res, v);
1738 }
1739
1740 return res;
1741}
1742
1743int ValueCalc::count (const Value &range, bool full)
1744{
1745 Value res = 0;
1746 arrayWalk (range, res, awFunc (full ? "counta" : "count"), 0);
1747 return converter->asInteger (res).asInteger ();
1748}
1749
1750int ValueCalc::count (TQValueVector<Value> range, bool full)
1751{
1752 Value res = 0;
1753 arrayWalk (range, res, awFunc (full ? "counta" : "count"), 0);
1754 return converter->asInteger (res).asInteger ();
1755}
1756
1757int ValueCalc::countIf (const Value &range, const Condition &cond)
1758{
1759 if (!range.isArray())
1760 {
1761 if (matches (cond, range))
1762 return range.isEmpty() ? 0 : 1;
1763 return 0;
1764 }
1765
1766 int res = 0;
1767
1768 int cols = range.columns ();
1769 int rows = range.rows ();
1770 for (int r = 0; r < rows; r++)
1771 for (int c = 0; c < cols; c++)
1772 {
1773 Value v = range.element (c, r);
1774
1775 if (v.isArray())
1776 res += countIf (v, cond);
1777 else
1778 if (matches (cond, v))
1779 res++;
1780 }
1781
1782 return res;
1783}
1784
1785Value ValueCalc::avg (const Value &range, bool full)
1786{
1787 int cnt = count (range, full);
1788 if (cnt)
1789 return div (sum (range, full), cnt);
1790 return Value (0.0);
1791}
1792
1793Value ValueCalc::avg (TQValueVector<Value> range, bool full)
1794{
1795 int cnt = count (range, full);
1796 if (cnt)
1797 return div (sum (range, full), cnt);
1798 return Value (0.0);
1799}
1800
1801Value ValueCalc::max (const Value &range, bool full)
1802{
1803 Value res;
1804 arrayWalk (range, res, awFunc (full ? "maxa" : "max"), 0);
1805 return res;
1806}
1807
1808Value ValueCalc::max (TQValueVector<Value> range, bool full)
1809{
1810 Value res;
1811 arrayWalk (range, res, awFunc (full ? "maxa" : "max"), 0);
1812 return res;
1813}
1814
1815Value ValueCalc::min (const Value &range, bool full)
1816{
1817 Value res;
1818 arrayWalk (range, res, awFunc (full ? "mina" : "min"), 0);
1819 return res;
1820}
1821
1822Value ValueCalc::min (TQValueVector<Value> range, bool full)
1823{
1824 Value res;
1825 arrayWalk (range, res, awFunc (full ? "mina" : "min"), 0);
1826 return res;
1827}
1828
1829Value ValueCalc::product (const Value &range, Value init,
1830 bool full)
1831{
1832 Value res = init;
1833 if (isZero (init)) // special handling of a zero, due to excel-compat
1834 {
1835 if (count (range, full) == 0)
1836 return init;
1837 res = 1.0;
1838 }
1839 arrayWalk (range, res, awFunc (full ? "proda" : "prod"), 0);
1840 return res;
1841}
1842
1843Value ValueCalc::product (TQValueVector<Value> range,
1844 Value init, bool full)
1845{
1846 Value res = init;
1847 if (isZero (init)) // special handling of a zero, due to excel-compat
1848 {
1849 if (count (range, full) == 0)
1850 return init;
1851 res = 1.0;
1852 }
1853 arrayWalk (range, res, awFunc (full ? "proda" : "prod"), 0);
1854 return res;
1855}
1856
1857Value ValueCalc::stddev (const Value &range, bool full)
1858{
1859 return stddev (range, avg (range, full), full);
1860}
1861
1862Value ValueCalc::stddev (const Value &range, Value avg,
1863 bool full)
1864{
1865 Value res;
1866 int cnt = count (range, full);
1867 arrayWalk (range, res, awFunc (full ? "devsqa" : "devsq"), avg);
1868 return sqrt (div (res, cnt-1));
1869}
1870
1871Value ValueCalc::stddev (TQValueVector<Value> range, bool full)
1872{
1873 return stddev (range, avg (range, full), full);
1874}
1875
1876Value ValueCalc::stddev (TQValueVector<Value> range,
1877 Value avg, bool full)
1878{
1879 Value res;
1880 int cnt = count (range, full);
1881 arrayWalk (range, res, awFunc (full ? "devsqa" : "devsq"), avg);
1882 return sqrt (div (res, cnt-1));
1883}
1884
1885Value ValueCalc::stddevP (const Value &range, bool full)
1886{
1887 return stddevP (range, avg (range, full), full);
1888}
1889
1890Value ValueCalc::stddevP (const Value &range, Value avg,
1891 bool full)
1892{
1893 Value res;
1894 int cnt = count (range, full);
1895 arrayWalk (range, res, awFunc (full ? "devsqa" : "devsq"), avg);
1896 return sqrt (div (res, cnt));
1897}
1898
1899Value ValueCalc::stddevP (TQValueVector<Value> range, bool full)
1900{
1901 return stddevP (range, avg (range, full), full);
1902}
1903
1904Value ValueCalc::stddevP (TQValueVector<Value> range,
1905 Value avg, bool full)
1906{
1907 Value res;
1908 int cnt = count (range, full);
1909 arrayWalk (range, res, awFunc (full ? "devsqa" : "devsq"), avg);
1910 return sqrt (div (res, cnt));
1911}
1912
1913Value::Format ValueCalc::format (Value::Format a,
1914 Value::Format b)
1915{
1916 if ((a == Value::fmt_None) || (a == Value::fmt_Boolean))
1917 return b;
1918 return a;
1919}
1920
1921
1922// ------------------------------------------------------
1923
1924void ValueCalc::getCond (Condition &cond, Value val)
1925{
1926 // not a string - we simply take it as a numeric value
1927 // that also handles floats, logical values, date/time and such
1928 if (!val.isString()) {
1929 cond.comp = isEqual;
1930 cond.type = numeric;
1931 cond.value = converter->asFloat (val).asFloat();
1932 return;
1933 }
1934 TQString text = converter->asString (val).asString();
1935 cond.comp = isEqual;
1936 text = text.stripWhiteSpace();
1937
1938 if ( text.startsWith( "<=" ) )
1939 {
1940 cond.comp = lessEqual;
1941 text = text.remove( 0, 2 );
1942 }
1943 else if ( text.startsWith( ">=" ) )
1944 {
1945 cond.comp = greaterEqual;
1946 text = text.remove( 0, 2 );
1947 }
1948 else if ( text.startsWith( "!=" ) || text.startsWith( "<>" ) )
1949 {
1950 cond.comp = notEqual;
1951 text = text.remove( 0, 2 );
1952 }
1953 else if ( text.startsWith( "==" ) )
1954 {
1955 cond.comp = isEqual;
1956 text = text.remove( 0, 2 );
1957 }
1958 else if ( text.startsWith( "<" ) )
1959 {
1960 cond.comp = isLess;
1961 text = text.remove( 0, 1 );
1962 }
1963 else if ( text.startsWith( ">" ) )
1964 {
1965 cond.comp = isGreater;
1966 text = text.remove( 0, 1 );
1967 }
1968 else if ( text.startsWith( "=" ) )
1969 {
1970 cond.comp = isEqual;
1971 text = text.remove( 0, 1 );
1972 }
1973
1974 text = text.stripWhiteSpace();
1975
1976 bool ok = false;
1977 double d = text.toDouble( &ok );
1978 if ( ok )
1979 {
1980 cond.type = numeric;
1981 cond.value = d;
1982 }
1983 else
1984 {
1985 cond.type = string;
1986 cond.stringValue = text;
1987 }
1988}
1989
1990bool ValueCalc::matches (const Condition &cond, Value val)
1991{
1992 if (val.isEmpty())
1993 return false;
1994 if (cond.type == numeric) {
1995 double d = converter->asFloat (val).asFloat();
1996 switch ( cond.comp )
1997 {
1998 case isEqual:
1999 if (approxEqual (d, cond.value)) return true;
2000 break;
2001
2002 case isLess:
2003 if (d < cond.value) return true;
2004 break;
2005
2006 case isGreater:
2007 if (d > cond.value) return true;
2008 break;
2009
2010 case lessEqual:
2011 if (d <= cond.value) return true;
2012 break;
2013
2014 case greaterEqual:
2015 if (d >= cond.value) return true;
2016 break;
2017
2018 case notEqual:
2019 if (d != cond.value) return true;
2020 break;
2021 }
2022 } else {
2023 TQString d = converter->asString (val).asString();
2024 switch ( cond.comp )
2025 {
2026 case isEqual:
2027 if (d == cond.stringValue) return true;
2028 break;
2029
2030 case isLess:
2031 if (d < cond.stringValue) return true;
2032 break;
2033
2034 case isGreater:
2035 if (d > cond.stringValue) return true;
2036 break;
2037
2038 case lessEqual:
2039 if (d <= cond.stringValue) return true;
2040 break;
2041
2042 case greaterEqual:
2043 if (d >= cond.stringValue) return true;
2044 break;
2045
2046 case notEqual:
2047 if (d != cond.stringValue) return true;
2048 break;
2049 }
2050 }
2051 return false;
2052}
2053
The ValueCalc class is used to perform all sorts of calculations.
Definition valuecalc.h:69
Value gcd(const Value &a, const Value &b)
greatest common divisor
Value random(double range=1.0)
random number from <0.0, range)
bool strLower(const Value &a, const Value &b, bool CS=true)
string comparison
Value sum(const Value &range, bool full=true)
basic range functions
bool gequal(const Value &a, const Value &b)
numerical comparison - greater or equal
bool strGreater(const Value &a, const Value &b, bool CS=true)
string comparison
bool naturalGequal(const Value &a, const Value &b, bool CS=true)
string or numerical comparison - greater or equal
std::map< TQString, arrayWalkFunc > awFuncs
registered array-walk functions
Definition valuecalc.h:281
bool approxEqual(const Value &a, const Value &b)
numerical comparison with a little epsilon tolerance
Value phi(Value x)
some statistical stuff TODO: we may want to move these over to a separate class or something,...
Value pi()
constants
Value factDouble(int which)
double factorial (every other number multiplied)
bool matches(const Condition &cond, Value d)
Returns true if value d matches the condition cond, built with getCond().
bool greater(const Value &a, const Value &b)
numerical comparison
Value besseli(Value v, Value x)
bessel functions - may also end up being separated from here
bool isZero(const Value &a)
comparison and related
Value roundDown(const Value &a, const Value &digits)
rounding
Value erf(Value x)
error functions (see: man erf)
Value fact(const Value &which)
some computational functions
Value sin(const Value &number)
goniometric functions
Value combin(int n, int k)
combinations
bool equal(const Value &a, const Value &b)
numerical comparison
void arrayWalk(const Value &range, Value &res, arrayWalkFunc func, Value param)
array/range walking
Value::Format format(Value::Format a, Value::Format b)
return result formatting, based on these two values
Value log(const Value &number, const Value &base)
logarithms and exponentials
void getCond(Condition &cond, Value val)
This method parses the condition in string text to the condition cond.
bool naturalLower(const Value &a, const Value &b, bool CS=true)
string or numerical comparison
Value fromBase(const Value &val, int base=16)
base conversion base -> 10
bool strEqual(const Value &a, const Value &b, bool CS=true)
string comparison
Value lcm(const Value &a, const Value &b)
lowest common multiplicator
bool naturalEqual(const Value &a, const Value &b, bool CS=true)
string or numerical comparison
bool lower(const Value &a, const Value &b)
numerical comparison
bool naturalGreater(const Value &a, const Value &b, bool CS=true)
string or numerical comparison
bool strGequal(const Value &a, const Value &b, bool CS=true)
string comparison - greater or equal
Value add(const Value &a, const Value &b)
basic arithmetic operations
Value sinh(const Value &number)
hyperbolic functions
Value base(const Value &val, int base=16, int prec=0)
base conversion 10 -> base
The ValueConverter class can convert Value between various different formats.
Value asNumeric(const Value &value) const
convert to a numeric value - not necessarily float
Provides a wrapper for cell value.
unsigned columns() const
If this value is an array, return the number of columns.
Value element(unsigned column, unsigned row) const
Return an element in the array value.
static const Value & errorDIV0()
Returns constant reference to #DIV/0! error.
void setFormat(Format fmt)
Sets format information for this value.
bool greater(const Value &v) const
Returns true if this value is greater than v.
Format format() const
Returns the format of the value (i.e.
unsigned rows() const
If this value is an array, return the number of rows.
bool isBoolean() const
Returns true if the type of this value is Boolean.
bool isEmpty() const
Returns true if empty.
bool isNumber() const
Returns true if the type of this value is either integer or floating-point.
bool equal(const Value &v) const
Returns true if this value is equal to v.
bool isArray() const
Returns true if the type of this value is array.
bool allowComparison(const Value &v) const
Returns true if it is OK to compare this value with v.
double asFloat() const
Returns the floating-point value of this value.
long asInteger() const
Returns the integer value of this value.
TQString asString() const
Returns the string value of this value.
static const Value & errorVALUE()
Returns constant reference to #VALUE! error.
bool isError() const
Returns true if this value holds error information.
bool isString() const
Returns true if the type of this value is string.
bool isInteger() const
Returns true if the type of this value is integer.
static const Value & errorNA()
Returns constant reference to #N/A error.
The KSpread namespace.
Definition commands.h:39