Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/solar.h>
21 : #include <stdlib.h>
22 : #include <string.h>
23 :
24 : #include "interpre.hxx"
25 : #include "global.hxx"
26 : #include "compiler.hxx"
27 : #include "formulacell.hxx"
28 : #include "document.hxx"
29 : #include "dociter.hxx"
30 : #include "scmatrix.hxx"
31 : #include "globstr.hrc"
32 :
33 : #include <math.h>
34 : #include <vector>
35 : #include <algorithm>
36 :
37 : using ::std::vector;
38 : using namespace formula;
39 :
40 : // STATIC DATA
41 : #define MAX_ANZ_DOUBLE_FOR_SORT 100000
42 :
43 : const double ScInterpreter::fMaxGammaArgument = 171.624376956302; // found experimental
44 : const double fMachEps = ::std::numeric_limits<double>::epsilon();
45 :
46 0 : class ScDistFunc
47 : {
48 : public:
49 : virtual double GetValue(double x) const = 0;
50 :
51 : protected:
52 0 : ~ScDistFunc() {}
53 : };
54 :
55 : // iteration for inverse distributions
56 :
57 : //template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError )
58 :
59 : /** u*w<0.0 fails for values near zero */
60 0 : static inline bool lcl_HasChangeOfSign( double u, double w )
61 : {
62 0 : return (u < 0.0 && w > 0.0) || (u > 0.0 && w < 0.0);
63 : }
64 :
65 0 : static double lcl_IterateInverse( const ScDistFunc& rFunction, double fAx, double fBx, bool& rConvError )
66 : {
67 0 : rConvError = false;
68 0 : const double fYEps = 1.0E-307;
69 0 : const double fXEps = ::std::numeric_limits<double>::epsilon();
70 :
71 : OSL_ENSURE(fAx<fBx, "IterateInverse: wrong interval");
72 :
73 : // find enclosing interval
74 :
75 0 : double fAy = rFunction.GetValue(fAx);
76 0 : double fBy = rFunction.GetValue(fBx);
77 : double fTemp;
78 : unsigned short nCount;
79 0 : for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++)
80 : {
81 0 : if (fabs(fAy) <= fabs(fBy))
82 : {
83 0 : fTemp = fAx;
84 0 : fAx += 2.0 * (fAx - fBx);
85 0 : if (fAx < 0.0)
86 0 : fAx = 0.0;
87 0 : fBx = fTemp;
88 0 : fBy = fAy;
89 0 : fAy = rFunction.GetValue(fAx);
90 : }
91 : else
92 : {
93 0 : fTemp = fBx;
94 0 : fBx += 2.0 * (fBx - fAx);
95 0 : fAx = fTemp;
96 0 : fAy = fBy;
97 0 : fBy = rFunction.GetValue(fBx);
98 : }
99 : }
100 :
101 0 : if (fAy == 0.0)
102 0 : return fAx;
103 0 : if (fBy == 0.0)
104 0 : return fBx;
105 0 : if (!lcl_HasChangeOfSign( fAy, fBy))
106 : {
107 0 : rConvError = true;
108 0 : return 0.0;
109 : }
110 : // inverse quadric interpolation with additional brackets
111 : // set three points
112 0 : double fPx = fAx;
113 0 : double fPy = fAy;
114 0 : double fQx = fBx;
115 0 : double fQy = fBy;
116 0 : double fRx = fAx;
117 0 : double fRy = fAy;
118 0 : double fSx = 0.5 * (fAx + fBx); // potential next point
119 0 : bool bHasToInterpolate = true;
120 0 : nCount = 0;
121 0 : while ( nCount < 500 && fabs(fRy) > fYEps &&
122 0 : (fBx-fAx) > ::std::max( fabs(fAx), fabs(fBx)) * fXEps )
123 : {
124 0 : if (bHasToInterpolate)
125 : {
126 0 : if (fPy!=fQy && fQy!=fRy && fRy!=fPy)
127 : {
128 0 : fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)
129 0 : + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)
130 0 : + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);
131 0 : bHasToInterpolate = (fAx < fSx) && (fSx < fBx); // inside the brackets?
132 : }
133 : else
134 0 : bHasToInterpolate = false;
135 : }
136 0 : if(!bHasToInterpolate)
137 : {
138 0 : fSx = 0.5 * (fAx + fBx);
139 : // reset points
140 0 : fPx = fAx; fPy = fAy;
141 0 : fQx = fBx; fQy = fBy;
142 0 : bHasToInterpolate = true;
143 : }
144 : // shift points for next interpolation
145 0 : fPx = fQx; fQx = fRx; fRx = fSx;
146 0 : fPy = fQy; fQy = fRy; fRy = rFunction.GetValue(fSx);
147 : // update brackets
148 0 : if (lcl_HasChangeOfSign( fAy, fRy))
149 : {
150 0 : fBx = fRx; fBy = fRy;
151 : }
152 : else
153 : {
154 0 : fAx = fRx; fAy = fRy;
155 : }
156 : // if last interration brought to small advance, then do bisection next
157 : // time, for safety
158 0 : bHasToInterpolate = bHasToInterpolate && (fabs(fRy) * 2.0 <= fabs(fQy));
159 0 : ++nCount;
160 : }
161 0 : return fRx;
162 : }
163 :
164 : // Allgemeine Funktionen
165 :
166 0 : void ScInterpreter::ScNoName()
167 : {
168 0 : PushError(errNoName);
169 0 : }
170 :
171 0 : void ScInterpreter::ScBadName()
172 : {
173 0 : short nParamCount = GetByte();
174 0 : while (nParamCount-- > 0)
175 : {
176 0 : PopError();
177 : }
178 0 : PushError( errNoName);
179 0 : }
180 :
181 0 : double ScInterpreter::phi(double x)
182 : {
183 0 : return 0.39894228040143268 * exp(-(x * x) / 2.0);
184 : }
185 :
186 0 : double ScInterpreter::integralPhi(double x)
187 : { // Using gauss(x)+0.5 has severe cancellation errors for x<-4
188 0 : return 0.5 * ::rtl::math::erfc(-x * 0.7071067811865475); // * 1/sqrt(2)
189 : }
190 :
191 0 : double ScInterpreter::taylor(const double* pPolynom, sal_uInt16 nMax, double x)
192 : {
193 0 : double nVal = pPolynom[nMax];
194 0 : for (short i = nMax-1; i >= 0; i--)
195 : {
196 0 : nVal = pPolynom[i] + (nVal * x);
197 : }
198 0 : return nVal;
199 : }
200 :
201 0 : double ScInterpreter::gauss(double x)
202 : {
203 :
204 0 : double xAbs = fabs(x);
205 0 : sal_uInt16 xShort = (sal_uInt16)::rtl::math::approxFloor(xAbs);
206 0 : double nVal = 0.0;
207 0 : if (xShort == 0)
208 : {
209 : static const double t0[] =
210 : { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
211 : -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
212 : 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
213 : 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
214 0 : nVal = taylor(t0, 11, (xAbs * xAbs)) * xAbs;
215 : }
216 0 : else if ((xShort >= 1) && (xShort <= 2))
217 : {
218 : static const double t2[] =
219 : { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
220 : 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
221 : 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
222 : 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
223 : 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
224 : -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
225 : -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
226 : -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
227 0 : nVal = taylor(t2, 23, (xAbs - 2.0));
228 : }
229 0 : else if ((xShort >= 3) && (xShort <= 4))
230 : {
231 : static const double t4[] =
232 : { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
233 : 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
234 : -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
235 : -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
236 : 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
237 : 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
238 : 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
239 0 : nVal = taylor(t4, 20, (xAbs - 4.0));
240 : }
241 : else
242 : {
243 : static const double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
244 0 : nVal = 0.5 + phi(xAbs) * taylor(asympt, 4, 1.0 / (xAbs * xAbs)) / xAbs;
245 : }
246 0 : if (x < 0.0)
247 0 : return -nVal;
248 : else
249 0 : return nVal;
250 : }
251 :
252 :
253 : // #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
254 :
255 :
256 0 : double ScInterpreter::gaussinv(double x)
257 : {
258 : double q,t,z;
259 :
260 0 : q=x-0.5;
261 :
262 0 : if(fabs(q)<=.425)
263 : {
264 0 : t=0.180625-q*q;
265 :
266 : z=
267 0 : q*
268 : (
269 : (
270 : (
271 : (
272 : (
273 : (
274 : (
275 0 : t*2509.0809287301226727+33430.575583588128105
276 : )
277 0 : *t+67265.770927008700853
278 : )
279 0 : *t+45921.953931549871457
280 : )
281 0 : *t+13731.693765509461125
282 : )
283 0 : *t+1971.5909503065514427
284 : )
285 0 : *t+133.14166789178437745
286 : )
287 0 : *t+3.387132872796366608
288 : )
289 : /
290 : (
291 : (
292 : (
293 : (
294 : (
295 : (
296 : (
297 0 : t*5226.495278852854561+28729.085735721942674
298 : )
299 0 : *t+39307.89580009271061
300 : )
301 0 : *t+21213.794301586595867
302 : )
303 0 : *t+5394.1960214247511077
304 : )
305 0 : *t+687.1870074920579083
306 : )
307 0 : *t+42.313330701600911252
308 : )
309 0 : *t+1.0
310 0 : );
311 :
312 : }
313 : else
314 : {
315 0 : if(q>0) t=1-x;
316 0 : else t=x;
317 :
318 0 : t=sqrt(-log(t));
319 :
320 0 : if(t<=5.0)
321 : {
322 0 : t+=-1.6;
323 :
324 : z=
325 : (
326 : (
327 : (
328 : (
329 : (
330 : (
331 : (
332 0 : t*7.7454501427834140764e-4+0.0227238449892691845833
333 : )
334 0 : *t+0.24178072517745061177
335 : )
336 0 : *t+1.27045825245236838258
337 : )
338 0 : *t+3.64784832476320460504
339 : )
340 0 : *t+5.7694972214606914055
341 : )
342 0 : *t+4.6303378461565452959
343 : )
344 0 : *t+1.42343711074968357734
345 : )
346 : /
347 : (
348 : (
349 : (
350 : (
351 : (
352 : (
353 : (
354 0 : t*1.05075007164441684324e-9+5.475938084995344946e-4
355 : )
356 0 : *t+0.0151986665636164571966
357 : )
358 0 : *t+0.14810397642748007459
359 : )
360 0 : *t+0.68976733498510000455
361 : )
362 0 : *t+1.6763848301838038494
363 : )
364 0 : *t+2.05319162663775882187
365 : )
366 0 : *t+1.0
367 0 : );
368 :
369 : }
370 : else
371 : {
372 0 : t+=-5.0;
373 :
374 : z=
375 : (
376 : (
377 : (
378 : (
379 : (
380 : (
381 : (
382 0 : t*2.01033439929228813265e-7+2.71155556874348757815e-5
383 : )
384 0 : *t+0.0012426609473880784386
385 : )
386 0 : *t+0.026532189526576123093
387 : )
388 0 : *t+0.29656057182850489123
389 : )
390 0 : *t+1.7848265399172913358
391 : )
392 0 : *t+5.4637849111641143699
393 : )
394 0 : *t+6.6579046435011037772
395 : )
396 : /
397 : (
398 : (
399 : (
400 : (
401 : (
402 : (
403 : (
404 0 : t*2.04426310338993978564e-15+1.4215117583164458887e-7
405 : )
406 0 : *t+1.8463183175100546818e-5
407 : )
408 0 : *t+7.868691311456132591e-4
409 : )
410 0 : *t+0.0148753612908506148525
411 : )
412 0 : *t+0.13692988092273580531
413 : )
414 0 : *t+0.59983220655588793769
415 : )
416 0 : *t+1.0
417 0 : );
418 :
419 : }
420 :
421 0 : if(q<0.0) z=-z;
422 : }
423 :
424 0 : return z;
425 : }
426 :
427 0 : double ScInterpreter::Fakultaet(double x)
428 : {
429 0 : x = ::rtl::math::approxFloor(x);
430 0 : if (x < 0.0)
431 0 : return 0.0;
432 0 : else if (x == 0.0)
433 0 : return 1.0;
434 0 : else if (x <= 170.0)
435 : {
436 0 : double fTemp = x;
437 0 : while (fTemp > 2.0)
438 : {
439 0 : fTemp--;
440 0 : x *= fTemp;
441 : }
442 : }
443 : else
444 0 : SetError(errNoValue);
445 0 : return x;
446 : }
447 :
448 0 : double ScInterpreter::BinomKoeff(double n, double k)
449 : {
450 : // this method has been duplicated as BinomialCoefficient()
451 : // in scaddins/source/analysis/analysishelper.cxx
452 :
453 0 : double nVal = 0.0;
454 0 : k = ::rtl::math::approxFloor(k);
455 0 : if (n < k)
456 0 : nVal = 0.0;
457 0 : else if (k == 0.0)
458 0 : nVal = 1.0;
459 : else
460 : {
461 0 : nVal = n/k;
462 0 : n--;
463 0 : k--;
464 0 : while (k > 0.0)
465 : {
466 0 : nVal *= n/k;
467 0 : k--;
468 0 : n--;
469 : }
470 :
471 : }
472 0 : return nVal;
473 : }
474 :
475 : // The algorithm is based on lanczos13m53 in lanczos.hpp
476 : // in math library from http://www.boost.org
477 : /** you must ensure fZ>0
478 : Uses a variant of the Lanczos sum with a rational function. */
479 0 : static double lcl_getLanczosSum(double fZ)
480 : {
481 : static const double fNum[13] ={
482 : 23531376880.41075968857200767445163675473,
483 : 42919803642.64909876895789904700198885093,
484 : 35711959237.35566804944018545154716670596,
485 : 17921034426.03720969991975575445893111267,
486 : 6039542586.35202800506429164430729792107,
487 : 1439720407.311721673663223072794912393972,
488 : 248874557.8620541565114603864132294232163,
489 : 31426415.58540019438061423162831820536287,
490 : 2876370.628935372441225409051620849613599,
491 : 186056.2653952234950402949897160456992822,
492 : 8071.672002365816210638002902272250613822,
493 : 210.8242777515793458725097339207133627117,
494 : 2.506628274631000270164908177133837338626
495 : };
496 : static const double fDenom[13] = {
497 : 0,
498 : 39916800,
499 : 120543840,
500 : 150917976,
501 : 105258076,
502 : 45995730,
503 : 13339535,
504 : 2637558,
505 : 357423,
506 : 32670,
507 : 1925,
508 : 66,
509 : 1
510 : };
511 : // Horner scheme
512 : double fSumNum;
513 : double fSumDenom;
514 : int nI;
515 0 : if (fZ<=1.0)
516 : {
517 0 : fSumNum = fNum[12];
518 0 : fSumDenom = fDenom[12];
519 0 : for (nI = 11; nI >= 0; --nI)
520 : {
521 0 : fSumNum *= fZ;
522 0 : fSumNum += fNum[nI];
523 0 : fSumDenom *= fZ;
524 0 : fSumDenom += fDenom[nI];
525 : }
526 : }
527 : else
528 : // Cancel down with fZ^12; Horner scheme with reverse coefficients
529 : {
530 0 : double fZInv = 1/fZ;
531 0 : fSumNum = fNum[0];
532 0 : fSumDenom = fDenom[0];
533 0 : for (nI = 1; nI <=12; ++nI)
534 : {
535 0 : fSumNum *= fZInv;
536 0 : fSumNum += fNum[nI];
537 0 : fSumDenom *= fZInv;
538 0 : fSumDenom += fDenom[nI];
539 : }
540 : }
541 0 : return fSumNum/fSumDenom;
542 : }
543 :
544 : // The algorithm is based on tgamma in gamma.hpp
545 : // in math library from http://www.boost.org
546 : /** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
547 0 : static double lcl_GetGammaHelper(double fZ)
548 : {
549 0 : double fGamma = lcl_getLanczosSum(fZ);
550 0 : const double fg = 6.024680040776729583740234375;
551 0 : double fZgHelp = fZ + fg - 0.5;
552 : // avoid intermediate overflow
553 0 : double fHalfpower = pow( fZgHelp, fZ / 2 - 0.25);
554 0 : fGamma *= fHalfpower;
555 0 : fGamma /= exp(fZgHelp);
556 0 : fGamma *= fHalfpower;
557 0 : if (fZ <= 20.0 && fZ == ::rtl::math::approxFloor(fZ))
558 0 : fGamma = ::rtl::math::round(fGamma);
559 0 : return fGamma;
560 : }
561 :
562 : // The algorithm is based on tgamma in gamma.hpp
563 : // in math library from http://www.boost.org
564 : /** You must ensure fZ>0 */
565 0 : static double lcl_GetLogGammaHelper(double fZ)
566 : {
567 0 : const double fg = 6.024680040776729583740234375;
568 0 : double fZgHelp = fZ + fg - 0.5;
569 0 : return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp;
570 : }
571 :
572 : /** You must ensure non integer arguments for fZ<1 */
573 0 : double ScInterpreter::GetGamma(double fZ)
574 : {
575 0 : const double fLogPi = log(F_PI);
576 0 : const double fLogDblMax = log( ::std::numeric_limits<double>::max());
577 :
578 0 : if (fZ > fMaxGammaArgument)
579 : {
580 0 : SetError(errIllegalFPOperation);
581 0 : return HUGE_VAL;
582 : }
583 :
584 0 : if (fZ >= 1.0)
585 0 : return lcl_GetGammaHelper(fZ);
586 :
587 0 : if (fZ >= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
588 0 : return lcl_GetGammaHelper(fZ+1) / fZ;
589 :
590 0 : if (fZ >= -0.5) // shift to x>=1, might overflow
591 : {
592 0 : double fLogTest = lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log( fabs(fZ));
593 0 : if (fLogTest >= fLogDblMax)
594 : {
595 0 : SetError( errIllegalFPOperation);
596 0 : return HUGE_VAL;
597 : }
598 0 : return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ;
599 : }
600 : // fZ<-0.5
601 : // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
602 0 : double fLogDivisor = lcl_GetLogGammaHelper(1-fZ) + log( fabs( ::rtl::math::sin( F_PI*fZ)));
603 0 : if (fLogDivisor - fLogPi >= fLogDblMax) // underflow
604 0 : return 0.0;
605 :
606 0 : if (fLogDivisor<0.0)
607 0 : if (fLogPi - fLogDivisor > fLogDblMax) // overflow
608 : {
609 0 : SetError(errIllegalFPOperation);
610 0 : return HUGE_VAL;
611 : }
612 :
613 0 : return exp( fLogPi - fLogDivisor) * ((::rtl::math::sin( F_PI*fZ) < 0.0) ? -1.0 : 1.0);
614 : }
615 :
616 : /** You must ensure fZ>0 */
617 0 : double ScInterpreter::GetLogGamma(double fZ)
618 : {
619 0 : if (fZ >= fMaxGammaArgument)
620 0 : return lcl_GetLogGammaHelper(fZ);
621 0 : if (fZ >= 1.0)
622 0 : return log(lcl_GetGammaHelper(fZ));
623 0 : if (fZ >= 0.5)
624 0 : return log( lcl_GetGammaHelper(fZ+1) / fZ);
625 0 : return lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log(fZ);
626 : }
627 :
628 0 : double ScInterpreter::GetFDist(double x, double fF1, double fF2)
629 : {
630 0 : double arg = fF2/(fF2+fF1*x);
631 0 : double alpha = fF2/2.0;
632 0 : double beta = fF1/2.0;
633 0 : return (GetBetaDist(arg, alpha, beta));
634 : }
635 :
636 0 : double ScInterpreter::GetTDist( double T, double fDF, int nType )
637 : {
638 0 : switch ( nType )
639 : {
640 : case 1 : // 1-tailed T-distribution
641 0 : return 0.5 * GetBetaDist( fDF / ( fDF + T * T ), fDF / 2.0, 0.5 );
642 : case 2 : // 2-tailed T-distribution
643 0 : return GetBetaDist( fDF / ( fDF + T * T ), fDF / 2.0, 0.5);
644 : case 3 : // left-tailed T-distribution (probability density function)
645 0 : return pow( 1 + ( T * T / fDF ), -( fDF + 1 ) / 2 ) / ( sqrt( fDF ) * GetBeta( 0.5, fDF / 2.0 ) );
646 : case 4 : // left-tailed T-distribution (cumulative distribution function)
647 0 : double X = fDF / ( T * T + fDF );
648 0 : double R = 0.5 * GetBetaDist( X, 0.5 * fDF, 0.5 );
649 0 : return ( T < 0 ? R : 1 - R );
650 : }
651 0 : SetError( errIllegalArgument );
652 0 : return HUGE_VAL;
653 : }
654 :
655 : // for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
656 : /** You must ensure fDF>0.0 */
657 0 : double ScInterpreter::GetChiDist(double fX, double fDF)
658 : {
659 0 : if (fX <= 0.0)
660 0 : return 1.0; // see ODFF
661 : else
662 0 : return GetUpRegIGamma( fDF/2.0, fX/2.0);
663 : }
664 :
665 : // ready for ODF 1.2
666 : // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
667 : // returns left tail
668 : /** You must ensure fDF>0.0 */
669 0 : double ScInterpreter::GetChiSqDistCDF(double fX, double fDF)
670 : {
671 0 : if (fX <= 0.0)
672 0 : return 0.0; // see ODFF
673 : else
674 0 : return GetLowRegIGamma( fDF/2.0, fX/2.0);
675 : }
676 :
677 0 : double ScInterpreter::GetChiSqDistPDF(double fX, double fDF)
678 : {
679 : // you must ensure fDF is positive integer
680 : double fValue;
681 0 : if (fX <= 0.0)
682 0 : return 0.0; // see ODFF
683 0 : if (fDF*fX > 1391000.0)
684 : {
685 : // intermediate invalid values, use log
686 0 : fValue = exp((0.5*fDF - 1) * log(fX*0.5) - 0.5 * fX - log(2.0) - GetLogGamma(0.5*fDF));
687 : }
688 : else // fDF is small in most cases, we can iterate
689 : {
690 : double fCount;
691 0 : if (fmod(fDF,2.0)<0.5)
692 : {
693 : // even
694 0 : fValue = 0.5;
695 0 : fCount = 2.0;
696 : }
697 : else
698 : {
699 0 : fValue = 1/sqrt(fX*2*F_PI);
700 0 : fCount = 1.0;
701 : }
702 0 : while ( fCount < fDF)
703 : {
704 0 : fValue *= (fX / fCount);
705 0 : fCount += 2.0;
706 : }
707 0 : if (fX>=1425.0) // underflow in e^(-x/2)
708 0 : fValue = exp(log(fValue)-fX/2);
709 : else
710 0 : fValue *= exp(-fX/2);
711 : }
712 0 : return fValue;
713 : }
714 :
715 0 : void ScInterpreter::ScChiSqDist()
716 : {
717 0 : sal_uInt8 nParamCount = GetByte();
718 0 : if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
719 0 : return;
720 : bool bCumulative;
721 0 : if (nParamCount == 3)
722 0 : bCumulative = GetBool();
723 : else
724 0 : bCumulative = true;
725 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
726 0 : if (fDF < 1.0)
727 0 : PushIllegalArgument();
728 : else
729 : {
730 0 : double fX = GetDouble();
731 0 : if (bCumulative)
732 0 : PushDouble(GetChiSqDistCDF(fX,fDF));
733 : else
734 0 : PushDouble(GetChiSqDistPDF(fX,fDF));
735 : }
736 : }
737 :
738 0 : void ScInterpreter::ScChiSqDist_MS()
739 : {
740 0 : sal_uInt8 nParamCount = GetByte();
741 0 : if ( !MustHaveParamCount( nParamCount, 3, 3 ) )
742 0 : return;
743 0 : bool bCumulative = GetBool();
744 0 : double fDF = ::rtl::math::approxFloor( GetDouble() );
745 0 : if ( fDF < 1.0 || fDF > 1E10 )
746 0 : PushIllegalArgument();
747 : else
748 : {
749 0 : double fX = GetDouble();
750 0 : if ( fX < 0 )
751 0 : PushIllegalArgument();
752 : else
753 : {
754 0 : if ( bCumulative )
755 0 : PushDouble( GetChiSqDistCDF( fX, fDF ) );
756 : else
757 0 : PushDouble( GetChiSqDistPDF( fX, fDF ) );
758 : }
759 : }
760 : }
761 :
762 0 : void ScInterpreter::ScGamma()
763 : {
764 0 : double x = GetDouble();
765 0 : if (x <= 0.0 && x == ::rtl::math::approxFloor(x))
766 0 : PushIllegalArgument();
767 : else
768 : {
769 0 : double fResult = GetGamma(x);
770 0 : if (nGlobalError)
771 : {
772 0 : PushError( nGlobalError);
773 0 : return;
774 : }
775 0 : PushDouble(fResult);
776 : }
777 : }
778 :
779 0 : void ScInterpreter::ScLogGamma()
780 : {
781 0 : double x = GetDouble();
782 0 : if (x > 0.0) // constraint from ODFF
783 0 : PushDouble( GetLogGamma(x));
784 : else
785 0 : PushIllegalArgument();
786 0 : }
787 :
788 0 : double ScInterpreter::GetBeta(double fAlpha, double fBeta)
789 : {
790 : double fA;
791 : double fB;
792 0 : if (fAlpha > fBeta)
793 : {
794 0 : fA = fAlpha; fB = fBeta;
795 : }
796 : else
797 : {
798 0 : fA = fBeta; fB = fAlpha;
799 : }
800 0 : if (fA+fB < fMaxGammaArgument) // simple case
801 0 : return GetGamma(fA)/GetGamma(fA+fB)*GetGamma(fB);
802 : // need logarithm
803 : // GetLogGamma is not accurate enough, back to Lanczos for all three
804 : // GetGamma and arrange factors newly.
805 0 : const double fg = 6.024680040776729583740234375; //see GetGamma
806 0 : double fgm = fg - 0.5;
807 0 : double fLanczos = lcl_getLanczosSum(fA);
808 0 : fLanczos /= lcl_getLanczosSum(fA+fB);
809 0 : fLanczos *= lcl_getLanczosSum(fB);
810 0 : double fABgm = fA+fB+fgm;
811 0 : fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm));
812 0 : double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
813 0 : double fTempB = fA/(fB+fgm);
814 0 : double fResult = exp(-fA * ::rtl::math::log1p(fTempA)
815 0 : -fB * ::rtl::math::log1p(fTempB)-fgm);
816 0 : fResult *= fLanczos;
817 0 : return fResult;
818 : }
819 :
820 : // Same as GetBeta but with logarithm
821 0 : double ScInterpreter::GetLogBeta(double fAlpha, double fBeta)
822 : {
823 : double fA;
824 : double fB;
825 0 : if (fAlpha > fBeta)
826 : {
827 0 : fA = fAlpha; fB = fBeta;
828 : }
829 : else
830 : {
831 0 : fA = fBeta; fB = fAlpha;
832 : }
833 0 : const double fg = 6.024680040776729583740234375; //see GetGamma
834 0 : double fgm = fg - 0.5;
835 0 : double fLanczos = lcl_getLanczosSum(fA);
836 0 : fLanczos /= lcl_getLanczosSum(fA+fB);
837 0 : fLanczos *= lcl_getLanczosSum(fB);
838 0 : double fLogLanczos = log(fLanczos);
839 0 : double fABgm = fA+fB+fgm;
840 0 : fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm));
841 0 : double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
842 0 : double fTempB = fA/(fB+fgm);
843 0 : double fResult = -fA * ::rtl::math::log1p(fTempA)
844 0 : -fB * ::rtl::math::log1p(fTempB)-fgm;
845 0 : fResult += fLogLanczos;
846 0 : return fResult;
847 : }
848 :
849 : // beta distribution probability density function
850 0 : double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB)
851 : {
852 : // special cases
853 0 : if (fA == 1.0) // result b*(1-x)^(b-1)
854 : {
855 0 : if (fB == 1.0)
856 0 : return 1.0;
857 0 : if (fB == 2.0)
858 0 : return -2.0*fX + 2.0;
859 0 : if (fX == 1.0 && fB < 1.0)
860 : {
861 0 : SetError(errIllegalArgument);
862 0 : return HUGE_VAL;
863 : }
864 0 : if (fX <= 0.01)
865 0 : return fB + fB * ::rtl::math::expm1((fB-1.0) * ::rtl::math::log1p(-fX));
866 : else
867 0 : return fB * pow(0.5-fX+0.5,fB-1.0);
868 : }
869 0 : if (fB == 1.0) // result a*x^(a-1)
870 : {
871 0 : if (fA == 2.0)
872 0 : return fA * fX;
873 0 : if (fX == 0.0 && fA < 1.0)
874 : {
875 0 : SetError(errIllegalArgument);
876 0 : return HUGE_VAL;
877 : }
878 0 : return fA * pow(fX,fA-1);
879 : }
880 0 : if (fX <= 0.0)
881 : {
882 0 : if (fA < 1.0 && fX == 0.0)
883 : {
884 0 : SetError(errIllegalArgument);
885 0 : return HUGE_VAL;
886 : }
887 : else
888 0 : return 0.0;
889 : }
890 0 : if (fX >= 1.0)
891 : {
892 0 : if (fB < 1.0 && fX == 1.0)
893 : {
894 0 : SetError(errIllegalArgument);
895 0 : return HUGE_VAL;
896 : }
897 : else
898 0 : return 0.0;
899 : }
900 :
901 : // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
902 0 : const double fLogDblMax = log( ::std::numeric_limits<double>::max());
903 0 : const double fLogDblMin = log( ::std::numeric_limits<double>::min());
904 0 : double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5);
905 0 : double fLogX = log(fX);
906 0 : double fAm1LogX = (fA-1.0) * fLogX;
907 0 : double fBm1LogY = (fB-1.0) * fLogY;
908 0 : double fLogBeta = GetLogBeta(fA,fB);
909 : // check whether parts over- or underflow
910 0 : if ( fAm1LogX < fLogDblMax && fAm1LogX > fLogDblMin
911 0 : && fBm1LogY < fLogDblMax && fBm1LogY > fLogDblMin
912 0 : && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin
913 0 : && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > fLogDblMin)
914 0 : return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB);
915 : else // need logarithm;
916 : // might overflow as a whole, but seldom, not worth to pre-detect it
917 0 : return exp( fAm1LogX + fBm1LogY - fLogBeta);
918 : }
919 :
920 : /*
921 : x^a * (1-x)^b
922 : I_x(a,b) = ---------------- * result of ContFrac
923 : a * Beta(a,b)
924 : */
925 0 : static double lcl_GetBetaHelperContFrac(double fX, double fA, double fB)
926 : { // like old version
927 : double a1, b1, a2, b2, fnorm, apl2m, d2m, d2m1, cfnew, cf;
928 0 : a1 = 1.0; b1 = 1.0;
929 0 : b2 = 1.0 - (fA+fB)/(fA+1.0)*fX;
930 0 : if (b2 == 0.0)
931 : {
932 0 : a2 = 0.0;
933 0 : fnorm = 1.0;
934 0 : cf = 1.0;
935 : }
936 : else
937 : {
938 0 : a2 = 1.0;
939 0 : fnorm = 1.0/b2;
940 0 : cf = a2*fnorm;
941 : }
942 0 : cfnew = 1.0;
943 0 : double rm = 1.0;
944 :
945 0 : const double fMaxIter = 50000.0;
946 : // loop security, normal cases converge in less than 100 iterations.
947 : // FIXME: You will get so much iteratons for fX near mean,
948 : // I do not know a better algorithm.
949 0 : bool bfinished = false;
950 0 : do
951 : {
952 0 : apl2m = fA + 2.0*rm;
953 0 : d2m = rm*(fB-rm)*fX/((apl2m-1.0)*apl2m);
954 0 : d2m1 = -(fA+rm)*(fA+fB+rm)*fX/(apl2m*(apl2m+1.0));
955 0 : a1 = (a2+d2m*a1)*fnorm;
956 0 : b1 = (b2+d2m*b1)*fnorm;
957 0 : a2 = a1 + d2m1*a2*fnorm;
958 0 : b2 = b1 + d2m1*b2*fnorm;
959 0 : if (b2 != 0.0)
960 : {
961 0 : fnorm = 1.0/b2;
962 0 : cfnew = a2*fnorm;
963 0 : bfinished = (fabs(cf-cfnew) < fabs(cf)*fMachEps);
964 : }
965 0 : cf = cfnew;
966 0 : rm += 1.0;
967 : }
968 0 : while (rm < fMaxIter && !bfinished);
969 0 : return cf;
970 : }
971 :
972 : // cumulative distribution function, normalized
973 0 : double ScInterpreter::GetBetaDist(double fXin, double fAlpha, double fBeta)
974 : {
975 : // special cases
976 0 : if (fXin <= 0.0) // values are valid, see spec
977 0 : return 0.0;
978 0 : if (fXin >= 1.0) // values are valid, see spec
979 0 : return 1.0;
980 0 : if (fBeta == 1.0)
981 0 : return pow(fXin, fAlpha);
982 0 : if (fAlpha == 1.0)
983 : // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
984 0 : return -::rtl::math::expm1(fBeta * ::rtl::math::log1p(-fXin));
985 : //FIXME: need special algorithm for fX near fP for large fA,fB
986 : double fResult;
987 : // I use always continued fraction, power series are neither
988 : // faster nor more accurate.
989 0 : double fY = (0.5-fXin)+0.5;
990 0 : double flnY = ::rtl::math::log1p(-fXin);
991 0 : double fX = fXin;
992 0 : double flnX = log(fXin);
993 0 : double fA = fAlpha;
994 0 : double fB = fBeta;
995 0 : bool bReflect = fXin > fAlpha/(fAlpha+fBeta);
996 0 : if (bReflect)
997 : {
998 0 : fA = fBeta;
999 0 : fB = fAlpha;
1000 0 : fX = fY;
1001 0 : fY = fXin;
1002 0 : flnX = flnY;
1003 0 : flnY = log(fXin);
1004 : }
1005 0 : fResult = lcl_GetBetaHelperContFrac(fX,fA,fB);
1006 0 : fResult = fResult/fA;
1007 0 : double fP = fA/(fA+fB);
1008 0 : double fQ = fB/(fA+fB);
1009 : double fTemp;
1010 0 : if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97) //found experimental
1011 0 : fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY;
1012 : else
1013 0 : fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB));
1014 0 : fResult *= fTemp;
1015 0 : if (bReflect)
1016 0 : fResult = 0.5 - fResult + 0.5;
1017 0 : if (fResult > 1.0) // ensure valid range
1018 0 : fResult = 1.0;
1019 0 : if (fResult < 0.0)
1020 0 : fResult = 0.0;
1021 0 : return fResult;
1022 : }
1023 :
1024 0 : void ScInterpreter::ScBetaDist()
1025 : {
1026 0 : sal_uInt8 nParamCount = GetByte();
1027 0 : if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) // expanded, see #i91547#
1028 0 : return;
1029 : double fLowerBound, fUpperBound;
1030 : double alpha, beta, x;
1031 : bool bIsCumulative;
1032 0 : if (nParamCount == 6)
1033 0 : bIsCumulative = GetBool();
1034 : else
1035 0 : bIsCumulative = true;
1036 0 : if (nParamCount >= 5)
1037 0 : fUpperBound = GetDouble();
1038 : else
1039 0 : fUpperBound = 1.0;
1040 0 : if (nParamCount >= 4)
1041 0 : fLowerBound = GetDouble();
1042 : else
1043 0 : fLowerBound = 0.0;
1044 0 : beta = GetDouble();
1045 0 : alpha = GetDouble();
1046 0 : x = GetDouble();
1047 0 : double fScale = fUpperBound - fLowerBound;
1048 0 : if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0)
1049 : {
1050 0 : PushIllegalArgument();
1051 0 : return;
1052 : }
1053 0 : if (bIsCumulative) // cumulative distribution function
1054 : {
1055 : // special cases
1056 0 : if (x < fLowerBound)
1057 : {
1058 0 : PushDouble(0.0); return; //see spec
1059 : }
1060 0 : if (x > fUpperBound)
1061 : {
1062 0 : PushDouble(1.0); return; //see spec
1063 : }
1064 : // normal cases
1065 0 : x = (x-fLowerBound)/fScale; // convert to standard form
1066 0 : PushDouble(GetBetaDist(x, alpha, beta));
1067 0 : return;
1068 : }
1069 : else // probability density function
1070 : {
1071 0 : if (x < fLowerBound || x > fUpperBound)
1072 : {
1073 0 : PushDouble(0.0);
1074 0 : return;
1075 : }
1076 0 : x = (x-fLowerBound)/fScale;
1077 0 : PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1078 0 : return;
1079 : }
1080 : }
1081 :
1082 : /**
1083 : fdo#71008
1084 : Microsoft version has parameters in different order
1085 : Also, upper and lowerbound are optional and have default values
1086 : otherwise, function is identical with ScInterpreter::ScBetaDist()
1087 : */
1088 0 : void ScInterpreter::ScBetaDist_MS()
1089 : {
1090 0 : sal_uInt8 nParamCount = GetByte();
1091 0 : if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1092 0 : return;
1093 : double fLowerBound, fUpperBound;
1094 : double alpha, beta, x;
1095 : bool bIsCumulative;
1096 0 : if (nParamCount == 6)
1097 0 : fUpperBound = GetDouble();
1098 : else
1099 0 : fUpperBound = 1.0;
1100 0 : if (nParamCount >= 4)
1101 0 : fLowerBound = GetDouble();
1102 : else
1103 0 : fLowerBound = 0.0;
1104 0 : bIsCumulative = GetBool();
1105 0 : beta = GetDouble();
1106 0 : alpha = GetDouble();
1107 0 : x = GetDouble();
1108 0 : double fScale = fUpperBound - fLowerBound;
1109 0 : if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0)
1110 : {
1111 0 : PushIllegalArgument();
1112 0 : return;
1113 : }
1114 0 : if (bIsCumulative) // cumulative distribution function
1115 : {
1116 : // special cases
1117 0 : if (x < fLowerBound)
1118 : {
1119 0 : PushDouble(0.0); return; //see spec
1120 : }
1121 0 : if (x > fUpperBound)
1122 : {
1123 0 : PushDouble(1.0); return; //see spec
1124 : }
1125 : // normal cases
1126 0 : x = (x-fLowerBound)/fScale; // convert to standard form
1127 0 : PushDouble(GetBetaDist(x, alpha, beta));
1128 0 : return;
1129 : }
1130 : else // probability density function
1131 : {
1132 0 : if (x < fLowerBound || x > fUpperBound)
1133 : {
1134 0 : PushDouble(0.0);
1135 0 : return;
1136 : }
1137 0 : x = (x-fLowerBound)/fScale;
1138 0 : PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1139 0 : return;
1140 : }
1141 : }
1142 :
1143 0 : void ScInterpreter::ScPhi()
1144 : {
1145 0 : PushDouble(phi(GetDouble()));
1146 0 : }
1147 :
1148 0 : void ScInterpreter::ScGauss()
1149 : {
1150 0 : PushDouble(gauss(GetDouble()));
1151 0 : }
1152 :
1153 0 : void ScInterpreter::ScFisher()
1154 : {
1155 0 : double fVal = GetDouble();
1156 0 : if (fabs(fVal) >= 1.0)
1157 0 : PushIllegalArgument();
1158 : else
1159 0 : PushDouble( ::rtl::math::atanh( fVal));
1160 0 : }
1161 :
1162 0 : void ScInterpreter::ScFisherInv()
1163 : {
1164 0 : PushDouble( tanh( GetDouble()));
1165 0 : }
1166 :
1167 0 : void ScInterpreter::ScFact()
1168 : {
1169 0 : double nVal = GetDouble();
1170 0 : if (nVal < 0.0)
1171 0 : PushIllegalArgument();
1172 : else
1173 0 : PushDouble(Fakultaet(nVal));
1174 0 : }
1175 :
1176 0 : void ScInterpreter::ScKombin()
1177 : {
1178 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1179 : {
1180 0 : double k = ::rtl::math::approxFloor(GetDouble());
1181 0 : double n = ::rtl::math::approxFloor(GetDouble());
1182 0 : if (k < 0.0 || n < 0.0 || k > n)
1183 0 : PushIllegalArgument();
1184 : else
1185 0 : PushDouble(BinomKoeff(n, k));
1186 : }
1187 0 : }
1188 :
1189 0 : void ScInterpreter::ScKombin2()
1190 : {
1191 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1192 : {
1193 0 : double k = ::rtl::math::approxFloor(GetDouble());
1194 0 : double n = ::rtl::math::approxFloor(GetDouble());
1195 0 : if (k < 0.0 || n < 0.0 || k > n)
1196 0 : PushIllegalArgument();
1197 : else
1198 0 : PushDouble(BinomKoeff(n + k - 1, k));
1199 : }
1200 0 : }
1201 :
1202 0 : void ScInterpreter::ScVariationen()
1203 : {
1204 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1205 : {
1206 0 : double k = ::rtl::math::approxFloor(GetDouble());
1207 0 : double n = ::rtl::math::approxFloor(GetDouble());
1208 0 : if (n < 0.0 || k < 0.0 || k > n)
1209 0 : PushIllegalArgument();
1210 0 : else if (k == 0.0)
1211 0 : PushInt(1); // (n! / (n - 0)!) == 1
1212 : else
1213 : {
1214 0 : double nVal = n;
1215 0 : for (sal_uLong i = (sal_uLong)k-1; i >= 1; i--)
1216 0 : nVal *= n-(double)i;
1217 0 : PushDouble(nVal);
1218 : }
1219 : }
1220 0 : }
1221 :
1222 0 : void ScInterpreter::ScVariationen2()
1223 : {
1224 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1225 : {
1226 0 : double k = ::rtl::math::approxFloor(GetDouble());
1227 0 : double n = ::rtl::math::approxFloor(GetDouble());
1228 0 : if (n < 0.0 || k < 0.0 || k > n)
1229 0 : PushIllegalArgument();
1230 : else
1231 0 : PushDouble(pow(n,k));
1232 : }
1233 0 : }
1234 :
1235 0 : double ScInterpreter::GetBinomDistPMF(double x, double n, double p)
1236 : // used in ScB and ScBinomDist
1237 : // preconditions: 0.0 <= x <= n, 0.0 < p < 1.0; x,n integral although double
1238 : {
1239 0 : double q = (0.5 - p) + 0.5;
1240 0 : double fFactor = pow(q, n);
1241 0 : if (fFactor <=::std::numeric_limits<double>::min())
1242 : {
1243 0 : fFactor = pow(p, n);
1244 0 : if (fFactor <= ::std::numeric_limits<double>::min())
1245 0 : return GetBetaDistPDF(p, x+1.0, n-x+1.0)/(n+1.0);
1246 : else
1247 : {
1248 0 : sal_uInt32 max = static_cast<sal_uInt32>(n - x);
1249 0 : for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1250 0 : fFactor *= (n-i)/(i+1)*q/p;
1251 0 : return fFactor;
1252 : }
1253 : }
1254 : else
1255 : {
1256 0 : sal_uInt32 max = static_cast<sal_uInt32>(x);
1257 0 : for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1258 0 : fFactor *= (n-i)/(i+1)*p/q;
1259 0 : return fFactor;
1260 : }
1261 : }
1262 :
1263 0 : double lcl_GetBinomDistRange(double n, double xs,double xe,
1264 : double fFactor /* q^n */, double p, double q)
1265 : //preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double
1266 : {
1267 : sal_uInt32 i;
1268 : double fSum;
1269 : // skip summands index 0 to xs-1, start sum with index xs
1270 0 : sal_uInt32 nXs = static_cast<sal_uInt32>( xs );
1271 0 : for (i = 1; i <= nXs && fFactor > 0.0; i++)
1272 0 : fFactor *= (n-i+1)/i * p/q;
1273 0 : fSum = fFactor; // Summand xs
1274 0 : sal_uInt32 nXe = static_cast<sal_uInt32>(xe);
1275 0 : for (i = nXs+1; i <= nXe && fFactor > 0.0; i++)
1276 : {
1277 0 : fFactor *= (n-i+1)/i * p/q;
1278 0 : fSum += fFactor;
1279 : }
1280 0 : return (fSum>1.0) ? 1.0 : fSum;
1281 : }
1282 :
1283 0 : void ScInterpreter::ScB()
1284 : {
1285 0 : sal_uInt8 nParamCount = GetByte();
1286 0 : if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1287 0 : return ;
1288 0 : if (nParamCount == 3) // mass function
1289 : {
1290 0 : double x = ::rtl::math::approxFloor(GetDouble());
1291 0 : double p = GetDouble();
1292 0 : double n = ::rtl::math::approxFloor(GetDouble());
1293 0 : if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1294 0 : PushIllegalArgument();
1295 0 : else if (p == 0.0)
1296 0 : PushDouble( (x == 0.0) ? 1.0 : 0.0 );
1297 0 : else if ( p == 1.0)
1298 0 : PushDouble( (x == n) ? 1.0 : 0.0);
1299 : else
1300 0 : PushDouble(GetBinomDistPMF(x,n,p));
1301 : }
1302 : else
1303 : { // nParamCount == 4
1304 0 : double xe = ::rtl::math::approxFloor(GetDouble());
1305 0 : double xs = ::rtl::math::approxFloor(GetDouble());
1306 0 : double p = GetDouble();
1307 0 : double n = ::rtl::math::approxFloor(GetDouble());
1308 0 : double q = (0.5 - p) + 0.5;
1309 0 : bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n);
1310 0 : if ( bIsValidX && 0.0 < p && p < 1.0)
1311 : {
1312 0 : if (xs == xe) // mass function
1313 0 : PushDouble(GetBinomDistPMF(xs,n,p));
1314 : else
1315 : {
1316 0 : double fFactor = pow(q, n);
1317 0 : if (fFactor > ::std::numeric_limits<double>::min())
1318 0 : PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q));
1319 : else
1320 : {
1321 0 : fFactor = pow(p, n);
1322 0 : if (fFactor > ::std::numeric_limits<double>::min())
1323 : {
1324 : // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)}
1325 : // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)}
1326 0 : PushDouble(lcl_GetBinomDistRange(n,n-xe,n-xs,fFactor,q,p));
1327 : }
1328 : else
1329 0 : PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) );
1330 : }
1331 0 : }
1332 : }
1333 : else
1334 : {
1335 0 : if ( bIsValidX ) // not(0<p<1)
1336 : {
1337 0 : if ( p == 0.0 )
1338 0 : PushDouble( (xs == 0.0) ? 1.0 : 0.0 );
1339 0 : else if ( p == 1.0 )
1340 0 : PushDouble( (xe == n) ? 1.0 : 0.0 );
1341 : else
1342 0 : PushIllegalArgument();
1343 : }
1344 : else
1345 0 : PushIllegalArgument();
1346 : }
1347 : }
1348 : }
1349 :
1350 0 : void ScInterpreter::ScBinomDist()
1351 : {
1352 0 : if ( MustHaveParamCount( GetByte(), 4 ) )
1353 : {
1354 0 : bool bIsCum = GetBool(); // false=mass function; true=cumulative
1355 0 : double p = GetDouble();
1356 0 : double n = ::rtl::math::approxFloor(GetDouble());
1357 0 : double x = ::rtl::math::approxFloor(GetDouble());
1358 0 : double q = (0.5 - p) + 0.5; // get one bit more for p near 1.0
1359 0 : if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1360 : {
1361 0 : PushIllegalArgument();
1362 0 : return;
1363 : }
1364 0 : if ( p == 0.0)
1365 : {
1366 0 : PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 );
1367 0 : return;
1368 : }
1369 0 : if ( p == 1.0)
1370 : {
1371 0 : PushDouble( (x==n) ? 1.0 : 0.0);
1372 0 : return;
1373 : }
1374 0 : if (!bIsCum)
1375 0 : PushDouble( GetBinomDistPMF(x,n,p));
1376 : else
1377 : {
1378 0 : if (x == n)
1379 0 : PushDouble(1.0);
1380 : else
1381 : {
1382 0 : double fFactor = pow(q, n);
1383 0 : if (x == 0.0)
1384 0 : PushDouble(fFactor);
1385 0 : else if (fFactor <= ::std::numeric_limits<double>::min())
1386 : {
1387 0 : fFactor = pow(p, n);
1388 0 : if (fFactor <= ::std::numeric_limits<double>::min())
1389 0 : PushDouble(GetBetaDist(q,n-x,x+1.0));
1390 : else
1391 : {
1392 0 : if (fFactor > fMachEps)
1393 : {
1394 0 : double fSum = 1.0 - fFactor;
1395 0 : sal_uInt32 max = static_cast<sal_uInt32> (n - x) - 1;
1396 0 : for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1397 : {
1398 0 : fFactor *= (n-i)/(i+1)*q/p;
1399 0 : fSum -= fFactor;
1400 : }
1401 0 : PushDouble( (fSum < 0.0) ? 0.0 : fSum );
1402 : }
1403 : else
1404 0 : PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p));
1405 : }
1406 : }
1407 : else
1408 0 : PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ;
1409 : }
1410 : }
1411 : }
1412 : }
1413 :
1414 0 : void ScInterpreter::ScCritBinom()
1415 : {
1416 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1417 : {
1418 0 : double alpha = GetDouble();
1419 0 : double p = GetDouble();
1420 0 : double n = ::rtl::math::approxFloor(GetDouble());
1421 0 : if (n < 0.0 || alpha <= 0.0 || alpha >= 1.0 || p < 0.0 || p > 1.0)
1422 0 : PushIllegalArgument();
1423 : else
1424 : {
1425 : double fFactor;
1426 0 : double q = (0.5 - p) + 0.5; // get one bit more for p near 1.0
1427 0 : if ( q > p ) // work from the side where the cumulative curve is
1428 : {
1429 : // work from 0 upwards
1430 0 : fFactor = pow(q,n);
1431 0 : if (fFactor > ::std::numeric_limits<double>::min())
1432 : {
1433 0 : double fSum = fFactor;
1434 0 : sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1435 0 : for (i = 0; i < max && fSum < alpha; i++)
1436 : {
1437 0 : fFactor *= (n-i)/(i+1)*p/q;
1438 0 : fSum += fFactor;
1439 : }
1440 0 : PushDouble(i);
1441 : }
1442 : else
1443 : {
1444 : // accumulate BinomDist until accumulated BinomDist reaches alpha
1445 0 : double fSum = 0.0, x;
1446 0 : sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1447 0 : for (i = 0; i < max && fSum < alpha; i++)
1448 : {
1449 0 : x = GetBetaDistPDF( p, ( i + 1 ), ( n - i + 1 ) )/( n + 1 );
1450 0 : if ( !nGlobalError )
1451 : {
1452 0 : fSum += x;
1453 : }
1454 : else
1455 : {
1456 0 : PushNoValue();
1457 0 : return;
1458 : }
1459 : }
1460 0 : PushDouble( i - 1 );
1461 : }
1462 : }
1463 : else
1464 : {
1465 : // work from n backwards
1466 0 : fFactor = pow(p, n);
1467 0 : if (fFactor > ::std::numeric_limits<double>::min())
1468 : {
1469 0 : double fSum = 1.0 - fFactor;
1470 0 : sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1471 0 : for (i = 0; i < max && fSum >= alpha; i++)
1472 : {
1473 0 : fFactor *= (n-i)/(i+1)*q/p;
1474 0 : fSum -= fFactor;
1475 : }
1476 0 : PushDouble(n-i);
1477 : }
1478 : else
1479 : {
1480 : // accumulate BinomDist until accumulated BinomDist reaches alpha
1481 0 : double fSum = 0.0, x;
1482 0 : sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1483 0 : alpha = 1 - alpha;
1484 0 : for (i = 0; i < max && fSum < alpha; i++)
1485 : {
1486 0 : x = GetBetaDistPDF( q, ( i + 1 ), ( n - i + 1 ) )/( n + 1 );
1487 0 : if ( !nGlobalError )
1488 : {
1489 0 : fSum += x;
1490 : }
1491 : else
1492 : {
1493 0 : PushNoValue();
1494 0 : return;
1495 : }
1496 : }
1497 0 : PushDouble( n - i + 1 );
1498 : }
1499 : }
1500 : }
1501 : }
1502 : }
1503 :
1504 0 : void ScInterpreter::ScNegBinomDist()
1505 : {
1506 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1507 : {
1508 0 : double p = GetDouble(); // p
1509 0 : double r = GetDouble(); // r
1510 0 : double x = GetDouble(); // x
1511 0 : if (r < 0.0 || x < 0.0 || p < 0.0 || p > 1.0)
1512 0 : PushIllegalArgument();
1513 : else
1514 : {
1515 0 : double q = 1.0 - p;
1516 0 : double fFactor = pow(p,r);
1517 0 : for (double i = 0.0; i < x; i++)
1518 0 : fFactor *= (i+r)/(i+1.0)*q;
1519 0 : PushDouble(fFactor);
1520 : }
1521 : }
1522 0 : }
1523 :
1524 0 : void ScInterpreter::ScNegBinomDist_MS()
1525 : {
1526 0 : if ( MustHaveParamCount( GetByte(), 4 ) )
1527 : {
1528 0 : bool bCumulative = GetBool();
1529 0 : double p = GetDouble(); // p
1530 0 : double r = GetDouble(); // r
1531 0 : double x = GetDouble(); // x
1532 0 : if ( r < 0.0 || x < 0.0 || p < 0.0 || p > 1.0 )
1533 0 : PushIllegalArgument();
1534 : else
1535 : {
1536 0 : double q = 1.0 - p;
1537 0 : if ( bCumulative )
1538 0 : PushDouble( 1.0 - GetBetaDist( q, x + 1, r ) );
1539 : else
1540 : {
1541 0 : double fFactor = pow( p, r );
1542 0 : for ( double i = 0.0; i < x; i++ )
1543 0 : fFactor *= ( i + r ) / ( i + 1.0 ) * q;
1544 0 : PushDouble( fFactor );
1545 : }
1546 : }
1547 : }
1548 0 : }
1549 :
1550 0 : void ScInterpreter::ScNormDist( int nMinParamCount )
1551 : {
1552 0 : sal_uInt8 nParamCount = GetByte();
1553 0 : if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
1554 0 : return;
1555 0 : bool bCumulative = nParamCount == 4 ? GetBool() : true;
1556 0 : double sigma = GetDouble(); // standard deviation
1557 0 : double mue = GetDouble(); // mean
1558 0 : double x = GetDouble(); // x
1559 0 : if (sigma <= 0.0)
1560 : {
1561 0 : PushIllegalArgument();
1562 0 : return;
1563 : }
1564 0 : if (bCumulative)
1565 0 : PushDouble(integralPhi((x-mue)/sigma));
1566 : else
1567 0 : PushDouble(phi((x-mue)/sigma)/sigma);
1568 : }
1569 :
1570 0 : void ScInterpreter::ScLogNormDist( int nMinParamCount ) //expanded, see #i100119# and fdo72158
1571 : {
1572 0 : sal_uInt8 nParamCount = GetByte();
1573 0 : if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
1574 0 : return;
1575 0 : bool bCumulative = nParamCount == 4 ? GetBool() : true; // cumulative
1576 0 : double sigma = nParamCount >= 3 ? GetDouble() : 1.0; // standard deviation
1577 0 : double mue = nParamCount >= 2 ? GetDouble() : 0.0; // mean
1578 0 : double x = GetDouble(); // x
1579 0 : if (sigma <= 0.0)
1580 : {
1581 0 : PushIllegalArgument();
1582 0 : return;
1583 : }
1584 0 : if (bCumulative)
1585 : { // cumulative
1586 0 : if (x <= 0.0)
1587 0 : PushDouble(0.0);
1588 : else
1589 0 : PushDouble(integralPhi((log(x)-mue)/sigma));
1590 : }
1591 : else
1592 : { // density
1593 0 : if (x <= 0.0)
1594 0 : PushIllegalArgument();
1595 : else
1596 0 : PushDouble(phi((log(x)-mue)/sigma)/sigma/x);
1597 : }
1598 : }
1599 :
1600 0 : void ScInterpreter::ScStdNormDist()
1601 : {
1602 0 : PushDouble(integralPhi(GetDouble()));
1603 0 : }
1604 :
1605 0 : void ScInterpreter::ScStdNormDist_MS()
1606 : {
1607 0 : sal_uInt8 nParamCount = GetByte();
1608 0 : if ( !MustHaveParamCount( nParamCount, 2 ) )
1609 0 : return;
1610 0 : bool bCumulative = GetBool(); // cumulative
1611 0 : double x = GetDouble(); // x
1612 :
1613 0 : if ( bCumulative )
1614 0 : PushDouble( integralPhi( x ) );
1615 : else
1616 0 : PushDouble( exp( - pow( x, 2 ) / 2 ) / sqrt( 2 * F_PI ) );
1617 : }
1618 :
1619 0 : void ScInterpreter::ScExpDist()
1620 : {
1621 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1622 : {
1623 0 : double kum = GetDouble(); // 0 oder 1
1624 0 : double lambda = GetDouble(); // lambda
1625 0 : double x = GetDouble(); // x
1626 0 : if (lambda <= 0.0)
1627 0 : PushIllegalArgument();
1628 0 : else if (kum == 0.0) // Dichte
1629 : {
1630 0 : if (x >= 0.0)
1631 0 : PushDouble(lambda * exp(-lambda*x));
1632 : else
1633 0 : PushInt(0);
1634 : }
1635 : else // Verteilung
1636 : {
1637 0 : if (x > 0.0)
1638 0 : PushDouble(1.0 - exp(-lambda*x));
1639 : else
1640 0 : PushInt(0);
1641 : }
1642 : }
1643 0 : }
1644 :
1645 0 : void ScInterpreter::ScTDist()
1646 : {
1647 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
1648 0 : return;
1649 0 : double fFlag = ::rtl::math::approxFloor(GetDouble());
1650 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
1651 0 : double T = GetDouble();
1652 0 : if (fDF < 1.0 || T < 0.0 || (fFlag != 1.0 && fFlag != 2.0) )
1653 : {
1654 0 : PushIllegalArgument();
1655 0 : return;
1656 : }
1657 0 : PushDouble( GetTDist( T, fDF, ( int )fFlag ) );
1658 : }
1659 :
1660 0 : void ScInterpreter::ScTDist_T( int nTails )
1661 : {
1662 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
1663 0 : return;
1664 0 : double fDF = ::rtl::math::approxFloor( GetDouble() );
1665 0 : double T = GetDouble();
1666 0 : if ( fDF < 1.0 || T < 0.0 )
1667 : {
1668 0 : PushIllegalArgument();
1669 0 : return;
1670 : }
1671 0 : PushDouble( GetTDist( T, fDF, nTails ) );
1672 : }
1673 :
1674 0 : void ScInterpreter::ScTDist_MS()
1675 : {
1676 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
1677 0 : return;
1678 0 : bool bCumulative = GetBool();
1679 0 : double fDF = ::rtl::math::approxFloor( GetDouble() );
1680 0 : double T = GetDouble();
1681 0 : if ( fDF < 1.0 )
1682 : {
1683 0 : PushIllegalArgument();
1684 0 : return;
1685 : }
1686 0 : PushDouble( GetTDist( T, fDF, ( bCumulative ? 4 : 3 ) ) );
1687 : }
1688 :
1689 0 : void ScInterpreter::ScFDist()
1690 : {
1691 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
1692 0 : return;
1693 0 : double fF2 = ::rtl::math::approxFloor(GetDouble());
1694 0 : double fF1 = ::rtl::math::approxFloor(GetDouble());
1695 0 : double fF = GetDouble();
1696 0 : if (fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10)
1697 : {
1698 0 : PushIllegalArgument();
1699 0 : return;
1700 : }
1701 0 : PushDouble(GetFDist(fF, fF1, fF2));
1702 : }
1703 :
1704 0 : void ScInterpreter::ScFDist_LT()
1705 : {
1706 0 : if ( !MustHaveParamCount( GetByte(), 4 ) )
1707 0 : return;
1708 0 : bool bCum = GetBool();
1709 0 : double fF2 = ::rtl::math::approxFloor( GetDouble() );
1710 0 : double fF1 = ::rtl::math::approxFloor( GetDouble() );
1711 0 : double fF = GetDouble();
1712 0 : if ( fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 )
1713 : {
1714 0 : PushIllegalArgument();
1715 0 : return;
1716 : }
1717 0 : if ( bCum )
1718 : {
1719 : // left tail cumulative distribution
1720 0 : PushDouble( 1.0 - GetFDist( fF, fF1, fF2 ) );
1721 : }
1722 : else
1723 : {
1724 : // probability density function
1725 0 : PushDouble( pow( fF1 / fF2, fF1 / 2 ) * pow( fF, ( fF1 / 2 ) - 1 ) /
1726 0 : ( pow( ( 1 + ( fF * fF1 / fF2 ) ), ( fF1 + fF2 ) / 2 ) *
1727 0 : GetBeta( fF1 / 2, fF2 / 2 ) ) );
1728 : }
1729 : }
1730 :
1731 0 : void ScInterpreter::ScChiDist()
1732 : {
1733 : double fResult;
1734 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
1735 0 : return;
1736 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
1737 0 : double fChi = GetDouble();
1738 0 : if (fDF < 1.0) // x<=0 returns 1, see ODFF 6.17.10
1739 : {
1740 0 : PushIllegalArgument();
1741 0 : return;
1742 : }
1743 0 : fResult = GetChiDist( fChi, fDF);
1744 0 : if (nGlobalError)
1745 : {
1746 0 : PushError( nGlobalError);
1747 0 : return;
1748 : }
1749 0 : PushDouble(fResult);
1750 : }
1751 :
1752 0 : void ScInterpreter::ScWeibull()
1753 : {
1754 0 : if ( MustHaveParamCount( GetByte(), 4 ) )
1755 : {
1756 0 : double kum = GetDouble(); // 0 oder 1
1757 0 : double beta = GetDouble(); // beta
1758 0 : double alpha = GetDouble(); // alpha
1759 0 : double x = GetDouble(); // x
1760 0 : if (alpha <= 0.0 || beta <= 0.0 || x < 0.0)
1761 0 : PushIllegalArgument();
1762 0 : else if (kum == 0.0) // Dichte
1763 0 : PushDouble(alpha/pow(beta,alpha)*pow(x,alpha-1.0)*
1764 0 : exp(-pow(x/beta,alpha)));
1765 : else // Verteilung
1766 0 : PushDouble(1.0 - exp(-pow(x/beta,alpha)));
1767 : }
1768 0 : }
1769 :
1770 0 : void ScInterpreter::ScPoissonDist()
1771 : {
1772 0 : sal_uInt8 nParamCount = GetByte();
1773 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
1774 : {
1775 0 : bool bCumulative = (nParamCount == 3 ? GetBool() : true); // default cumulative
1776 0 : double lambda = GetDouble(); // Mean
1777 0 : double x = ::rtl::math::approxFloor(GetDouble()); // discrete distribution
1778 0 : if (lambda < 0.0 || x < 0.0)
1779 0 : PushIllegalArgument();
1780 0 : else if (!bCumulative) // Probability mass function
1781 : {
1782 0 : if (lambda == 0.0)
1783 0 : PushInt(0);
1784 : else
1785 : {
1786 0 : if (lambda >712) // underflow in exp(-lambda)
1787 : { // accuracy 11 Digits
1788 0 : PushDouble( exp(x*log(lambda)-lambda-GetLogGamma(x+1.0)));
1789 : }
1790 : else
1791 : {
1792 0 : double fPoissonVar = 1.0;
1793 0 : for ( double f = 0.0; f < x; ++f )
1794 0 : fPoissonVar *= lambda / ( f + 1.0 );
1795 0 : PushDouble( fPoissonVar * exp( -lambda ) );
1796 : }
1797 : }
1798 : }
1799 : else // Cumulative distribution function
1800 : {
1801 0 : if (lambda == 0.0)
1802 0 : PushInt(1);
1803 : else
1804 : {
1805 0 : if (lambda > 712 ) // underflow in exp(-lambda)
1806 : { // accuracy 12 Digits
1807 0 : PushDouble(GetUpRegIGamma(x+1.0,lambda));
1808 : }
1809 : else
1810 : {
1811 0 : if (x >= 936.0) // result is always undistinghable from 1
1812 0 : PushDouble (1.0);
1813 : else
1814 : {
1815 0 : double fSummand = exp(-lambda);
1816 0 : double fSum = fSummand;
1817 0 : int nEnd = sal::static_int_cast<int>( x );
1818 0 : for (int i = 1; i <= nEnd; i++)
1819 : {
1820 0 : fSummand = (fSummand * lambda)/(double)i;
1821 0 : fSum += fSummand;
1822 : }
1823 0 : PushDouble(fSum);
1824 : }
1825 : }
1826 : }
1827 : }
1828 : }
1829 0 : }
1830 :
1831 : /** Local function used in the calculation of the hypergeometric distribution.
1832 : */
1833 0 : static void lcl_PutFactorialElements( ::std::vector< double >& cn, double fLower, double fUpper, double fBase )
1834 : {
1835 0 : for ( double i = fLower; i <= fUpper; ++i )
1836 : {
1837 0 : double fVal = fBase - i;
1838 0 : if ( fVal > 1.0 )
1839 0 : cn.push_back( fVal );
1840 : }
1841 0 : }
1842 :
1843 : /** Calculates a value of the hypergeometric distribution.
1844 :
1845 : @author Kohei Yoshida <kohei@openoffice.org>
1846 :
1847 : @see #i47296#
1848 :
1849 : */
1850 0 : void ScInterpreter::ScHypGeomDist()
1851 : {
1852 0 : if ( !MustHaveParamCount( GetByte(), 4 ) )
1853 0 : return;
1854 :
1855 0 : double N = ::rtl::math::approxFloor(GetDouble());
1856 0 : double M = ::rtl::math::approxFloor(GetDouble());
1857 0 : double n = ::rtl::math::approxFloor(GetDouble());
1858 0 : double x = ::rtl::math::approxFloor(GetDouble());
1859 :
1860 0 : if( (x < 0.0) || (n < x) || (M < x) || (N < n) || (N < M) || (x < n - N + M) )
1861 : {
1862 0 : PushIllegalArgument();
1863 0 : return;
1864 : }
1865 :
1866 0 : PushDouble( GetHypGeomDist( x, n, M, N ) );
1867 : }
1868 :
1869 : /** Calculates a value of the hypergeometric distribution (Excel 2010 function).
1870 :
1871 : This function has an extra argument bCumulative as compared to ScHypGeomDist(),
1872 : which only calculates the non-cumulative distribution.
1873 :
1874 : @see fdo#71722
1875 : */
1876 0 : void ScInterpreter::ScHypGeomDist_MS()
1877 : {
1878 0 : if ( !MustHaveParamCount( GetByte(), 5 ) )
1879 0 : return;
1880 :
1881 0 : bool bCumulative = GetBool();
1882 0 : double N = ::rtl::math::approxFloor(GetDouble());
1883 0 : double M = ::rtl::math::approxFloor(GetDouble());
1884 0 : double n = ::rtl::math::approxFloor(GetDouble());
1885 0 : double x = ::rtl::math::approxFloor(GetDouble());
1886 :
1887 0 : if( (x < 0.0) || (n < x) || (M < x) || (N < n) || (N < M) || (x < n - N + M) )
1888 : {
1889 0 : PushIllegalArgument();
1890 0 : return;
1891 : }
1892 :
1893 0 : if ( bCumulative )
1894 : {
1895 0 : double fVal = 0.0;
1896 :
1897 0 : for ( int i = 0; i <= x && !nGlobalError; i++ )
1898 0 : fVal += GetHypGeomDist( i, n, M, N );
1899 :
1900 0 : PushDouble( fVal );
1901 : }
1902 : else
1903 0 : PushDouble( GetHypGeomDist( x, n, M, N ) );
1904 : }
1905 :
1906 : /** Calculates a value of the hypergeometric distribution.
1907 :
1908 : The algorithm is designed to avoid unnecessary multiplications and division
1909 : by expanding all factorial elements (9 of them). It is done by excluding
1910 : those ranges that overlap in the numerator and the denominator. This allows
1911 : for a fast calculation for large values which would otherwise cause an overflow
1912 : in the intermediate values.
1913 :
1914 : @author Kohei Yoshida <kohei@openoffice.org>
1915 :
1916 : @see #i47296#
1917 :
1918 : */
1919 0 : double ScInterpreter::GetHypGeomDist( double x, double n, double M, double N )
1920 : {
1921 0 : const size_t nMaxArraySize = 500000; // arbitrary max array size
1922 :
1923 : typedef ::std::vector< double > HypContainer;
1924 0 : HypContainer cnNumer, cnDenom;
1925 :
1926 0 : size_t nEstContainerSize = static_cast<size_t>( x + ::std::min( n, M ) );
1927 0 : size_t nMaxSize = ::std::min( cnNumer.max_size(), nMaxArraySize );
1928 0 : if ( nEstContainerSize > nMaxSize )
1929 : {
1930 0 : PushNoValue();
1931 0 : return 0;
1932 : }
1933 0 : cnNumer.reserve( nEstContainerSize + 10 );
1934 0 : cnDenom.reserve( nEstContainerSize + 10 );
1935 :
1936 : // Trim coefficient C first
1937 0 : double fCNumVarUpper = N - n - M + x - 1.0;
1938 0 : double fCDenomVarLower = 1.0;
1939 0 : if ( N - n - M + x >= M - x + 1.0 )
1940 : {
1941 0 : fCNumVarUpper = M - x - 1.0;
1942 0 : fCDenomVarLower = N - n - 2.0*(M - x) + 1.0;
1943 : }
1944 :
1945 : #if OSL_DEBUG_LEVEL > 0
1946 : double fCNumLower = N - n - fCNumVarUpper;
1947 : #endif
1948 0 : double fCDenomUpper = N - n - M + x + 1.0 - fCDenomVarLower;
1949 :
1950 0 : double fDNumVarLower = n - M;
1951 :
1952 0 : if ( n >= M + 1.0 )
1953 : {
1954 0 : if ( N - M < n + 1.0 )
1955 : {
1956 : // Case 1
1957 :
1958 0 : if ( N - n < n + 1.0 )
1959 : {
1960 : // no overlap
1961 0 : lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1962 0 : lcl_PutFactorialElements( cnDenom, 0.0, N - n - 1.0, N );
1963 : }
1964 : else
1965 : {
1966 : // overlap
1967 : OSL_ENSURE( fCNumLower < n + 1.0, "ScHypGeomDist: wrong assertion" );
1968 0 : lcl_PutFactorialElements( cnNumer, N - 2.0*n, fCNumVarUpper, N - n );
1969 0 : lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
1970 : }
1971 :
1972 : OSL_ENSURE( fCDenomUpper <= N - M, "ScHypGeomDist: wrong assertion" );
1973 :
1974 0 : if ( fCDenomUpper < n - x + 1.0 )
1975 : // no overlap
1976 0 : lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
1977 : else
1978 : {
1979 : // overlap
1980 0 : lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
1981 :
1982 0 : fCDenomUpper = n - x;
1983 0 : fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
1984 : }
1985 : }
1986 : else
1987 : {
1988 : // Case 2
1989 :
1990 0 : if ( n > M - 1.0 )
1991 : {
1992 : // no overlap
1993 0 : lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1994 0 : lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
1995 : }
1996 : else
1997 : {
1998 0 : lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
1999 0 : lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
2000 : }
2001 :
2002 : OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
2003 :
2004 0 : if ( fCDenomUpper < n - x + 1.0 )
2005 : // no overlap
2006 0 : lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - n + x, N - M + 1.0 );
2007 : else
2008 : {
2009 0 : lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
2010 0 : fCDenomUpper = n - x;
2011 0 : fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2012 : }
2013 : }
2014 :
2015 : OSL_ENSURE( fCDenomUpper <= M, "ScHypGeomDist: wrong assertion" );
2016 : }
2017 : else
2018 : {
2019 0 : if ( N - M < M + 1.0 )
2020 : {
2021 : // Case 3
2022 :
2023 0 : if ( N - n < M + 1.0 )
2024 : {
2025 : // No overlap
2026 0 : lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2027 0 : lcl_PutFactorialElements( cnDenom, 0.0, N - M - 1.0, N );
2028 : }
2029 : else
2030 : {
2031 0 : lcl_PutFactorialElements( cnNumer, N - n - M, fCNumVarUpper, N - n );
2032 0 : lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
2033 : }
2034 :
2035 0 : if ( n - x + 1.0 > fCDenomUpper )
2036 : // No overlap
2037 0 : lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
2038 : else
2039 : {
2040 : // Overlap
2041 0 : lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
2042 :
2043 0 : fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2044 0 : fCDenomUpper = n - x;
2045 : }
2046 : }
2047 : else
2048 : {
2049 : // Case 4
2050 :
2051 : OSL_ENSURE( M >= n - x, "ScHypGeomDist: wrong assertion" );
2052 : OSL_ENSURE( M - x <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
2053 :
2054 0 : if ( N - n < N - M + 1.0 )
2055 : {
2056 : // No overlap
2057 0 : lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2058 0 : lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
2059 : }
2060 : else
2061 : {
2062 : // Overlap
2063 : OSL_ENSURE( fCNumLower <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
2064 0 : lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
2065 0 : lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
2066 : }
2067 :
2068 0 : if ( n - x + 1.0 > fCDenomUpper )
2069 : // No overlap
2070 0 : lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - n + x, N - M + 1.0 );
2071 0 : else if ( M >= fCDenomUpper )
2072 : {
2073 0 : lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
2074 :
2075 0 : fCDenomUpper = n - x;
2076 0 : fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2077 : }
2078 : else
2079 : {
2080 : OSL_ENSURE( M <= fCDenomUpper, "ScHypGeomDist: wrong assertion" );
2081 0 : lcl_PutFactorialElements( cnDenom, fCDenomVarLower, N - n - 2.0*M + x,
2082 0 : N - n - M + x + 1.0 );
2083 :
2084 0 : fCDenomUpper = n - x;
2085 0 : fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2086 : }
2087 : }
2088 :
2089 : OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
2090 :
2091 0 : fDNumVarLower = 0.0;
2092 : }
2093 :
2094 0 : double nDNumVarUpper = fCDenomUpper < x + 1.0 ? n - x - 1.0 : n - fCDenomUpper - 1.0;
2095 0 : double nDDenomVarLower = fCDenomUpper < x + 1.0 ? fCDenomVarLower : N - n - M + 1.0;
2096 0 : lcl_PutFactorialElements( cnNumer, fDNumVarLower, nDNumVarUpper, n );
2097 0 : lcl_PutFactorialElements( cnDenom, nDDenomVarLower, N - n - M + x, N - n - M + x + 1.0 );
2098 :
2099 0 : ::std::sort( cnNumer.begin(), cnNumer.end() );
2100 0 : ::std::sort( cnDenom.begin(), cnDenom.end() );
2101 0 : HypContainer::reverse_iterator it1 = cnNumer.rbegin(), it1End = cnNumer.rend();
2102 0 : HypContainer::reverse_iterator it2 = cnDenom.rbegin(), it2End = cnDenom.rend();
2103 :
2104 0 : double fFactor = 1.0;
2105 0 : for ( ; it1 != it1End || it2 != it2End; )
2106 : {
2107 0 : double fEnum = 1.0, fDenom = 1.0;
2108 0 : if ( it1 != it1End )
2109 0 : fEnum = *it1++;
2110 0 : if ( it2 != it2End )
2111 0 : fDenom = *it2++;
2112 0 : fFactor *= fEnum / fDenom;
2113 : }
2114 :
2115 0 : return fFactor;
2116 : }
2117 :
2118 0 : void ScInterpreter::ScGammaDist( int nMinParamCount )
2119 : {
2120 0 : sal_uInt8 nParamCount = GetByte();
2121 0 : if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
2122 0 : return;
2123 : bool bCumulative;
2124 0 : if (nParamCount == 4)
2125 0 : bCumulative = GetBool();
2126 : else
2127 0 : bCumulative = true;
2128 0 : double fBeta = GetDouble(); // scale
2129 0 : double fAlpha = GetDouble(); // shape
2130 0 : double fX = GetDouble(); // x
2131 0 : if (fAlpha <= 0.0 || fBeta <= 0.0)
2132 0 : PushIllegalArgument();
2133 : else
2134 : {
2135 0 : if (bCumulative) // distribution
2136 0 : PushDouble( GetGammaDist( fX, fAlpha, fBeta));
2137 : else // density
2138 0 : PushDouble( GetGammaDistPDF( fX, fAlpha, fBeta));
2139 : }
2140 : }
2141 :
2142 0 : void ScInterpreter::ScNormInv()
2143 : {
2144 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2145 : {
2146 0 : double sigma = GetDouble();
2147 0 : double mue = GetDouble();
2148 0 : double x = GetDouble();
2149 0 : if (sigma <= 0.0 || x < 0.0 || x > 1.0)
2150 0 : PushIllegalArgument();
2151 0 : else if (x == 0.0 || x == 1.0)
2152 0 : PushNoValue();
2153 : else
2154 0 : PushDouble(gaussinv(x)*sigma + mue);
2155 : }
2156 0 : }
2157 :
2158 0 : void ScInterpreter::ScSNormInv()
2159 : {
2160 0 : double x = GetDouble();
2161 0 : if (x < 0.0 || x > 1.0)
2162 0 : PushIllegalArgument();
2163 0 : else if (x == 0.0 || x == 1.0)
2164 0 : PushNoValue();
2165 : else
2166 0 : PushDouble(gaussinv(x));
2167 0 : }
2168 :
2169 0 : void ScInterpreter::ScLogNormInv()
2170 : {
2171 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2172 : {
2173 0 : double sigma = GetDouble(); // Stdabw
2174 0 : double mue = GetDouble(); // Mittelwert
2175 0 : double y = GetDouble(); // y
2176 0 : if (sigma <= 0.0 || y <= 0.0 || y >= 1.0)
2177 0 : PushIllegalArgument();
2178 : else
2179 0 : PushDouble(exp(mue+sigma*gaussinv(y)));
2180 : }
2181 0 : }
2182 :
2183 : class ScGammaDistFunction : public ScDistFunc
2184 : {
2185 : ScInterpreter& rInt;
2186 : double fp, fAlpha, fBeta;
2187 :
2188 : public:
2189 0 : ScGammaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
2190 0 : rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
2191 :
2192 0 : virtual ~ScGammaDistFunction() {}
2193 :
2194 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetGammaDist(x, fAlpha, fBeta); }
2195 : };
2196 :
2197 0 : void ScInterpreter::ScGammaInv()
2198 : {
2199 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
2200 0 : return;
2201 0 : double fBeta = GetDouble();
2202 0 : double fAlpha = GetDouble();
2203 0 : double fP = GetDouble();
2204 0 : if (fAlpha <= 0.0 || fBeta <= 0.0 || fP < 0.0 || fP >= 1.0 )
2205 : {
2206 0 : PushIllegalArgument();
2207 0 : return;
2208 : }
2209 0 : if (fP == 0.0)
2210 0 : PushInt(0);
2211 : else
2212 : {
2213 : bool bConvError;
2214 0 : ScGammaDistFunction aFunc( *this, fP, fAlpha, fBeta );
2215 0 : double fStart = fAlpha * fBeta;
2216 0 : double fVal = lcl_IterateInverse( aFunc, fStart*0.5, fStart, bConvError );
2217 0 : if (bConvError)
2218 0 : SetError(errNoConvergence);
2219 0 : PushDouble(fVal);
2220 : }
2221 : }
2222 :
2223 : class ScBetaDistFunction : public ScDistFunc
2224 : {
2225 : ScInterpreter& rInt;
2226 : double fp, fAlpha, fBeta;
2227 :
2228 : public:
2229 0 : ScBetaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
2230 0 : rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
2231 :
2232 0 : virtual ~ScBetaDistFunction() {}
2233 :
2234 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetBetaDist(x, fAlpha, fBeta); }
2235 : };
2236 :
2237 0 : void ScInterpreter::ScBetaInv()
2238 : {
2239 0 : sal_uInt8 nParamCount = GetByte();
2240 0 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
2241 0 : return;
2242 : double fP, fA, fB, fAlpha, fBeta;
2243 0 : if (nParamCount == 5)
2244 0 : fB = GetDouble();
2245 : else
2246 0 : fB = 1.0;
2247 0 : if (nParamCount >= 4)
2248 0 : fA = GetDouble();
2249 : else
2250 0 : fA = 0.0;
2251 0 : fBeta = GetDouble();
2252 0 : fAlpha = GetDouble();
2253 0 : fP = GetDouble();
2254 0 : if (fP < 0.0 || fP >= 1.0 || fA == fB || fAlpha <= 0.0 || fBeta <= 0.0)
2255 : {
2256 0 : PushIllegalArgument();
2257 0 : return;
2258 : }
2259 0 : if (fP == 0.0)
2260 0 : PushInt(0);
2261 : else
2262 : {
2263 : bool bConvError;
2264 0 : ScBetaDistFunction aFunc( *this, fP, fAlpha, fBeta );
2265 : // 0..1 as range for iteration so it isn't extended beyond the valid range
2266 0 : double fVal = lcl_IterateInverse( aFunc, 0.0, 1.0, bConvError );
2267 0 : if (bConvError)
2268 0 : PushError( errNoConvergence);
2269 : else
2270 0 : PushDouble(fA + fVal*(fB-fA)); // scale to (A,B)
2271 : }
2272 : }
2273 :
2274 : // Achtung: T, F und Chi
2275 : // sind monoton fallend,
2276 : // deshalb 1-Dist als Funktion
2277 :
2278 : class ScTDistFunction : public ScDistFunc
2279 : {
2280 : ScInterpreter& rInt;
2281 : double fp, fDF;
2282 : int nT;
2283 :
2284 : public:
2285 0 : ScTDistFunction( ScInterpreter& rI, double fpVal, double fDFVal, int nType ) :
2286 0 : rInt( rI ), fp( fpVal ), fDF( fDFVal ), nT( nType ) {}
2287 :
2288 0 : virtual ~ScTDistFunction() {}
2289 :
2290 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetTDist( x, fDF, nT ); }
2291 : };
2292 :
2293 0 : void ScInterpreter::ScTInv( int nType )
2294 : {
2295 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
2296 0 : return;
2297 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
2298 0 : double fP = GetDouble();
2299 0 : if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2300 : {
2301 0 : PushIllegalArgument();
2302 0 : return;
2303 : }
2304 0 : if ( nType == 4 ) // left-tailed cumulative t-distribution
2305 : {
2306 0 : if ( fP < 0.5 )
2307 0 : PushDouble( -GetTInv( 1 - fP, fDF, nType ) );
2308 : else
2309 0 : PushDouble( GetTInv( fP, fDF, nType ) );
2310 : }
2311 : else
2312 0 : PushDouble( GetTInv( fP, fDF, nType ) );
2313 : };
2314 :
2315 0 : double ScInterpreter::GetTInv( double fAlpha, double fSize, int nType )
2316 : {
2317 : bool bConvError;
2318 0 : ScTDistFunction aFunc( *this, fAlpha, fSize, nType );
2319 0 : double fVal = lcl_IterateInverse( aFunc, fSize * 0.5, fSize, bConvError );
2320 0 : if (bConvError)
2321 0 : SetError(errNoConvergence);
2322 0 : return( fVal );
2323 : }
2324 :
2325 : class ScFDistFunction : public ScDistFunc
2326 : {
2327 : ScInterpreter& rInt;
2328 : double fp, fF1, fF2;
2329 :
2330 : public:
2331 0 : ScFDistFunction( ScInterpreter& rI, double fpVal, double fF1Val, double fF2Val ) :
2332 0 : rInt(rI), fp(fpVal), fF1(fF1Val), fF2(fF2Val) {}
2333 :
2334 0 : virtual ~ScFDistFunction() {}
2335 :
2336 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetFDist(x, fF1, fF2); }
2337 : };
2338 :
2339 0 : void ScInterpreter::ScFInv()
2340 : {
2341 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
2342 0 : return;
2343 0 : double fF2 = ::rtl::math::approxFloor(GetDouble());
2344 0 : double fF1 = ::rtl::math::approxFloor(GetDouble());
2345 0 : double fP = GetDouble();
2346 0 : if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0)
2347 : {
2348 0 : PushIllegalArgument();
2349 0 : return;
2350 : }
2351 :
2352 : bool bConvError;
2353 0 : ScFDistFunction aFunc( *this, fP, fF1, fF2 );
2354 0 : double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2355 0 : if (bConvError)
2356 0 : SetError(errNoConvergence);
2357 0 : PushDouble(fVal);
2358 : }
2359 :
2360 0 : void ScInterpreter::ScFInv_LT()
2361 : {
2362 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
2363 0 : return;
2364 0 : double fF2 = ::rtl::math::approxFloor(GetDouble());
2365 0 : double fF1 = ::rtl::math::approxFloor(GetDouble());
2366 0 : double fP = GetDouble();
2367 0 : if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0)
2368 : {
2369 0 : PushIllegalArgument();
2370 0 : return;
2371 : }
2372 :
2373 : bool bConvError;
2374 0 : ScFDistFunction aFunc( *this, ( 1.0 - fP ), fF1, fF2 );
2375 0 : double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2376 0 : if (bConvError)
2377 0 : SetError(errNoConvergence);
2378 0 : PushDouble(fVal);
2379 : }
2380 :
2381 : class ScChiDistFunction : public ScDistFunc
2382 : {
2383 : ScInterpreter& rInt;
2384 : double fp, fDF;
2385 :
2386 : public:
2387 0 : ScChiDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
2388 0 : rInt(rI), fp(fpVal), fDF(fDFVal) {}
2389 :
2390 0 : virtual ~ScChiDistFunction() {}
2391 :
2392 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetChiDist(x, fDF); }
2393 : };
2394 :
2395 0 : void ScInterpreter::ScChiInv()
2396 : {
2397 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
2398 0 : return;
2399 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
2400 0 : double fP = GetDouble();
2401 0 : if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2402 : {
2403 0 : PushIllegalArgument();
2404 0 : return;
2405 : }
2406 :
2407 : bool bConvError;
2408 0 : ScChiDistFunction aFunc( *this, fP, fDF );
2409 0 : double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2410 0 : if (bConvError)
2411 0 : SetError(errNoConvergence);
2412 0 : PushDouble(fVal);
2413 : }
2414 :
2415 : /***********************************************/
2416 : class ScChiSqDistFunction : public ScDistFunc
2417 : {
2418 : ScInterpreter& rInt;
2419 : double fp, fDF;
2420 :
2421 : public:
2422 0 : ScChiSqDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
2423 0 : rInt(rI), fp(fpVal), fDF(fDFVal) {}
2424 :
2425 0 : virtual ~ScChiSqDistFunction() {}
2426 :
2427 0 : double GetValue( double x ) const SAL_OVERRIDE { return fp - rInt.GetChiSqDistCDF(x, fDF); }
2428 : };
2429 :
2430 0 : void ScInterpreter::ScChiSqInv()
2431 : {
2432 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
2433 0 : return;
2434 0 : double fDF = ::rtl::math::approxFloor(GetDouble());
2435 0 : double fP = GetDouble();
2436 0 : if (fDF < 1.0 || fP < 0.0 || fP >= 1.0 )
2437 : {
2438 0 : PushIllegalArgument();
2439 0 : return;
2440 : }
2441 :
2442 : bool bConvError;
2443 0 : ScChiSqDistFunction aFunc( *this, fP, fDF );
2444 0 : double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2445 0 : if (bConvError)
2446 0 : SetError(errNoConvergence);
2447 0 : PushDouble(fVal);
2448 : }
2449 :
2450 0 : void ScInterpreter::ScConfidence()
2451 : {
2452 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2453 : {
2454 0 : double n = ::rtl::math::approxFloor(GetDouble());
2455 0 : double sigma = GetDouble();
2456 0 : double alpha = GetDouble();
2457 0 : if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0)
2458 0 : PushIllegalArgument();
2459 : else
2460 0 : PushDouble( gaussinv(1.0-alpha/2.0) * sigma/sqrt(n) );
2461 : }
2462 0 : }
2463 :
2464 0 : void ScInterpreter::ScConfidenceT()
2465 : {
2466 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2467 : {
2468 0 : double n = ::rtl::math::approxFloor(GetDouble());
2469 0 : double sigma = GetDouble();
2470 0 : double alpha = GetDouble();
2471 0 : if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0)
2472 0 : PushIllegalArgument();
2473 : else
2474 0 : PushDouble( sigma * GetTInv( alpha, n - 1, 2 ) / sqrt( n ) );
2475 : }
2476 0 : }
2477 :
2478 0 : void ScInterpreter::ScZTest()
2479 : {
2480 0 : sal_uInt8 nParamCount = GetByte();
2481 0 : if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
2482 0 : return;
2483 0 : double sigma = 0.0, x;
2484 0 : if (nParamCount == 3)
2485 : {
2486 0 : sigma = GetDouble();
2487 0 : if (sigma <= 0.0)
2488 : {
2489 0 : PushIllegalArgument();
2490 0 : return;
2491 : }
2492 : }
2493 0 : x = GetDouble();
2494 :
2495 0 : double fSum = 0.0;
2496 0 : double fSumSqr = 0.0;
2497 : double fVal;
2498 0 : double rValCount = 0.0;
2499 0 : switch (GetStackType())
2500 : {
2501 : case formula::svDouble :
2502 : {
2503 0 : fVal = GetDouble();
2504 0 : fSum += fVal;
2505 0 : fSumSqr += fVal*fVal;
2506 0 : rValCount++;
2507 : }
2508 0 : break;
2509 : case svSingleRef :
2510 : {
2511 0 : ScAddress aAdr;
2512 0 : PopSingleRef( aAdr );
2513 0 : ScRefCellValue aCell;
2514 0 : aCell.assign(*pDok, aAdr);
2515 0 : if (aCell.hasNumeric())
2516 : {
2517 0 : fVal = GetCellValue(aAdr, aCell);
2518 0 : fSum += fVal;
2519 0 : fSumSqr += fVal*fVal;
2520 0 : rValCount++;
2521 0 : }
2522 : }
2523 0 : break;
2524 : case svRefList :
2525 : case formula::svDoubleRef :
2526 : {
2527 0 : short nParam = 1;
2528 0 : size_t nRefInList = 0;
2529 0 : while (nParam-- > 0)
2530 : {
2531 0 : ScRange aRange;
2532 0 : sal_uInt16 nErr = 0;
2533 0 : PopDoubleRef( aRange, nParam, nRefInList);
2534 0 : ScValueIterator aValIter(pDok, aRange, glSubTotal);
2535 0 : if (aValIter.GetFirst(fVal, nErr))
2536 : {
2537 0 : fSum += fVal;
2538 0 : fSumSqr += fVal*fVal;
2539 0 : rValCount++;
2540 0 : while ((nErr == 0) && aValIter.GetNext(fVal, nErr))
2541 : {
2542 0 : fSum += fVal;
2543 0 : fSumSqr += fVal*fVal;
2544 0 : rValCount++;
2545 : }
2546 0 : SetError(nErr);
2547 : }
2548 : }
2549 : }
2550 0 : break;
2551 : case svMatrix :
2552 : case svExternalSingleRef:
2553 : case svExternalDoubleRef:
2554 : {
2555 0 : ScMatrixRef pMat = GetMatrix();
2556 0 : if (pMat)
2557 : {
2558 0 : SCSIZE nCount = pMat->GetElementCount();
2559 0 : if (pMat->IsNumeric())
2560 : {
2561 0 : for ( SCSIZE i = 0; i < nCount; i++ )
2562 : {
2563 0 : fVal= pMat->GetDouble(i);
2564 0 : fSum += fVal;
2565 0 : fSumSqr += fVal * fVal;
2566 0 : rValCount++;
2567 : }
2568 : }
2569 : else
2570 : {
2571 0 : for (SCSIZE i = 0; i < nCount; i++)
2572 0 : if (!pMat->IsString(i))
2573 : {
2574 0 : fVal= pMat->GetDouble(i);
2575 0 : fSum += fVal;
2576 0 : fSumSqr += fVal * fVal;
2577 0 : rValCount++;
2578 : }
2579 : }
2580 0 : }
2581 : }
2582 0 : break;
2583 0 : default : SetError(errIllegalParameter); break;
2584 : }
2585 0 : if (rValCount <= 1.0)
2586 0 : PushError( errDivisionByZero);
2587 : else
2588 : {
2589 0 : double mue = fSum/rValCount;
2590 :
2591 0 : if (nParamCount != 3)
2592 : {
2593 0 : sigma = (fSumSqr - fSum*fSum/rValCount)/(rValCount-1.0);
2594 0 : PushDouble(0.5 - gauss((mue-x)/sqrt(sigma/rValCount)));
2595 : }
2596 : else
2597 0 : PushDouble(0.5 - gauss((mue-x)*sqrt(rValCount)/sigma));
2598 : }
2599 : }
2600 :
2601 0 : bool ScInterpreter::CalculateTest(bool _bTemplin
2602 : ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
2603 : ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
2604 : ,double& fT,double& fF)
2605 : {
2606 0 : double fCount1 = 0.0;
2607 0 : double fCount2 = 0.0;
2608 0 : double fSum1 = 0.0;
2609 0 : double fSumSqr1 = 0.0;
2610 0 : double fSum2 = 0.0;
2611 0 : double fSumSqr2 = 0.0;
2612 : double fVal;
2613 : SCSIZE i,j;
2614 0 : for (i = 0; i < nC1; i++)
2615 0 : for (j = 0; j < nR1; j++)
2616 : {
2617 0 : if (!pMat1->IsString(i,j))
2618 : {
2619 0 : fVal = pMat1->GetDouble(i,j);
2620 0 : fSum1 += fVal;
2621 0 : fSumSqr1 += fVal * fVal;
2622 0 : fCount1++;
2623 : }
2624 : }
2625 0 : for (i = 0; i < nC2; i++)
2626 0 : for (j = 0; j < nR2; j++)
2627 : {
2628 0 : if (!pMat2->IsString(i,j))
2629 : {
2630 0 : fVal = pMat2->GetDouble(i,j);
2631 0 : fSum2 += fVal;
2632 0 : fSumSqr2 += fVal * fVal;
2633 0 : fCount2++;
2634 : }
2635 : }
2636 0 : if (fCount1 < 2.0 || fCount2 < 2.0)
2637 : {
2638 0 : PushNoValue();
2639 0 : return false;
2640 : } // if (fCount1 < 2.0 || fCount2 < 2.0)
2641 0 : if ( _bTemplin )
2642 : {
2643 0 : double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0)/fCount1;
2644 0 : double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0)/fCount2;
2645 0 : if (fS1 + fS2 == 0.0)
2646 : {
2647 0 : PushNoValue();
2648 0 : return false;
2649 : }
2650 0 : fT = fabs(fSum1/fCount1 - fSum2/fCount2)/sqrt(fS1+fS2);
2651 0 : double c = fS1/(fS1+fS2);
2652 : // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen
2653 : // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#):
2654 0 : fF = 1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0));
2655 : }
2656 : else
2657 : {
2658 : // laut Bronstein-Semendjajew
2659 0 : double fS1 = (fSumSqr1 - fSum1*fSum1/fCount1) / (fCount1 - 1.0); // Varianz
2660 0 : double fS2 = (fSumSqr2 - fSum2*fSum2/fCount2) / (fCount2 - 1.0);
2661 0 : fT = fabs( fSum1/fCount1 - fSum2/fCount2 ) /
2662 0 : sqrt( (fCount1-1.0)*fS1 + (fCount2-1.0)*fS2 ) *
2663 0 : sqrt( fCount1*fCount2*(fCount1+fCount2-2)/(fCount1+fCount2) );
2664 0 : fF = fCount1 + fCount2 - 2;
2665 : }
2666 0 : return true;
2667 : }
2668 0 : void ScInterpreter::ScTTest()
2669 : {
2670 0 : if ( !MustHaveParamCount( GetByte(), 4 ) )
2671 0 : return;
2672 0 : double fTyp = ::rtl::math::approxFloor(GetDouble());
2673 0 : double fTails = ::rtl::math::approxFloor(GetDouble());
2674 0 : if (fTails != 1.0 && fTails != 2.0)
2675 : {
2676 0 : PushIllegalArgument();
2677 0 : return;
2678 : }
2679 :
2680 0 : ScMatrixRef pMat2 = GetMatrix();
2681 0 : ScMatrixRef pMat1 = GetMatrix();
2682 0 : if (!pMat1 || !pMat2)
2683 : {
2684 0 : PushIllegalParameter();
2685 0 : return;
2686 : }
2687 : double fT, fF;
2688 : SCSIZE nC1, nC2;
2689 : SCSIZE nR1, nR2;
2690 : SCSIZE i, j;
2691 0 : pMat1->GetDimensions(nC1, nR1);
2692 0 : pMat2->GetDimensions(nC2, nR2);
2693 0 : if (fTyp == 1.0)
2694 : {
2695 0 : if (nC1 != nC2 || nR1 != nR2)
2696 : {
2697 0 : PushIllegalArgument();
2698 0 : return;
2699 : }
2700 0 : double fCount = 0.0;
2701 0 : double fSum1 = 0.0;
2702 0 : double fSum2 = 0.0;
2703 0 : double fSumSqrD = 0.0;
2704 : double fVal1, fVal2;
2705 0 : for (i = 0; i < nC1; i++)
2706 0 : for (j = 0; j < nR1; j++)
2707 : {
2708 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
2709 : {
2710 0 : fVal1 = pMat1->GetDouble(i,j);
2711 0 : fVal2 = pMat2->GetDouble(i,j);
2712 0 : fSum1 += fVal1;
2713 0 : fSum2 += fVal2;
2714 0 : fSumSqrD += (fVal1 - fVal2)*(fVal1 - fVal2);
2715 0 : fCount++;
2716 : }
2717 : }
2718 0 : if (fCount < 1.0)
2719 : {
2720 0 : PushNoValue();
2721 0 : return;
2722 : }
2723 0 : fT = sqrt(fCount-1.0) * fabs(fSum1 - fSum2) /
2724 0 : sqrt(fCount * fSumSqrD - (fSum1-fSum2)*(fSum1-fSum2));
2725 0 : fF = fCount - 1.0;
2726 : }
2727 0 : else if (fTyp == 2.0)
2728 : {
2729 0 : CalculateTest(false,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF);
2730 : }
2731 0 : else if (fTyp == 3.0)
2732 : {
2733 0 : CalculateTest(true,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF);
2734 : }
2735 :
2736 : else
2737 : {
2738 0 : PushIllegalArgument();
2739 0 : return;
2740 : }
2741 0 : PushDouble( GetTDist( fT, fF, ( int )fTails ) );
2742 : }
2743 :
2744 0 : void ScInterpreter::ScFTest()
2745 : {
2746 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
2747 0 : return;
2748 0 : ScMatrixRef pMat2 = GetMatrix();
2749 0 : ScMatrixRef pMat1 = GetMatrix();
2750 0 : if (!pMat1 || !pMat2)
2751 : {
2752 0 : PushIllegalParameter();
2753 0 : return;
2754 : }
2755 : SCSIZE nC1, nC2;
2756 : SCSIZE nR1, nR2;
2757 : SCSIZE i, j;
2758 0 : pMat1->GetDimensions(nC1, nR1);
2759 0 : pMat2->GetDimensions(nC2, nR2);
2760 0 : double fCount1 = 0.0;
2761 0 : double fCount2 = 0.0;
2762 0 : double fSum1 = 0.0;
2763 0 : double fSumSqr1 = 0.0;
2764 0 : double fSum2 = 0.0;
2765 0 : double fSumSqr2 = 0.0;
2766 : double fVal;
2767 0 : for (i = 0; i < nC1; i++)
2768 0 : for (j = 0; j < nR1; j++)
2769 : {
2770 0 : if (!pMat1->IsString(i,j))
2771 : {
2772 0 : fVal = pMat1->GetDouble(i,j);
2773 0 : fSum1 += fVal;
2774 0 : fSumSqr1 += fVal * fVal;
2775 0 : fCount1++;
2776 : }
2777 : }
2778 0 : for (i = 0; i < nC2; i++)
2779 0 : for (j = 0; j < nR2; j++)
2780 : {
2781 0 : if (!pMat2->IsString(i,j))
2782 : {
2783 0 : fVal = pMat2->GetDouble(i,j);
2784 0 : fSum2 += fVal;
2785 0 : fSumSqr2 += fVal * fVal;
2786 0 : fCount2++;
2787 : }
2788 : }
2789 0 : if (fCount1 < 2.0 || fCount2 < 2.0)
2790 : {
2791 0 : PushNoValue();
2792 0 : return;
2793 : }
2794 0 : double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0);
2795 0 : double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0);
2796 0 : if (fS1 == 0.0 || fS2 == 0.0)
2797 : {
2798 0 : PushNoValue();
2799 0 : return;
2800 : }
2801 : double fF, fF1, fF2;
2802 0 : if (fS1 > fS2)
2803 : {
2804 0 : fF = fS1/fS2;
2805 0 : fF1 = fCount1-1.0;
2806 0 : fF2 = fCount2-1.0;
2807 : }
2808 : else
2809 : {
2810 0 : fF = fS2/fS1;
2811 0 : fF1 = fCount2-1.0;
2812 0 : fF2 = fCount1-1.0;
2813 : }
2814 0 : PushDouble(2.0*GetFDist(fF, fF1, fF2));
2815 : }
2816 :
2817 0 : void ScInterpreter::ScChiTest()
2818 : {
2819 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
2820 0 : return;
2821 0 : ScMatrixRef pMat2 = GetMatrix();
2822 0 : ScMatrixRef pMat1 = GetMatrix();
2823 0 : if (!pMat1 || !pMat2)
2824 : {
2825 0 : PushIllegalParameter();
2826 0 : return;
2827 : }
2828 : SCSIZE nC1, nC2;
2829 : SCSIZE nR1, nR2;
2830 0 : pMat1->GetDimensions(nC1, nR1);
2831 0 : pMat2->GetDimensions(nC2, nR2);
2832 0 : if (nR1 != nR2 || nC1 != nC2)
2833 : {
2834 0 : PushIllegalArgument();
2835 0 : return;
2836 : }
2837 0 : double fChi = 0.0;
2838 0 : for (SCSIZE i = 0; i < nC1; i++)
2839 : {
2840 0 : for (SCSIZE j = 0; j < nR1; j++)
2841 : {
2842 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
2843 : {
2844 0 : double fValX = pMat1->GetDouble(i,j);
2845 0 : double fValE = pMat2->GetDouble(i,j);
2846 0 : fChi += (fValX - fValE) * (fValX - fValE) / fValE;
2847 : }
2848 : else
2849 : {
2850 0 : PushIllegalArgument();
2851 0 : return;
2852 : }
2853 : }
2854 : }
2855 : double fDF;
2856 0 : if (nC1 == 1 || nR1 == 1)
2857 : {
2858 0 : fDF = (double)(nC1*nR1 - 1);
2859 0 : if (fDF == 0.0)
2860 : {
2861 0 : PushNoValue();
2862 0 : return;
2863 : }
2864 : }
2865 : else
2866 0 : fDF = (double)(nC1-1)*(double)(nR1-1);
2867 0 : PushDouble(GetChiDist(fChi, fDF));
2868 : }
2869 :
2870 0 : void ScInterpreter::ScKurt()
2871 : {
2872 : double fSum,fCount,vSum;
2873 0 : std::vector<double> values;
2874 0 : if ( !CalculateSkew(fSum,fCount,vSum,values) )
2875 0 : return;
2876 :
2877 0 : if (fCount == 0.0)
2878 : {
2879 0 : PushError( errDivisionByZero);
2880 0 : return;
2881 : }
2882 :
2883 0 : double fMean = fSum / fCount;
2884 :
2885 0 : for (size_t i = 0; i < values.size(); i++)
2886 0 : vSum += (values[i] - fMean) * (values[i] - fMean);
2887 :
2888 0 : double fStdDev = sqrt(vSum / (fCount - 1.0));
2889 0 : double dx = 0.0;
2890 0 : double xpower4 = 0.0;
2891 :
2892 0 : if (fStdDev == 0.0)
2893 : {
2894 0 : PushError( errDivisionByZero);
2895 0 : return;
2896 : }
2897 :
2898 0 : for (size_t i = 0; i < values.size(); i++)
2899 : {
2900 0 : dx = (values[i] - fMean) / fStdDev;
2901 0 : xpower4 = xpower4 + (dx * dx * dx * dx);
2902 : }
2903 :
2904 0 : double k_d = (fCount - 2.0) * (fCount - 3.0);
2905 0 : double k_l = fCount * (fCount + 1.0) / ((fCount - 1.0) * k_d);
2906 0 : double k_t = 3.0 * (fCount - 1.0) * (fCount - 1.0) / k_d;
2907 :
2908 0 : PushDouble(xpower4 * k_l - k_t);
2909 : }
2910 :
2911 0 : void ScInterpreter::ScHarMean()
2912 : {
2913 0 : short nParamCount = GetByte();
2914 0 : double nVal = 0.0;
2915 0 : double nValCount = 0.0;
2916 0 : ScAddress aAdr;
2917 0 : ScRange aRange;
2918 0 : size_t nRefInList = 0;
2919 0 : while ((nGlobalError == 0) && (nParamCount-- > 0))
2920 : {
2921 0 : switch (GetStackType())
2922 : {
2923 : case formula::svDouble :
2924 : {
2925 0 : double x = GetDouble();
2926 0 : if (x > 0.0)
2927 : {
2928 0 : nVal += 1.0/x;
2929 0 : nValCount++;
2930 : }
2931 : else
2932 0 : SetError( errIllegalArgument);
2933 0 : break;
2934 : }
2935 : case svSingleRef :
2936 : {
2937 0 : PopSingleRef( aAdr );
2938 0 : ScRefCellValue aCell;
2939 0 : aCell.assign(*pDok, aAdr);
2940 0 : if (aCell.hasNumeric())
2941 : {
2942 0 : double x = GetCellValue(aAdr, aCell);
2943 0 : if (x > 0.0)
2944 : {
2945 0 : nVal += 1.0/x;
2946 0 : nValCount++;
2947 : }
2948 : else
2949 0 : SetError( errIllegalArgument);
2950 : }
2951 0 : break;
2952 : }
2953 : case formula::svDoubleRef :
2954 : case svRefList :
2955 : {
2956 0 : sal_uInt16 nErr = 0;
2957 0 : PopDoubleRef( aRange, nParamCount, nRefInList);
2958 : double nCellVal;
2959 0 : ScValueIterator aValIter(pDok, aRange, glSubTotal);
2960 0 : if (aValIter.GetFirst(nCellVal, nErr))
2961 : {
2962 0 : if (nCellVal > 0.0)
2963 : {
2964 0 : nVal += 1.0/nCellVal;
2965 0 : nValCount++;
2966 : }
2967 : else
2968 0 : SetError( errIllegalArgument);
2969 0 : SetError(nErr);
2970 0 : while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
2971 : {
2972 0 : if (nCellVal > 0.0)
2973 : {
2974 0 : nVal += 1.0/nCellVal;
2975 0 : nValCount++;
2976 : }
2977 : else
2978 0 : SetError( errIllegalArgument);
2979 : }
2980 0 : SetError(nErr);
2981 : }
2982 : }
2983 0 : break;
2984 : case svMatrix :
2985 : case svExternalSingleRef:
2986 : case svExternalDoubleRef:
2987 : {
2988 0 : ScMatrixRef pMat = GetMatrix();
2989 0 : if (pMat)
2990 : {
2991 0 : SCSIZE nCount = pMat->GetElementCount();
2992 0 : if (pMat->IsNumeric())
2993 : {
2994 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
2995 : {
2996 0 : double x = pMat->GetDouble(nElem);
2997 0 : if (x > 0.0)
2998 : {
2999 0 : nVal += 1.0/x;
3000 0 : nValCount++;
3001 : }
3002 : else
3003 0 : SetError( errIllegalArgument);
3004 : }
3005 : }
3006 : else
3007 : {
3008 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3009 0 : if (!pMat->IsString(nElem))
3010 : {
3011 0 : double x = pMat->GetDouble(nElem);
3012 0 : if (x > 0.0)
3013 : {
3014 0 : nVal += 1.0/x;
3015 0 : nValCount++;
3016 : }
3017 : else
3018 0 : SetError( errIllegalArgument);
3019 : }
3020 : }
3021 0 : }
3022 : }
3023 0 : break;
3024 0 : default : SetError(errIllegalParameter); break;
3025 : }
3026 : }
3027 0 : if (nGlobalError == 0)
3028 0 : PushDouble((double)nValCount/nVal);
3029 : else
3030 0 : PushError( nGlobalError);
3031 0 : }
3032 :
3033 0 : void ScInterpreter::ScGeoMean()
3034 : {
3035 0 : short nParamCount = GetByte();
3036 0 : double nVal = 0.0;
3037 0 : double nValCount = 0.0;
3038 0 : ScAddress aAdr;
3039 0 : ScRange aRange;
3040 :
3041 0 : size_t nRefInList = 0;
3042 0 : while ((nGlobalError == 0) && (nParamCount-- > 0))
3043 : {
3044 0 : switch (GetStackType())
3045 : {
3046 : case formula::svDouble :
3047 : {
3048 0 : double x = GetDouble();
3049 0 : if (x > 0.0)
3050 : {
3051 0 : nVal += log(x);
3052 0 : nValCount++;
3053 : }
3054 : else
3055 0 : SetError( errIllegalArgument);
3056 0 : break;
3057 : }
3058 : case svSingleRef :
3059 : {
3060 0 : PopSingleRef( aAdr );
3061 0 : ScRefCellValue aCell;
3062 0 : aCell.assign(*pDok, aAdr);
3063 0 : if (aCell.hasNumeric())
3064 : {
3065 0 : double x = GetCellValue(aAdr, aCell);
3066 0 : if (x > 0.0)
3067 : {
3068 0 : nVal += log(x);
3069 0 : nValCount++;
3070 : }
3071 : else
3072 0 : SetError( errIllegalArgument);
3073 : }
3074 0 : break;
3075 : }
3076 : case formula::svDoubleRef :
3077 : case svRefList :
3078 : {
3079 0 : sal_uInt16 nErr = 0;
3080 0 : PopDoubleRef( aRange, nParamCount, nRefInList);
3081 : double nCellVal;
3082 0 : ScValueIterator aValIter(pDok, aRange, glSubTotal);
3083 0 : if (aValIter.GetFirst(nCellVal, nErr))
3084 : {
3085 0 : if (nCellVal > 0.0)
3086 : {
3087 0 : nVal += log(nCellVal);
3088 0 : nValCount++;
3089 : }
3090 : else
3091 0 : SetError( errIllegalArgument);
3092 0 : SetError(nErr);
3093 0 : while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
3094 : {
3095 0 : if (nCellVal > 0.0)
3096 : {
3097 0 : nVal += log(nCellVal);
3098 0 : nValCount++;
3099 : }
3100 : else
3101 0 : SetError( errIllegalArgument);
3102 : }
3103 0 : SetError(nErr);
3104 : }
3105 : }
3106 0 : break;
3107 : case svMatrix :
3108 : case svExternalSingleRef:
3109 : case svExternalDoubleRef:
3110 : {
3111 0 : ScMatrixRef pMat = GetMatrix();
3112 0 : if (pMat)
3113 : {
3114 0 : SCSIZE nCount = pMat->GetElementCount();
3115 0 : if (pMat->IsNumeric())
3116 : {
3117 0 : for (SCSIZE ui = 0; ui < nCount; ui++)
3118 : {
3119 0 : double x = pMat->GetDouble(ui);
3120 0 : if (x > 0.0)
3121 : {
3122 0 : nVal += log(x);
3123 0 : nValCount++;
3124 : }
3125 : else
3126 0 : SetError( errIllegalArgument);
3127 : }
3128 : }
3129 : else
3130 : {
3131 0 : for (SCSIZE ui = 0; ui < nCount; ui++)
3132 0 : if (!pMat->IsString(ui))
3133 : {
3134 0 : double x = pMat->GetDouble(ui);
3135 0 : if (x > 0.0)
3136 : {
3137 0 : nVal += log(x);
3138 0 : nValCount++;
3139 : }
3140 : else
3141 0 : SetError( errIllegalArgument);
3142 : }
3143 : }
3144 0 : }
3145 : }
3146 0 : break;
3147 0 : default : SetError(errIllegalParameter); break;
3148 : }
3149 : }
3150 0 : if (nGlobalError == 0)
3151 0 : PushDouble(exp(nVal / nValCount));
3152 : else
3153 0 : PushError( nGlobalError);
3154 0 : }
3155 :
3156 0 : void ScInterpreter::ScStandard()
3157 : {
3158 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
3159 : {
3160 0 : double sigma = GetDouble();
3161 0 : double mue = GetDouble();
3162 0 : double x = GetDouble();
3163 0 : if (sigma < 0.0)
3164 0 : PushError( errIllegalArgument);
3165 0 : else if (sigma == 0.0)
3166 0 : PushError( errDivisionByZero);
3167 : else
3168 0 : PushDouble((x-mue)/sigma);
3169 : }
3170 0 : }
3171 0 : bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::vector<double>& values)
3172 : {
3173 0 : short nParamCount = GetByte();
3174 0 : if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3175 0 : return false;
3176 :
3177 0 : fSum = 0.0;
3178 0 : fCount = 0.0;
3179 0 : vSum = 0.0;
3180 0 : double fVal = 0.0;
3181 0 : ScAddress aAdr;
3182 0 : ScRange aRange;
3183 0 : size_t nRefInList = 0;
3184 0 : while (nParamCount-- > 0)
3185 : {
3186 0 : switch (GetStackType())
3187 : {
3188 : case formula::svDouble :
3189 : {
3190 0 : fVal = GetDouble();
3191 0 : fSum += fVal;
3192 0 : values.push_back(fVal);
3193 0 : fCount++;
3194 : }
3195 0 : break;
3196 : case svSingleRef :
3197 : {
3198 0 : PopSingleRef( aAdr );
3199 0 : ScRefCellValue aCell;
3200 0 : aCell.assign(*pDok, aAdr);
3201 0 : if (aCell.hasNumeric())
3202 : {
3203 0 : fVal = GetCellValue(aAdr, aCell);
3204 0 : fSum += fVal;
3205 0 : values.push_back(fVal);
3206 0 : fCount++;
3207 0 : }
3208 : }
3209 0 : break;
3210 : case formula::svDoubleRef :
3211 : case svRefList :
3212 : {
3213 0 : PopDoubleRef( aRange, nParamCount, nRefInList);
3214 0 : sal_uInt16 nErr = 0;
3215 0 : ScValueIterator aValIter(pDok, aRange);
3216 0 : if (aValIter.GetFirst(fVal, nErr))
3217 : {
3218 0 : fSum += fVal;
3219 0 : values.push_back(fVal);
3220 0 : fCount++;
3221 0 : SetError(nErr);
3222 0 : while ((nErr == 0) && aValIter.GetNext(fVal, nErr))
3223 : {
3224 0 : fSum += fVal;
3225 0 : values.push_back(fVal);
3226 0 : fCount++;
3227 : }
3228 0 : SetError(nErr);
3229 : }
3230 : }
3231 0 : break;
3232 : case svMatrix :
3233 : case svExternalSingleRef:
3234 : case svExternalDoubleRef:
3235 : {
3236 0 : ScMatrixRef pMat = GetMatrix();
3237 0 : if (pMat)
3238 : {
3239 0 : SCSIZE nCount = pMat->GetElementCount();
3240 0 : if (pMat->IsNumeric())
3241 : {
3242 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3243 : {
3244 0 : fVal = pMat->GetDouble(nElem);
3245 0 : fSum += fVal;
3246 0 : values.push_back(fVal);
3247 0 : fCount++;
3248 : }
3249 : }
3250 : else
3251 : {
3252 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3253 0 : if (!pMat->IsString(nElem))
3254 : {
3255 0 : fVal = pMat->GetDouble(nElem);
3256 0 : fSum += fVal;
3257 0 : values.push_back(fVal);
3258 0 : fCount++;
3259 : }
3260 : }
3261 0 : }
3262 : }
3263 0 : break;
3264 : default :
3265 0 : SetError(errIllegalParameter);
3266 0 : break;
3267 : }
3268 : }
3269 :
3270 0 : if (nGlobalError)
3271 : {
3272 0 : PushError( nGlobalError);
3273 0 : return false;
3274 : } // if (nGlobalError)
3275 0 : return true;
3276 : }
3277 :
3278 0 : void ScInterpreter::CalculateSkewOrSkewp( bool bSkewp )
3279 : {
3280 : double fSum, fCount, vSum;
3281 0 : std::vector<double> values;
3282 0 : if (!CalculateSkew( fSum, fCount, vSum, values))
3283 0 : return;
3284 :
3285 0 : double fMean = fSum / fCount;
3286 :
3287 0 : for (size_t i = 0; i < values.size(); ++i)
3288 0 : vSum += (values[i] - fMean) * (values[i] - fMean);
3289 :
3290 0 : double fStdDev = sqrt( vSum / (bSkewp ? fCount : (fCount - 1.0)));
3291 0 : double dx = 0.0;
3292 0 : double xcube = 0.0;
3293 :
3294 0 : if (fStdDev == 0)
3295 : {
3296 0 : PushIllegalArgument();
3297 0 : return;
3298 : }
3299 :
3300 0 : for (size_t i = 0; i < values.size(); ++i)
3301 : {
3302 0 : dx = (values[i] - fMean) / fStdDev;
3303 0 : xcube = xcube + (dx * dx * dx);
3304 : }
3305 :
3306 0 : if (bSkewp)
3307 0 : PushDouble( xcube / fCount );
3308 : else
3309 0 : PushDouble( ((xcube * fCount) / (fCount - 1.0)) / (fCount - 2.0) );
3310 : }
3311 :
3312 0 : void ScInterpreter::ScSkew()
3313 : {
3314 0 : CalculateSkewOrSkewp( false );
3315 0 : }
3316 :
3317 0 : void ScInterpreter::ScSkewp()
3318 : {
3319 0 : CalculateSkewOrSkewp( true );
3320 0 : }
3321 :
3322 0 : double ScInterpreter::GetMedian( vector<double> & rArray )
3323 : {
3324 0 : size_t nSize = rArray.size();
3325 0 : if (rArray.empty() || nSize == 0 || nGlobalError)
3326 : {
3327 0 : SetError( errNoValue);
3328 0 : return 0.0;
3329 : }
3330 :
3331 : // Upper median.
3332 0 : size_t nMid = nSize / 2;
3333 0 : vector<double>::iterator iMid = rArray.begin() + nMid;
3334 0 : ::std::nth_element( rArray.begin(), iMid, rArray.end());
3335 0 : if (nSize & 1)
3336 0 : return *iMid; // Lower and upper median are equal.
3337 : else
3338 : {
3339 0 : double fUp = *iMid;
3340 : // Lower median.
3341 0 : iMid = rArray.begin() + nMid - 1;
3342 0 : ::std::nth_element( rArray.begin(), iMid, rArray.end());
3343 0 : return (fUp + *iMid) / 2;
3344 : }
3345 : }
3346 :
3347 0 : void ScInterpreter::ScMedian()
3348 : {
3349 0 : sal_uInt8 nParamCount = GetByte();
3350 0 : if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3351 0 : return;
3352 0 : vector<double> aArray;
3353 0 : GetNumberSequenceArray( nParamCount, aArray);
3354 0 : PushDouble( GetMedian( aArray));
3355 : }
3356 :
3357 0 : double ScInterpreter::GetPercentile( vector<double> & rArray, double fPercentile )
3358 : {
3359 0 : size_t nSize = rArray.size();
3360 0 : if (rArray.empty() || nSize == 0 || nGlobalError)
3361 : {
3362 0 : SetError( errNoValue);
3363 0 : return 0.0;
3364 : }
3365 :
3366 0 : if (nSize == 1)
3367 0 : return rArray[0];
3368 : else
3369 : {
3370 0 : size_t nIndex = (size_t)::rtl::math::approxFloor( fPercentile * (nSize-1));
3371 0 : double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1));
3372 : OSL_ENSURE(nIndex < nSize, "GetPercentile: wrong index(1)");
3373 0 : vector<double>::iterator iter = rArray.begin() + nIndex;
3374 0 : ::std::nth_element( rArray.begin(), iter, rArray.end());
3375 0 : if (fDiff == 0.0)
3376 0 : return *iter;
3377 : else
3378 : {
3379 : OSL_ENSURE(nIndex < nSize-1, "GetPercentile: wrong index(2)");
3380 0 : double fVal = *iter;
3381 0 : iter = rArray.begin() + nIndex+1;
3382 0 : ::std::nth_element( rArray.begin(), iter, rArray.end());
3383 0 : return fVal + fDiff * (*iter - fVal);
3384 : }
3385 : }
3386 : }
3387 :
3388 0 : double ScInterpreter::GetPercentileExclusive( vector<double> & rArray, double fPercentile )
3389 : {
3390 0 : size_t nSize1 = rArray.size() + 1;
3391 0 : if ( rArray.empty() || nSize1 == 1 || nGlobalError )
3392 : {
3393 0 : SetError( errNoValue );
3394 0 : return 0.0;
3395 : }
3396 0 : if ( fPercentile * nSize1 < 1.0 || fPercentile * nSize1 > (double) ( nSize1 - 1 ) )
3397 : {
3398 0 : SetError( errIllegalParameter );
3399 0 : return 0.0;
3400 : }
3401 :
3402 0 : size_t nIndex = (size_t)::rtl::math::approxFloor( fPercentile * nSize1 - 1 );
3403 0 : double fDiff = fPercentile * nSize1 - 1 - ::rtl::math::approxFloor( fPercentile * nSize1 - 1 );
3404 : OSL_ENSURE(nIndex < ( nSize1 - 1 ), "GetPercentile: wrong index(1)");
3405 0 : vector<double>::iterator iter = rArray.begin() + nIndex;
3406 0 : ::std::nth_element( rArray.begin(), iter, rArray.end());
3407 0 : if (fDiff == 0.0)
3408 0 : return *iter;
3409 : else
3410 : {
3411 : OSL_ENSURE(nIndex < nSize1, "GetPercentile: wrong index(2)");
3412 0 : double fVal = *iter;
3413 0 : iter = rArray.begin() + nIndex + 1;
3414 0 : ::std::nth_element( rArray.begin(), iter, rArray.end());
3415 0 : return fVal + fDiff * (*iter - fVal);
3416 : }
3417 : }
3418 :
3419 0 : void ScInterpreter::ScPercentile( bool bInclusive )
3420 : {
3421 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
3422 0 : return;
3423 0 : double alpha = GetDouble();
3424 0 : if ( bInclusive ? ( alpha < 0.0 || alpha > 1.0 ) : ( alpha <= 0.0 || alpha >= 1.0 ) )
3425 : {
3426 0 : PushIllegalArgument();
3427 0 : return;
3428 : }
3429 0 : vector<double> aArray;
3430 0 : GetNumberSequenceArray( 1, aArray);
3431 0 : if ( bInclusive )
3432 0 : PushDouble( GetPercentile( aArray, alpha ));
3433 : else
3434 0 : PushDouble( GetPercentileExclusive( aArray, alpha ));
3435 : }
3436 :
3437 0 : void ScInterpreter::ScQuartile( bool bInclusive )
3438 : {
3439 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
3440 0 : return;
3441 0 : double fFlag = ::rtl::math::approxFloor(GetDouble());
3442 0 : if ( bInclusive ? ( fFlag < 0.0 || fFlag > 4.0 ) : ( fFlag <= 0.0 || fFlag >= 4.0 ) )
3443 : {
3444 0 : PushIllegalArgument();
3445 0 : return;
3446 : }
3447 0 : vector<double> aArray;
3448 0 : GetNumberSequenceArray( 1, aArray);
3449 0 : if ( bInclusive )
3450 0 : PushDouble( fFlag == 2.0 ? GetMedian( aArray ) : GetPercentile( aArray, 0.25 * fFlag ) );
3451 : else
3452 0 : PushDouble( fFlag == 2.0 ? GetMedian( aArray ) : GetPercentileExclusive( aArray, 0.25 * fFlag ) );
3453 : }
3454 :
3455 0 : void ScInterpreter::ScModalValue()
3456 : {
3457 0 : sal_uInt8 nParamCount = GetByte();
3458 0 : if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3459 0 : return;
3460 0 : vector<double> aSortArray;
3461 0 : GetSortArray(nParamCount, aSortArray);
3462 0 : SCSIZE nSize = aSortArray.size();
3463 0 : if (aSortArray.empty() || nSize == 0 || nGlobalError)
3464 0 : PushNoValue();
3465 : else
3466 : {
3467 0 : SCSIZE nMaxIndex = 0, nMax = 1, nCount = 1;
3468 0 : double nOldVal = aSortArray[0];
3469 : SCSIZE i;
3470 :
3471 0 : for ( i = 1; i < nSize; i++)
3472 : {
3473 0 : if (aSortArray[i] == nOldVal)
3474 0 : nCount++;
3475 : else
3476 : {
3477 0 : nOldVal = aSortArray[i];
3478 0 : if (nCount > nMax)
3479 : {
3480 0 : nMax = nCount;
3481 0 : nMaxIndex = i-1;
3482 : }
3483 0 : nCount = 1;
3484 : }
3485 : }
3486 0 : if (nCount > nMax)
3487 : {
3488 0 : nMax = nCount;
3489 0 : nMaxIndex = i-1;
3490 : }
3491 0 : if (nMax == 1 && nCount == 1)
3492 0 : PushNoValue();
3493 0 : else if (nMax == 1)
3494 0 : PushDouble(nOldVal);
3495 : else
3496 0 : PushDouble(aSortArray[nMaxIndex]);
3497 0 : }
3498 : }
3499 :
3500 0 : void ScInterpreter::CalculateSmallLarge(bool bSmall)
3501 : {
3502 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
3503 0 : return;
3504 0 : double f = ::rtl::math::approxFloor(GetDouble());
3505 0 : if (f < 1.0)
3506 : {
3507 0 : PushIllegalArgument();
3508 0 : return;
3509 : }
3510 0 : SCSIZE k = static_cast<SCSIZE>(f);
3511 0 : vector<double> aSortArray;
3512 : /* TODO: using nth_element() is best for one single value, but LARGE/SMALL
3513 : * actually are defined to return an array of values if an array of
3514 : * positions was passed, in which case, depending on the number of values,
3515 : * we may or will need a real sorted array again, see #i32345. */
3516 0 : GetNumberSequenceArray(1, aSortArray);
3517 0 : SCSIZE nSize = aSortArray.size();
3518 0 : if (aSortArray.empty() || nSize == 0 || nGlobalError || nSize < k)
3519 0 : PushNoValue();
3520 : else
3521 : {
3522 : // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] );
3523 0 : vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k);
3524 0 : ::std::nth_element( aSortArray.begin(), iPos, aSortArray.end());
3525 0 : PushDouble( *iPos);
3526 0 : }
3527 : }
3528 :
3529 0 : void ScInterpreter::ScLarge()
3530 : {
3531 0 : CalculateSmallLarge(false);
3532 0 : }
3533 :
3534 0 : void ScInterpreter::ScSmall()
3535 : {
3536 0 : CalculateSmallLarge(true);
3537 0 : }
3538 :
3539 0 : void ScInterpreter::ScPercentrank( bool bInclusive )
3540 : {
3541 0 : sal_uInt8 nParamCount = GetByte();
3542 0 : if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
3543 0 : return;
3544 0 : double fSignificance = ( nParamCount == 3 ? ::rtl::math::approxFloor( GetDouble() ) : 3.0 );
3545 0 : double fNum = GetDouble();
3546 0 : vector<double> aSortArray;
3547 0 : GetSortArray( 1, aSortArray );
3548 0 : SCSIZE nSize = aSortArray.size();
3549 0 : if ( aSortArray.empty() || nSize == 0 || nGlobalError )
3550 0 : PushNoValue();
3551 : else
3552 : {
3553 0 : if ( fNum < aSortArray[ 0 ] || fNum > aSortArray[ nSize - 1 ] )
3554 0 : PushNoValue();
3555 : else
3556 : {
3557 : double fRes;
3558 0 : if ( nSize == 1 )
3559 0 : fRes = 1.0; // fNum == aSortArray[ 0 ], see test above
3560 : else
3561 0 : fRes = GetPercentrank( aSortArray, fNum, bInclusive );
3562 0 : if ( fRes != 0.0 )
3563 : {
3564 0 : double fExp = ::rtl::math::approxFloor( log( fRes ) );
3565 0 : fRes = ::rtl::math::round( fRes * pow( 10, -fExp + fSignificance - 1 ) ) / pow( 10, -fExp + fSignificance - 1 );
3566 : }
3567 0 : PushDouble( fRes );
3568 : }
3569 0 : }
3570 : }
3571 :
3572 0 : double ScInterpreter::GetPercentrank( ::std::vector<double> & rArray, double fVal, bool bInclusive )
3573 : {
3574 0 : SCSIZE nSize = rArray.size();
3575 : double fRes;
3576 0 : if ( fVal == rArray[ 0 ] )
3577 : {
3578 0 : if ( bInclusive )
3579 0 : fRes = 0.0;
3580 : else
3581 0 : fRes = 1.0 / ( double )( nSize + 1 );
3582 : }
3583 : else
3584 : {
3585 0 : SCSIZE nOldCount = 0;
3586 0 : double fOldVal = rArray[ 0 ];
3587 : SCSIZE i;
3588 0 : for ( i = 1; i < nSize && rArray[ i ] < fVal; i++ )
3589 : {
3590 0 : if ( rArray[ i ] != fOldVal )
3591 : {
3592 0 : nOldCount = i;
3593 0 : fOldVal = rArray[ i ];
3594 : }
3595 : }
3596 0 : if ( rArray[ i ] != fOldVal )
3597 0 : nOldCount = i;
3598 0 : if ( fVal == rArray[ i ] )
3599 : {
3600 0 : if ( bInclusive )
3601 0 : fRes = ( double )nOldCount / ( double )( nSize - 1 );
3602 : else
3603 0 : fRes = ( double )( i + 1 ) / ( double )( nSize + 1 );
3604 : }
3605 : else
3606 : {
3607 : // nOldCount is the count of smaller entries
3608 : // fVal is between rArray[ nOldCount - 1 ] and rArray[ nOldCount ]
3609 : // use linear interpolation to find a position between the entries
3610 0 : if ( nOldCount == 0 )
3611 : {
3612 : OSL_FAIL( "should not happen" );
3613 0 : fRes = 0.0;
3614 : }
3615 : else
3616 : {
3617 0 : double fFract = ( fVal - rArray[ nOldCount - 1 ] ) /
3618 0 : ( rArray[ nOldCount ] - rArray[ nOldCount - 1 ] );
3619 0 : if ( bInclusive )
3620 0 : fRes = ( ( double )( nOldCount - 1 ) + fFract ) / ( double )( nSize - 1 );
3621 : else
3622 0 : fRes = ( ( double )nOldCount + fFract ) / ( double )( nSize + 1 );
3623 : }
3624 : }
3625 : }
3626 0 : return fRes;
3627 : }
3628 :
3629 0 : void ScInterpreter::ScTrimMean()
3630 : {
3631 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
3632 0 : return;
3633 0 : double alpha = GetDouble();
3634 0 : if (alpha < 0.0 || alpha >= 1.0)
3635 : {
3636 0 : PushIllegalArgument();
3637 0 : return;
3638 : }
3639 0 : vector<double> aSortArray;
3640 0 : GetSortArray(1, aSortArray);
3641 0 : SCSIZE nSize = aSortArray.size();
3642 0 : if (aSortArray.empty() || nSize == 0 || nGlobalError)
3643 0 : PushNoValue();
3644 : else
3645 : {
3646 0 : sal_uLong nIndex = (sal_uLong) ::rtl::math::approxFloor(alpha*(double)nSize);
3647 0 : if (nIndex % 2 != 0)
3648 0 : nIndex--;
3649 0 : nIndex /= 2;
3650 : OSL_ENSURE(nIndex < nSize, "ScTrimMean: falscher Index");
3651 0 : double fSum = 0.0;
3652 0 : for (SCSIZE i = nIndex; i < nSize-nIndex; i++)
3653 0 : fSum += aSortArray[i];
3654 0 : PushDouble(fSum/(double)(nSize-2*nIndex));
3655 0 : }
3656 : }
3657 :
3658 0 : void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray )
3659 : {
3660 0 : ScAddress aAdr;
3661 0 : ScRange aRange;
3662 0 : short nParam = nParamCount;
3663 0 : size_t nRefInList = 0;
3664 0 : while (nParam-- > 0)
3665 : {
3666 0 : switch (GetStackType())
3667 : {
3668 : case formula::svDouble :
3669 0 : rArray.push_back( PopDouble());
3670 0 : break;
3671 : case svSingleRef :
3672 : {
3673 0 : PopSingleRef( aAdr );
3674 0 : ScRefCellValue aCell;
3675 0 : aCell.assign(*pDok, aAdr);
3676 0 : if (aCell.hasNumeric())
3677 0 : rArray.push_back(GetCellValue(aAdr, aCell));
3678 : }
3679 0 : break;
3680 : case formula::svDoubleRef :
3681 : case svRefList :
3682 : {
3683 0 : PopDoubleRef( aRange, nParam, nRefInList);
3684 0 : if (nGlobalError)
3685 0 : break;
3686 :
3687 0 : aRange.Justify();
3688 0 : SCSIZE nCellCount = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
3689 0 : nCellCount *= aRange.aEnd.Row() - aRange.aStart.Row() + 1;
3690 0 : rArray.reserve( rArray.size() + nCellCount);
3691 :
3692 0 : sal_uInt16 nErr = 0;
3693 : double fCellVal;
3694 0 : ScValueIterator aValIter(pDok, aRange);
3695 0 : if (aValIter.GetFirst( fCellVal, nErr))
3696 : {
3697 0 : rArray.push_back( fCellVal);
3698 0 : SetError(nErr);
3699 0 : while ((nErr == 0) && aValIter.GetNext( fCellVal, nErr))
3700 0 : rArray.push_back( fCellVal);
3701 0 : SetError(nErr);
3702 : }
3703 : }
3704 0 : break;
3705 : case svMatrix :
3706 : case svExternalSingleRef:
3707 : case svExternalDoubleRef:
3708 : {
3709 0 : ScMatrixRef pMat = GetMatrix();
3710 0 : if (!pMat)
3711 0 : break;
3712 :
3713 0 : SCSIZE nCount = pMat->GetElementCount();
3714 0 : rArray.reserve( rArray.size() + nCount);
3715 0 : if (pMat->IsNumeric())
3716 : {
3717 0 : for (SCSIZE i = 0; i < nCount; ++i)
3718 0 : rArray.push_back( pMat->GetDouble(i));
3719 : }
3720 : else
3721 : {
3722 0 : for (SCSIZE i = 0; i < nCount; ++i)
3723 0 : if (!pMat->IsString(i))
3724 0 : rArray.push_back( pMat->GetDouble(i));
3725 0 : }
3726 : }
3727 0 : break;
3728 : default :
3729 0 : PopError();
3730 0 : SetError( errIllegalParameter);
3731 0 : break;
3732 : }
3733 0 : if (nGlobalError)
3734 0 : break; // while
3735 : }
3736 : // nParam > 0 in case of error, clean stack environment and obtain earlier
3737 : // error if there was one.
3738 0 : while (nParam-- > 0)
3739 0 : PopError();
3740 0 : }
3741 :
3742 0 : void ScInterpreter::GetSortArray( sal_uInt8 nParamCount, vector<double>& rSortArray, vector<long>* pIndexOrder )
3743 : {
3744 0 : GetNumberSequenceArray( nParamCount, rSortArray);
3745 :
3746 0 : if (rSortArray.size() > MAX_ANZ_DOUBLE_FOR_SORT)
3747 0 : SetError( errStackOverflow);
3748 0 : else if (rSortArray.empty())
3749 0 : SetError( errNoValue);
3750 :
3751 0 : if (nGlobalError == 0)
3752 0 : QuickSort( rSortArray, pIndexOrder);
3753 0 : }
3754 :
3755 0 : static void lcl_QuickSort( long nLo, long nHi, vector<double>& rSortArray, vector<long>* pIndexOrder )
3756 : {
3757 : // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
3758 :
3759 : using ::std::swap;
3760 :
3761 0 : if (nHi - nLo == 1)
3762 : {
3763 0 : if (rSortArray[nLo] > rSortArray[nHi])
3764 : {
3765 0 : swap(rSortArray[nLo], rSortArray[nHi]);
3766 0 : if (pIndexOrder)
3767 0 : swap(pIndexOrder->at(nLo), pIndexOrder->at(nHi));
3768 : }
3769 0 : return;
3770 : }
3771 :
3772 0 : long ni = nLo;
3773 0 : long nj = nHi;
3774 0 : do
3775 : {
3776 0 : double fLo = rSortArray[nLo];
3777 0 : while (ni <= nHi && rSortArray[ni] < fLo) ni++;
3778 0 : while (nj >= nLo && fLo < rSortArray[nj]) nj--;
3779 0 : if (ni <= nj)
3780 : {
3781 0 : if (ni != nj)
3782 : {
3783 0 : swap(rSortArray[ni], rSortArray[nj]);
3784 0 : if (pIndexOrder)
3785 0 : swap(pIndexOrder->at(ni), pIndexOrder->at(nj));
3786 : }
3787 :
3788 0 : ++ni;
3789 0 : --nj;
3790 : }
3791 : }
3792 : while (ni < nj);
3793 :
3794 0 : if ((nj - nLo) < (nHi - ni))
3795 : {
3796 0 : if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
3797 0 : if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
3798 : }
3799 : else
3800 : {
3801 0 : if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
3802 0 : if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
3803 : }
3804 : }
3805 :
3806 0 : void ScInterpreter::QuickSort( vector<double>& rSortArray, vector<long>* pIndexOrder )
3807 : {
3808 0 : long n = static_cast<long>(rSortArray.size());
3809 :
3810 0 : if (pIndexOrder)
3811 : {
3812 0 : pIndexOrder->clear();
3813 0 : pIndexOrder->reserve(n);
3814 0 : for (long i = 0; i < n; ++i)
3815 0 : pIndexOrder->push_back(i);
3816 : }
3817 :
3818 0 : if (n < 2)
3819 0 : return;
3820 :
3821 0 : size_t nValCount = rSortArray.size();
3822 0 : for (size_t i = 0; (i + 4) <= nValCount-1; i += 4)
3823 : {
3824 0 : size_t nInd = rand() % (int) (nValCount-1);
3825 0 : ::std::swap( rSortArray[i], rSortArray[nInd]);
3826 0 : if (pIndexOrder)
3827 0 : ::std::swap( pIndexOrder->at(i), pIndexOrder->at(nInd));
3828 : }
3829 :
3830 0 : lcl_QuickSort(0, n-1, rSortArray, pIndexOrder);
3831 : }
3832 :
3833 0 : void ScInterpreter::ScRank( bool bAverage )
3834 : {
3835 0 : sal_uInt8 nParamCount = GetByte();
3836 0 : if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
3837 0 : return;
3838 : bool bAscending;
3839 0 : if ( nParamCount == 3 )
3840 0 : bAscending = GetBool();
3841 : else
3842 0 : bAscending = false;
3843 :
3844 0 : vector<double> aSortArray;
3845 0 : GetSortArray( 1, aSortArray );
3846 0 : double fVal = GetDouble();
3847 0 : SCSIZE nSize = aSortArray.size();
3848 0 : if ( aSortArray.empty() || nSize == 0 || nGlobalError )
3849 0 : PushNoValue();
3850 : else
3851 : {
3852 0 : if ( fVal < aSortArray[ 0 ] || fVal > aSortArray[ nSize - 1 ] )
3853 0 : PushNoValue();
3854 : else
3855 : {
3856 0 : double fLastPos = 0;
3857 0 : double fFirstPos = -1.0;
3858 0 : bool bFinished = false;
3859 : SCSIZE i;
3860 0 : for ( i = 0; i < nSize && !bFinished && !nGlobalError; i++ )
3861 : {
3862 0 : if ( aSortArray[ i ] == fVal )
3863 : {
3864 0 : if ( fFirstPos < 0 )
3865 0 : fFirstPos = i + 1.0;
3866 : }
3867 : else
3868 : {
3869 0 : if ( aSortArray[ i ] > fVal )
3870 : {
3871 0 : fLastPos = i;
3872 0 : bFinished = true;
3873 : }
3874 : }
3875 : }
3876 0 : if ( !bFinished )
3877 0 : fLastPos = i;
3878 0 : if ( !bAverage )
3879 : {
3880 0 : if ( bAscending )
3881 0 : PushDouble( fFirstPos );
3882 : else
3883 0 : PushDouble( nSize + 1.0 - fLastPos );
3884 : }
3885 : else
3886 : {
3887 0 : if ( bAscending )
3888 0 : PushDouble( ( fFirstPos + fLastPos ) / 2.0 );
3889 : else
3890 0 : PushDouble( nSize + 1.0 - ( fFirstPos + fLastPos ) / 2.0 );
3891 : }
3892 : }
3893 0 : }
3894 : }
3895 :
3896 0 : void ScInterpreter::ScAveDev()
3897 : {
3898 0 : sal_uInt8 nParamCount = GetByte();
3899 0 : if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3900 0 : return;
3901 0 : sal_uInt16 SaveSP = sp;
3902 0 : double nMiddle = 0.0;
3903 0 : double rVal = 0.0;
3904 0 : double rValCount = 0.0;
3905 0 : ScAddress aAdr;
3906 0 : ScRange aRange;
3907 0 : short nParam = nParamCount;
3908 0 : size_t nRefInList = 0;
3909 0 : while (nParam-- > 0)
3910 : {
3911 0 : switch (GetStackType())
3912 : {
3913 : case formula::svDouble :
3914 0 : rVal += GetDouble();
3915 0 : rValCount++;
3916 0 : break;
3917 : case svSingleRef :
3918 : {
3919 0 : PopSingleRef( aAdr );
3920 0 : ScRefCellValue aCell;
3921 0 : aCell.assign(*pDok, aAdr);
3922 0 : if (aCell.hasNumeric())
3923 : {
3924 0 : rVal += GetCellValue(aAdr, aCell);
3925 0 : rValCount++;
3926 0 : }
3927 : }
3928 0 : break;
3929 : case formula::svDoubleRef :
3930 : case svRefList :
3931 : {
3932 0 : sal_uInt16 nErr = 0;
3933 : double nCellVal;
3934 0 : PopDoubleRef( aRange, nParam, nRefInList);
3935 0 : ScValueIterator aValIter(pDok, aRange);
3936 0 : if (aValIter.GetFirst(nCellVal, nErr))
3937 : {
3938 0 : rVal += nCellVal;
3939 0 : rValCount++;
3940 0 : SetError(nErr);
3941 0 : while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
3942 : {
3943 0 : rVal += nCellVal;
3944 0 : rValCount++;
3945 : }
3946 0 : SetError(nErr);
3947 : }
3948 : }
3949 0 : break;
3950 : case svMatrix :
3951 : case svExternalSingleRef:
3952 : case svExternalDoubleRef:
3953 : {
3954 0 : ScMatrixRef pMat = GetMatrix();
3955 0 : if (pMat)
3956 : {
3957 0 : SCSIZE nCount = pMat->GetElementCount();
3958 0 : if (pMat->IsNumeric())
3959 : {
3960 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3961 : {
3962 0 : rVal += pMat->GetDouble(nElem);
3963 0 : rValCount++;
3964 : }
3965 : }
3966 : else
3967 : {
3968 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3969 0 : if (!pMat->IsString(nElem))
3970 : {
3971 0 : rVal += pMat->GetDouble(nElem);
3972 0 : rValCount++;
3973 : }
3974 : }
3975 0 : }
3976 : }
3977 0 : break;
3978 : default :
3979 0 : SetError(errIllegalParameter);
3980 0 : break;
3981 : }
3982 : }
3983 0 : if (nGlobalError)
3984 : {
3985 0 : PushError( nGlobalError);
3986 0 : return;
3987 : }
3988 0 : nMiddle = rVal / rValCount;
3989 0 : sp = SaveSP;
3990 0 : rVal = 0.0;
3991 0 : nParam = nParamCount;
3992 0 : nRefInList = 0;
3993 0 : while (nParam-- > 0)
3994 : {
3995 0 : switch (GetStackType())
3996 : {
3997 : case formula::svDouble :
3998 0 : rVal += fabs(GetDouble() - nMiddle);
3999 0 : break;
4000 : case svSingleRef :
4001 : {
4002 0 : PopSingleRef( aAdr );
4003 0 : ScRefCellValue aCell;
4004 0 : aCell.assign(*pDok, aAdr);
4005 0 : if (aCell.hasNumeric())
4006 0 : rVal += fabs(GetCellValue(aAdr, aCell) - nMiddle);
4007 : }
4008 0 : break;
4009 : case formula::svDoubleRef :
4010 : case svRefList :
4011 : {
4012 0 : sal_uInt16 nErr = 0;
4013 : double nCellVal;
4014 0 : PopDoubleRef( aRange, nParam, nRefInList);
4015 0 : ScValueIterator aValIter(pDok, aRange);
4016 0 : if (aValIter.GetFirst(nCellVal, nErr))
4017 : {
4018 0 : rVal += (fabs(nCellVal - nMiddle));
4019 0 : while (aValIter.GetNext(nCellVal, nErr))
4020 0 : rVal += fabs(nCellVal - nMiddle);
4021 : }
4022 : }
4023 0 : break;
4024 : case svMatrix :
4025 : case svExternalSingleRef:
4026 : case svExternalDoubleRef:
4027 : {
4028 0 : ScMatrixRef pMat = GetMatrix();
4029 0 : if (pMat)
4030 : {
4031 0 : SCSIZE nCount = pMat->GetElementCount();
4032 0 : if (pMat->IsNumeric())
4033 : {
4034 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4035 : {
4036 0 : rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
4037 : }
4038 : }
4039 : else
4040 : {
4041 0 : for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4042 : {
4043 0 : if (!pMat->IsString(nElem))
4044 0 : rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
4045 : }
4046 : }
4047 0 : }
4048 : }
4049 0 : break;
4050 0 : default : SetError(errIllegalParameter); break;
4051 : }
4052 : }
4053 0 : PushDouble(rVal / rValCount);
4054 : }
4055 :
4056 0 : void ScInterpreter::ScDevSq()
4057 : {
4058 : double nVal;
4059 : double nValCount;
4060 0 : GetStVarParams(nVal, nValCount);
4061 0 : PushDouble(nVal);
4062 0 : }
4063 :
4064 0 : void ScInterpreter::ScProbability()
4065 : {
4066 0 : sal_uInt8 nParamCount = GetByte();
4067 0 : if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
4068 0 : return;
4069 : double fUp, fLo;
4070 0 : fUp = GetDouble();
4071 0 : if (nParamCount == 4)
4072 0 : fLo = GetDouble();
4073 : else
4074 0 : fLo = fUp;
4075 0 : if (fLo > fUp)
4076 : {
4077 0 : double fTemp = fLo;
4078 0 : fLo = fUp;
4079 0 : fUp = fTemp;
4080 : }
4081 0 : ScMatrixRef pMatP = GetMatrix();
4082 0 : ScMatrixRef pMatW = GetMatrix();
4083 0 : if (!pMatP || !pMatW)
4084 0 : PushIllegalParameter();
4085 : else
4086 : {
4087 : SCSIZE nC1, nC2;
4088 : SCSIZE nR1, nR2;
4089 0 : pMatP->GetDimensions(nC1, nR1);
4090 0 : pMatW->GetDimensions(nC2, nR2);
4091 0 : if (nC1 != nC2 || nR1 != nR2 || nC1 == 0 || nR1 == 0 ||
4092 0 : nC2 == 0 || nR2 == 0)
4093 0 : PushNA();
4094 : else
4095 : {
4096 0 : double fSum = 0.0;
4097 0 : double fRes = 0.0;
4098 0 : bool bStop = false;
4099 : double fP, fW;
4100 0 : for ( SCSIZE i = 0; i < nC1 && !bStop; i++ )
4101 : {
4102 0 : for (SCSIZE j = 0; j < nR1 && !bStop; ++j )
4103 : {
4104 0 : if (pMatP->IsValue(i,j) && pMatW->IsValue(i,j))
4105 : {
4106 0 : fP = pMatP->GetDouble(i,j);
4107 0 : fW = pMatW->GetDouble(i,j);
4108 0 : if (fP < 0.0 || fP > 1.0)
4109 0 : bStop = true;
4110 : else
4111 : {
4112 0 : fSum += fP;
4113 0 : if (fW >= fLo && fW <= fUp)
4114 0 : fRes += fP;
4115 : }
4116 : }
4117 : else
4118 0 : SetError( errIllegalArgument);
4119 : }
4120 : }
4121 0 : if (bStop || fabs(fSum -1.0) > 1.0E-7)
4122 0 : PushNoValue();
4123 : else
4124 0 : PushDouble(fRes);
4125 : }
4126 0 : }
4127 : }
4128 :
4129 0 : void ScInterpreter::ScCorrel()
4130 : {
4131 : // This is identical to ScPearson()
4132 0 : ScPearson();
4133 0 : }
4134 :
4135 0 : void ScInterpreter::ScCovarianceP()
4136 : {
4137 0 : CalculatePearsonCovar( false, false, false );
4138 0 : }
4139 :
4140 0 : void ScInterpreter::ScCovarianceS()
4141 : {
4142 0 : CalculatePearsonCovar( false, false, true );
4143 0 : }
4144 :
4145 0 : void ScInterpreter::ScPearson()
4146 : {
4147 0 : CalculatePearsonCovar( true, false, false );
4148 0 : }
4149 :
4150 0 : void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _bSample )
4151 : {
4152 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
4153 0 : return;
4154 0 : ScMatrixRef pMat1 = GetMatrix();
4155 0 : ScMatrixRef pMat2 = GetMatrix();
4156 0 : if (!pMat1 || !pMat2)
4157 : {
4158 0 : PushIllegalParameter();
4159 0 : return;
4160 : }
4161 : SCSIZE nC1, nC2;
4162 : SCSIZE nR1, nR2;
4163 0 : pMat1->GetDimensions(nC1, nR1);
4164 0 : pMat2->GetDimensions(nC2, nR2);
4165 0 : if (nR1 != nR2 || nC1 != nC2)
4166 : {
4167 0 : PushIllegalArgument();
4168 0 : return;
4169 : }
4170 : /* #i78250#
4171 : * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
4172 : * but the latter produces wrong results if the absolute values are high,
4173 : * for example above 10^8
4174 : */
4175 0 : double fCount = 0.0;
4176 0 : double fSumX = 0.0;
4177 0 : double fSumY = 0.0;
4178 :
4179 0 : for (SCSIZE i = 0; i < nC1; i++)
4180 : {
4181 0 : for (SCSIZE j = 0; j < nR1; j++)
4182 : {
4183 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4184 : {
4185 0 : double fValX = pMat1->GetDouble(i,j);
4186 0 : double fValY = pMat2->GetDouble(i,j);
4187 0 : fSumX += fValX;
4188 0 : fSumY += fValY;
4189 0 : fCount++;
4190 : }
4191 : }
4192 : }
4193 0 : if (fCount < (_bStexy ? 3.0 : (_bSample ? 2.0 : 1.0)))
4194 0 : PushNoValue();
4195 : else
4196 : {
4197 0 : double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4198 0 : double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
4199 0 : double fSumSqrDeltaY = 0.0; // sum of (ValY-MeanY)^2
4200 0 : const double fMeanX = fSumX / fCount;
4201 0 : const double fMeanY = fSumY / fCount;
4202 0 : for (SCSIZE i = 0; i < nC1; i++)
4203 : {
4204 0 : for (SCSIZE j = 0; j < nR1; j++)
4205 : {
4206 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4207 : {
4208 0 : const double fValX = pMat1->GetDouble(i,j);
4209 0 : const double fValY = pMat2->GetDouble(i,j);
4210 0 : fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4211 0 : if ( _bPearson )
4212 : {
4213 0 : fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
4214 0 : fSumSqrDeltaY += (fValY - fMeanY) * (fValY - fMeanY);
4215 : }
4216 : }
4217 : }
4218 : }
4219 0 : if ( _bPearson )
4220 : {
4221 0 : if (fSumSqrDeltaX == 0.0 || ( !_bStexy && fSumSqrDeltaY == 0.0) )
4222 0 : PushError( errDivisionByZero);
4223 0 : else if ( _bStexy )
4224 0 : PushDouble( sqrt( (fSumSqrDeltaY - fSumDeltaXDeltaY *
4225 0 : fSumDeltaXDeltaY / fSumSqrDeltaX) / (fCount-2)));
4226 : else
4227 0 : PushDouble( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY));
4228 : }
4229 : else
4230 : {
4231 0 : if ( _bSample )
4232 0 : PushDouble( fSumDeltaXDeltaY / ( fCount - 1 ) );
4233 : else
4234 0 : PushDouble( fSumDeltaXDeltaY / fCount);
4235 : }
4236 0 : }
4237 : }
4238 :
4239 0 : void ScInterpreter::ScRSQ()
4240 : {
4241 : // Same as ScPearson()*ScPearson()
4242 0 : ScPearson();
4243 0 : if (!nGlobalError)
4244 : {
4245 0 : switch (GetStackType())
4246 : {
4247 : case formula::svDouble:
4248 : {
4249 0 : double fVal = PopDouble();
4250 0 : PushDouble( fVal * fVal);
4251 : }
4252 0 : break;
4253 : default:
4254 0 : PopError();
4255 0 : PushNoValue();
4256 : }
4257 : }
4258 0 : }
4259 :
4260 0 : void ScInterpreter::ScSTEXY()
4261 : {
4262 0 : CalculatePearsonCovar( true, true, false );
4263 0 : }
4264 0 : void ScInterpreter::CalculateSlopeIntercept(bool bSlope)
4265 : {
4266 0 : if ( !MustHaveParamCount( GetByte(), 2 ) )
4267 0 : return;
4268 0 : ScMatrixRef pMat1 = GetMatrix();
4269 0 : ScMatrixRef pMat2 = GetMatrix();
4270 0 : if (!pMat1 || !pMat2)
4271 : {
4272 0 : PushIllegalParameter();
4273 0 : return;
4274 : }
4275 : SCSIZE nC1, nC2;
4276 : SCSIZE nR1, nR2;
4277 0 : pMat1->GetDimensions(nC1, nR1);
4278 0 : pMat2->GetDimensions(nC2, nR2);
4279 0 : if (nR1 != nR2 || nC1 != nC2)
4280 : {
4281 0 : PushIllegalArgument();
4282 0 : return;
4283 : }
4284 : // #i78250# numerical stability improved
4285 0 : double fCount = 0.0;
4286 0 : double fSumX = 0.0;
4287 0 : double fSumY = 0.0;
4288 :
4289 0 : for (SCSIZE i = 0; i < nC1; i++)
4290 : {
4291 0 : for (SCSIZE j = 0; j < nR1; j++)
4292 : {
4293 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4294 : {
4295 0 : double fValX = pMat1->GetDouble(i,j);
4296 0 : double fValY = pMat2->GetDouble(i,j);
4297 0 : fSumX += fValX;
4298 0 : fSumY += fValY;
4299 0 : fCount++;
4300 : }
4301 : }
4302 : }
4303 0 : if (fCount < 1.0)
4304 0 : PushNoValue();
4305 : else
4306 : {
4307 0 : double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4308 0 : double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
4309 0 : double fMeanX = fSumX / fCount;
4310 0 : double fMeanY = fSumY / fCount;
4311 0 : for (SCSIZE i = 0; i < nC1; i++)
4312 : {
4313 0 : for (SCSIZE j = 0; j < nR1; j++)
4314 : {
4315 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4316 : {
4317 0 : double fValX = pMat1->GetDouble(i,j);
4318 0 : double fValY = pMat2->GetDouble(i,j);
4319 0 : fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4320 0 : fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
4321 : }
4322 : }
4323 : }
4324 0 : if (fSumSqrDeltaX == 0.0)
4325 0 : PushError( errDivisionByZero);
4326 : else
4327 : {
4328 0 : if ( bSlope )
4329 0 : PushDouble( fSumDeltaXDeltaY / fSumSqrDeltaX);
4330 : else
4331 0 : PushDouble( fMeanY - fSumDeltaXDeltaY / fSumSqrDeltaX * fMeanX);
4332 : }
4333 0 : }
4334 : }
4335 :
4336 0 : void ScInterpreter::ScSlope()
4337 : {
4338 0 : CalculateSlopeIntercept(true);
4339 0 : }
4340 :
4341 0 : void ScInterpreter::ScIntercept()
4342 : {
4343 0 : CalculateSlopeIntercept(false);
4344 0 : }
4345 :
4346 0 : void ScInterpreter::ScForecast()
4347 : {
4348 0 : if ( !MustHaveParamCount( GetByte(), 3 ) )
4349 0 : return;
4350 0 : ScMatrixRef pMat1 = GetMatrix();
4351 0 : ScMatrixRef pMat2 = GetMatrix();
4352 0 : if (!pMat1 || !pMat2)
4353 : {
4354 0 : PushIllegalParameter();
4355 0 : return;
4356 : }
4357 : SCSIZE nC1, nC2;
4358 : SCSIZE nR1, nR2;
4359 0 : pMat1->GetDimensions(nC1, nR1);
4360 0 : pMat2->GetDimensions(nC2, nR2);
4361 0 : if (nR1 != nR2 || nC1 != nC2)
4362 : {
4363 0 : PushIllegalArgument();
4364 0 : return;
4365 : }
4366 0 : double fVal = GetDouble();
4367 : // #i78250# numerical stability improved
4368 0 : double fCount = 0.0;
4369 0 : double fSumX = 0.0;
4370 0 : double fSumY = 0.0;
4371 :
4372 0 : for (SCSIZE i = 0; i < nC1; i++)
4373 : {
4374 0 : for (SCSIZE j = 0; j < nR1; j++)
4375 : {
4376 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4377 : {
4378 0 : double fValX = pMat1->GetDouble(i,j);
4379 0 : double fValY = pMat2->GetDouble(i,j);
4380 0 : fSumX += fValX;
4381 0 : fSumY += fValY;
4382 0 : fCount++;
4383 : }
4384 : }
4385 : }
4386 0 : if (fCount < 1.0)
4387 0 : PushNoValue();
4388 : else
4389 : {
4390 0 : double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4391 0 : double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2
4392 0 : double fMeanX = fSumX / fCount;
4393 0 : double fMeanY = fSumY / fCount;
4394 0 : for (SCSIZE i = 0; i < nC1; i++)
4395 : {
4396 0 : for (SCSIZE j = 0; j < nR1; j++)
4397 : {
4398 0 : if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
4399 : {
4400 0 : double fValX = pMat1->GetDouble(i,j);
4401 0 : double fValY = pMat2->GetDouble(i,j);
4402 0 : fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4403 0 : fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
4404 : }
4405 : }
4406 : }
4407 0 : if (fSumSqrDeltaX == 0.0)
4408 0 : PushError( errDivisionByZero);
4409 : else
4410 0 : PushDouble( fMeanY + fSumDeltaXDeltaY / fSumSqrDeltaX * (fVal - fMeanX));
4411 0 : }
4412 : }
4413 :
4414 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|