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