xref: /core/sc/source/core/tool/interpr3.cxx (revision 9d4c36d7)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <tools/solar.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <interpre.hxx>
25 #include <global.hxx>
26 #include <compiler.hxx>
27 #include <formulacell.hxx>
28 #include <document.hxx>
29 #include <dociter.hxx>
30 #include <matrixoperators.hxx>
31 #include <scmatrix.hxx>
32 
33 #include <math.h>
34 #include <cassert>
35 #include <memory>
36 #include <set>
37 #include <vector>
38 #include <algorithm>
39 #include <comphelper/random.hxx>
40 #include <o3tl/float_int_conversion.hxx>
41 #include <osl/diagnose.h>
42 #include <basegfx/numeric/ftools.hxx>
43 
44 using ::std::vector;
45 using namespace formula;
46 
47 /// Two columns of data should be sortable with GetSortArray() and QuickSort()
48 // This is an arbitrary limit.
49 #define MAX_COUNT_DOUBLE_FOR_SORT (MAXROWCOUNT * 2)
50 
51 const double ScInterpreter::fMaxGammaArgument = 171.624376956302;  // found experimental
52 const double fMachEps = ::std::numeric_limits<double>::epsilon();
53 
54 namespace {
55 
56 class ScDistFunc
57 {
58 public:
59     virtual double GetValue(double x) const = 0;
60 
61 protected:
62     ~ScDistFunc() {}
63 };
64 
65 }
66 
67 //  iteration for inverse distributions
68 
69 //template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError )
70 
71 /** u*w<0.0 fails for values near zero */
72 static bool lcl_HasChangeOfSign( double u, double w )
73 {
74     return (u < 0.0 && w > 0.0) || (u > 0.0 && w < 0.0);
75 }
76 
77 static double lcl_IterateInverse( const ScDistFunc& rFunction, double fAx, double fBx, bool& rConvError )
78 {
79     rConvError = false;
80     const double fYEps = 1.0E-307;
81     const double fXEps = ::std::numeric_limits<double>::epsilon();
82 
83     OSL_ENSURE(fAx<fBx, "IterateInverse: wrong interval");
84 
85     //  find enclosing interval
86 
87     double fAy = rFunction.GetValue(fAx);
88     double fBy = rFunction.GetValue(fBx);
89     double fTemp;
90     unsigned short nCount;
91     for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++)
92     {
93         if (fabs(fAy) <= fabs(fBy))
94         {
95             fTemp = fAx;
96             fAx += 2.0 * (fAx - fBx);
97             if (fAx < 0.0)
98                 fAx = 0.0;
99             fBx = fTemp;
100             fBy = fAy;
101             fAy = rFunction.GetValue(fAx);
102         }
103         else
104         {
105             fTemp = fBx;
106             fBx += 2.0 * (fBx - fAx);
107             fAx = fTemp;
108             fAy = fBy;
109             fBy = rFunction.GetValue(fBx);
110         }
111     }
112 
113     if (fAy == 0.0)
114         return fAx;
115     if (fBy == 0.0)
116         return fBx;
117     if (!lcl_HasChangeOfSign( fAy, fBy))
118     {
119         rConvError = true;
120         return 0.0;
121     }
122     // inverse quadric interpolation with additional brackets
123     // set three points
124     double fPx = fAx;
125     double fPy = fAy;
126     double fQx = fBx;
127     double fQy = fBy;
128     double fRx = fAx;
129     double fRy = fAy;
130     double fSx = 0.5 * (fAx + fBx); // potential next point
131     bool bHasToInterpolate = true;
132     nCount = 0;
133     while ( nCount < 500 && fabs(fRy) > fYEps &&
134             (fBx-fAx) > ::std::max( fabs(fAx), fabs(fBx)) * fXEps )
135     {
136         if (bHasToInterpolate)
137         {
138             if (fPy!=fQy && fQy!=fRy && fRy!=fPy)
139             {
140                 fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy)
141                     + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy)
142                     + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy);
143                 bHasToInterpolate = (fAx < fSx) && (fSx < fBx); // inside the brackets?
144             }
145             else
146                 bHasToInterpolate = false;
147         }
148         if(!bHasToInterpolate)
149         {
150             fSx = 0.5 * (fAx + fBx);
151             // reset points
152             fQx = fBx; fQy = fBy;
153             bHasToInterpolate = true;
154         }
155         // shift points for next interpolation
156         fPx = fQx; fQx = fRx; fRx = fSx;
157         fPy = fQy; fQy = fRy; fRy = rFunction.GetValue(fSx);
158         // update brackets
159         if (lcl_HasChangeOfSign( fAy, fRy))
160         {
161             fBx = fRx; fBy = fRy;
162         }
163         else
164         {
165             fAx = fRx; fAy = fRy;
166         }
167         // if last iteration brought too small advance, then do bisection next
168         // time, for safety
169         bHasToInterpolate = bHasToInterpolate && (fabs(fRy) * 2.0 <= fabs(fQy));
170         ++nCount;
171     }
172     return fRx;
173 }
174 
175 // General functions
176 
177 void ScInterpreter::ScNoName()
178 {
179     PushError(FormulaError::NoName);
180 }
181 
182 void ScInterpreter::ScBadName()
183 {
184     short nParamCount = GetByte();
185     while (nParamCount-- > 0)
186     {
187         PopError();
188     }
189     PushError( FormulaError::NoName);
190 }
191 
192 double ScInterpreter::phi(double x)
193 {
194     return  0.39894228040143268 * exp(-(x * x) / 2.0);
195 }
196 
197 double ScInterpreter::integralPhi(double x)
198 { // Using gauss(x)+0.5 has severe cancellation errors for x<-4
199     return 0.5 * ::rtl::math::erfc(-x * 0.7071067811865475); // * 1/sqrt(2)
200 }
201 
202 double ScInterpreter::taylor(const double* pPolynom, sal_uInt16 nMax, double x)
203 {
204     double nVal = pPolynom[nMax];
205     for (short i = nMax-1; i >= 0; i--)
206     {
207         nVal = pPolynom[i] + (nVal * x);
208     }
209     return nVal;
210 }
211 
212 double ScInterpreter::gauss(double x)
213 {
214 
215     double xAbs = fabs(x);
216     sal_uInt16 xShort = static_cast<sal_uInt16>(::rtl::math::approxFloor(xAbs));
217     double nVal = 0.0;
218     if (xShort == 0)
219     {
220         static const double t0[] =
221         { 0.39894228040143268, -0.06649038006690545,  0.00997355701003582,
222          -0.00118732821548045,  0.00011543468761616, -0.00000944465625950,
223           0.00000066596935163, -0.00000004122667415,  0.00000000227352982,
224           0.00000000011301172,  0.00000000000511243, -0.00000000000021218 };
225         nVal = taylor(t0, 11, (xAbs * xAbs)) * xAbs;
226     }
227     else if (xShort <= 2)
228     {
229         static const double t2[] =
230         { 0.47724986805182079,  0.05399096651318805, -0.05399096651318805,
231           0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
232           0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
233           0.00003704737285544,  0.00000282690796889, -0.00000354513195524,
234           0.00000037669563126,  0.00000019202407921, -0.00000005226908590,
235          -0.00000000491799345,  0.00000000366377919, -0.00000000015981997,
236          -0.00000000017381238,  0.00000000002624031,  0.00000000000560919,
237          -0.00000000000172127, -0.00000000000008634,  0.00000000000007894 };
238         nVal = taylor(t2, 23, (xAbs - 2.0));
239     }
240     else if (xShort <= 4)
241     {
242         static const double t4[] =
243        { 0.49996832875816688,  0.00013383022576489, -0.00026766045152977,
244          0.00033457556441221, -0.00028996548915725,  0.00018178605666397,
245         -0.00008252863922168,  0.00002551802519049, -0.00000391665839292,
246         -0.00000074018205222,  0.00000064422023359, -0.00000017370155340,
247          0.00000000909595465,  0.00000000944943118, -0.00000000329957075,
248          0.00000000029492075,  0.00000000011874477, -0.00000000004420396,
249          0.00000000000361422,  0.00000000000143638, -0.00000000000045848 };
250         nVal = taylor(t4, 20, (xAbs - 4.0));
251     }
252     else
253     {
254         static const double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
255         nVal = 0.5 + phi(xAbs) * taylor(asympt, 4, 1.0 / (xAbs * xAbs)) / xAbs;
256     }
257     if (x < 0.0)
258         return -nVal;
259     else
260         return nVal;
261 }
262 
263 //  #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
264 
265 double ScInterpreter::gaussinv(double x)
266 {
267     double q,t,z;
268 
269     q=x-0.5;
270 
271     if(fabs(q)<=.425)
272     {
273         t=0.180625-q*q;
274 
275         z=
276         q*
277         (
278             (
279                 (
280                     (
281                         (
282                             (
283                                 (
284                                     t*2509.0809287301226727+33430.575583588128105
285                                 )
286                                 *t+67265.770927008700853
287                             )
288                             *t+45921.953931549871457
289                         )
290                         *t+13731.693765509461125
291                     )
292                     *t+1971.5909503065514427
293                 )
294                 *t+133.14166789178437745
295             )
296             *t+3.387132872796366608
297         )
298         /
299         (
300             (
301                 (
302                     (
303                         (
304                             (
305                                 (
306                                     t*5226.495278852854561+28729.085735721942674
307                                 )
308                                 *t+39307.89580009271061
309                             )
310                             *t+21213.794301586595867
311                         )
312                         *t+5394.1960214247511077
313                     )
314                     *t+687.1870074920579083
315                 )
316                 *t+42.313330701600911252
317             )
318             *t+1.0
319         );
320 
321     }
322     else
323     {
324         if(q>0) t=1-x;
325         else        t=x;
326 
327         t=sqrt(-log(t));
328 
329         if(t<=5.0)
330         {
331             t+=-1.6;
332 
333             z=
334             (
335                 (
336                     (
337                         (
338                             (
339                                 (
340                                     (
341                                         t*7.7454501427834140764e-4+0.0227238449892691845833
342                                     )
343                                     *t+0.24178072517745061177
344                                 )
345                                 *t+1.27045825245236838258
346                             )
347                             *t+3.64784832476320460504
348                         )
349                         *t+5.7694972214606914055
350                     )
351                     *t+4.6303378461565452959
352                 )
353                 *t+1.42343711074968357734
354             )
355             /
356             (
357                 (
358                     (
359                         (
360                             (
361                                 (
362                                     (
363                                         t*1.05075007164441684324e-9+5.475938084995344946e-4
364                                     )
365                                     *t+0.0151986665636164571966
366                                 )
367                                 *t+0.14810397642748007459
368                             )
369                             *t+0.68976733498510000455
370                         )
371                         *t+1.6763848301838038494
372                     )
373                     *t+2.05319162663775882187
374                 )
375                 *t+1.0
376             );
377 
378         }
379         else
380         {
381             t+=-5.0;
382 
383             z=
384             (
385                 (
386                     (
387                         (
388                             (
389                                 (
390                                     (
391                                         t*2.01033439929228813265e-7+2.71155556874348757815e-5
392                                     )
393                                     *t+0.0012426609473880784386
394                                 )
395                                 *t+0.026532189526576123093
396                             )
397                             *t+0.29656057182850489123
398                         )
399                         *t+1.7848265399172913358
400                     )
401                     *t+5.4637849111641143699
402                 )
403                 *t+6.6579046435011037772
404             )
405             /
406             (
407                 (
408                     (
409                         (
410                             (
411                                 (
412                                     (
413                                         t*2.04426310338993978564e-15+1.4215117583164458887e-7
414                                     )
415                                     *t+1.8463183175100546818e-5
416                                 )
417                                 *t+7.868691311456132591e-4
418                             )
419                             *t+0.0148753612908506148525
420                         )
421                         *t+0.13692988092273580531
422                     )
423                     *t+0.59983220655588793769
424                 )
425                 *t+1.0
426             );
427 
428         }
429 
430         if(q<0.0) z=-z;
431     }
432 
433     return z;
434 }
435 
436 double ScInterpreter::Fakultaet(double x)
437 {
438     x = ::rtl::math::approxFloor(x);
439     if (x < 0.0)
440         return 0.0;
441     else if (x == 0.0)
442         return 1.0;
443     else if (x <= 170.0)
444     {
445         double fTemp = x;
446         while (fTemp > 2.0)
447         {
448             fTemp--;
449             x *= fTemp;
450         }
451     }
452     else
453         SetError(FormulaError::NoValue);
454     return x;
455 }
456 
457 double ScInterpreter::BinomKoeff(double n, double k)
458 {
459     // this method has been duplicated as BinomialCoefficient()
460     // in scaddins/source/analysis/analysishelper.cxx
461 
462     double nVal = 0.0;
463     k = ::rtl::math::approxFloor(k);
464     if (n < k)
465         nVal = 0.0;
466     else if (k == 0.0)
467         nVal = 1.0;
468     else
469     {
470         nVal = n/k;
471         n--;
472         k--;
473         while (k > 0.0)
474         {
475             nVal *= n/k;
476             k--;
477             n--;
478         }
479 
480     }
481     return nVal;
482 }
483 
484 // The algorithm is based on lanczos13m53 in lanczos.hpp
485 // in math library from http://www.boost.org
486 /** you must ensure fZ>0
487     Uses a variant of the Lanczos sum with a rational function. */
488 static double lcl_getLanczosSum(double fZ)
489 {
490     static const double fNum[13] ={
491         23531376880.41075968857200767445163675473,
492         42919803642.64909876895789904700198885093,
493         35711959237.35566804944018545154716670596,
494         17921034426.03720969991975575445893111267,
495         6039542586.35202800506429164430729792107,
496         1439720407.311721673663223072794912393972,
497         248874557.8620541565114603864132294232163,
498         31426415.58540019438061423162831820536287,
499         2876370.628935372441225409051620849613599,
500         186056.2653952234950402949897160456992822,
501         8071.672002365816210638002902272250613822,
502         210.8242777515793458725097339207133627117,
503         2.506628274631000270164908177133837338626
504         };
505     static const double fDenom[13] = {
506         0,
507         39916800,
508         120543840,
509         150917976,
510         105258076,
511         45995730,
512         13339535,
513         2637558,
514         357423,
515         32670,
516         1925,
517         66,
518         1
519         };
520     // Horner scheme
521     double fSumNum;
522     double fSumDenom;
523     int nI;
524     if (fZ<=1.0)
525     {
526         fSumNum = fNum[12];
527         fSumDenom = fDenom[12];
528         for (nI = 11; nI >= 0; --nI)
529         {
530             fSumNum *= fZ;
531             fSumNum += fNum[nI];
532             fSumDenom *= fZ;
533             fSumDenom += fDenom[nI];
534         }
535     }
536     else
537     // Cancel down with fZ^12; Horner scheme with reverse coefficients
538     {
539         double fZInv = 1/fZ;
540         fSumNum = fNum[0];
541         fSumDenom = fDenom[0];
542         for (nI = 1; nI <=12; ++nI)
543         {
544             fSumNum *= fZInv;
545             fSumNum += fNum[nI];
546             fSumDenom *= fZInv;
547             fSumDenom += fDenom[nI];
548         }
549     }
550     return fSumNum/fSumDenom;
551 }
552 
553 // The algorithm is based on tgamma in gamma.hpp
554 // in math library from http://www.boost.org
555 /** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
556 static double lcl_GetGammaHelper(double fZ)
557 {
558     double fGamma = lcl_getLanczosSum(fZ);
559     const double fg = 6.024680040776729583740234375;
560     double fZgHelp = fZ + fg - 0.5;
561     // avoid intermediate overflow
562     double fHalfpower = pow( fZgHelp, fZ / 2 - 0.25);
563     fGamma *= fHalfpower;
564     fGamma /= exp(fZgHelp);
565     fGamma *= fHalfpower;
566     if (fZ <= 20.0 && fZ == ::rtl::math::approxFloor(fZ))
567         fGamma = ::rtl::math::round(fGamma);
568     return fGamma;
569 }
570 
571 // The algorithm is based on tgamma in gamma.hpp
572 // in math library from http://www.boost.org
573 /** You must ensure fZ>0 */
574 static double lcl_GetLogGammaHelper(double fZ)
575 {
576     const double fg = 6.024680040776729583740234375;
577     double fZgHelp = fZ + fg - 0.5;
578     return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp;
579 }
580 
581 /** You must ensure non integer arguments for fZ<1 */
582 double ScInterpreter::GetGamma(double fZ)
583 {
584     const double fLogPi = log(F_PI);
585     const double fLogDblMax = log( ::std::numeric_limits<double>::max());
586 
587     if (fZ > fMaxGammaArgument)
588     {
589         SetError(FormulaError::IllegalFPOperation);
590         return HUGE_VAL;
591     }
592 
593     if (fZ >= 1.0)
594         return lcl_GetGammaHelper(fZ);
595 
596     if (fZ >= 0.5)  // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
597         return lcl_GetGammaHelper(fZ+1) / fZ;
598 
599     if (fZ >= -0.5) // shift to x>=1, might overflow
600     {
601         double fLogTest = lcl_GetLogGammaHelper(fZ+2) - rtl::math::log1p(fZ) - log( fabs(fZ));
602         if (fLogTest >= fLogDblMax)
603         {
604             SetError( FormulaError::IllegalFPOperation);
605             return HUGE_VAL;
606         }
607         return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ;
608     }
609     // fZ<-0.5
610     // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
611     double fLogDivisor = lcl_GetLogGammaHelper(1-fZ) + log( fabs( ::rtl::math::sin( F_PI*fZ)));
612     if (fLogDivisor - fLogPi >= fLogDblMax)     // underflow
613         return 0.0;
614 
615     if (fLogDivisor<0.0)
616         if (fLogPi - fLogDivisor > fLogDblMax)  // overflow
617         {
618             SetError(FormulaError::IllegalFPOperation);
619             return HUGE_VAL;
620         }
621 
622     return exp( fLogPi - fLogDivisor) * ((::rtl::math::sin( F_PI*fZ) < 0.0) ? -1.0 : 1.0);
623 }
624 
625 /** You must ensure fZ>0 */
626 double ScInterpreter::GetLogGamma(double fZ)
627 {
628     if (fZ >= fMaxGammaArgument)
629         return lcl_GetLogGammaHelper(fZ);
630     if (fZ >= 1.0)
631         return log(lcl_GetGammaHelper(fZ));
632     if (fZ >= 0.5)
633         return log( lcl_GetGammaHelper(fZ+1) / fZ);
634     return lcl_GetLogGammaHelper(fZ+2) - rtl::math::log1p(fZ) - log(fZ);
635 }
636 
637 double ScInterpreter::GetFDist(double x, double fF1, double fF2)
638 {
639     double arg = fF2/(fF2+fF1*x);
640     double alpha = fF2/2.0;
641     double beta = fF1/2.0;
642     return GetBetaDist(arg, alpha, beta);
643 }
644 
645 double ScInterpreter::GetTDist( double T, double fDF, int nType )
646 {
647     switch ( nType )
648     {
649         case 1 : // 1-tailed T-distribution
650             return 0.5 * GetBetaDist( fDF / ( fDF + T * T ), fDF / 2.0, 0.5 );
651         case 2 : // 2-tailed T-distribution
652             return GetBetaDist( fDF / ( fDF + T * T ), fDF / 2.0, 0.5);
653         case 3 : // left-tailed T-distribution (probability density function)
654             return pow( 1 + ( T * T / fDF ), -( fDF + 1 ) / 2 ) / ( sqrt( fDF ) * GetBeta( 0.5, fDF / 2.0 ) );
655         case 4 : // left-tailed T-distribution (cumulative distribution function)
656             double X = fDF / ( T * T + fDF );
657             double R = 0.5 * GetBetaDist( X, 0.5 * fDF, 0.5 );
658             return ( T < 0 ? R : 1 - R );
659     }
660     SetError( FormulaError::IllegalArgument );
661     return HUGE_VAL;
662 }
663 
664 // for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
665 /** You must ensure fDF>0.0 */
666 double ScInterpreter::GetChiDist(double fX, double fDF)
667 {
668     if (fX <= 0.0)
669         return 1.0; // see ODFF
670     else
671         return GetUpRegIGamma( fDF/2.0, fX/2.0);
672 }
673 
674 // ready for ODF 1.2
675 // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
676 // returns left tail
677 /** You must ensure fDF>0.0 */
678 double ScInterpreter::GetChiSqDistCDF(double fX, double fDF)
679 {
680     if (fX <= 0.0)
681         return 0.0; // see ODFF
682     else
683         return GetLowRegIGamma( fDF/2.0, fX/2.0);
684 }
685 
686 double ScInterpreter::GetChiSqDistPDF(double fX, double fDF)
687 {
688     // you must ensure fDF is positive integer
689     double fValue;
690     if (fX <= 0.0)
691         return 0.0; // see ODFF
692     if (fDF*fX > 1391000.0)
693     {
694         // intermediate invalid values, use log
695         fValue = exp((0.5*fDF - 1) * log(fX*0.5) - 0.5 * fX - log(2.0) - GetLogGamma(0.5*fDF));
696     }
697     else // fDF is small in most cases, we can iterate
698     {
699         double fCount;
700         if (fmod(fDF,2.0)<0.5)
701         {
702             // even
703             fValue = 0.5;
704             fCount = 2.0;
705         }
706         else
707         {
708             fValue = 1/sqrt(fX*2*F_PI);
709             fCount = 1.0;
710         }
711         while ( fCount < fDF)
712         {
713             fValue *= (fX / fCount);
714             fCount += 2.0;
715         }
716         if (fX>=1425.0) // underflow in e^(-x/2)
717             fValue = exp(log(fValue)-fX/2);
718         else
719             fValue *= exp(-fX/2);
720     }
721     return fValue;
722 }
723 
724 void ScInterpreter::ScChiSqDist()
725 {
726     sal_uInt8 nParamCount = GetByte();
727     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
728         return;
729     bool bCumulative;
730     if (nParamCount == 3)
731         bCumulative = GetBool();
732     else
733         bCumulative = true;
734     double fDF = ::rtl::math::approxFloor(GetDouble());
735     if (fDF < 1.0)
736         PushIllegalArgument();
737     else
738     {
739         double fX = GetDouble();
740         if (bCumulative)
741             PushDouble(GetChiSqDistCDF(fX,fDF));
742         else
743             PushDouble(GetChiSqDistPDF(fX,fDF));
744     }
745 }
746 
747 void ScInterpreter::ScChiSqDist_MS()
748 {
749     sal_uInt8 nParamCount = GetByte();
750     if ( !MustHaveParamCount( nParamCount, 3, 3 ) )
751         return;
752     bool bCumulative = GetBool();
753     double fDF = ::rtl::math::approxFloor( GetDouble() );
754     if ( fDF < 1.0 || fDF > 1E10 )
755         PushIllegalArgument();
756     else
757     {
758         double fX = GetDouble();
759         if ( fX < 0 )
760             PushIllegalArgument();
761         else
762         {
763             if ( bCumulative )
764                 PushDouble( GetChiSqDistCDF( fX, fDF ) );
765             else
766                 PushDouble( GetChiSqDistPDF( fX, fDF ) );
767         }
768     }
769 }
770 
771 void ScInterpreter::ScGamma()
772 {
773     double x = GetDouble();
774     if (x <= 0.0 && x == ::rtl::math::approxFloor(x))
775         PushIllegalArgument();
776     else
777     {
778         double fResult = GetGamma(x);
779         if (nGlobalError != FormulaError::NONE)
780         {
781             PushError( nGlobalError);
782             return;
783         }
784         PushDouble(fResult);
785     }
786 }
787 
788 void ScInterpreter::ScLogGamma()
789 {
790     double x = GetDouble();
791     if (x > 0.0)    // constraint from ODFF
792         PushDouble( GetLogGamma(x));
793     else
794         PushIllegalArgument();
795 }
796 
797 double ScInterpreter::GetBeta(double fAlpha, double fBeta)
798 {
799     double fA;
800     double fB;
801     if (fAlpha > fBeta)
802     {
803         fA = fAlpha; fB = fBeta;
804     }
805     else
806     {
807         fA = fBeta; fB = fAlpha;
808     }
809     if (fA+fB < fMaxGammaArgument) // simple case
810         return GetGamma(fA)/GetGamma(fA+fB)*GetGamma(fB);
811     // need logarithm
812     // GetLogGamma is not accurate enough, back to Lanczos for all three
813     // GetGamma and arrange factors newly.
814     const double fg = 6.024680040776729583740234375; //see GetGamma
815     double fgm = fg - 0.5;
816     double fLanczos = lcl_getLanczosSum(fA);
817     fLanczos /= lcl_getLanczosSum(fA+fB);
818     fLanczos *= lcl_getLanczosSum(fB);
819     double fABgm = fA+fB+fgm;
820     fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm));
821     double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
822     double fTempB = fA/(fB+fgm);
823     double fResult = exp(-fA * ::rtl::math::log1p(fTempA)
824                             -fB * ::rtl::math::log1p(fTempB)-fgm);
825     fResult *= fLanczos;
826     return fResult;
827 }
828 
829 // Same as GetBeta but with logarithm
830 double ScInterpreter::GetLogBeta(double fAlpha, double fBeta)
831 {
832     double fA;
833     double fB;
834     if (fAlpha > fBeta)
835     {
836         fA = fAlpha; fB = fBeta;
837     }
838     else
839     {
840         fA = fBeta; fB = fAlpha;
841     }
842     const double fg = 6.024680040776729583740234375; //see GetGamma
843     double fgm = fg - 0.5;
844     double fLanczos = lcl_getLanczosSum(fA);
845     fLanczos /= lcl_getLanczosSum(fA+fB);
846     fLanczos *= lcl_getLanczosSum(fB);
847     double fLogLanczos = log(fLanczos);
848     double fABgm = fA+fB+fgm;
849     fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm));
850     double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
851     double fTempB = fA/(fB+fgm);
852     double fResult = -fA * ::rtl::math::log1p(fTempA)
853                         -fB * ::rtl::math::log1p(fTempB)-fgm;
854     fResult += fLogLanczos;
855     return fResult;
856 }
857 
858 // beta distribution probability density function
859 double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB)
860 {
861     // special cases
862     if (fA == 1.0) // result b*(1-x)^(b-1)
863     {
864         if (fB == 1.0)
865             return 1.0;
866         if (fB == 2.0)
867             return -2.0*fX + 2.0;
868         if (fX == 1.0 && fB < 1.0)
869         {
870             SetError(FormulaError::IllegalArgument);
871             return HUGE_VAL;
872         }
873         if (fX <= 0.01)
874             return fB + fB * ::rtl::math::expm1((fB-1.0) * ::rtl::math::log1p(-fX));
875         else
876             return fB * pow(0.5-fX+0.5,fB-1.0);
877     }
878     if (fB == 1.0) // result a*x^(a-1)
879     {
880         if (fA == 2.0)
881             return fA * fX;
882         if (fX == 0.0 && fA < 1.0)
883         {
884             SetError(FormulaError::IllegalArgument);
885             return HUGE_VAL;
886         }
887         return fA * pow(fX,fA-1);
888     }
889     if (fX <= 0.0)
890     {
891         if (fA < 1.0 && fX == 0.0)
892         {
893             SetError(FormulaError::IllegalArgument);
894             return HUGE_VAL;
895         }
896         else
897             return 0.0;
898     }
899     if (fX >= 1.0)
900     {
901         if (fB < 1.0 && fX == 1.0)
902         {
903             SetError(FormulaError::IllegalArgument);
904             return HUGE_VAL;
905         }
906         else
907             return 0.0;
908     }
909 
910     // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
911     const double fLogDblMax = log( ::std::numeric_limits<double>::max());
912     const double fLogDblMin = log( ::std::numeric_limits<double>::min());
913     double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5);
914     double fLogX = log(fX);
915     double fAm1LogX = (fA-1.0) * fLogX;
916     double fBm1LogY = (fB-1.0) * fLogY;
917     double fLogBeta = GetLogBeta(fA,fB);
918     // check whether parts over- or underflow
919     if (   fAm1LogX < fLogDblMax  && fAm1LogX > fLogDblMin
920         && fBm1LogY < fLogDblMax  && fBm1LogY > fLogDblMin
921         && fLogBeta < fLogDblMax  && fLogBeta > fLogDblMin
922         && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > fLogDblMin)
923         return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB);
924     else // need logarithm;
925         // might overflow as a whole, but seldom, not worth to pre-detect it
926         return exp( fAm1LogX + fBm1LogY - fLogBeta);
927 }
928 
929 /*
930                 x^a * (1-x)^b
931     I_x(a,b) = ----------------  * result of ContFrac
932                 a * Beta(a,b)
933 */
934 static double lcl_GetBetaHelperContFrac(double fX, double fA, double fB)
935 {   // like old version
936     double a1, b1, a2, b2, fnorm, cfnew, cf;
937     a1 = 1.0; b1 = 1.0;
938     b2 = 1.0 - (fA+fB)/(fA+1.0)*fX;
939     if (b2 == 0.0)
940     {
941         a2 = 0.0;
942         fnorm = 1.0;
943         cf = 1.0;
944     }
945     else
946     {
947         a2 = 1.0;
948         fnorm = 1.0/b2;
949         cf = a2*fnorm;
950     }
951     cfnew = 1.0;
952     double rm = 1.0;
953 
954     const double fMaxIter = 50000.0;
955     // loop security, normal cases converge in less than 100 iterations.
956     // FIXME: You will get so much iterations for fX near mean,
957     // I do not know a better algorithm.
958     bool bfinished = false;
959     do
960     {
961         const double apl2m = fA + 2.0*rm;
962         const double d2m = rm*(fB-rm)*fX/((apl2m-1.0)*apl2m);
963         const double d2m1 = -(fA+rm)*(fA+fB+rm)*fX/(apl2m*(apl2m+1.0));
964         a1 = (a2+d2m*a1)*fnorm;
965         b1 = (b2+d2m*b1)*fnorm;
966         a2 = a1 + d2m1*a2*fnorm;
967         b2 = b1 + d2m1*b2*fnorm;
968         if (b2 != 0.0)
969         {
970             fnorm = 1.0/b2;
971             cfnew = a2*fnorm;
972             bfinished = (fabs(cf-cfnew) < fabs(cf)*fMachEps);
973         }
974         cf = cfnew;
975         rm += 1.0;
976     }
977     while (rm < fMaxIter && !bfinished);
978     return cf;
979 }
980 
981 // cumulative distribution function, normalized
982 double ScInterpreter::GetBetaDist(double fXin, double fAlpha, double fBeta)
983 {
984 // special cases
985     if (fXin <= 0.0)  // values are valid, see spec
986         return 0.0;
987     if (fXin >= 1.0)  // values are valid, see spec
988         return 1.0;
989     if (fBeta == 1.0)
990         return pow(fXin, fAlpha);
991     if (fAlpha == 1.0)
992     //            1.0 - pow(1.0-fX,fBeta) is not accurate enough
993         return -::rtl::math::expm1(fBeta * ::rtl::math::log1p(-fXin));
994     //FIXME: need special algorithm for fX near fP for large fA,fB
995     double fResult;
996     // I use always continued fraction, power series are neither
997     // faster nor more accurate.
998     double fY = (0.5-fXin)+0.5;
999     double flnY = ::rtl::math::log1p(-fXin);
1000     double fX = fXin;
1001     double flnX = log(fXin);
1002     double fA = fAlpha;
1003     double fB = fBeta;
1004     bool bReflect = fXin > fAlpha/(fAlpha+fBeta);
1005     if (bReflect)
1006     {
1007         fA = fBeta;
1008         fB = fAlpha;
1009         fX = fY;
1010         fY = fXin;
1011         flnX = flnY;
1012         flnY = log(fXin);
1013     }
1014     fResult = lcl_GetBetaHelperContFrac(fX,fA,fB);
1015     fResult = fResult/fA;
1016     double fP = fA/(fA+fB);
1017     double fQ = fB/(fA+fB);
1018     double fTemp;
1019     if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97) //found experimental
1020         fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY;
1021     else
1022         fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB));
1023     fResult *= fTemp;
1024     if (bReflect)
1025         fResult = 0.5 - fResult + 0.5;
1026     if (fResult > 1.0) // ensure valid range
1027         fResult = 1.0;
1028     if (fResult < 0.0)
1029         fResult = 0.0;
1030     return fResult;
1031 }
1032 
1033 void ScInterpreter::ScBetaDist()
1034 {
1035     sal_uInt8 nParamCount = GetByte();
1036     if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) // expanded, see #i91547#
1037         return;
1038     double fLowerBound, fUpperBound;
1039     double alpha, beta, x;
1040     bool bIsCumulative;
1041     if (nParamCount == 6)
1042         bIsCumulative = GetBool();
1043     else
1044         bIsCumulative = true;
1045     if (nParamCount >= 5)
1046         fUpperBound = GetDouble();
1047     else
1048         fUpperBound = 1.0;
1049     if (nParamCount >= 4)
1050         fLowerBound = GetDouble();
1051     else
1052         fLowerBound = 0.0;
1053     beta = GetDouble();
1054     alpha = GetDouble();
1055     x = GetDouble();
1056     double fScale = fUpperBound - fLowerBound;
1057     if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0)
1058     {
1059         PushIllegalArgument();
1060         return;
1061     }
1062     if (bIsCumulative) // cumulative distribution function
1063     {
1064         // special cases
1065         if (x < fLowerBound)
1066         {
1067             PushDouble(0.0); return; //see spec
1068         }
1069         if (x > fUpperBound)
1070         {
1071             PushDouble(1.0); return; //see spec
1072         }
1073         // normal cases
1074         x = (x-fLowerBound)/fScale;  // convert to standard form
1075         PushDouble(GetBetaDist(x, alpha, beta));
1076         return;
1077     }
1078     else // probability density function
1079     {
1080         if (x < fLowerBound || x > fUpperBound)
1081         {
1082             PushDouble(0.0);
1083             return;
1084         }
1085         x = (x-fLowerBound)/fScale;
1086         PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1087         return;
1088     }
1089 }
1090 
1091 /**
1092   Microsoft version has parameters in different order
1093   Also, upper and lowerbound are optional and have default values
1094   and different constraints apply.
1095   Basically, function is identical with ScInterpreter::ScBetaDist()
1096 */
1097 void ScInterpreter::ScBetaDist_MS()
1098 {
1099     sal_uInt8 nParamCount = GetByte();
1100     if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1101         return;
1102     double fLowerBound, fUpperBound;
1103     double alpha, beta, x;
1104     bool bIsCumulative;
1105     if (nParamCount == 6)
1106         fUpperBound = GetDouble();
1107     else
1108         fUpperBound = 1.0;
1109     if (nParamCount >= 5)
1110         fLowerBound = GetDouble();
1111     else
1112         fLowerBound = 0.0;
1113     bIsCumulative = GetBool();
1114     beta = GetDouble();
1115     alpha = GetDouble();
1116     x = GetDouble();
1117     if (alpha <= 0.0 || beta <= 0.0 || x < fLowerBound || x > fUpperBound)
1118     {
1119         PushIllegalArgument();
1120         return;
1121     }
1122     double fScale = fUpperBound - fLowerBound;
1123     if (bIsCumulative) // cumulative distribution function
1124     {
1125         x = (x-fLowerBound)/fScale;  // convert to standard form
1126         PushDouble(GetBetaDist(x, alpha, beta));
1127         return;
1128     }
1129     else // probability density function
1130     {
1131         x = (x-fLowerBound)/fScale;
1132         PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1133         return;
1134     }
1135 }
1136 
1137 void ScInterpreter::ScPhi()
1138 {
1139     PushDouble(phi(GetDouble()));
1140 }
1141 
1142 void ScInterpreter::ScGauss()
1143 {
1144     PushDouble(gauss(GetDouble()));
1145 }
1146 
1147 void ScInterpreter::ScFisher()
1148 {
1149     double fVal = GetDouble();
1150     if (fabs(fVal) >= 1.0)
1151         PushIllegalArgument();
1152     else
1153         PushDouble( ::rtl::math::atanh( fVal));
1154 }
1155 
1156 void ScInterpreter::ScFisherInv()
1157 {
1158     PushDouble( tanh( GetDouble()));
1159 }
1160 
1161 void ScInterpreter::ScFact()
1162 {
1163     double nVal = GetDouble();
1164     if (nVal < 0.0)
1165         PushIllegalArgument();
1166     else
1167         PushDouble(Fakultaet(nVal));
1168 }
1169 
1170 void ScInterpreter::ScCombin()
1171 {
1172     if ( MustHaveParamCount( GetByte(), 2 ) )
1173     {
1174         double k = ::rtl::math::approxFloor(GetDouble());
1175         double n = ::rtl::math::approxFloor(GetDouble());
1176         if (k < 0.0 || n < 0.0 || k > n)
1177             PushIllegalArgument();
1178         else
1179             PushDouble(BinomKoeff(n, k));
1180     }
1181 }
1182 
1183 void ScInterpreter::ScCombinA()
1184 {
1185     if ( MustHaveParamCount( GetByte(), 2 ) )
1186     {
1187         double k = ::rtl::math::approxFloor(GetDouble());
1188         double n = ::rtl::math::approxFloor(GetDouble());
1189         if (k < 0.0 || n < 0.0 || k > n)
1190             PushIllegalArgument();
1191         else
1192             PushDouble(BinomKoeff(n + k - 1, k));
1193     }
1194 }
1195 
1196 void ScInterpreter::ScPermut()
1197 {
1198     if ( MustHaveParamCount( GetByte(), 2 ) )
1199     {
1200         double k = ::rtl::math::approxFloor(GetDouble());
1201         double n = ::rtl::math::approxFloor(GetDouble());
1202         if (n < 0.0 || k < 0.0 || k > n)
1203             PushIllegalArgument();
1204         else if (k == 0.0)
1205             PushInt(1);     // (n! / (n - 0)!) == 1
1206         else
1207         {
1208             double nVal = n;
1209             for (sal_uLong i = static_cast<sal_uLong>(k)-1; i >= 1; i--)
1210                 nVal *= n-static_cast<double>(i);
1211             PushDouble(nVal);
1212         }
1213     }
1214 }
1215 
1216 void ScInterpreter::ScPermutationA()
1217 {
1218     if ( MustHaveParamCount( GetByte(), 2 ) )
1219     {
1220         double k = ::rtl::math::approxFloor(GetDouble());
1221         double n = ::rtl::math::approxFloor(GetDouble());
1222         if (n < 0.0 || k < 0.0)
1223             PushIllegalArgument();
1224         else
1225             PushDouble(pow(n,k));
1226     }
1227 }
1228 
1229 double ScInterpreter::GetBinomDistPMF(double x, double n, double p)
1230 // used in ScB and ScBinomDist
1231 // preconditions: 0.0 <= x <= n, 0.0 < p < 1.0;  x,n integral although double
1232 {
1233     double q = (0.5 - p) + 0.5;
1234     double fFactor = pow(q, n);
1235     if (fFactor <=::std::numeric_limits<double>::min())
1236     {
1237         fFactor = pow(p, n);
1238         if (fFactor <= ::std::numeric_limits<double>::min())
1239             return GetBetaDistPDF(p, x+1.0, n-x+1.0)/(n+1.0);
1240         else
1241         {
1242             sal_uInt32 max = static_cast<sal_uInt32>(n - x);
1243             for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1244                 fFactor *= (n-i)/(i+1)*q/p;
1245             return fFactor;
1246         }
1247     }
1248     else
1249     {
1250         sal_uInt32 max = static_cast<sal_uInt32>(x);
1251         for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1252             fFactor *= (n-i)/(i+1)*p/q;
1253         return fFactor;
1254     }
1255 }
1256 
1257 static double lcl_GetBinomDistRange(double n, double xs,double xe,
1258             double fFactor /* q^n */, double p, double q)
1259 //preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double
1260 {
1261     sal_uInt32 i;
1262     double fSum;
1263     // skip summands index 0 to xs-1, start sum with index xs
1264     sal_uInt32 nXs = static_cast<sal_uInt32>( xs );
1265     for (i = 1; i <= nXs && fFactor > 0.0; i++)
1266         fFactor *= (n-i+1)/i * p/q;
1267     fSum = fFactor; // Summand xs
1268     sal_uInt32 nXe = static_cast<sal_uInt32>(xe);
1269     for (i = nXs+1; i <= nXe && fFactor > 0.0; i++)
1270     {
1271         fFactor *= (n-i+1)/i * p/q;
1272         fSum += fFactor;
1273     }
1274     return std::min(fSum,1.0);
1275 }
1276 
1277 void ScInterpreter::ScB()
1278 {
1279     sal_uInt8 nParamCount = GetByte();
1280     if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1281         return ;
1282     if (nParamCount == 3)   // mass function
1283     {
1284         double x = ::rtl::math::approxFloor(GetDouble());
1285         double p = GetDouble();
1286         double n = ::rtl::math::approxFloor(GetDouble());
1287         if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1288             PushIllegalArgument();
1289         else if (p == 0.0)
1290             PushDouble( (x == 0.0) ? 1.0 : 0.0 );
1291         else if ( p == 1.0)
1292             PushDouble( (x == n) ? 1.0 : 0.0);
1293         else
1294             PushDouble(GetBinomDistPMF(x,n,p));
1295     }
1296     else
1297     {   // nParamCount == 4
1298         double xe = ::rtl::math::approxFloor(GetDouble());
1299         double xs = ::rtl::math::approxFloor(GetDouble());
1300         double p = GetDouble();
1301         double n = ::rtl::math::approxFloor(GetDouble());
1302         double q = (0.5 - p) + 0.5;
1303         bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n);
1304         if ( bIsValidX && 0.0 < p && p < 1.0)
1305         {
1306             if (xs == xe)       // mass function
1307                 PushDouble(GetBinomDistPMF(xs,n,p));
1308             else
1309             {
1310                 double fFactor = pow(q, n);
1311                 if (fFactor > ::std::numeric_limits<double>::min())
1312                     PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q));
1313                 else
1314                 {
1315                     fFactor = pow(p, n);
1316                     if (fFactor > ::std::numeric_limits<double>::min())
1317                     {
1318                         // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)}
1319                         // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)}
1320                         PushDouble(lcl_GetBinomDistRange(n,n-xe,n-xs,fFactor,q,p));
1321                     }
1322                     else
1323                         PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) );
1324                 }
1325             }
1326         }
1327         else
1328         {
1329             if ( bIsValidX ) // not(0<p<1)
1330             {
1331                 if ( p == 0.0 )
1332                     PushDouble( (xs == 0.0) ? 1.0 : 0.0 );
1333                 else if ( p == 1.0 )
1334                     PushDouble( (xe == n) ? 1.0 : 0.0 );
1335                 else
1336                     PushIllegalArgument();
1337             }
1338             else
1339                 PushIllegalArgument();
1340         }
1341     }
1342 }
1343 
1344 void ScInterpreter::ScBinomDist()
1345 {
1346     if ( MustHaveParamCount( GetByte(), 4 ) )
1347     {
1348         bool bIsCum   = GetBool();     // false=mass function; true=cumulative
1349         double p      = GetDouble();
1350         double n      = ::rtl::math::approxFloor(GetDouble());
1351         double x      = ::rtl::math::approxFloor(GetDouble());
1352         double q = (0.5 - p) + 0.5;           // get one bit more for p near 1.0
1353         if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1354         {
1355             PushIllegalArgument();
1356             return;
1357         }
1358         if ( p == 0.0)
1359         {
1360             PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 );
1361             return;
1362         }
1363         if ( p == 1.0)
1364         {
1365             PushDouble( (x==n) ? 1.0 : 0.0);
1366             return;
1367         }
1368         if (!bIsCum)
1369             PushDouble( GetBinomDistPMF(x,n,p));
1370         else
1371         {
1372             if (x == n)
1373                 PushDouble(1.0);
1374             else
1375             {
1376                 double fFactor = pow(q, n);
1377                 if (x == 0.0)
1378                     PushDouble(fFactor);
1379                 else if (fFactor <= ::std::numeric_limits<double>::min())
1380                 {
1381                     fFactor = pow(p, n);
1382                     if (fFactor <= ::std::numeric_limits<double>::min())
1383                         PushDouble(GetBetaDist(q,n-x,x+1.0));
1384                     else
1385                     {
1386                         if (fFactor > fMachEps)
1387                         {
1388                             double fSum = 1.0 - fFactor;
1389                             sal_uInt32 max = static_cast<sal_uInt32> (n - x) - 1;
1390                             for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1391                             {
1392                                 fFactor *= (n-i)/(i+1)*q/p;
1393                                 fSum -= fFactor;
1394                             }
1395                             PushDouble( (fSum < 0.0) ? 0.0 : fSum );
1396                         }
1397                         else
1398                             PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p));
1399                     }
1400                 }
1401                 else
1402                     PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ;
1403             }
1404         }
1405     }
1406 }
1407 
1408 void ScInterpreter::ScCritBinom()
1409 {
1410     if ( MustHaveParamCount( GetByte(), 3 ) )
1411     {
1412         double alpha  = GetDouble();
1413         double p      = GetDouble();
1414         double n      = ::rtl::math::approxFloor(GetDouble());
1415         if (n < 0.0 || alpha < 0.0 || alpha > 1.0 || p < 0.0 || p > 1.0)
1416             PushIllegalArgument();
1417         else if ( alpha == 0.0 )
1418             PushDouble( 0.0 );
1419         else if ( alpha == 1.0 )
1420             PushDouble( p == 0 ? 0.0 : n );
1421         else
1422         {
1423             double fFactor;
1424             double q = (0.5 - p) + 0.5;           // get one bit more for p near 1.0
1425             if ( q > p )                          // work from the side where the cumulative curve is
1426             {
1427                 // work from 0 upwards
1428                 fFactor = pow(q,n);
1429                 if (fFactor > ::std::numeric_limits<double>::min())
1430                 {
1431                     double fSum = fFactor;
1432                     sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1433                     for (i = 0; i < max && fSum < alpha; i++)
1434                     {
1435                         fFactor *= (n-i)/(i+1)*p/q;
1436                         fSum += fFactor;
1437                     }
1438                     PushDouble(i);
1439                 }
1440                 else
1441                 {
1442                     // accumulate BinomDist until accumulated BinomDist reaches alpha
1443                     double fSum = 0.0;
1444                     sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1445                     for (i = 0; i < max && fSum < alpha; i++)
1446                     {
1447                         const double x = GetBetaDistPDF( p, ( i + 1 ), ( n - i + 1 ) )/( n + 1 );
1448                         if ( nGlobalError == FormulaError::NONE )
1449                         {
1450                             fSum += x;
1451                         }
1452                         else
1453                         {
1454                             PushNoValue();
1455                             return;
1456                         }
1457                     }
1458                     PushDouble( i - 1 );
1459                 }
1460             }
1461             else
1462             {
1463                 // work from n backwards
1464                 fFactor = pow(p, n);
1465                 if (fFactor > ::std::numeric_limits<double>::min())
1466                 {
1467                     double fSum = 1.0 - fFactor;
1468                     sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1469                     for (i = 0; i < max && fSum >= alpha; i++)
1470                     {
1471                         fFactor *= (n-i)/(i+1)*q/p;
1472                         fSum -= fFactor;
1473                     }
1474                     PushDouble(n-i);
1475                 }
1476                 else
1477                 {
1478                     // accumulate BinomDist until accumulated BinomDist reaches alpha
1479                     double fSum = 0.0;
1480                     sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1481                     alpha = 1 - alpha;
1482                     for (i = 0; i < max && fSum < alpha; i++)
1483                     {
1484                         const double x = GetBetaDistPDF( q, ( i + 1 ), ( n - i + 1 ) )/( n + 1 );
1485                         if ( nGlobalError == FormulaError::NONE )
1486                         {
1487                             fSum += x;
1488                         }
1489                         else
1490                         {
1491                             PushNoValue();
1492                             return;
1493                         }
1494                     }
1495                     PushDouble( n - i + 1 );
1496                 }
1497             }
1498         }
1499     }
1500 }
1501 
1502 void ScInterpreter::ScNegBinomDist()
1503 {
1504     if ( MustHaveParamCount( GetByte(), 3 ) )
1505     {
1506         double p = GetDouble();                            // probability
1507         double s = ::rtl::math::approxFloor(GetDouble());  // No of successes
1508         double f = ::rtl::math::approxFloor(GetDouble());  // No of failures
1509         if ((f + s) <= 1.0 || p < 0.0 || p > 1.0)
1510             PushIllegalArgument();
1511         else
1512         {
1513             double q = 1.0 - p;
1514             double fFactor = pow(p,s);
1515             for (double i = 0.0; i < f; i++)
1516                 fFactor *= (i+s)/(i+1.0)*q;
1517             PushDouble(fFactor);
1518         }
1519     }
1520 }
1521 
1522 void ScInterpreter::ScNegBinomDist_MS()
1523 {
1524     if ( MustHaveParamCount( GetByte(), 4 ) )
1525     {
1526         bool bCumulative = GetBool();
1527         double p = GetDouble();                            // probability
1528         double s = ::rtl::math::approxFloor(GetDouble());  // No of successes
1529         double f = ::rtl::math::approxFloor(GetDouble());  // No of failures
1530         if ( s < 1.0 || f < 0.0 || p < 0.0 || p > 1.0 )
1531             PushIllegalArgument();
1532         else
1533         {
1534             double q = 1.0 - p;
1535             if ( bCumulative )
1536                 PushDouble( 1.0 - GetBetaDist( q, f + 1, s ) );
1537             else
1538             {
1539                 double fFactor = pow( p, s );
1540                 for ( double i = 0.0; i < f; i++ )
1541                     fFactor *= ( i + s ) / ( i + 1.0 ) * q;
1542                 PushDouble( fFactor );
1543             }
1544         }
1545     }
1546 }
1547 
1548 void ScInterpreter::ScNormDist( int nMinParamCount )
1549 {
1550     sal_uInt8 nParamCount = GetByte();
1551     if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
1552         return;
1553     bool bCumulative = nParamCount != 4 || GetBool();
1554     double sigma = GetDouble();                 // standard deviation
1555     double mue = GetDouble();                   // mean
1556     double x = GetDouble();                     // x
1557     if (sigma <= 0.0)
1558     {
1559         PushIllegalArgument();
1560         return;
1561     }
1562     if (bCumulative)
1563         PushDouble(integralPhi((x-mue)/sigma));
1564     else
1565         PushDouble(phi((x-mue)/sigma)/sigma);
1566 }
1567 
1568 void ScInterpreter::ScLogNormDist( int nMinParamCount ) //expanded, see #i100119# and fdo72158
1569 {
1570     sal_uInt8 nParamCount = GetByte();
1571     if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
1572         return;
1573     bool bCumulative = nParamCount != 4 || GetBool(); // cumulative
1574     double sigma = nParamCount >= 3 ? GetDouble() : 1.0; // standard deviation
1575     double mue = nParamCount >= 2 ? GetDouble() : 0.0;   // mean
1576     double x = GetDouble();                              // x
1577     if (sigma <= 0.0)
1578     {
1579         PushIllegalArgument();
1580         return;
1581     }
1582     if (bCumulative)
1583     { // cumulative
1584         if (x <= 0.0)
1585             PushDouble(0.0);
1586         else
1587             PushDouble(integralPhi((log(x)-mue)/sigma));
1588     }
1589     else
1590     { // density
1591         if (x <= 0.0)
1592             PushIllegalArgument();
1593         else
1594             PushDouble(phi((log(x)-mue)/sigma)/sigma/x);
1595     }
1596 }
1597 
1598 void ScInterpreter::ScStdNormDist()
1599 {
1600     PushDouble(integralPhi(GetDouble()));
1601 }
1602 
1603 void ScInterpreter::ScStdNormDist_MS()
1604 {
1605     sal_uInt8 nParamCount = GetByte();
1606     if ( !MustHaveParamCount( nParamCount, 2 ) )
1607         return;
1608     bool bCumulative = GetBool();                        // cumulative
1609     double x = GetDouble();                              // x
1610 
1611     if ( bCumulative )
1612         PushDouble( integralPhi( x ) );
1613     else
1614         PushDouble( exp( - pow( x, 2 ) / 2 ) / sqrt( 2 * F_PI ) );
1615 }
1616 
1617 void ScInterpreter::ScExpDist()
1618 {
1619     if ( MustHaveParamCount( GetByte(), 3 ) )
1620     {
1621         double kum    = GetDouble();                    // 0 or 1
1622         double lambda = GetDouble();                    // lambda
1623         double x      = GetDouble();                    // x
1624         if (lambda <= 0.0)
1625             PushIllegalArgument();
1626         else if (kum == 0.0)                        // density
1627         {
1628             if (x >= 0.0)
1629                 PushDouble(lambda * exp(-lambda*x));
1630             else
1631                 PushInt(0);
1632         }
1633         else                                        // distribution
1634         {
1635             if (x > 0.0)
1636                 PushDouble(1.0 - exp(-lambda*x));
1637             else
1638                 PushInt(0);
1639         }
1640     }
1641 }
1642 
1643 void ScInterpreter::ScTDist()
1644 {
1645     if ( !MustHaveParamCount( GetByte(), 3 ) )
1646         return;
1647     double fFlag = ::rtl::math::approxFloor(GetDouble());
1648     double fDF   = ::rtl::math::approxFloor(GetDouble());
1649     double T     = GetDouble();
1650     if (fDF < 1.0 || T < 0.0 || (fFlag != 1.0 && fFlag != 2.0) )
1651     {
1652         PushIllegalArgument();
1653         return;
1654     }
1655     PushDouble( GetTDist( T, fDF, static_cast<int>(fFlag) ) );
1656 }
1657 
1658 void ScInterpreter::ScTDist_T( int nTails )
1659 {
1660     if ( !MustHaveParamCount( GetByte(), 2 ) )
1661         return;
1662     double fDF = ::rtl::math::approxFloor( GetDouble() );
1663     double fT  = GetDouble();
1664     if ( fDF < 1.0 || ( nTails == 2 && fT < 0.0 ) )
1665     {
1666         PushIllegalArgument();
1667         return;
1668     }
1669     double fRes = GetTDist( fT, fDF, nTails );
1670     if ( nTails == 1 && fT < 0.0 )
1671         PushDouble( 1.0 - fRes ); // tdf#105937, right tail, negative X
1672     else
1673         PushDouble( fRes );
1674 }
1675 
1676 void ScInterpreter::ScTDist_MS()
1677 {
1678     if ( !MustHaveParamCount( GetByte(), 3 ) )
1679         return;
1680     bool   bCumulative = GetBool();
1681     double fDF = ::rtl::math::approxFloor( GetDouble() );
1682     double T   = GetDouble();
1683     if ( fDF < 1.0 )
1684     {
1685         PushIllegalArgument();
1686         return;
1687     }
1688     PushDouble( GetTDist( T, fDF, ( bCumulative ? 4 : 3 ) ) );
1689 }
1690 
1691 void ScInterpreter::ScFDist()
1692 {
1693     if ( !MustHaveParamCount( GetByte(), 3 ) )
1694         return;
1695     double fF2 = ::rtl::math::approxFloor(GetDouble());
1696     double fF1 = ::rtl::math::approxFloor(GetDouble());
1697     double fF  = GetDouble();
1698     if (fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10)
1699     {
1700         PushIllegalArgument();
1701         return;
1702     }
1703     PushDouble(GetFDist(fF, fF1, fF2));
1704 }
1705 
1706 void ScInterpreter::ScFDist_LT()
1707 {
1708     int nParamCount = GetByte();
1709     if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1710         return;
1711     bool bCum;
1712     if ( nParamCount == 3 )
1713         bCum = true;
1714     else if ( IsMissing() )
1715     {
1716         bCum = true;
1717         Pop();
1718     }
1719     else
1720         bCum = GetBool();
1721     double fF2 = ::rtl::math::approxFloor( GetDouble() );
1722     double fF1 = ::rtl::math::approxFloor( GetDouble() );
1723     double fF  = GetDouble();
1724     if ( fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 )
1725     {
1726         PushIllegalArgument();
1727         return;
1728     }
1729     if ( bCum )
1730     {
1731         // left tail cumulative distribution
1732         PushDouble( 1.0 - GetFDist( fF, fF1, fF2 ) );
1733     }
1734     else
1735     {
1736         // probability density function
1737         PushDouble( pow( fF1 / fF2, fF1 / 2 ) * pow( fF, ( fF1 / 2 ) - 1 ) /
1738                     ( pow( ( 1 + ( fF * fF1 / fF2 ) ), ( fF1 + fF2 ) / 2 ) *
1739                       GetBeta( fF1 / 2, fF2 / 2 ) ) );
1740     }
1741 }
1742 
1743 void ScInterpreter::ScChiDist( bool bODFF )
1744 {
1745     double fResult;
1746     if ( !MustHaveParamCount( GetByte(), 2 ) )
1747         return;
1748     double fDF  = ::rtl::math::approxFloor(GetDouble());
1749     double fChi = GetDouble();
1750     if ( fDF < 1.0 // x<=0 returns 1, see ODFF1.2 6.18.11
1751        || ( !bODFF && fChi < 0 ) ) // Excel does not accept negative fChi
1752     {
1753         PushIllegalArgument();
1754         return;
1755     }
1756     fResult = GetChiDist( fChi, fDF);
1757     if (nGlobalError != FormulaError::NONE)
1758     {
1759         PushError( nGlobalError);
1760         return;
1761     }
1762     PushDouble(fResult);
1763 }
1764 
1765 void ScInterpreter::ScWeibull()
1766 {
1767     if ( MustHaveParamCount( GetByte(), 4 ) )
1768     {
1769         double kum   = GetDouble();                 // 0 or 1
1770         double beta  = GetDouble();                 // beta
1771         double alpha = GetDouble();                 // alpha
1772         double x     = GetDouble();                 // x
1773         if (alpha <= 0.0 || beta <= 0.0 || x < 0.0)
1774             PushIllegalArgument();
1775         else if (kum == 0.0)                        // Density
1776             PushDouble(alpha/pow(beta,alpha)*pow(x,alpha-1.0)*
1777                        exp(-pow(x/beta,alpha)));
1778         else                                        // Distribution
1779             PushDouble(1.0 - exp(-pow(x/beta,alpha)));
1780     }
1781 }
1782 
1783 void ScInterpreter::ScPoissonDist( bool bODFF )
1784 {
1785     sal_uInt8 nParamCount = GetByte();
1786     if ( MustHaveParamCount( nParamCount, ( bODFF ? 2 : 3 ), 3 ) )
1787     {
1788         bool bCumulative = nParamCount != 3 || GetBool();         // default cumulative
1789         double lambda    = GetDouble();                           // Mean
1790         double x         = ::rtl::math::approxFloor(GetDouble()); // discrete distribution
1791         if (lambda <= 0.0 || x < 0.0)
1792             PushIllegalArgument();
1793         else if (!bCumulative)                            // Probability mass function
1794         {
1795             if (lambda >712.0)    // underflow in exp(-lambda)
1796             {   // accuracy 11 Digits
1797                 PushDouble( exp(x*log(lambda)-lambda-GetLogGamma(x+1.0)));
1798             }
1799             else
1800             {
1801                 double fPoissonVar = 1.0;
1802                 for ( double f = 0.0; f < x; ++f )
1803                     fPoissonVar *= lambda / ( f + 1.0 );
1804                 PushDouble( fPoissonVar * exp( -lambda ) );
1805             }
1806         }
1807         else                                // Cumulative distribution function
1808         {
1809             if (lambda > 712.0)  // underflow in exp(-lambda)
1810             {   // accuracy 12 Digits
1811                 PushDouble(GetUpRegIGamma(x+1.0,lambda));
1812             }
1813             else
1814             {
1815                 if (x >= 936.0) // result is always indistinguishable from 1
1816                     PushDouble (1.0);
1817                 else
1818                 {
1819                     double fSummand = exp(-lambda);
1820                     double fSum = fSummand;
1821                     int nEnd = sal::static_int_cast<int>( x );
1822                     for (int i = 1; i <= nEnd; i++)
1823                     {
1824                         fSummand = (fSummand * lambda)/static_cast<double>(i);
1825                         fSum += fSummand;
1826                     }
1827                     PushDouble(fSum);
1828                 }
1829             }
1830         }
1831     }
1832 }
1833 
1834 /** Local function used in the calculation of the hypergeometric distribution.
1835  */
1836 static void lcl_PutFactorialElements( ::std::vector< double >& cn, double fLower, double fUpper, double fBase )
1837 {
1838     for ( double i = fLower; i <= fUpper; ++i )
1839     {
1840         double fVal = fBase - i;
1841         if ( fVal > 1.0 )
1842             cn.push_back( fVal );
1843     }
1844 }
1845 
1846 /** Calculates a value of the hypergeometric distribution.
1847 
1848     @see #i47296#
1849 
1850     This function has an extra argument bCumulative,
1851     which only calculates the non-cumulative distribution and
1852     which is optional in Calc and mandatory with Excel's HYPGEOM.DIST()
1853 
1854     @see fdo#71722
1855     @see tdf#102948, make Calc function ODFF1.2-compliant
1856     @see tdf#117041, implement note at bottom of ODFF1.2 par.6.18.37
1857  */
1858 void ScInterpreter::ScHypGeomDist( int nMinParamCount )
1859 {
1860     sal_uInt8 nParamCount = GetByte();
1861     if ( !MustHaveParamCount( nParamCount, nMinParamCount, 5 ) )
1862         return;
1863 
1864     bool bCumulative = ( nParamCount == 5 && GetBool() );
1865     double N = ::rtl::math::approxFloor(GetDouble());
1866     double M = ::rtl::math::approxFloor(GetDouble());
1867     double n = ::rtl::math::approxFloor(GetDouble());
1868     double x = ::rtl::math::approxFloor(GetDouble());
1869 
1870     if ( (x < 0.0) || (n < x) || (N < n) || (N < M) || (M < 0.0) )
1871     {
1872         PushIllegalArgument();
1873         return;
1874     }
1875 
1876     double fVal = 0.0;
1877 
1878     for ( int i = ( bCumulative ? 0 : x ); i <= x && nGlobalError == FormulaError::NONE; i++ )
1879     {
1880         if ( (n - i <= N - M) && (i <= M) )
1881             fVal +=  GetHypGeomDist( i, n, M, N );
1882     }
1883 
1884     PushDouble( fVal );
1885 }
1886 
1887 /** Calculates a value of the hypergeometric distribution.
1888 
1889     The algorithm is designed to avoid unnecessary multiplications and division
1890     by expanding all factorial elements (9 of them).  It is done by excluding
1891     those ranges that overlap in the numerator and the denominator.  This allows
1892     for a fast calculation for large values which would otherwise cause an overflow
1893     in the intermediate values.
1894 
1895     @see #i47296#
1896  */
1897 double ScInterpreter::GetHypGeomDist( double x, double n, double M, double N )
1898 {
1899     const size_t nMaxArraySize = 500000; // arbitrary max array size
1900 
1901     std::vector<double> cnNumer, cnDenom;
1902 
1903     size_t nEstContainerSize = static_cast<size_t>( x + ::std::min( n, M ) );
1904     size_t nMaxSize = ::std::min( cnNumer.max_size(), nMaxArraySize );
1905     if ( nEstContainerSize > nMaxSize )
1906     {
1907         PushNoValue();
1908         return 0;
1909     }
1910     cnNumer.reserve( nEstContainerSize + 10 );
1911     cnDenom.reserve( nEstContainerSize + 10 );
1912 
1913     // Trim coefficient C first
1914     double fCNumVarUpper = N - n - M + x - 1.0;
1915     double fCDenomVarLower = 1.0;
1916     if ( N - n - M + x >= M - x + 1.0 )
1917     {
1918         fCNumVarUpper = M - x - 1.0;
1919         fCDenomVarLower = N - n - 2.0*(M - x) + 1.0;
1920     }
1921 
1922     double fCNumLower = N - n - fCNumVarUpper;
1923     double fCDenomUpper = N - n - M + x + 1.0 - fCDenomVarLower;
1924 
1925     double fDNumVarLower = n - M;
1926 
1927     if ( n >= M + 1.0 )
1928     {
1929         if ( N - M < n + 1.0 )
1930         {
1931             // Case 1
1932 
1933             if ( N - n < n + 1.0 )
1934             {
1935                 // no overlap
1936                 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1937                 lcl_PutFactorialElements( cnDenom, 0.0, N - n - 1.0, N );
1938             }
1939             else
1940             {
1941                 // overlap
1942                 OSL_ENSURE( fCNumLower < n + 1.0, "ScHypGeomDist: wrong assertion" );
1943                 lcl_PutFactorialElements( cnNumer, N - 2.0*n, fCNumVarUpper, N - n );
1944                 lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
1945             }
1946 
1947             OSL_ENSURE( fCDenomUpper <= N - M, "ScHypGeomDist: wrong assertion" );
1948 
1949             if ( fCDenomUpper < n - x + 1.0 )
1950                 // no overlap
1951                 lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
1952             else
1953             {
1954                 // overlap
1955                 lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
1956 
1957                 fCDenomUpper = n - x;
1958                 fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
1959             }
1960         }
1961         else
1962         {
1963             // Case 2
1964 
1965             if ( n > M - 1.0 )
1966             {
1967                 // no overlap
1968                 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1969                 lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
1970             }
1971             else
1972             {
1973                 lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
1974                 lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
1975             }
1976 
1977             OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
1978 
1979             if ( fCDenomUpper < n - x + 1.0 )
1980                 // no overlap
1981                 lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - n + x, N - M + 1.0 );
1982             else
1983             {
1984                 lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
1985                 fCDenomUpper = n - x;
1986                 fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
1987             }
1988         }
1989 
1990         OSL_ENSURE( fCDenomUpper <= M, "ScHypGeomDist: wrong assertion" );
1991     }
1992     else
1993     {
1994         if ( N - M < M + 1.0 )
1995         {
1996             // Case 3
1997 
1998             if ( N - n < M + 1.0 )
1999             {
2000                 // No overlap
2001                 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2002                 lcl_PutFactorialElements( cnDenom, 0.0, N - M - 1.0, N );
2003             }
2004             else
2005             {
2006                 lcl_PutFactorialElements( cnNumer, N - n - M, fCNumVarUpper, N - n );
2007                 lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
2008             }
2009 
2010             if ( n - x + 1.0 > fCDenomUpper )
2011                 // No overlap
2012                 lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
2013             else
2014             {
2015                 // Overlap
2016                 lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 );
2017 
2018                 fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2019                 fCDenomUpper = n - x;
2020             }
2021         }
2022         else
2023         {
2024             // Case 4
2025 
2026             OSL_ENSURE( M >= n - x, "ScHypGeomDist: wrong assertion" );
2027             OSL_ENSURE( M - x <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
2028 
2029             if ( N - n < N - M + 1.0 )
2030             {
2031                 // No overlap
2032                 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2033                 lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
2034             }
2035             else
2036             {
2037                 // Overlap
2038                 OSL_ENSURE( fCNumLower <= N - M + 1.0, "ScHypGeomDist: wrong assertion" );
2039                 lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n );
2040                 lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N );
2041             }
2042 
2043             if ( n - x + 1.0 > fCDenomUpper )
2044                 // No overlap
2045                 lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - n + x, N - M + 1.0 );
2046             else if ( M >= fCDenomUpper )
2047             {
2048                 lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - fCDenomUpper, N - M + 1.0 );
2049 
2050                 fCDenomUpper = n - x;
2051                 fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2052             }
2053             else
2054             {
2055                 OSL_ENSURE( M <= fCDenomUpper, "ScHypGeomDist: wrong assertion" );
2056                 lcl_PutFactorialElements( cnDenom, fCDenomVarLower, N - n - 2.0*M + x,
2057                         N - n - M + x + 1.0 );
2058 
2059                 fCDenomUpper = n - x;
2060                 fCDenomVarLower = N - M - 2.0*(n - x) + 1.0;
2061             }
2062         }
2063 
2064         OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" );
2065 
2066         fDNumVarLower = 0.0;
2067     }
2068 
2069     double nDNumVarUpper   = fCDenomUpper < x + 1.0 ? n - x - 1.0     : n - fCDenomUpper - 1.0;
2070     double nDDenomVarLower = fCDenomUpper < x + 1.0 ? fCDenomVarLower : N - n - M + 1.0;
2071     lcl_PutFactorialElements( cnNumer, fDNumVarLower, nDNumVarUpper, n );
2072     lcl_PutFactorialElements( cnDenom, nDDenomVarLower, N - n - M + x, N - n - M + x + 1.0 );
2073 
2074     ::std::sort( cnNumer.begin(), cnNumer.end() );
2075     ::std::sort( cnDenom.begin(), cnDenom.end() );
2076     auto it1 = cnNumer.rbegin(), it1End = cnNumer.rend();
2077     auto it2 = cnDenom.rbegin(), it2End = cnDenom.rend();
2078 
2079     double fFactor = 1.0;
2080     for ( ; it1 != it1End || it2 != it2End; )
2081     {
2082         double fEnum = 1.0, fDenom = 1.0;
2083         if ( it1 != it1End )
2084             fEnum  = *it1++;
2085         if ( it2 != it2End )
2086             fDenom = *it2++;
2087         fFactor *= fEnum / fDenom;
2088     }
2089 
2090     return fFactor;
2091 }
2092 
2093 void ScInterpreter::ScGammaDist( bool bODFF )
2094 {
2095     sal_uInt8 nMinParamCount = ( bODFF ? 3 : 4 );
2096     sal_uInt8 nParamCount = GetByte();
2097     if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
2098         return;
2099     bool bCumulative;
2100     if (nParamCount == 4)
2101         bCumulative = GetBool();
2102     else
2103         bCumulative = true;
2104     double fBeta = GetDouble();                 // scale
2105     double fAlpha = GetDouble();                // shape
2106     double fX = GetDouble();                    // x
2107     if ((!bODFF && fX < 0) || fAlpha <= 0.0 || fBeta <= 0.0)
2108         PushIllegalArgument();
2109     else
2110     {
2111         if (bCumulative)                        // distribution
2112             PushDouble( GetGammaDist( fX, fAlpha, fBeta));
2113         else                                    // density
2114             PushDouble( GetGammaDistPDF( fX, fAlpha, fBeta));
2115     }
2116 }
2117 
2118 void ScInterpreter::ScNormInv()
2119 {
2120     if ( MustHaveParamCount( GetByte(), 3 ) )
2121     {
2122         double sigma = GetDouble();
2123         double mue   = GetDouble();
2124         double x     = GetDouble();
2125         if (sigma <= 0.0 || x < 0.0 || x > 1.0)
2126             PushIllegalArgument();
2127         else if (x == 0.0 || x == 1.0)
2128             PushNoValue();
2129         else
2130             PushDouble(gaussinv(x)*sigma + mue);
2131     }
2132 }
2133 
2134 void ScInterpreter::ScSNormInv()
2135 {
2136     double x = GetDouble();
2137     if (x < 0.0 || x > 1.0)
2138         PushIllegalArgument();
2139     else if (x == 0.0 || x == 1.0)
2140         PushNoValue();
2141     else
2142         PushDouble(gaussinv(x));
2143 }
2144 
2145 void ScInterpreter::ScLogNormInv()
2146 {
2147     sal_uInt8 nParamCount = GetByte();
2148     if ( MustHaveParamCount( nParamCount, 1, 3 ) )
2149     {
2150         double fSigma = ( nParamCount == 3 ? GetDouble() : 1.0 );  // Stddev
2151         double fMue = ( nParamCount >= 2 ? GetDouble() : 0.0 );    // Mean
2152         double fP = GetDouble();                                   // p
2153         if ( fSigma <= 0.0 || fP <= 0.0 || fP >= 1.0 )
2154             PushIllegalArgument();
2155         else
2156             PushDouble( exp( fMue + fSigma * gaussinv( fP ) ) );
2157     }
2158 }
2159 
2160 class ScGammaDistFunction : public ScDistFunc
2161 {
2162     ScInterpreter&  rInt;
2163     double          fp, fAlpha, fBeta;
2164 
2165 public:
2166             ScGammaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
2167                 rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
2168 
2169     virtual ~ScGammaDistFunction() {}
2170 
2171     double  GetValue( double x ) const override  { return fp - rInt.GetGammaDist(x, fAlpha, fBeta); }
2172 };
2173 
2174 void ScInterpreter::ScGammaInv()
2175 {
2176     if ( !MustHaveParamCount( GetByte(), 3 ) )
2177         return;
2178     double fBeta  = GetDouble();
2179     double fAlpha = GetDouble();
2180     double fP = GetDouble();
2181     if (fAlpha <= 0.0 || fBeta <= 0.0 || fP < 0.0 || fP >= 1.0 )
2182     {
2183         PushIllegalArgument();
2184         return;
2185     }
2186     if (fP == 0.0)
2187         PushInt(0);
2188     else
2189     {
2190         bool bConvError;
2191         ScGammaDistFunction aFunc( *this, fP, fAlpha, fBeta );
2192         double fStart = fAlpha * fBeta;
2193         double fVal = lcl_IterateInverse( aFunc, fStart*0.5, fStart, bConvError );
2194         if (bConvError)
2195             SetError(FormulaError::NoConvergence);
2196         PushDouble(fVal);
2197     }
2198 }
2199 
2200 class ScBetaDistFunction : public ScDistFunc
2201 {
2202     ScInterpreter&  rInt;
2203     double          fp, fAlpha, fBeta;
2204 
2205 public:
2206             ScBetaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) :
2207                 rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {}
2208 
2209     virtual ~ScBetaDistFunction() {}
2210 
2211     double  GetValue( double x ) const override  { return fp - rInt.GetBetaDist(x, fAlpha, fBeta); }
2212 };
2213 
2214 void ScInterpreter::ScBetaInv()
2215 {
2216     sal_uInt8 nParamCount = GetByte();
2217     if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
2218         return;
2219     double fP, fA, fB, fAlpha, fBeta;
2220     if (nParamCount == 5)
2221         fB = GetDouble();
2222     else
2223         fB = 1.0;
2224     if (nParamCount >= 4)
2225         fA = GetDouble();
2226     else
2227         fA = 0.0;
2228     fBeta  = GetDouble();
2229     fAlpha = GetDouble();
2230     fP     = GetDouble();
2231     if (fP < 0.0 || fP > 1.0 || fA >= fB || fAlpha <= 0.0 || fBeta <= 0.0)
2232     {
2233         PushIllegalArgument();
2234         return;
2235     }
2236 
2237     bool bConvError;
2238     ScBetaDistFunction aFunc( *this, fP, fAlpha, fBeta );
2239     // 0..1 as range for iteration so it isn't extended beyond the valid range
2240     double fVal = lcl_IterateInverse( aFunc, 0.0, 1.0, bConvError );
2241     if (bConvError)
2242         PushError( FormulaError::NoConvergence);
2243     else
2244         PushDouble(fA + fVal*(fB-fA));                  // scale to (A,B)
2245 }
2246 
2247 // Note: T, F, and Chi are
2248 // monotonically decreasing,
2249 // therefore 1-Dist as function
2250 
2251 class ScTDistFunction : public ScDistFunc
2252 {
2253     ScInterpreter&  rInt;
2254     double          fp, fDF;
2255     int             nT;
2256 
2257 public:
2258             ScTDistFunction( ScInterpreter& rI, double fpVal, double fDFVal, int nType ) :
2259                 rInt( rI ), fp( fpVal ), fDF( fDFVal ), nT( nType ) {}
2260 
2261     virtual ~ScTDistFunction() {}
2262 
2263     double  GetValue( double x ) const override  { return fp - rInt.GetTDist( x, fDF, nT ); }
2264 };
2265 
2266 void ScInterpreter::ScTInv( int nType )
2267 {
2268     if ( !MustHaveParamCount( GetByte(), 2 ) )
2269         return;
2270     double fDF  = ::rtl::math::approxFloor(GetDouble());
2271     double fP = GetDouble();
2272     if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2273     {
2274         PushIllegalArgument();
2275         return;
2276     }
2277     if ( nType == 4 ) // left-tailed cumulative t-distribution
2278     {
2279         if ( fP == 1.0 )
2280             PushIllegalArgument();
2281         else if ( fP < 0.5 )
2282             PushDouble( -GetTInv( 1 - fP, fDF, nType ) );
2283         else
2284             PushDouble( GetTInv( fP, fDF, nType ) );
2285     }
2286     else
2287         PushDouble( GetTInv( fP, fDF, nType ) );
2288 };
2289 
2290 double ScInterpreter::GetTInv( double fAlpha, double fSize, int nType )
2291 {
2292     bool bConvError;
2293     ScTDistFunction aFunc( *this, fAlpha, fSize, nType );
2294     double fVal = lcl_IterateInverse( aFunc, fSize * 0.5, fSize, bConvError );
2295     if (bConvError)
2296         SetError(FormulaError::NoConvergence);
2297     return fVal;
2298 }
2299 
2300 class ScFDistFunction : public ScDistFunc
2301 {
2302     ScInterpreter&  rInt;
2303     double          fp, fF1, fF2;
2304 
2305 public:
2306             ScFDistFunction( ScInterpreter& rI, double fpVal, double fF1Val, double fF2Val ) :
2307                 rInt(rI), fp(fpVal), fF1(fF1Val), fF2(fF2Val) {}
2308 
2309     virtual ~ScFDistFunction() {}
2310 
2311     double  GetValue( double x ) const override  { return fp - rInt.GetFDist(x, fF1, fF2); }
2312 };
2313 
2314 void ScInterpreter::ScFInv()
2315 {
2316     if ( !MustHaveParamCount( GetByte(), 3 ) )
2317         return;
2318     double fF2 = ::rtl::math::approxFloor(GetDouble());
2319     double fF1 = ::rtl::math::approxFloor(GetDouble());
2320     double fP  = GetDouble();
2321     if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0)
2322     {
2323         PushIllegalArgument();
2324         return;
2325     }
2326 
2327     bool bConvError;
2328     ScFDistFunction aFunc( *this, fP, fF1, fF2 );
2329     double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2330     if (bConvError)
2331         SetError(FormulaError::NoConvergence);
2332     PushDouble(fVal);
2333 }
2334 
2335 void ScInterpreter::ScFInv_LT()
2336 {
2337     if ( !MustHaveParamCount( GetByte(), 3 ) )
2338         return;
2339     double fF2 = ::rtl::math::approxFloor(GetDouble());
2340     double fF1 = ::rtl::math::approxFloor(GetDouble());
2341     double fP  = GetDouble();
2342     if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0)
2343     {
2344         PushIllegalArgument();
2345         return;
2346     }
2347 
2348     bool bConvError;
2349     ScFDistFunction aFunc( *this, ( 1.0 - fP ), fF1, fF2 );
2350     double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2351     if (bConvError)
2352         SetError(FormulaError::NoConvergence);
2353     PushDouble(fVal);
2354 }
2355 
2356 class ScChiDistFunction : public ScDistFunc
2357 {
2358     ScInterpreter&  rInt;
2359     double          fp, fDF;
2360 
2361 public:
2362             ScChiDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
2363                 rInt(rI), fp(fpVal), fDF(fDFVal) {}
2364 
2365     virtual ~ScChiDistFunction() {}
2366 
2367     double  GetValue( double x ) const override  { return fp - rInt.GetChiDist(x, fDF); }
2368 };
2369 
2370 void ScInterpreter::ScChiInv()
2371 {
2372     if ( !MustHaveParamCount( GetByte(), 2 ) )
2373         return;
2374     double fDF  = ::rtl::math::approxFloor(GetDouble());
2375     double fP = GetDouble();
2376     if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2377     {
2378         PushIllegalArgument();
2379         return;
2380     }
2381 
2382     bool bConvError;
2383     ScChiDistFunction aFunc( *this, fP, fDF );
2384     double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2385     if (bConvError)
2386         SetError(FormulaError::NoConvergence);
2387     PushDouble(fVal);
2388 }
2389 
2390 /***********************************************/
2391 class ScChiSqDistFunction : public ScDistFunc
2392 {
2393     ScInterpreter&  rInt;
2394     double          fp, fDF;
2395 
2396 public:
2397             ScChiSqDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) :
2398                 rInt(rI), fp(fpVal), fDF(fDFVal) {}
2399 
2400     virtual ~ScChiSqDistFunction() {}
2401 
2402     double  GetValue( double x ) const override  { return fp - rInt.GetChiSqDistCDF(x, fDF); }
2403 };
2404 
2405 void ScInterpreter::ScChiSqInv()
2406 {
2407     if ( !MustHaveParamCount( GetByte(), 2 ) )
2408         return;
2409     double fDF  = ::rtl::math::approxFloor(GetDouble());
2410     double fP = GetDouble();
2411     if (fDF < 1.0 || fP < 0.0 || fP >= 1.0 )
2412     {
2413         PushIllegalArgument();
2414         return;
2415     }
2416 
2417     bool bConvError;
2418     ScChiSqDistFunction aFunc( *this, fP, fDF );
2419     double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2420     if (bConvError)
2421         SetError(FormulaError::NoConvergence);
2422     PushDouble(fVal);
2423 }
2424 
2425 void ScInterpreter::ScConfidence()
2426 {
2427     if ( MustHaveParamCount( GetByte(), 3 ) )
2428     {
2429         double n     = ::rtl::math::approxFloor(GetDouble());
2430         double sigma = GetDouble();
2431         double alpha = GetDouble();
2432         if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0)
2433             PushIllegalArgument();
2434         else
2435             PushDouble( gaussinv(1.0-alpha/2.0) * sigma/sqrt(n) );
2436     }
2437 }
2438 
2439 void ScInterpreter::ScConfidenceT()
2440 {
2441     if ( MustHaveParamCount( GetByte(), 3 ) )
2442     {
2443         double n     = ::rtl::math::approxFloor(GetDouble());
2444         double sigma = GetDouble();
2445         double alpha = GetDouble();
2446         if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0)
2447             PushIllegalArgument();
2448         else if (n == 1.0) // for interoperability with Excel
2449             PushError(FormulaError::DivisionByZero);
2450         else
2451             PushDouble( sigma * GetTInv( alpha, n - 1, 2 ) / sqrt( n ) );
2452     }
2453 }
2454 
2455 void ScInterpreter::ScZTest()
2456 {
2457     sal_uInt8 nParamCount = GetByte();
2458     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
2459         return;
2460     double sigma = 0.0, x;
2461     if (nParamCount == 3)
2462     {
2463         sigma = GetDouble();
2464         if (sigma <= 0.0)
2465         {
2466             PushIllegalArgument();
2467             return;
2468         }
2469     }
2470     x = GetDouble();
2471 
2472     double fSum    = 0.0;
2473     double fSumSqr = 0.0;
2474     double fVal;
2475     double rValCount = 0.0;
2476     switch (GetStackType())
2477     {
2478         case svDouble :
2479         {
2480             fVal = GetDouble();
2481             fSum    += fVal;
2482             fSumSqr += fVal*fVal;
2483             rValCount++;
2484         }
2485         break;
2486         case svSingleRef :
2487         {
2488             ScAddress aAdr;
2489             PopSingleRef( aAdr );
2490             ScRefCellValue aCell(*pDok, aAdr);
2491             if (aCell.hasNumeric())
2492             {
2493                 fVal = GetCellValue(aAdr, aCell);
2494                 fSum += fVal;
2495                 fSumSqr += fVal*fVal;
2496                 rValCount++;
2497             }
2498         }
2499         break;
2500         case svRefList :
2501         case svDoubleRef :
2502         {
2503             short nParam = 1;
2504             size_t nRefInList = 0;
2505             while (nParam-- > 0)
2506             {
2507                 ScRange aRange;
2508                 FormulaError nErr = FormulaError::NONE;
2509                 PopDoubleRef( aRange, nParam, nRefInList);
2510                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
2511                 if (aValIter.GetFirst(fVal, nErr))
2512                 {
2513                     fSum += fVal;
2514                     fSumSqr += fVal*fVal;
2515                     rValCount++;
2516                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(fVal, nErr))
2517                     {
2518                         fSum += fVal;
2519                         fSumSqr += fVal*fVal;
2520                         rValCount++;
2521                     }
2522                     SetError(nErr);
2523                 }
2524             }
2525         }
2526         break;
2527         case svMatrix :
2528         case svExternalSingleRef:
2529         case svExternalDoubleRef:
2530         {
2531             ScMatrixRef pMat = GetMatrix();
2532             if (pMat)
2533             {
2534                 SCSIZE nCount = pMat->GetElementCount();
2535                 if (pMat->IsNumeric())
2536                 {
2537                     for ( SCSIZE i = 0; i < nCount; i++ )
2538                     {
2539                         fVal= pMat->GetDouble(i);
2540                         fSum += fVal;
2541                         fSumSqr += fVal * fVal;
2542                         rValCount++;
2543                     }
2544                 }
2545                 else
2546                 {
2547                     for (SCSIZE i = 0; i < nCount; i++)
2548                         if (!pMat->IsStringOrEmpty(i))
2549                         {
2550                             fVal= pMat->GetDouble(i);
2551                             fSum += fVal;
2552                             fSumSqr += fVal * fVal;
2553                             rValCount++;
2554                         }
2555                 }
2556             }
2557         }
2558         break;
2559         default : SetError(FormulaError::IllegalParameter); break;
2560     }
2561     if (rValCount <= 1.0)
2562         PushError( FormulaError::DivisionByZero);
2563     else
2564     {
2565         double mue = fSum/rValCount;
2566 
2567         if (nParamCount != 3)
2568         {
2569             sigma = (fSumSqr - fSum*fSum/rValCount)/(rValCount-1.0);
2570             if (sigma == 0.0)
2571             {
2572                 PushError(FormulaError::DivisionByZero);
2573                 return;
2574             }
2575             PushDouble(0.5 - gauss((mue-x)/sqrt(sigma/rValCount)));
2576         }
2577         else
2578             PushDouble(0.5 - gauss((mue-x)*sqrt(rValCount)/sigma));
2579     }
2580 }
2581 
2582 bool ScInterpreter::CalculateTest(bool _bTemplin
2583                                   ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
2584                                   ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
2585                                   ,double& fT,double& fF)
2586 {
2587     double fCount1  = 0.0;
2588     double fCount2  = 0.0;
2589     double fSum1    = 0.0;
2590     double fSumSqr1 = 0.0;
2591     double fSum2    = 0.0;
2592     double fSumSqr2 = 0.0;
2593     double fVal;
2594     SCSIZE i,j;
2595     for (i = 0; i < nC1; i++)
2596         for (j = 0; j < nR1; j++)
2597         {
2598             if (!pMat1->IsStringOrEmpty(i,j))
2599             {
2600                 fVal = pMat1->GetDouble(i,j);
2601                 fSum1    += fVal;
2602                 fSumSqr1 += fVal * fVal;
2603                 fCount1++;
2604             }
2605         }
2606     for (i = 0; i < nC2; i++)
2607         for (j = 0; j < nR2; j++)
2608         {
2609             if (!pMat2->IsStringOrEmpty(i,j))
2610             {
2611                 fVal = pMat2->GetDouble(i,j);
2612                 fSum2    += fVal;
2613                 fSumSqr2 += fVal * fVal;
2614                 fCount2++;
2615             }
2616         }
2617     if (fCount1 < 2.0 || fCount2 < 2.0)
2618     {
2619         PushNoValue();
2620         return false;
2621     } // if (fCount1 < 2.0 || fCount2 < 2.0)
2622     if ( _bTemplin )
2623     {
2624         double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0)/fCount1;
2625         double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0)/fCount2;
2626         if (fS1 + fS2 == 0.0)
2627         {
2628             PushNoValue();
2629             return false;
2630         }
2631         fT = fabs(fSum1/fCount1 - fSum2/fCount2)/sqrt(fS1+fS2);
2632         double c = fS1/(fS1+fS2);
2633     //  GetTDist is calculated via GetBetaDist and also works with non-integral
2634     // degrees of freedom. The result matches Excel
2635         fF = 1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0));
2636     }
2637     else
2638     {
2639         //  according to Bronstein-Semendjajew
2640         double fS1 = (fSumSqr1 - fSum1*fSum1/fCount1) / (fCount1 - 1.0);    // Variance
2641         double fS2 = (fSumSqr2 - fSum2*fSum2/fCount2) / (fCount2 - 1.0);
2642         fT = fabs( fSum1/fCount1 - fSum2/fCount2 ) /
2643              sqrt( (fCount1-1.0)*fS1 + (fCount2-1.0)*fS2 ) *
2644              sqrt( fCount1*fCount2*(fCount1+fCount2-2)/(fCount1+fCount2) );
2645         fF = fCount1 + fCount2 - 2;
2646     }
2647     return true;
2648 }
2649 void ScInterpreter::ScTTest()
2650 {
2651     if ( !MustHaveParamCount( GetByte(), 4 ) )
2652         return;
2653     double fTyp   = ::rtl::math::approxFloor(GetDouble());
2654     double fTails = ::rtl::math::approxFloor(GetDouble());
2655     if (fTails != 1.0 && fTails != 2.0)
2656     {
2657         PushIllegalArgument();
2658         return;
2659     }
2660 
2661     ScMatrixRef pMat2 = GetMatrix();
2662     ScMatrixRef pMat1 = GetMatrix();
2663     if (!pMat1 || !pMat2)
2664     {
2665         PushIllegalParameter();
2666         return;
2667     }
2668     double fT, fF;
2669     SCSIZE nC1, nC2;
2670     SCSIZE nR1, nR2;
2671     SCSIZE i, j;
2672     pMat1->GetDimensions(nC1, nR1);
2673     pMat2->GetDimensions(nC2, nR2);
2674     if (fTyp == 1.0)
2675     {
2676         if (nC1 != nC2 || nR1 != nR2)
2677         {
2678             PushIllegalArgument();
2679             return;
2680         }
2681         double fCount   = 0.0;
2682         double fSum1    = 0.0;
2683         double fSum2    = 0.0;
2684         double fSumSqrD = 0.0;
2685         double fVal1, fVal2;
2686         for (i = 0; i < nC1; i++)
2687             for (j = 0; j < nR1; j++)
2688             {
2689                 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
2690                 {
2691                     fVal1 = pMat1->GetDouble(i,j);
2692                     fVal2 = pMat2->GetDouble(i,j);
2693                     fSum1    += fVal1;
2694                     fSum2    += fVal2;
2695                     fSumSqrD += (fVal1 - fVal2)*(fVal1 - fVal2);
2696                     fCount++;
2697                 }
2698             }
2699         if (fCount < 1.0)
2700         {
2701             PushNoValue();
2702             return;
2703         }
2704         double fSumD = fSum1 - fSum2;
2705         double fDivider = fCount*fSumSqrD - fSumD*fSumD;
2706         if ( fDivider == 0.0 )
2707         {
2708             PushError(FormulaError::DivisionByZero);
2709             return;
2710         }
2711         fT = fabs(fSumD) * sqrt((fCount-1.0) / fDivider);
2712         fF = fCount - 1.0;
2713     }
2714     else if (fTyp == 2.0)
2715     {
2716         if (!CalculateTest(false,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF))
2717             return;     // error was pushed
2718     }
2719     else if (fTyp == 3.0)
2720     {
2721         if (!CalculateTest(true,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF))
2722             return;     // error was pushed
2723     }
2724     else
2725     {
2726         PushIllegalArgument();
2727         return;
2728     }
2729     PushDouble( GetTDist( fT, fF, static_cast<int>(fTails) ) );
2730 }
2731 
2732 void ScInterpreter::ScFTest()
2733 {
2734     if ( !MustHaveParamCount( GetByte(), 2 ) )
2735         return;
2736     ScMatrixRef pMat2 = GetMatrix();
2737     ScMatrixRef pMat1 = GetMatrix();
2738     if (!pMat1 || !pMat2)
2739     {
2740         PushIllegalParameter();
2741         return;
2742     }
2743     SCSIZE nC1, nC2;
2744     SCSIZE nR1, nR2;
2745     pMat1->GetDimensions(nC1, nR1);
2746     pMat2->GetDimensions(nC2, nR2);
2747     double fCount1  = 0.0;
2748     double fCount2  = 0.0;
2749     double fSum1    = 0.0;
2750     double fSumSqr1 = 0.0;
2751     double fSum2    = 0.0;
2752     double fSumSqr2 = 0.0;
2753 
2754     std::vector<sc::op::Op> aOp;
2755     aOp.emplace_back(sc::op::Op(0.0, [](double& rAccum, double fVal){rAccum += fVal;}));
2756     aOp.emplace_back(sc::op::Op(0.0, [](double& rAccum, double fVal){rAccum += fVal * fVal;}));
2757 
2758     auto aVal1 = pMat1->Collect(aOp);
2759     fSum1 = aVal1[0].mfFirst + aVal1[0].mfRest;
2760     fSumSqr1 = aVal1[1].mfFirst + aVal1[1].mfRest;
2761     fCount1 = aVal1[2].mnCount;
2762 
2763     auto aVal2 = pMat2->Collect(aOp);
2764     fSum2 = aVal2[0].mfFirst + aVal2[0].mfRest;
2765     fSumSqr2 = aVal2[1].mfFirst + aVal2[1].mfRest;
2766     fCount2 = aVal2[2].mnCount;
2767 
2768     if (fCount1 < 2.0 || fCount2 < 2.0)
2769     {
2770         PushNoValue();
2771         return;
2772     }
2773     double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0);
2774     double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0);
2775     if (fS1 == 0.0 || fS2 == 0.0)
2776     {
2777         PushNoValue();
2778         return;
2779     }
2780     double fF, fF1, fF2;
2781     if (fS1 > fS2)
2782     {
2783         fF = fS1/fS2;
2784         fF1 = fCount1-1.0;
2785         fF2 = fCount2-1.0;
2786     }
2787     else
2788     {
2789         fF = fS2/fS1;
2790         fF1 = fCount2-1.0;
2791         fF2 = fCount1-1.0;
2792     }
2793     double fFcdf = GetFDist(fF, fF1, fF2);
2794     PushDouble(2.0*std::min(fFcdf, 1.0 - fFcdf));
2795 }
2796 
2797 void ScInterpreter::ScChiTest()
2798 {
2799     if ( !MustHaveParamCount( GetByte(), 2 ) )
2800         return;
2801     ScMatrixRef pMat2 = GetMatrix();
2802     ScMatrixRef pMat1 = GetMatrix();
2803     if (!pMat1 || !pMat2)
2804     {
2805         PushIllegalParameter();
2806         return;
2807     }
2808     SCSIZE nC1, nC2;
2809     SCSIZE nR1, nR2;
2810     pMat1->GetDimensions(nC1, nR1);
2811     pMat2->GetDimensions(nC2, nR2);
2812     if (nR1 != nR2 || nC1 != nC2)
2813     {
2814         PushIllegalArgument();
2815         return;
2816     }
2817     double fChi = 0.0;
2818     bool bEmpty = true;
2819     for (SCSIZE i = 0; i < nC1; i++)
2820     {
2821         for (SCSIZE j = 0; j < nR1; j++)
2822         {
2823             if (!(pMat1->IsEmpty(i,j) || pMat2->IsEmpty(i,j)))
2824             {
2825                 bEmpty = false;
2826                 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
2827                 {
2828                     double fValX = pMat1->GetDouble(i,j);
2829                     double fValE = pMat2->GetDouble(i,j);
2830                     if ( fValE == 0.0 )
2831                     {
2832                         PushError(FormulaError::DivisionByZero);
2833                         return;
2834                     }
2835                     // These fTemp values guard against a failure when compiled
2836                     // with optimization (using g++ 4.8.2 on tinderbox 71-TDF),
2837                     // where ((fValX - fValE) * (fValX - fValE)) with
2838                     // fValE==1e+308 should had produced Infinity but did
2839                     // not, instead the result of divide() then was 1e+308.
2840                     volatile double fTemp1 = (fValX - fValE) * (fValX - fValE);
2841                     double fTemp2 = fTemp1;
2842                     fChi += sc::divide( fTemp2, fValE);
2843                 }
2844                 else
2845                 {
2846                     PushIllegalArgument();
2847                     return;
2848                 }
2849             }
2850         }
2851     }
2852     if ( bEmpty )
2853     {
2854         // not in ODFF1.2, but for interoperability with Excel
2855         PushIllegalArgument();
2856         return;
2857     }
2858     double fDF;
2859     if (nC1 == 1 || nR1 == 1)
2860     {
2861         fDF = static_cast<double>(nC1*nR1 - 1);
2862         if (fDF == 0.0)
2863         {
2864             PushNoValue();
2865             return;
2866         }
2867     }
2868     else
2869         fDF = static_cast<double>(nC1-1)*static_cast<double>(nR1-1);
2870     PushDouble(GetChiDist(fChi, fDF));
2871 }
2872 
2873 void ScInterpreter::ScKurt()
2874 {
2875     double fSum,fCount,vSum;
2876     std::vector<double> values;
2877     if ( !CalculateSkew(fSum,fCount,vSum,values) )
2878         return;
2879 
2880     // ODF 1.2 constraints: # of numbers >= 4
2881     if (fCount < 4.0)
2882     {
2883         // for interoperability with Excel
2884         PushError( FormulaError::DivisionByZero);
2885         return;
2886     }
2887 
2888     double fMean = fSum / fCount;
2889 
2890     for (double v : values)
2891         vSum += (v - fMean) * (v - fMean);
2892 
2893     double fStdDev = sqrt(vSum / (fCount - 1.0));
2894     double xpower4 = 0.0;
2895 
2896     if (fStdDev == 0.0)
2897     {
2898         PushError( FormulaError::DivisionByZero);
2899         return;
2900     }
2901 
2902     for (double v : values)
2903     {
2904         double dx = (v - fMean) / fStdDev;
2905         xpower4 = xpower4 + (dx * dx * dx * dx);
2906     }
2907 
2908     double k_d = (fCount - 2.0) * (fCount - 3.0);
2909     double k_l = fCount * (fCount + 1.0) / ((fCount - 1.0) * k_d);
2910     double k_t = 3.0 * (fCount - 1.0) * (fCount - 1.0) / k_d;
2911 
2912     PushDouble(xpower4 * k_l - k_t);
2913 }
2914 
2915 void ScInterpreter::ScHarMean()
2916 {
2917     short nParamCount = GetByte();
2918     double nVal = 0.0;
2919     double nValCount = 0.0;
2920     ScAddress aAdr;
2921     ScRange aRange;
2922     size_t nRefInList = 0;
2923     while ((nGlobalError == FormulaError::NONE) && (nParamCount-- > 0))
2924     {
2925         switch (GetStackType())
2926         {
2927             case svDouble    :
2928             {
2929                 double x = GetDouble();
2930                 if (x > 0.0)
2931                 {
2932                     nVal += 1.0/x;
2933                     nValCount++;
2934                 }
2935                 else
2936                     SetError( FormulaError::IllegalArgument);
2937                 break;
2938             }
2939             case svSingleRef :
2940             {
2941                 PopSingleRef( aAdr );
2942                 ScRefCellValue aCell(*pDok, aAdr);
2943                 if (aCell.hasNumeric())
2944                 {
2945                     double x = GetCellValue(aAdr, aCell);
2946                     if (x > 0.0)
2947                     {
2948                         nVal += 1.0/x;
2949                         nValCount++;
2950                     }
2951                     else
2952                         SetError( FormulaError::IllegalArgument);
2953                 }
2954                 break;
2955             }
2956             case svDoubleRef :
2957             case svRefList :
2958             {
2959                 FormulaError nErr = FormulaError::NONE;
2960                 PopDoubleRef( aRange, nParamCount, nRefInList);
2961                 double nCellVal;
2962                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
2963                 if (aValIter.GetFirst(nCellVal, nErr))
2964                 {
2965                     if (nCellVal > 0.0)
2966                     {
2967                         nVal += 1.0/nCellVal;
2968                         nValCount++;
2969                     }
2970                     else
2971                         SetError( FormulaError::IllegalArgument);
2972                     SetError(nErr);
2973                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
2974                     {
2975                         if (nCellVal > 0.0)
2976                         {
2977                             nVal += 1.0/nCellVal;
2978                             nValCount++;
2979                         }
2980                         else
2981                             SetError( FormulaError::IllegalArgument);
2982                     }
2983                     SetError(nErr);
2984                 }
2985             }
2986             break;
2987             case svMatrix :
2988             case svExternalSingleRef:
2989             case svExternalDoubleRef:
2990             {
2991                 ScMatrixRef pMat = GetMatrix();
2992                 if (pMat)
2993                 {
2994                     SCSIZE nCount = pMat->GetElementCount();
2995                     if (pMat->IsNumeric())
2996                     {
2997                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
2998                         {
2999                             double x = pMat->GetDouble(nElem);
3000                             if (x > 0.0)
3001                             {
3002                                 nVal += 1.0/x;
3003                                 nValCount++;
3004                             }
3005                             else
3006                                 SetError( FormulaError::IllegalArgument);
3007                         }
3008                     }
3009                     else
3010                     {
3011                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3012                             if (!pMat->IsStringOrEmpty(nElem))
3013                             {
3014                                 double x = pMat->GetDouble(nElem);
3015                                 if (x > 0.0)
3016                                 {
3017                                     nVal += 1.0/x;
3018                                     nValCount++;
3019                                 }
3020                                 else
3021                                     SetError( FormulaError::IllegalArgument);
3022                             }
3023                     }
3024                 }
3025             }
3026             break;
3027             default : SetError(FormulaError::IllegalParameter); break;
3028         }
3029     }
3030     if (nGlobalError == FormulaError::NONE)
3031         PushDouble( nValCount / nVal );
3032     else
3033         PushError( nGlobalError);
3034 }
3035 
3036 void ScInterpreter::ScGeoMean()
3037 {
3038     short nParamCount = GetByte();
3039     double nVal = 0.0;
3040     double nValCount = 0.0;
3041     ScAddress aAdr;
3042     ScRange aRange;
3043 
3044     size_t nRefInList = 0;
3045     while ((nGlobalError == FormulaError::NONE) && (nParamCount-- > 0))
3046     {
3047         switch (GetStackType())
3048         {
3049             case svDouble    :
3050             {
3051                 double x = GetDouble();
3052                 if (x > 0.0)
3053                 {
3054                     nVal += log(x);
3055                     nValCount++;
3056                 }
3057                 else if ( x == 0.0 )
3058                 {
3059                     // value of 0 means that function result will be 0
3060                     while ( nParamCount-- > 0 )
3061                         PopError();
3062                     PushDouble( 0.0 );
3063                     return;
3064                 }
3065                 else
3066                     SetError( FormulaError::IllegalArgument);
3067                 break;
3068             }
3069             case svSingleRef :
3070             {
3071                 PopSingleRef( aAdr );
3072                 ScRefCellValue aCell(*pDok, aAdr);
3073                 if (aCell.hasNumeric())
3074                 {
3075                     double x = GetCellValue(aAdr, aCell);
3076                     if (x > 0.0)
3077                     {
3078                         nVal += log(x);
3079                         nValCount++;
3080                     }
3081                     else if ( x == 0.0 )
3082                     {
3083                         // value of 0 means that function result will be 0
3084                         while ( nParamCount-- > 0 )
3085                             PopError();
3086                         PushDouble( 0.0 );
3087                         return;
3088                     }
3089                     else
3090                         SetError( FormulaError::IllegalArgument);
3091                 }
3092                 break;
3093             }
3094             case svDoubleRef :
3095             case svRefList :
3096             {
3097                 FormulaError nErr = FormulaError::NONE;
3098                 PopDoubleRef( aRange, nParamCount, nRefInList);
3099                 double nCellVal;
3100                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
3101                 if (aValIter.GetFirst(nCellVal, nErr))
3102                 {
3103                     if (nCellVal > 0.0)
3104                     {
3105                         nVal += log(nCellVal);
3106                         nValCount++;
3107                     }
3108                     else if ( nCellVal == 0.0 )
3109                     {
3110                         // value of 0 means that function result will be 0
3111                         while ( nParamCount-- > 0 )
3112                             PopError();
3113                         PushDouble( 0.0 );
3114                         return;
3115                     }
3116                     else
3117                         SetError( FormulaError::IllegalArgument);
3118                     SetError(nErr);
3119                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
3120                     {
3121                         if (nCellVal > 0.0)
3122                         {
3123                             nVal += log(nCellVal);
3124                             nValCount++;
3125                         }
3126                         else if ( nCellVal == 0.0 )
3127                         {
3128                             // value of 0 means that function result will be 0
3129                             while ( nParamCount-- > 0 )
3130                                 PopError();
3131                             PushDouble( 0.0 );
3132                             return;
3133                         }
3134                         else
3135                             SetError( FormulaError::IllegalArgument);
3136                     }
3137                     SetError(nErr);
3138                 }
3139             }
3140             break;
3141             case svMatrix :
3142             case svExternalSingleRef:
3143             case svExternalDoubleRef:
3144             {
3145                 ScMatrixRef pMat = GetMatrix();
3146                 if (pMat)
3147                 {
3148                     SCSIZE nCount = pMat->GetElementCount();
3149                     if (pMat->IsNumeric())
3150                     {
3151                         for (SCSIZE ui = 0; ui < nCount; ui++)
3152                         {
3153                             double x = pMat->GetDouble(ui);
3154                             if (x > 0.0)
3155                             {
3156                                 nVal += log(x);
3157                                 nValCount++;
3158                             }
3159                             else if ( x == 0.0 )
3160                             {
3161                                 // value of 0 means that function result will be 0
3162                                 while ( nParamCount-- > 0 )
3163                                     PopError();
3164                                 PushDouble( 0.0 );
3165                                 return;
3166                             }
3167                             else
3168                                 SetError( FormulaError::IllegalArgument);
3169                         }
3170                     }
3171                     else
3172                     {
3173                         for (SCSIZE ui = 0; ui < nCount; ui++)
3174                         {
3175                             if (!pMat->IsStringOrEmpty(ui))
3176                             {
3177                                 double x = pMat->GetDouble(ui);
3178                                 if (x > 0.0)
3179                                 {
3180                                     nVal += log(x);
3181                                     nValCount++;
3182                                 }
3183                                 else if ( x == 0.0 )
3184                                 {
3185                                     // value of 0 means that function result will be 0
3186                                     while ( nParamCount-- > 0 )
3187                                         PopError();
3188                                     PushDouble( 0.0 );
3189                                     return;
3190                                 }
3191                                 else
3192                                     SetError( FormulaError::IllegalArgument);
3193                             }
3194                         }
3195                     }
3196                 }
3197             }
3198             break;
3199             default : SetError(FormulaError::IllegalParameter); break;
3200         }
3201     }
3202     if (nGlobalError == FormulaError::NONE)
3203         PushDouble(exp(nVal / nValCount));
3204     else
3205         PushError( nGlobalError);
3206 }
3207 
3208 void ScInterpreter::ScStandard()
3209 {
3210     if ( MustHaveParamCount( GetByte(), 3 ) )
3211     {
3212         double sigma = GetDouble();
3213         double mue   = GetDouble();
3214         double x     = GetDouble();
3215         if (sigma < 0.0)
3216             PushError( FormulaError::IllegalArgument);
3217         else if (sigma == 0.0)
3218             PushError( FormulaError::DivisionByZero);
3219         else
3220             PushDouble((x-mue)/sigma);
3221     }
3222 }
3223 bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::vector<double>& values)
3224 {
3225     short nParamCount = GetByte();
3226     if ( !MustHaveParamCountMin( nParamCount, 1 )  )
3227         return false;
3228 
3229     fSum   = 0.0;
3230     fCount = 0.0;
3231     vSum   = 0.0;
3232     double fVal = 0.0;
3233     ScAddress aAdr;
3234     ScRange aRange;
3235     size_t nRefInList = 0;
3236     while (nParamCount-- > 0)
3237     {
3238         switch (GetStackType())
3239         {
3240             case svDouble :
3241             {
3242                 fVal = GetDouble();
3243                 fSum += fVal;
3244                 values.push_back(fVal);
3245                 fCount++;
3246             }
3247                 break;
3248             case svSingleRef :
3249             {
3250                 PopSingleRef( aAdr );
3251                 ScRefCellValue aCell(*pDok, aAdr);
3252                 if (aCell.hasNumeric())
3253                 {
3254                     fVal = GetCellValue(aAdr, aCell);
3255                     fSum += fVal;
3256                     values.push_back(fVal);
3257                     fCount++;
3258                 }
3259             }
3260             break;
3261             case svDoubleRef :
3262             case svRefList :
3263             {
3264                 PopDoubleRef( aRange, nParamCount, nRefInList);
3265                 FormulaError nErr = FormulaError::NONE;
3266                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
3267                 if (aValIter.GetFirst(fVal, nErr))
3268                 {
3269                     fSum += fVal;
3270                     values.push_back(fVal);
3271                     fCount++;
3272                     SetError(nErr);
3273                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(fVal, nErr))
3274                     {
3275                         fSum += fVal;
3276                         values.push_back(fVal);
3277                         fCount++;
3278                     }
3279                     SetError(nErr);
3280                 }
3281             }
3282             break;
3283             case svMatrix :
3284             case svExternalSingleRef:
3285             case svExternalDoubleRef:
3286             {
3287                 ScMatrixRef pMat = GetMatrix();
3288                 if (pMat)
3289                 {
3290                     SCSIZE nCount = pMat->GetElementCount();
3291                     if (pMat->IsNumeric())
3292                     {
3293                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3294                         {
3295                             fVal = pMat->GetDouble(nElem);
3296                             fSum += fVal;
3297                             values.push_back(fVal);
3298                             fCount++;
3299                         }
3300                     }
3301                     else
3302                     {
3303                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3304                             if (!pMat->IsStringOrEmpty(nElem))
3305                             {
3306                                 fVal = pMat->GetDouble(nElem);
3307                                 fSum += fVal;
3308                                 values.push_back(fVal);
3309                                 fCount++;
3310                             }
3311                     }
3312                 }
3313             }
3314             break;
3315             default :
3316                 SetError(FormulaError::IllegalParameter);
3317             break;
3318         }
3319     }
3320 
3321     if (nGlobalError != FormulaError::NONE)
3322     {
3323         PushError( nGlobalError);
3324         return false;
3325     } // if (nGlobalError != FormulaError::NONE)
3326     return true;
3327 }
3328 
3329 void ScInterpreter::CalculateSkewOrSkewp( bool bSkewp )
3330 {
3331     double fSum, fCount, vSum;
3332     std::vector<double> values;
3333     if (!CalculateSkew( fSum, fCount, vSum, values))
3334         return;
3335      // SKEW/SKEWP's constraints: they require at least three numbers
3336     if (fCount < 3.0)
3337     {
3338         // for interoperability with Excel
3339         PushError(FormulaError::DivisionByZero);
3340         return;
3341     }
3342 
3343     double fMean = fSum / fCount;
3344 
3345     for (double v : values)
3346         vSum += (v - fMean) * (v - fMean);
3347 
3348     double fStdDev = sqrt( vSum / (bSkewp ? fCount : (fCount - 1.0)));
3349     double xcube = 0.0;
3350 
3351     if (fStdDev == 0)
3352     {
3353         PushIllegalArgument();
3354         return;
3355     }
3356 
3357     for (double v : values)
3358     {
3359         double dx = (v - fMean) / fStdDev;
3360         xcube = xcube + (dx * dx * dx);
3361     }
3362 
3363     if (bSkewp)
3364         PushDouble( xcube / fCount );
3365     else
3366         PushDouble( ((xcube * fCount) / (fCount - 1.0)) / (fCount - 2.0) );
3367 }
3368 
3369 void ScInterpreter::ScSkew()
3370 {
3371     CalculateSkewOrSkewp( false );
3372 }
3373 
3374 void ScInterpreter::ScSkewp()
3375 {
3376     CalculateSkewOrSkewp( true );
3377 }
3378 
3379 double ScInterpreter::GetMedian( vector<double> & rArray )
3380 {
3381     size_t nSize = rArray.size();
3382     if (nSize == 0 || nGlobalError != FormulaError::NONE)
3383     {
3384         SetError( FormulaError::NoValue);
3385         return 0.0;
3386     }
3387 
3388     // Upper median.
3389     size_t nMid = nSize / 2;
3390     vector<double>::iterator iMid = rArray.begin() + nMid;
3391     ::std::nth_element( rArray.begin(), iMid, rArray.end());
3392     if (nSize & 1)
3393         return *iMid;   // Lower and upper median are equal.
3394     else
3395     {
3396         double fUp = *iMid;
3397         // Lower median.
3398         iMid = ::std::max_element( rArray.begin(), rArray.begin() + nMid);
3399         return (fUp + *iMid) / 2;
3400     }
3401 }
3402 
3403 void ScInterpreter::ScMedian()
3404 {
3405     sal_uInt8 nParamCount = GetByte();
3406     if ( !MustHaveParamCountMin( nParamCount, 1 )  )
3407         return;
3408     vector<double> aArray;
3409     GetNumberSequenceArray( nParamCount, aArray, false );
3410     PushDouble( GetMedian( aArray));
3411 }
3412 
3413 double ScInterpreter::GetPercentile( vector<double> & rArray, double fPercentile )
3414 {
3415     size_t nSize = rArray.size();
3416     if (nSize == 1)
3417         return rArray[0];
3418     else
3419     {
3420         size_t nIndex = static_cast<size_t>(::rtl::math::approxFloor( fPercentile * (nSize-1)));
3421         double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1));
3422         OSL_ENSURE(nIndex < nSize, "GetPercentile: wrong index(1)");
3423         vector<double>::iterator iter = rArray.begin() + nIndex;
3424         ::std::nth_element( rArray.begin(), iter, rArray.end());
3425         if (fDiff == 0.0)
3426             return *iter;
3427         else
3428         {
3429             OSL_ENSURE(nIndex < nSize-1, "GetPercentile: wrong index(2)");
3430             double fVal = *iter;
3431             iter = ::std::min_element( rArray.begin() + nIndex + 1, rArray.end());
3432             return fVal + fDiff * (*iter - fVal);
3433         }
3434     }
3435 }
3436 
3437 double ScInterpreter::GetPercentileExclusive( vector<double> & rArray, double fPercentile )
3438 {
3439     size_t nSize1 = rArray.size() + 1;
3440     if ( rArray.empty() || nSize1 == 1 || nGlobalError != FormulaError::NONE)
3441     {
3442         SetError( FormulaError::NoValue );
3443         return 0.0;
3444     }
3445     if ( fPercentile * nSize1 < 1.0 || fPercentile * nSize1 > static_cast<double>( nSize1 - 1 ) )
3446     {
3447         SetError( FormulaError::IllegalParameter );
3448         return 0.0;
3449     }
3450 
3451     size_t nIndex = static_cast<size_t>(::rtl::math::approxFloor( fPercentile * nSize1 - 1 ));
3452     double fDiff = fPercentile *  nSize1 - 1 - ::rtl::math::approxFloor( fPercentile * nSize1 - 1 );
3453     OSL_ENSURE(nIndex < ( nSize1 - 1 ), "GetPercentile: wrong index(1)");
3454     vector<double>::iterator iter = rArray.begin() + nIndex;
3455     ::std::nth_element( rArray.begin(), iter, rArray.end());
3456     if (fDiff == 0.0)
3457         return *iter;
3458     else
3459     {
3460         OSL_ENSURE(nIndex < nSize1, "GetPercentile: wrong index(2)");
3461         double fVal = *iter;
3462         iter = ::std::min_element( rArray.begin() + nIndex + 1, rArray.end());
3463         return fVal + fDiff * (*iter - fVal);
3464     }
3465 }
3466 
3467 void ScInterpreter::ScPercentile( bool bInclusive )
3468 {
3469     if ( !MustHaveParamCount( GetByte(), 2 ) )
3470         return;
3471     double alpha = GetDouble();
3472     if ( bInclusive ? ( alpha < 0.0 || alpha > 1.0 ) : ( alpha <= 0.0 || alpha >= 1.0 ) )
3473     {
3474         PushIllegalArgument();
3475         return;
3476     }
3477     vector<double> aArray;
3478     GetNumberSequenceArray( 1, aArray, false );
3479     if ( aArray.empty() || nGlobalError != FormulaError::NONE )
3480     {
3481         SetError( FormulaError::NoValue );
3482         return;
3483     }
3484     if ( bInclusive )
3485         PushDouble( GetPercentile( aArray, alpha ));
3486     else
3487         PushDouble( GetPercentileExclusive( aArray, alpha ));
3488 }
3489 
3490 void ScInterpreter::ScQuartile( bool bInclusive )
3491 {
3492     if ( !MustHaveParamCount( GetByte(), 2 ) )
3493         return;
3494     double fFlag = ::rtl::math::approxFloor(GetDouble());
3495     if ( bInclusive ? ( fFlag < 0.0 || fFlag > 4.0 ) : ( fFlag <= 0.0 || fFlag >= 4.0 ) )
3496     {
3497         PushIllegalArgument();
3498         return;
3499     }
3500     vector<double> aArray;
3501     GetNumberSequenceArray( 1, aArray, false );
3502     if ( aArray.empty() || nGlobalError != FormulaError::NONE )
3503     {
3504         SetError( FormulaError::NoValue );
3505         return;
3506     }
3507     if ( bInclusive )
3508         PushDouble( fFlag == 2.0 ? GetMedian( aArray ) : GetPercentile( aArray, 0.25 * fFlag ) );
3509     else
3510         PushDouble( fFlag == 2.0 ? GetMedian( aArray ) : GetPercentileExclusive( aArray, 0.25 * fFlag ) );
3511 }
3512 
3513 void ScInterpreter::ScModalValue()
3514 {
3515     sal_uInt8 nParamCount = GetByte();
3516     if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3517         return;
3518     vector<double> aSortArray;
3519     GetSortArray( nParamCount, aSortArray, nullptr, false, false );
3520     SCSIZE nSize = aSortArray.size();
3521     if (nSize == 0 || nGlobalError != FormulaError::NONE)
3522         PushNoValue();
3523     else
3524     {
3525         SCSIZE nMaxIndex = 0, nMax = 1, nCount = 1;
3526         double nOldVal = aSortArray[0];
3527         SCSIZE i;
3528         for ( i = 1; i < nSize; i++)
3529         {
3530             if (aSortArray[i] == nOldVal)
3531                 nCount++;
3532             else
3533             {
3534                 nOldVal = aSortArray[i];
3535                 if (nCount > nMax)
3536                 {
3537                     nMax = nCount;
3538                     nMaxIndex = i-1;
3539                 }
3540                 nCount = 1;
3541             }
3542         }
3543         if (nCount > nMax)
3544         {
3545             nMax = nCount;
3546             nMaxIndex = i-1;
3547         }
3548         if (nMax == 1 && nCount == 1)
3549             PushNoValue();
3550         else if (nMax == 1)
3551             PushDouble(nOldVal);
3552         else
3553             PushDouble(aSortArray[nMaxIndex]);
3554     }
3555 }
3556 
3557 void ScInterpreter::ScModalValue_MS( bool bSingle )
3558 {
3559     sal_uInt8 nParamCount = GetByte();
3560     if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3561         return;
3562     vector<double> aArray;
3563     GetNumberSequenceArray( nParamCount, aArray, false );
3564     vector< double > aSortArray( aArray );
3565     QuickSort( aSortArray, nullptr );
3566     SCSIZE nSize = aSortArray.size();
3567     if ( nSize == 0 || nGlobalError != FormulaError::NONE )
3568         PushNoValue();
3569     else
3570     {
3571         SCSIZE nMax = 1, nCount = 1;
3572         double nOldVal = aSortArray[ 0 ];
3573         vector< double > aResultArray( 1 );
3574         SCSIZE i;
3575         for ( i = 1; i < nSize; i++ )
3576         {
3577             if ( aSortArray[ i ] == nOldVal )
3578                 nCount++;
3579             else
3580             {
3581                 if ( nCount >= nMax && nCount > 1 )
3582                 {
3583                     if ( nCount > nMax )
3584                     {
3585                         nMax = nCount;
3586                         if ( aResultArray.size() != 1 )
3587                             vector< double >( 1 ).swap( aResultArray );
3588                         aResultArray[ 0 ] = nOldVal;
3589                     }
3590                     else
3591                         aResultArray.emplace_back( nOldVal );
3592                 }
3593                 nOldVal = aSortArray[ i ];
3594                 nCount = 1;
3595             }
3596         }
3597         if ( nCount >= nMax && nCount > 1 )
3598         {
3599             if ( nCount > nMax )
3600                 vector< double >().swap( aResultArray );
3601             aResultArray.emplace_back( nOldVal );
3602         }
3603         if ( nMax == 1 && nCount == 1 )
3604             PushNoValue();
3605         else if ( nMax == 1 )
3606             PushDouble( nOldVal ); // there is only 1 result, no reordering needed
3607         else
3608         {
3609             // sort resultArray according to ordering of aArray
3610             vector< vector< double > > aOrder;
3611             aOrder.resize( aResultArray.size(), vector< double >( 2 ) );
3612             for ( i = 0; i < aResultArray.size(); i++ )
3613             {
3614                 for ( SCSIZE j = 0; j < nSize; j++ )
3615                 {
3616                     if ( aArray[ j ] == aResultArray[ i ] )
3617                     {
3618                         aOrder[ i ][ 0 ] = aResultArray[ i ];
3619                         aOrder[ i ][ 1 ] = j;
3620                         break;
3621                     }
3622                 }
3623             }
3624             sort( aOrder.begin(), aOrder.end(), []( const std::vector< double >& lhs,
3625                                                     const std::vector< double >& rhs )
3626                                                     { return lhs[ 1 ] < rhs[ 1 ]; } );
3627 
3628             if ( bSingle )
3629                 PushDouble( aOrder[ 0 ][ 0 ] );
3630             else
3631             {
3632                 // put result in correct order in aResultArray
3633                 for ( i = 0; i < aResultArray.size(); i++ )
3634                     aResultArray[ i ] = aOrder[ i ][ 0 ];
3635                 ScMatrixRef pResMatrix = GetNewMat( 1, aResultArray.size(), true );
3636                 pResMatrix->PutDoubleVector( aResultArray, 0, 0 );
3637                 PushMatrix( pResMatrix );
3638             }
3639         }
3640     }
3641 }
3642 
3643 void ScInterpreter::CalculateSmallLarge(bool bSmall)
3644 {
3645     if ( !MustHaveParamCount( GetByte(), 2 )  )
3646         return;
3647 
3648     SCSIZE nCol = 0, nRow = 0;
3649     auto aArray = GetTopNumberArray(nCol, nRow);
3650     const auto nRankArraySize = aArray.size();
3651     if (nRankArraySize == 0 || nGlobalError != FormulaError::NONE)
3652     {
3653         PushNoValue();
3654         return;
3655     }
3656     assert(nRankArraySize == nCol * nRow);
3657 
3658     std::vector<SCSIZE> aRankArray;
3659     aRankArray.reserve(nRankArraySize);
3660     std::transform(aArray.begin(), aArray.end(), std::back_inserter(aRankArray),
3661             [](double f) {
3662                 f = rtl::math::approxFloor(f);
3663                 // Valid ranks are >= 1.
3664                 if (f < 1.0 || !o3tl::convertsToAtMost(f, std::numeric_limits<SCSIZE>::max()))
3665                     return static_cast<SCSIZE>(0);
3666                 return static_cast<SCSIZE>(f);
3667             });
3668 
3669     vector<double> aSortArray;
3670     GetNumberSequenceArray(1, aSortArray, false );
3671     const SCSIZE nSize = aSortArray.size();
3672     if (nSize == 0 || nGlobalError != FormulaError::NONE)
3673         PushNoValue();
3674     else if (nRankArraySize == 1)
3675     {
3676         const SCSIZE k = aRankArray[0];
3677         if (k < 1 || nSize < k)
3678             PushNoValue();
3679         else
3680         {
3681             vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k);
3682             ::std::nth_element( aSortArray.begin(), iPos, aSortArray.end());
3683             PushDouble( *iPos);
3684         }
3685     }
3686     else
3687     {
3688         std::set<SCSIZE> aIndices;
3689         for (SCSIZE n : aRankArray)
3690         {
3691             if (1 <= n && n <= nSize)
3692                 aIndices.insert(bSmall ? n-1 : nSize-n);
3693         }
3694         // We can spare sorting when the total number of ranks is small enough.
3695         // Find only the elements at given indices if, arbitrarily, the index size is
3696         // smaller than 1/3 of the haystack array's size; just sort it squarely, otherwise.
3697         if (aIndices.size() < nSize/3)
3698         {
3699             auto itBegin = aSortArray.begin();
3700             for (SCSIZE i : aIndices)
3701             {
3702                 auto it = aSortArray.begin() + i;
3703                 std::nth_element(itBegin, it, aSortArray.end());
3704                 itBegin = ++it;
3705             }
3706         }
3707         else
3708             std::sort(aSortArray.begin(), aSortArray.end());
3709 
3710         aArray.clear();
3711         for (SCSIZE n : aRankArray)
3712         {
3713             if (1 <= n && n <= nSize)
3714                 aArray.push_back( aSortArray[bSmall ? n-1 : nSize-n]);
3715             else
3716                 aArray.push_back( CreateDoubleError( FormulaError::NoValue));
3717         }
3718         ScMatrixRef pResult = GetNewMat(nCol, nRow, aArray);
3719         PushMatrix(pResult);
3720     }
3721 }
3722 
3723 void ScInterpreter::ScLarge()
3724 {
3725     CalculateSmallLarge(false);
3726 }
3727 
3728 void ScInterpreter::ScSmall()
3729 {
3730     CalculateSmallLarge(true);
3731 }
3732 
3733 void ScInterpreter::ScPercentrank( bool bInclusive )
3734 {
3735     sal_uInt8 nParamCount = GetByte();
3736     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
3737         return;
3738     double fSignificance = ( nParamCount == 3 ? ::rtl::math::approxFloor( GetDouble() ) : 3.0 );
3739     if ( fSignificance < 1.0 )
3740     {
3741         PushIllegalArgument();
3742         return;
3743     }
3744     double fNum = GetDouble();
3745     vector<double> aSortArray;
3746     GetSortArray( 1, aSortArray, nullptr, false, false );
3747     SCSIZE nSize = aSortArray.size();
3748     if ( nSize == 0 || nGlobalError != FormulaError::NONE )
3749         PushNoValue();
3750     else
3751     {
3752         if ( fNum < aSortArray[ 0 ] || fNum > aSortArray[ nSize - 1 ] )
3753             PushNoValue();
3754         else
3755         {
3756             double fRes;
3757             if ( nSize == 1 )
3758                 fRes = 1.0;            // fNum == aSortArray[ 0 ], see test above
3759             else
3760                 fRes = GetPercentrank( aSortArray, fNum, bInclusive );
3761             if ( fRes != 0.0 )
3762             {
3763                 double fExp = ::rtl::math::approxFloor( log10( fRes ) ) + 1.0 - fSignificance;
3764                 fRes = ::rtl::math::round( fRes * pow( 10, -fExp ) ) / pow( 10, -fExp );
3765             }
3766             PushDouble( fRes );
3767         }
3768     }
3769 }
3770 
3771 double ScInterpreter::GetPercentrank( ::std::vector<double> & rArray, double fVal, bool bInclusive )
3772 {
3773     SCSIZE nSize = rArray.size();
3774     double fRes;
3775     if ( fVal == rArray[ 0 ] )
3776     {
3777         if ( bInclusive )
3778             fRes = 0.0;
3779         else
3780             fRes = 1.0 / static_cast<double>( nSize + 1 );
3781     }
3782     else
3783     {
3784         SCSIZE nOldCount = 0;
3785         double fOldVal = rArray[ 0 ];
3786         SCSIZE i;
3787         for ( i = 1; i < nSize && rArray[ i ] < fVal; i++ )
3788         {
3789             if ( rArray[ i ] != fOldVal )
3790             {
3791                 nOldCount = i;
3792                 fOldVal = rArray[ i ];
3793             }
3794         }
3795         if ( rArray[ i ] != fOldVal )
3796             nOldCount = i;
3797         if ( fVal == rArray[ i ] )
3798         {
3799             if ( bInclusive )
3800                 fRes = div( nOldCount, nSize - 1 );
3801             else
3802                 fRes = static_cast<double>( i + 1 ) / static_cast<double>( nSize + 1 );
3803         }
3804         else
3805         {
3806             //  nOldCount is the count of smaller entries
3807             //  fVal is between rArray[ nOldCount - 1 ] and rArray[ nOldCount ]
3808             //  use linear interpolation to find a position between the entries
3809             if ( nOldCount == 0 )
3810             {
3811                 OSL_FAIL( "should not happen" );
3812                 fRes = 0.0;
3813             }
3814             else
3815             {
3816                 double fFract = ( fVal - rArray[ nOldCount - 1 ] ) /
3817                     ( rArray[ nOldCount ] - rArray[ nOldCount - 1 ] );
3818                 if ( bInclusive )
3819                     fRes = div( static_cast<double>( nOldCount - 1 ) + fFract, nSize - 1 );
3820                 else
3821                     fRes = ( static_cast<double>(nOldCount) + fFract ) / static_cast<double>( nSize + 1 );
3822             }
3823         }
3824     }
3825     return fRes;
3826 }
3827 
3828 void ScInterpreter::ScTrimMean()
3829 {
3830     if ( !MustHaveParamCount( GetByte(), 2 ) )
3831         return;
3832     double alpha = GetDouble();
3833     if (alpha < 0.0 || alpha >= 1.0)
3834     {
3835         PushIllegalArgument();
3836         return;
3837     }
3838     vector<double> aSortArray;
3839     GetSortArray( 1, aSortArray, nullptr, false, false );
3840     SCSIZE nSize = aSortArray.size();
3841     if (nSize == 0 || nGlobalError != FormulaError::NONE)
3842         PushNoValue();
3843     else
3844     {
3845         sal_uLong nIndex = static_cast<sal_uLong>(::rtl::math::approxFloor(alpha*static_cast<double>(nSize)));
3846         if (nIndex % 2 != 0)
3847             nIndex--;
3848         nIndex /= 2;
3849         OSL_ENSURE(nIndex < nSize, "ScTrimMean: wrong index");
3850         double fSum = 0.0;
3851         for (SCSIZE i = nIndex; i < nSize-nIndex; i++)
3852             fSum += aSortArray[i];
3853         PushDouble(fSum/static_cast<double>(nSize-2*nIndex));
3854     }
3855 }
3856 
3857 std::vector<double> ScInterpreter::GetTopNumberArray( SCSIZE& rCol, SCSIZE& rRow )
3858 {
3859     std::vector<double> aArray;
3860     switch (GetStackType())
3861     {
3862         case svDouble:
3863             aArray.push_back(PopDouble());
3864             rCol = rRow = 1;
3865         break;
3866         case svSingleRef:
3867         {
3868             ScAddress aAdr;
3869             PopSingleRef(aAdr);
3870             ScRefCellValue aCell(*pDok, aAdr);
3871             if (aCell.hasNumeric())
3872             {
3873                 aArray.push_back(GetCellValue(aAdr, aCell));
3874                 rCol = rRow = 1;
3875             }
3876         }
3877         break;
3878         case svDoubleRef:
3879         {
3880             ScRange aRange;
3881             PopDoubleRef(aRange, true);
3882             if (nGlobalError != FormulaError::NONE)
3883                 break;
3884 
3885             // give up unless the start and end are in the same sheet
3886             if (aRange.aStart.Tab() != aRange.aEnd.Tab())
3887             {
3888                 SetError(FormulaError::IllegalParameter);
3889                 break;
3890             }
3891 
3892             // the range already is in order
3893             assert(aRange.aStart.Col() <= aRange.aEnd.Col());
3894             assert(aRange.aStart.Row() <= aRange.aEnd.Row());
3895             rCol = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
3896             rRow = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
3897             aArray.reserve(rCol * rRow);
3898 
3899             FormulaError nErr = FormulaError::NONE;
3900             double fCellVal;
3901             ScValueIterator aValIter(pDok, aRange, mnSubTotalFlags);
3902             if (aValIter.GetFirst(fCellVal, nErr))
3903             {
3904                 do
3905                     aArray.push_back(fCellVal);
3906                 while (aValIter.GetNext(fCellVal, nErr) && nErr == FormulaError::NONE);
3907             }
3908             if (aArray.size() != rCol * rRow)
3909             {
3910                 aArray.clear();
3911                 SetError(nErr);
3912             }
3913         }
3914         break;
3915         case svMatrix:
3916         case svExternalSingleRef:
3917         case svExternalDoubleRef:
3918         {
3919             ScMatrixRef pMat = GetMatrix();
3920             if (!pMat)
3921                 break;
3922 
3923             if (pMat->IsNumeric())
3924             {
3925                 SCSIZE nCount = pMat->GetElementCount();
3926                 aArray.reserve(nCount);
3927                 for (SCSIZE i = 0; i < nCount; ++i)
3928                     aArray.push_back(pMat->GetDouble(i));
3929                 pMat->GetDimensions(rCol, rRow);
3930             }
3931             else
3932                 SetError(FormulaError::IllegalParameter);
3933         }
3934         break;
3935         default:
3936             SetError(FormulaError::IllegalParameter);
3937         break;
3938     }
3939     return aArray;
3940 }
3941 
3942 void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray, bool bConvertTextInArray )
3943 {
3944     ScAddress aAdr;
3945     ScRange aRange;
3946     const bool bIgnoreErrVal = bool(mnSubTotalFlags & SubtotalFlags::IgnoreErrVal);
3947     short nParam = nParamCount;
3948     size_t nRefInList = 0;
3949     ReverseStack( nParamCount );
3950     while (nParam-- > 0)
3951     {
3952         const StackVar eStackType = GetStackType();
3953         switch (eStackType)
3954         {
3955             case svDouble :
3956                 rArray.push_back( PopDouble());
3957             break;
3958             case svSingleRef :
3959             {
3960                 PopSingleRef( aAdr );
3961                 ScRefCellValue aCell(*pDok, aAdr);
3962                 if (bIgnoreErrVal && aCell.hasError())
3963                     ;   // nothing
3964                 else if (aCell.hasNumeric())
3965                     rArray.push_back(GetCellValue(aAdr, aCell));
3966             }
3967             break;
3968             case svDoubleRef :
3969             case svRefList :
3970             {
3971                 PopDoubleRef( aRange, nParam, nRefInList);
3972                 if (nGlobalError != FormulaError::NONE)
3973                     break;
3974 
3975                 aRange.PutInOrder();
3976                 SCSIZE nCellCount = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
3977                 nCellCount *= aRange.aEnd.Row() - aRange.aStart.Row() + 1;
3978                 rArray.reserve( rArray.size() + nCellCount);
3979 
3980                 FormulaError nErr = FormulaError::NONE;
3981                 double fCellVal;
3982                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
3983                 if (aValIter.GetFirst( fCellVal, nErr))
3984                 {
3985                     if (bIgnoreErrVal)
3986                     {
3987                         if (nErr == FormulaError::NONE)
3988                             rArray.push_back( fCellVal);
3989                         while (aValIter.GetNext( fCellVal, nErr))
3990                         {
3991                             if (nErr == FormulaError::NONE)
3992                                 rArray.push_back( fCellVal);
3993                         }
3994                     }
3995                     else
3996                     {
3997                         rArray.push_back( fCellVal);
3998                         SetError(nErr);
3999                         while ((nErr == FormulaError::NONE) && aValIter.GetNext( fCellVal, nErr))
4000                             rArray.push_back( fCellVal);
4001                         SetError(nErr);
4002                     }
4003                 }
4004             }
4005             break;
4006             case svMatrix :
4007             case svExternalSingleRef:
4008             case svExternalDoubleRef:
4009             {
4010                 ScMatrixRef pMat = GetMatrix();
4011                 if (!pMat)
4012                     break;
4013 
4014                 SCSIZE nCount = pMat->GetElementCount();
4015                 rArray.reserve( rArray.size() + nCount);
4016                 if (pMat->IsNumeric())
4017                 {
4018                     if (bIgnoreErrVal)
4019                     {
4020                         for (SCSIZE i = 0; i < nCount; ++i)
4021                         {
4022                             const double fVal = pMat->GetDouble(i);
4023                             if (nGlobalError == FormulaError::NONE)
4024                                 rArray.push_back( fVal);
4025                             else
4026                                 nGlobalError = FormulaError::NONE;
4027                         }
4028                     }
4029                     else
4030                     {
4031                         for (SCSIZE i = 0; i < nCount; ++i)
4032                             rArray.push_back( pMat->GetDouble(i));
4033                     }
4034                 }
4035                 else if (bConvertTextInArray && eStackType == svMatrix)
4036                 {
4037                     for (SCSIZE i = 0; i < nCount; ++i)
4038                     {
4039                         if ( pMat->IsValue( i ) )
4040                         {
4041                             if (bIgnoreErrVal)
4042                             {
4043                                 const double fVal = pMat->GetDouble(i);
4044                                 if (nGlobalError == FormulaError::NONE)
4045                                     rArray.push_back( fVal);
4046                                 else
4047                                     nGlobalError = FormulaError::NONE;
4048                             }
4049                             else
4050                                 rArray.push_back( pMat->GetDouble(i));
4051                         }
4052                         else
4053                         {
4054                             // tdf#88547 try to convert string to (date)value
4055                             OUString aStr = pMat->GetString( i ).getString();
4056                             if ( aStr.getLength() > 0 )
4057                             {
4058                                 FormulaError nErr = nGlobalError;
4059                                 nGlobalError = FormulaError::NONE;
4060                                 double fVal = ConvertStringToValue( aStr );
4061                                 if ( nGlobalError == FormulaError::NONE )
4062                                 {
4063                                     rArray.push_back( fVal );
4064                                     nGlobalError = nErr;
4065                                 }
4066                                 else
4067                                 {
4068                                     if (!bIgnoreErrVal)
4069                                         rArray.push_back( CreateDoubleError( FormulaError::NoValue));
4070                                     // Propagate previous error if any, else
4071                                     // the current #VALUE! error, unless
4072                                     // ignoring error values.
4073                                     if (nErr != FormulaError::NONE)
4074                                         nGlobalError = nErr;
4075                                     else if (!bIgnoreErrVal)
4076                                         nGlobalError = FormulaError::NoValue;
4077                                     else
4078                                         nGlobalError = FormulaError::NONE;
4079                                 }
4080                             }
4081                         }
4082                     }
4083                 }
4084                 else
4085                 {
4086                     if (bIgnoreErrVal)
4087                     {
4088                         for (SCSIZE i = 0; i < nCount; ++i)
4089                         {
4090                             if (pMat->IsValue(i))
4091                             {
4092                                 const double fVal = pMat->GetDouble(i);
4093                                 if (nGlobalError == FormulaError::NONE)
4094                                     rArray.push_back( fVal);
4095                                 else
4096                                     nGlobalError = FormulaError::NONE;
4097                             }
4098                         }
4099                     }
4100                     else
4101                     {
4102                         for (SCSIZE i = 0; i < nCount; ++i)
4103                         {
4104                             if (pMat->IsValue(i))
4105                                 rArray.push_back( pMat->GetDouble(i));
4106                         }
4107                     }
4108                 }
4109             }
4110             break;
4111             default :
4112                 PopError();
4113                 SetError( FormulaError::IllegalParameter);
4114             break;
4115         }
4116         if (nGlobalError != FormulaError::NONE)
4117             break;  // while
4118     }
4119     // nParam > 0 in case of error, clean stack environment and obtain earlier
4120     // error if there was one.
4121     while (nParam-- > 0)
4122         PopError();
4123 }
4124 
4125 void ScInterpreter::GetSortArray( sal_uInt8 nParamCount, vector<double>& rSortArray, vector<long>* pIndexOrder, bool bConvertTextInArray, bool bAllowEmptyArray )
4126 {
4127     GetNumberSequenceArray( nParamCount, rSortArray, bConvertTextInArray );
4128     if (rSortArray.size() > MAX_COUNT_DOUBLE_FOR_SORT)
4129         SetError( FormulaError::MatrixSize);
4130     else if ( rSortArray.empty() )
4131     {
4132         if ( bAllowEmptyArray )
4133             return;
4134         SetError( FormulaError::NoValue);
4135     }
4136 
4137     if (nGlobalError == FormulaError::NONE)
4138         QuickSort( rSortArray, pIndexOrder);
4139 }
4140 
4141 static void lcl_QuickSort( long nLo, long nHi, vector<double>& rSortArray, vector<long>* pIndexOrder )
4142 {
4143     // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
4144 
4145     using ::std::swap;
4146 
4147     if (nHi - nLo == 1)
4148     {
4149         if (rSortArray[nLo] > rSortArray[nHi])
4150         {
4151             swap(rSortArray[nLo],  rSortArray[nHi]);
4152             if (pIndexOrder)
4153                 swap(pIndexOrder->at(nLo), pIndexOrder->at(nHi));
4154         }
4155         return;
4156     }
4157 
4158     long ni = nLo;
4159     long nj = nHi;
4160     do
4161     {
4162         double fLo = rSortArray[nLo];
4163         while (ni <= nHi && rSortArray[ni] < fLo) ni++;
4164         while (nj >= nLo && fLo < rSortArray[nj]) nj--;
4165         if (ni <= nj)
4166         {
4167             if (ni != nj)
4168             {
4169                 swap(rSortArray[ni],  rSortArray[nj]);
4170                 if (pIndexOrder)
4171                     swap(pIndexOrder->at(ni), pIndexOrder->at(nj));
4172             }
4173 
4174             ++ni;
4175             --nj;
4176         }
4177     }
4178     while (ni < nj);
4179 
4180     if ((nj - nLo) < (nHi - ni))
4181     {
4182         if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
4183         if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
4184     }
4185     else
4186     {
4187         if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder);
4188         if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder);
4189     }
4190 }
4191 
4192 void ScInterpreter::QuickSort( vector<double>& rSortArray, vector<long>* pIndexOrder )
4193 {
4194     long n = static_cast<long>(rSortArray.size());
4195 
4196     if (pIndexOrder)
4197     {
4198         pIndexOrder->clear();
4199         pIndexOrder->reserve(n);
4200         for (long i = 0; i < n; ++i)
4201             pIndexOrder->push_back(i);
4202     }
4203 
4204     if (n < 2)
4205         return;
4206 
4207     size_t nValCount = rSortArray.size();
4208     for (size_t i = 0; (i + 4) <= nValCount-1; i += 4)
4209     {
4210         size_t nInd = comphelper::rng::uniform_size_distribution(0, nValCount-2);
4211         ::std::swap( rSortArray[i], rSortArray[nInd]);
4212         if (pIndexOrder)
4213             ::std::swap( pIndexOrder->at(i), pIndexOrder->at(nInd));
4214     }
4215 
4216     lcl_QuickSort(0, n-1, rSortArray, pIndexOrder);
4217 }
4218 
4219 void ScInterpreter::ScRank( bool bAverage )
4220 {
4221     sal_uInt8 nParamCount = GetByte();
4222     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
4223         return;
4224     bool bAscending;
4225     if ( nParamCount == 3 )
4226         bAscending = GetBool();
4227     else
4228         bAscending = false;
4229 
4230     vector<double> aSortArray;
4231     GetSortArray( 1, aSortArray, nullptr, false, false );
4232     double fVal = GetDouble();
4233     SCSIZE nSize = aSortArray.size();
4234     if ( nSize == 0 || nGlobalError != FormulaError::NONE )
4235         PushNoValue();
4236     else
4237     {
4238         if ( fVal < aSortArray[ 0 ] || fVal > aSortArray[ nSize - 1 ] )
4239             PushNoValue();
4240         else
4241         {
4242             double fLastPos = 0;
4243             double fFirstPos = -1.0;
4244             bool bFinished = false;
4245             SCSIZE i;
4246             for (i = 0; i < nSize && !bFinished; i++)
4247             {
4248                 if ( aSortArray[ i ] == fVal )
4249                 {
4250                     if ( fFirstPos < 0 )
4251                         fFirstPos = i + 1.0;
4252                 }
4253                 else
4254                 {
4255                     if ( aSortArray[ i ] > fVal )
4256                     {
4257                         fLastPos = i;
4258                         bFinished = true;
4259                     }
4260                 }
4261             }
4262             if ( !bFinished )
4263                 fLastPos = i;
4264             if ( !bAverage )
4265             {
4266                 if ( bAscending )
4267                     PushDouble( fFirstPos );
4268                 else
4269                     PushDouble( nSize + 1.0 - fLastPos );
4270             }
4271             else
4272             {
4273                 if ( bAscending )
4274                     PushDouble( ( fFirstPos + fLastPos ) / 2.0 );
4275                 else
4276                     PushDouble( nSize + 1.0 - ( fFirstPos + fLastPos ) / 2.0 );
4277             }
4278         }
4279     }
4280 }
4281 
4282 void ScInterpreter::ScAveDev()
4283 {
4284     sal_uInt8 nParamCount = GetByte();
4285     if ( !MustHaveParamCountMin( nParamCount, 1 ) )
4286         return;
4287     sal_uInt16 SaveSP = sp;
4288     double nMiddle = 0.0;
4289     double rVal = 0.0;
4290     double rValCount = 0.0;
4291     ScAddress aAdr;
4292     ScRange aRange;
4293     short nParam = nParamCount;
4294     size_t nRefInList = 0;
4295     while (nParam-- > 0)
4296     {
4297         switch (GetStackType())
4298         {
4299             case svDouble :
4300                 rVal += GetDouble();
4301                 rValCount++;
4302                 break;
4303             case svSingleRef :
4304             {
4305                 PopSingleRef( aAdr );
4306                 ScRefCellValue aCell(*pDok, aAdr);
4307                 if (aCell.hasNumeric())
4308                 {
4309                     rVal += GetCellValue(aAdr, aCell);
4310                     rValCount++;
4311                 }
4312             }
4313             break;
4314             case svDoubleRef :
4315             case svRefList :
4316             {
4317                 FormulaError nErr = FormulaError::NONE;
4318                 double nCellVal;
4319                 PopDoubleRef( aRange, nParam, nRefInList);
4320                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
4321                 if (aValIter.GetFirst(nCellVal, nErr))
4322                 {
4323                     rVal += nCellVal;
4324                     rValCount++;
4325                     SetError(nErr);
4326                     while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
4327                     {
4328                         rVal += nCellVal;
4329                         rValCount++;
4330                     }
4331                     SetError(nErr);
4332                 }
4333             }
4334             break;
4335             case svMatrix :
4336             case svExternalSingleRef:
4337             case svExternalDoubleRef:
4338             {
4339                 ScMatrixRef pMat = GetMatrix();
4340                 if (pMat)
4341                 {
4342                     SCSIZE nCount = pMat->GetElementCount();
4343                     if (pMat->IsNumeric())
4344                     {
4345                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4346                         {
4347                             rVal += pMat->GetDouble(nElem);
4348                             rValCount++;
4349                         }
4350                     }
4351                     else
4352                     {
4353                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4354                             if (!pMat->IsStringOrEmpty(nElem))
4355                             {
4356                                 rVal += pMat->GetDouble(nElem);
4357                                 rValCount++;
4358                             }
4359                     }
4360                 }
4361             }
4362             break;
4363             default :
4364                 SetError(FormulaError::IllegalParameter);
4365             break;
4366         }
4367     }
4368     if (nGlobalError != FormulaError::NONE)
4369     {
4370         PushError( nGlobalError);
4371         return;
4372     }
4373     nMiddle = rVal / rValCount;
4374     sp = SaveSP;
4375     rVal = 0.0;
4376     nParam = nParamCount;
4377     nRefInList = 0;
4378     while (nParam-- > 0)
4379     {
4380         switch (GetStackType())
4381         {
4382             case svDouble :
4383                 rVal += fabs(GetDouble() - nMiddle);
4384                 break;
4385             case svSingleRef :
4386             {
4387                 PopSingleRef( aAdr );
4388                 ScRefCellValue aCell(*pDok, aAdr);
4389                 if (aCell.hasNumeric())
4390                     rVal += fabs(GetCellValue(aAdr, aCell) - nMiddle);
4391             }
4392             break;
4393             case svDoubleRef :
4394             case svRefList :
4395             {
4396                 FormulaError nErr = FormulaError::NONE;
4397                 double nCellVal;
4398                 PopDoubleRef( aRange, nParam, nRefInList);
4399                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
4400                 if (aValIter.GetFirst(nCellVal, nErr))
4401                 {
4402                     rVal += (fabs(nCellVal - nMiddle));
4403                     while (aValIter.GetNext(nCellVal, nErr))
4404                          rVal += fabs(nCellVal - nMiddle);
4405                 }
4406             }
4407             break;
4408             case svMatrix :
4409             case svExternalSingleRef:
4410             case svExternalDoubleRef:
4411             {
4412                 ScMatrixRef pMat = GetMatrix();
4413                 if (pMat)
4414                 {
4415                     SCSIZE nCount = pMat->GetElementCount();
4416                     if (pMat->IsNumeric())
4417                     {
4418                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4419                         {
4420                             rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
4421                         }
4422                     }
4423                     else
4424                     {
4425                         for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4426                         {
4427                             if (!pMat->IsStringOrEmpty(nElem))
4428                                 rVal += fabs(pMat->GetDouble(nElem) - nMiddle);
4429                         }
4430                     }
4431                 }
4432             }
4433             break;
4434             default : SetError(FormulaError::IllegalParameter); break;
4435         }
4436     }
4437     PushDouble(rVal / rValCount);
4438 }
4439 
4440 void ScInterpreter::ScDevSq()
4441 {
4442     auto VarResult = []( double fVal, size_t /*nValCount*/ )
4443     {
4444         return fVal;
4445     };
4446     GetStVarParams( false /*bTextAsZero*/, VarResult);
4447 }
4448 
4449 void ScInterpreter::ScProbability()
4450 {
4451     sal_uInt8 nParamCount = GetByte();
4452     if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
4453         return;
4454     double fUp, fLo;
4455     fUp = GetDouble();
4456     if (nParamCount == 4)
4457         fLo = GetDouble();
4458     else
4459         fLo = fUp;
4460     if (fLo > fUp)
4461     {
4462         double fTemp = fLo;
4463         fLo = fUp;
4464         fUp = fTemp;
4465     }
4466     ScMatrixRef pMatP = GetMatrix();
4467     ScMatrixRef pMatW = GetMatrix();
4468     if (!pMatP || !pMatW)
4469         PushIllegalParameter();
4470     else
4471     {
4472         SCSIZE nC1, nC2;
4473         SCSIZE nR1, nR2;
4474         pMatP->GetDimensions(nC1, nR1);
4475         pMatW->GetDimensions(nC2, nR2);
4476         if (nC1 != nC2 || nR1 != nR2 || nC1 == 0 || nR1 == 0 ||
4477             nC2 == 0 || nR2 == 0)
4478             PushNA();
4479         else
4480         {
4481             double fSum = 0.0;
4482             double fRes = 0.0;
4483             bool bStop = false;
4484             double fP, fW;
4485             for ( SCSIZE i = 0; i < nC1 && !bStop; i++ )
4486             {
4487                 for (SCSIZE j = 0; j < nR1 && !bStop; ++j )
4488                 {
4489                     if (pMatP->IsValue(i,j) && pMatW->IsValue(i,j))
4490                     {
4491                         fP = pMatP->GetDouble(i,j);
4492                         fW = pMatW->GetDouble(i,j);
4493                         if (fP < 0.0 || fP > 1.0)
4494                             bStop = true;
4495                         else
4496                         {
4497                             fSum += fP;
4498                             if (fW >= fLo && fW <= fUp)
4499                                 fRes += fP;
4500                         }
4501                     }
4502                     else
4503                         SetError( FormulaError::IllegalArgument);
4504                 }
4505             }
4506             if (bStop || fabs(fSum -1.0) > 1.0E-7)
4507                 PushNoValue();
4508             else
4509                 PushDouble(fRes);
4510         }
4511     }
4512 }
4513 
4514 void ScInterpreter::ScCorrel()
4515 {
4516     // This is identical to ScPearson()
4517     ScPearson();
4518 }
4519 
4520 void ScInterpreter::ScCovarianceP()
4521 {
4522     CalculatePearsonCovar( false, false, false );
4523 }
4524 
4525 void ScInterpreter::ScCovarianceS()
4526 {
4527     CalculatePearsonCovar( false, false, true );
4528 }
4529 
4530 void ScInterpreter::ScPearson()
4531 {
4532     CalculatePearsonCovar( true, false, false );
4533 }
4534 
4535 void ScInterpreter::CalculatePearsonCovar( bool _bPearson, bool _bStexy, bool _bSample )
4536 {
4537     if ( !MustHaveParamCount( GetByte(), 2 ) )
4538         return;
4539     ScMatrixRef pMat1 = GetMatrix();
4540     ScMatrixRef pMat2 = GetMatrix();
4541     if (!pMat1 || !pMat2)
4542     {
4543         PushIllegalParameter();
4544         return;
4545     }
4546     SCSIZE nC1, nC2;
4547     SCSIZE nR1, nR2;
4548     pMat1->GetDimensions(nC1, nR1);
4549     pMat2->GetDimensions(nC2, nR2);
4550     if (nR1 != nR2 || nC1 != nC2)
4551     {
4552         PushIllegalArgument();
4553         return;
4554     }
4555     /* #i78250#
4556      * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
4557      * but the latter produces wrong results if the absolute values are high,
4558      * for example above 10^8
4559      */
4560     double fCount           = 0.0;
4561     double fSumX            = 0.0;
4562     double fSumY            = 0.0;
4563 
4564     for (SCSIZE i = 0; i < nC1; i++)
4565     {
4566         for (SCSIZE j = 0; j < nR1; j++)
4567         {
4568             if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4569             {
4570                 double fValX = pMat1->GetDouble(i,j);
4571                 double fValY = pMat2->GetDouble(i,j);
4572                 fSumX += fValX;
4573                 fSumY += fValY;
4574                 fCount++;
4575             }
4576         }
4577     }
4578     if (fCount < (_bStexy ? 3.0 : (_bSample ? 2.0 : 1.0)))
4579         PushNoValue();
4580     else
4581     {
4582         double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4583         double fSumSqrDeltaX    = 0.0; // sum of (ValX-MeanX)^2
4584         double fSumSqrDeltaY    = 0.0; // sum of (ValY-MeanY)^2
4585         const double fMeanX = fSumX / fCount;
4586         const double fMeanY = fSumY / fCount;
4587         for (SCSIZE i = 0; i < nC1; i++)
4588         {
4589             for (SCSIZE j = 0; j < nR1; j++)
4590             {
4591                 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4592                 {
4593                     const double fValX = pMat1->GetDouble(i,j);
4594                     const double fValY = pMat2->GetDouble(i,j);
4595                     fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4596                     if ( _bPearson )
4597                     {
4598                         fSumSqrDeltaX    += (fValX - fMeanX) * (fValX - fMeanX);
4599                         fSumSqrDeltaY    += (fValY - fMeanY) * (fValY - fMeanY);
4600                     }
4601                 }
4602             }
4603         }
4604         if ( _bPearson )
4605         {
4606             if (fSumSqrDeltaX == 0.0 || ( !_bStexy && fSumSqrDeltaY == 0.0) )
4607                 PushError( FormulaError::DivisionByZero);
4608             else if ( _bStexy )
4609                 PushDouble( sqrt( (fSumSqrDeltaY - fSumDeltaXDeltaY *
4610                             fSumDeltaXDeltaY / fSumSqrDeltaX) / (fCount-2)));
4611             else
4612                 PushDouble( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY));
4613         }
4614         else
4615         {
4616             if ( _bSample )
4617                 PushDouble( fSumDeltaXDeltaY / ( fCount - 1 ) );
4618             else
4619                 PushDouble( fSumDeltaXDeltaY / fCount);
4620         }
4621     }
4622 }
4623 
4624 void ScInterpreter::ScRSQ()
4625 {
4626     // Same as ScPearson()*ScPearson()
4627     ScPearson();
4628     if (nGlobalError == FormulaError::NONE)
4629     {
4630         switch (GetStackType())
4631         {
4632             case svDouble:
4633                 {
4634                     double fVal = PopDouble();
4635                     PushDouble( fVal * fVal);
4636                 }
4637                 break;
4638             default:
4639                 PopError();
4640                 PushNoValue();
4641         }
4642     }
4643 }
4644 
4645 void ScInterpreter::ScSTEYX()
4646 {
4647     CalculatePearsonCovar( true, true, false );
4648 }
4649 void ScInterpreter::CalculateSlopeIntercept(bool bSlope)
4650 {
4651     if ( !MustHaveParamCount( GetByte(), 2 ) )
4652         return;
4653     ScMatrixRef pMat1 = GetMatrix();
4654     ScMatrixRef pMat2 = GetMatrix();
4655     if (!pMat1 || !pMat2)
4656     {
4657         PushIllegalParameter();
4658         return;
4659     }
4660     SCSIZE nC1, nC2;
4661     SCSIZE nR1, nR2;
4662     pMat1->GetDimensions(nC1, nR1);
4663     pMat2->GetDimensions(nC2, nR2);
4664     if (nR1 != nR2 || nC1 != nC2)
4665     {
4666         PushIllegalArgument();
4667         return;
4668     }
4669     // #i78250# numerical stability improved
4670     double fCount           = 0.0;
4671     double fSumX            = 0.0;
4672     double fSumY            = 0.0;
4673 
4674     for (SCSIZE i = 0; i < nC1; i++)
4675     {
4676         for (SCSIZE j = 0; j < nR1; j++)
4677         {
4678             if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4679             {
4680                 double fValX = pMat1->GetDouble(i,j);
4681                 double fValY = pMat2->GetDouble(i,j);
4682                 fSumX += fValX;
4683                 fSumY += fValY;
4684                 fCount++;
4685             }
4686         }
4687     }
4688     if (fCount < 1.0)
4689         PushNoValue();
4690     else
4691     {
4692         double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4693         double fSumSqrDeltaX    = 0.0; // sum of (ValX-MeanX)^2
4694         double fMeanX = fSumX / fCount;
4695         double fMeanY = fSumY / fCount;
4696         for (SCSIZE i = 0; i < nC1; i++)
4697         {
4698             for (SCSIZE j = 0; j < nR1; j++)
4699             {
4700                 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4701                 {
4702                     double fValX = pMat1->GetDouble(i,j);
4703                     double fValY = pMat2->GetDouble(i,j);
4704                     fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4705                     fSumSqrDeltaX    += (fValX - fMeanX) * (fValX - fMeanX);
4706                 }
4707             }
4708         }
4709         if (fSumSqrDeltaX == 0.0)
4710             PushError( FormulaError::DivisionByZero);
4711         else
4712         {
4713             if ( bSlope )
4714                 PushDouble( fSumDeltaXDeltaY / fSumSqrDeltaX);
4715             else
4716                 PushDouble( fMeanY - fSumDeltaXDeltaY / fSumSqrDeltaX * fMeanX);
4717         }
4718     }
4719 }
4720 
4721 void ScInterpreter::ScSlope()
4722 {
4723     CalculateSlopeIntercept(true);
4724 }
4725 
4726 void ScInterpreter::ScIntercept()
4727 {
4728     CalculateSlopeIntercept(false);
4729 }
4730 
4731 void ScInterpreter::ScForecast()
4732 {
4733     if ( !MustHaveParamCount( GetByte(), 3 ) )
4734         return;
4735     ScMatrixRef pMat1 = GetMatrix();
4736     ScMatrixRef pMat2 = GetMatrix();
4737     if (!pMat1 || !pMat2)
4738     {
4739         PushIllegalParameter();
4740         return;
4741     }
4742     SCSIZE nC1, nC2;
4743     SCSIZE nR1, nR2;
4744     pMat1->GetDimensions(nC1, nR1);
4745     pMat2->GetDimensions(nC2, nR2);
4746     if (nR1 != nR2 || nC1 != nC2)
4747     {
4748         PushIllegalArgument();
4749         return;
4750     }
4751     double fVal = GetDouble();
4752     // #i78250# numerical stability improved
4753     double fCount           = 0.0;
4754     double fSumX            = 0.0;
4755     double fSumY            = 0.0;
4756 
4757     for (SCSIZE i = 0; i < nC1; i++)
4758     {
4759         for (SCSIZE j = 0; j < nR1; j++)
4760         {
4761             if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4762             {
4763                 double fValX = pMat1->GetDouble(i,j);
4764                 double fValY = pMat2->GetDouble(i,j);
4765                 fSumX += fValX;
4766                 fSumY += fValY;
4767                 fCount++;
4768             }
4769         }
4770     }
4771     if (fCount < 1.0)
4772         PushNoValue();
4773     else
4774     {
4775         double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4776         double fSumSqrDeltaX    = 0.0; // sum of (ValX-MeanX)^2
4777         double fMeanX = fSumX / fCount;
4778         double fMeanY = fSumY / fCount;
4779         for (SCSIZE i = 0; i < nC1; i++)
4780         {
4781             for (SCSIZE j = 0; j < nR1; j++)
4782             {
4783                 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
4784                 {
4785                     double fValX = pMat1->GetDouble(i,j);
4786                     double fValY = pMat2->GetDouble(i,j);
4787                     fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY);
4788                     fSumSqrDeltaX    += (fValX - fMeanX) * (fValX - fMeanX);
4789                 }
4790             }
4791         }
4792         if (fSumSqrDeltaX == 0.0)
4793             PushError( FormulaError::DivisionByZero);
4794         else
4795             PushDouble( fMeanY + fSumDeltaXDeltaY / fSumSqrDeltaX * (fVal - fMeanX));
4796     }
4797 }
4798 
4799 static void lcl_roundUpNearestPow2(SCSIZE& nNum, SCSIZE& nNumBits)
4800 {
4801     // Find the least power of 2 that is less than or equal to nNum.
4802     SCSIZE nPow2(1);
4803     nNumBits = std::numeric_limits<SCSIZE>::digits;
4804     nPow2 <<= (nNumBits - 1);
4805     while (nPow2 >= 1)
4806     {
4807         if (nNum & nPow2)
4808             break;
4809 
4810         --nNumBits;
4811         nPow2 >>= 1;
4812     }
4813 
4814     if (nPow2 != nNum)
4815         nNum = nPow2 ? (nPow2 << 1) : 1;
4816     else
4817         --nNumBits;
4818 }
4819 
4820 static SCSIZE lcl_bitReverse(SCSIZE nIn, SCSIZE nBound)
4821 {
4822     SCSIZE nOut = 0;
4823     for (SCSIZE nMask = 1; nMask < nBound; nMask <<= 1)
4824     {
4825         nOut <<= 1;
4826 
4827         if (nIn & nMask)
4828             nOut |= 1;
4829     }
4830 
4831     return nOut;
4832 }
4833 
4834 namespace {
4835 
4836 // Computes and stores twiddle factors for computing DFT later.
4837 struct ScTwiddleFactors
4838 {
4839     ScTwiddleFactors(SCSIZE nN, bool bInverse) :
4840         mfWReal(nN),
4841         mfWImag(nN),
4842         mnN(nN),
4843         mbInverse(bInverse)
4844     {}
4845 
4846     void Compute();
4847 
4848     void Conjugate()
4849     {
4850         mbInverse = !mbInverse;
4851         for (SCSIZE nIdx = 0; nIdx < mnN; ++nIdx)
4852             mfWImag[nIdx] = -mfWImag[nIdx];
4853     }
4854 
4855     std::vector<double> mfWReal;
4856     std::vector<double> mfWImag;
4857     SCSIZE mnN;
4858     bool mbInverse;
4859 };
4860 
4861 }
4862 
4863 void ScTwiddleFactors::Compute()
4864 {
4865     mfWReal.resize(mnN);
4866     mfWImag.resize(mnN);
4867 
4868     double nW = (mbInverse ? 2 : -2)*F_PI/static_cast<double>(mnN);
4869 
4870     if (mnN == 1)
4871     {
4872         mfWReal[0] = 1.0;
4873         mfWImag[0] = 0.0;
4874     }
4875     else if (mnN == 2)
4876     {
4877         mfWReal[0] = 1;
4878         mfWImag[0] = 0;
4879 
4880         mfWReal[1] = -1;
4881         mfWImag[1] = 0;
4882     }
4883     else if (mnN == 4)
4884     {
4885         mfWReal[0] = 1;
4886         mfWImag[0] = 0;
4887 
4888         mfWReal[1] = 0;
4889         mfWImag[1] = (mbInverse ? 1.0 : -1.0);
4890 
4891         mfWReal[2] = -1;
4892         mfWImag[2] = 0;
4893 
4894         mfWReal[3] = 0;
4895         mfWImag[3] = (mbInverse ? -1.0 : 1.0);
4896     }
4897     else if ((mnN % 4) == 0)
4898     {
4899         const SCSIZE nQSize = mnN >> 2;
4900         // Compute cos of the start quadrant.
4901         // This is the first quadrant if mbInverse == true, else it is the fourth quadrant.
4902         for (SCSIZE nIdx = 0; nIdx <= nQSize; ++nIdx)
4903             mfWReal[nIdx] = cos(nW*static_cast<double>(nIdx));
4904 
4905         if (mbInverse)
4906         {
4907             const SCSIZE nQ1End = nQSize;
4908             // First quadrant
4909             for (SCSIZE nIdx = 0; nIdx <= nQ1End; ++nIdx)
4910                 mfWImag[nIdx] = mfWReal[nQ1End-nIdx];
4911 
4912             // Second quadrant
4913             const SCSIZE nQ2End = nQ1End << 1;
4914             for (SCSIZE nIdx = nQ1End+1; nIdx <= nQ2End; ++nIdx)
4915             {
4916                 mfWReal[nIdx] = -mfWReal[nQ2End - nIdx];
4917                 mfWImag[nIdx] =  mfWImag[nQ2End - nIdx];
4918             }
4919 
4920             // Third quadrant
4921             const SCSIZE nQ3End = nQ2End + nQ1End;
4922             for (SCSIZE nIdx = nQ2End+1; nIdx <= nQ3End; ++nIdx)
4923             {
4924                 mfWReal[nIdx] = -mfWReal[nIdx - nQ2End];
4925                 mfWImag[nIdx] = -mfWImag[nIdx - nQ2End];
4926             }
4927 
4928             // Fourth Quadrant
4929             for (SCSIZE nIdx = nQ3End+1; nIdx < mnN; ++nIdx)
4930             {
4931                 mfWReal[nIdx] =  mfWReal[mnN - nIdx];
4932                 mfWImag[nIdx] = -mfWImag[mnN - nIdx];
4933             }
4934         }
4935         else
4936         {
4937             const SCSIZE nQ4End = nQSize;
4938             const SCSIZE nQ3End = nQSize << 1;
4939             const SCSIZE nQ2End = nQ3End + nQSize;
4940 
4941             // Fourth quadrant.
4942             for (SCSIZE nIdx = 0; nIdx <= nQ4End; ++nIdx)
4943                 mfWImag[nIdx] = -mfWReal[nQ4End - nIdx];
4944 
4945             // Third quadrant.
4946             for (SCSIZE nIdx = nQ4End+1; nIdx <= nQ3End; ++nIdx)
4947             {
4948                 mfWReal[nIdx] = -mfWReal[nQ3End - nIdx];
4949                 mfWImag[nIdx] =  mfWImag[nQ3End - nIdx];
4950             }
4951 
4952             // Second quadrant.
4953             for (SCSIZE nIdx = nQ3End+1; nIdx <= nQ2End; ++nIdx)
4954             {
4955                 mfWReal[nIdx] = -mfWReal[nIdx - nQ3End];
4956                 mfWImag[nIdx] = -mfWImag[nIdx - nQ3End];
4957             }
4958 
4959             // First quadrant.
4960             for (SCSIZE nIdx = nQ2End+1; nIdx < mnN; ++nIdx)
4961             {
4962                 mfWReal[nIdx] =  mfWReal[mnN - nIdx];
4963                 mfWImag[nIdx] = -mfWImag[mnN - nIdx];
4964             }
4965         }
4966     }
4967     else
4968     {
4969         for (SCSIZE nIdx = 0; nIdx < mnN; ++nIdx)
4970         {
4971             double fAngle = nW*static_cast<double>(nIdx);
4972             mfWReal[nIdx] = cos(fAngle);
4973             mfWImag[nIdx] = sin(fAngle);
4974         }
4975     }
4976 }
4977 
4978 namespace {
4979 
4980 // A radix-2 decimation in time FFT algorithm for complex valued input.
4981 class ScComplexFFT2
4982 {
4983 public:
4984     // rfArray.size() would always be even and a power of 2. (asserted in prepare())
4985     // rfArray's first half contains the real parts and the later half contains the imaginary parts.
4986     ScComplexFFT2(std::vector<double>& raArray, bool bInverse, bool bPolar, double fMinMag,
4987                   ScTwiddleFactors& rTF, bool bSubSampleTFs = false, bool bDisableNormalize = false) :
4988         mrArray(raArray),
4989         mfWReal(rTF.mfWReal),
4990         mfWImag(rTF.mfWImag),
4991         mnPoints(raArray.size()/2),
4992         mnStages(0),
4993         mfMinMag(fMinMag),
4994         mbInverse(bInverse),
4995         mbPolar(bPolar),
4996         mbDisableNormalize(bDisableNormalize),
4997         mbSubSampleTFs(bSubSampleTFs)
4998     {}
4999 
5000     void Compute();
5001 
5002 private:
5003 
5004     void prepare();
5005 
5006     double getReal(SCSIZE nIdx)
5007     {
5008         return mrArray[nIdx];
5009     }
5010 
5011     void setReal(double fVal, SCSIZE nIdx)
5012     {
5013         mrArray[nIdx] = fVal;
5014     }
5015 
5016     double getImag(SCSIZE nIdx)
5017     {
5018         return mrArray[mnPoints + nIdx];
5019     }
5020 
5021     void setImag(double fVal, SCSIZE nIdx)
5022     {
5023         mrArray[mnPoints + nIdx] = fVal;
5024     }
5025 
5026     SCSIZE getTFactorIndex(SCSIZE nPtIndex, SCSIZE nTfIdxScaleBits)
5027     {
5028         return ( ( nPtIndex << nTfIdxScaleBits ) & ( mnPoints - 1 ) ); // (x & (N-1)) is same as (x % N) but faster.
5029     }
5030 
5031     void computeFly(SCSIZE nTopIdx, SCSIZE nBottomIdx, SCSIZE nWIdx1, SCSIZE nWIdx2)
5032     {
5033         if (mbSubSampleTFs)
5034         {
5035             nWIdx1 <<= 1;
5036             nWIdx2 <<= 1;
5037         }
5038 
5039         const double x1r = getReal(nTopIdx);
5040         const double x2r = getReal(nBottomIdx);
5041 
5042         const double& w1r = mfWReal[nWIdx1];
5043         const double& w1i = mfWImag[nWIdx1];
5044 
5045         const double& w2r = mfWReal[nWIdx2];
5046         const double& w2i = mfWImag[nWIdx2];
5047 
5048         const double x1i = getImag(nTopIdx);
5049         const double x2i = getImag(nBottomIdx);
5050 
5051         setReal(x1r + x2r*w1r - x2i*w1i, nTopIdx);
5052         setImag(x1i + x2i*w1r + x2r*w1i, nTopIdx);
5053 
5054         setReal(x1r + x2r*w2r - x2i*w2i, nBottomIdx);
5055         setImag(x1i + x2i*w2r + x2r*w2i, nBottomIdx);
5056     }
5057 
5058     std::vector<double>& mrArray;
5059     std::vector<double>& mfWReal;
5060     std::vector<double>& mfWImag;
5061     SCSIZE mnPoints;
5062     SCSIZE mnStages;
5063     double mfMinMag;
5064     bool mbInverse:1;
5065     bool mbPolar:1;
5066     bool mbDisableNormalize:1;
5067     bool mbSubSampleTFs:1;
5068 };
5069 
5070 }
5071 
5072 void ScComplexFFT2::prepare()
5073 {
5074     SCSIZE nPoints = mnPoints;
5075     lcl_roundUpNearestPow2(nPoints, mnStages);
5076     assert(nPoints == mnPoints);
5077 
5078     // Reorder array by bit-reversed indices.
5079     for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx)
5080     {
5081         SCSIZE nRevIdx = lcl_bitReverse(nIdx, mnPoints);
5082         if (nIdx < nRevIdx)
5083         {
5084             double fTmp = getReal(nIdx);
5085             setReal(getReal(nRevIdx), nIdx);
5086             setReal(fTmp, nRevIdx);
5087 
5088             fTmp = getImag(nIdx);
5089             setImag(getImag(nRevIdx), nIdx);
5090             setImag(fTmp, nRevIdx);
5091         }
5092     }
5093 }
5094 
5095 static void lcl_normalize(std::vector<double>& rCmplxArray, bool bScaleOnlyReal)
5096 {
5097     const SCSIZE nPoints = rCmplxArray.size()/2;
5098     const double fScale = 1.0/static_cast<double>(nPoints);
5099 
5100     // Scale the real part
5101     for (SCSIZE nIdx = 0; nIdx < nPoints; ++nIdx)
5102         rCmplxArray[nIdx] *= fScale;
5103 
5104     if (!bScaleOnlyReal)
5105     {
5106         const SCSIZE nLen = nPoints*2;
5107         for (SCSIZE nIdx = nPoints; nIdx < nLen; ++nIdx)
5108             rCmplxArray[nIdx] *= fScale;
5109     }
5110 }
5111 
5112 static void lcl_convertToPolar(std::vector<double>& rCmplxArray, double fMinMag)
5113 {
5114     const SCSIZE nPoints = rCmplxArray.size()/2;
5115     double fMag, fPhase, fR, fI;
5116     for (SCSIZE nIdx = 0; nIdx < nPoints; ++nIdx)
5117     {
5118         fR = rCmplxArray[nIdx];
5119         fI = rCmplxArray[nPoints+nIdx];
5120         fMag = sqrt(fR*fR + fI*fI);
5121         if (fMag < fMinMag)
5122         {
5123             fMag = 0.0;
5124             fPhase = 0.0;
5125         }
5126         else
5127         {
5128             fPhase = atan2(fI, fR);
5129         }
5130 
5131         rCmplxArray[nIdx] = fMag;
5132         rCmplxArray[nPoints+nIdx] = fPhase;
5133     }
5134 }
5135 
5136 void ScComplexFFT2::Compute()
5137 {
5138     prepare();
5139 
5140     const SCSIZE nFliesInStage = mnPoints/2;
5141     for (SCSIZE nStage = 0; nStage < mnStages; ++nStage)
5142     {
5143         const SCSIZE nTFIdxScaleBits = mnStages - nStage - 1;  // Twiddle factor index's scale factor in bits.
5144         const SCSIZE nFliesInGroup = SCSIZE(1) << nStage;
5145         const SCSIZE nGroups = nFliesInStage/nFliesInGroup;
5146         const SCSIZE nFlyWidth = nFliesInGroup;
5147         for (SCSIZE nGroup = 0, nFlyTopIdx = 0; nGroup < nGroups; ++nGroup)
5148         {
5149             for (SCSIZE nFly = 0; nFly < nFliesInGroup; ++nFly, ++nFlyTopIdx)
5150             {
5151                 SCSIZE nFlyBottomIdx = nFlyTopIdx + nFlyWidth;
5152                 SCSIZE nWIdx1 = getTFactorIndex(nFlyTopIdx, nTFIdxScaleBits);
5153                 SCSIZE nWIdx2 = getTFactorIndex(nFlyBottomIdx, nTFIdxScaleBits);
5154 
5155                 computeFly(nFlyTopIdx, nFlyBottomIdx, nWIdx1, nWIdx2);
5156             }
5157 
5158             nFlyTopIdx += nFlyWidth;
5159         }
5160     }
5161 
5162     if (mbPolar)
5163         lcl_convertToPolar(mrArray, mfMinMag);
5164 
5165     // Normalize after converting to polar, so we have a chance to
5166     // save O(mnPoints) flops.
5167     if (mbInverse && !mbDisableNormalize)
5168         lcl_normalize(mrArray, mbPolar);
5169 }
5170 
5171 namespace {
5172 
5173 // Bluestein's algorithm or chirp z-transform algorithm that can be used to
5174 // compute DFT of a complex valued input of any length N in O(N lgN) time.
5175 class ScComplexBluesteinFFT
5176 {
5177 public:
5178 
5179     ScComplexBluesteinFFT(std::vector<double>& rArray, bool bReal, bool bInverse,
5180                           bool bPolar, double fMinMag, bool bDisableNormalize = false) :
5181         mrArray(rArray),
5182         mnPoints(rArray.size()/2), // rArray should have space for imaginary parts even if real input.
5183         mfMinMag(fMinMag),
5184         mbReal(bReal),
5185         mbInverse(bInverse),
5186         mbPolar(bPolar),
5187         mbDisableNormalize(bDisableNormalize)
5188     {}
5189 
5190     void Compute();
5191 
5192 private:
5193     std::vector<double>& mrArray;
5194     const SCSIZE mnPoints;
5195     double mfMinMag;
5196     bool mbReal:1;
5197     bool mbInverse:1;
5198     bool mbPolar:1;
5199     bool mbDisableNormalize:1;
5200 };
5201 
5202 }
5203 
5204 void ScComplexBluesteinFFT::Compute()
5205 {
5206     std::vector<double> aRealScalars(mnPoints);
5207     std::vector<double> aImagScalars(mnPoints);
5208     double fW = (mbInverse ? 2 : -2)*F_PI/static_cast<double>(mnPoints);
5209     for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx)
5210     {
5211         double fAngle = 0.5*fW*static_cast<double>(nIdx*nIdx);
5212         aRealScalars[nIdx] = cos(fAngle);
5213         aImagScalars[nIdx] = sin(fAngle);
5214     }
5215 
5216     SCSIZE nMinSize = mnPoints*2 - 1;
5217     SCSIZE nExtendedLength = nMinSize, nTmp = 0;
5218     lcl_roundUpNearestPow2(nExtendedLength, nTmp);
5219     std::vector<double> aASignal(nExtendedLength*2); // complex valued
5220     std::vector<double> aBSignal(nExtendedLength*2); // complex valued
5221 
5222     double fReal, fImag;
5223     for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx)
5224     {
5225         // Real part of A signal.
5226         aASignal[nIdx] = mrArray[nIdx]*aRealScalars[nIdx] + (mbReal ? 0.0 : -mrArray[mnPoints+nIdx]*aImagScalars[nIdx]);
5227         // Imaginary part of A signal.
5228         aASignal[nExtendedLength + nIdx] = mrArray[nIdx]*aImagScalars[nIdx] + (mbReal ? 0.0 : mrArray[mnPoints+nIdx]*aRealScalars[nIdx]);
5229 
5230         // Real part of B signal.
5231         aBSignal[nIdx] = fReal = aRealScalars[nIdx];
5232         // Imaginary part of B signal.
5233         aBSignal[nExtendedLength + nIdx] = fImag = -aImagScalars[nIdx]; // negative sign because B signal is the conjugation of the scalars.
5234 
5235         if (nIdx)
5236         {
5237             // B signal needs a mirror of its part in 0 < n < mnPoints at the tail end.
5238             aBSignal[nExtendedLength - nIdx] = fReal;
5239             aBSignal[(nExtendedLength<<1) - nIdx] = fImag;
5240         }
5241     }
5242 
5243     {
5244         ScTwiddleFactors aTF(nExtendedLength, false /*not inverse*/);
5245         aTF.Compute();
5246 
5247         // Do complex-FFT2 of both A and B signal.
5248         ScComplexFFT2 aFFT2A(aASignal, false /*not inverse*/, false /*no polar*/, 0.0 /* no clipping */,
5249                              aTF, false /*no subsample*/, true /* disable normalize */);
5250         aFFT2A.Compute();
5251 
5252         ScComplexFFT2 aFFT2B(aBSignal, false /*not inverse*/, false /*no polar*/, 0.0 /* no clipping */,
5253                              aTF, false /*no subsample*/, true /* disable normalize */);
5254         aFFT2B.Compute();
5255 
5256         double fAR, fAI, fBR, fBI;
5257         for (SCSIZE nIdx = 0; nIdx < nExtendedLength; ++nIdx)
5258         {
5259             fAR = aASignal[nIdx];
5260             fAI = aASignal[nExtendedLength + nIdx];
5261             fBR = aBSignal[nIdx];
5262             fBI = aBSignal[nExtendedLength + nIdx];
5263 
5264             // Do point-wise product inplace in A signal.
5265             aASignal[nIdx] = fAR*fBR - fAI*fBI;
5266             aASignal[nExtendedLength + nIdx] = fAR*fBI + fAI*fBR;
5267         }
5268 
5269         // Do complex-inverse-FFT2 of aASignal.
5270         aTF.Conjugate();
5271         ScComplexFFT2 aFFT2AI(aASignal, true /*inverse*/, false /*no polar*/, 0.0 /* no clipping */, aTF); // Need normalization here.
5272         aFFT2AI.Compute();
5273     }
5274 
5275     // Point-wise multiply with scalars.
5276     for (SCSIZE nIdx = 0; nIdx < mnPoints; ++nIdx)
5277     {
5278         fReal = aASignal[nIdx];
5279         fImag = aASignal[nExtendedLength + nIdx];
5280         mrArray[nIdx] = fReal*aRealScalars[nIdx] - fImag*aImagScalars[nIdx]; // no conjugation needed here.
5281         mrArray[mnPoints + nIdx] = fReal*aImagScalars[nIdx] + fImag*aRealScalars[nIdx];
5282     }
5283 
5284     // Normalize/Polar operations
5285     if (mbPolar)
5286         lcl_convertToPolar(mrArray, mfMinMag);
5287 
5288     // Normalize after converting to polar, so we have a chance to
5289     // save O(mnPoints) flops.
5290     if (mbInverse && !mbDisableNormalize)
5291         lcl_normalize(mrArray, mbPolar);
5292 }
5293 
5294 namespace {
5295 
5296 // Computes DFT of an even length(N) real-valued input by using a
5297 // ScComplexFFT2 if N == 2^k for some k or else by using a ScComplexBluesteinFFT
5298 // with a complex valued input of length = N/2.
5299 class ScRealFFT
5300 {
5301 public:
5302 
5303     ScRealFFT(std::vector<double>& rInArray, std::vector<double>& rOutArray, bool bInverse,
5304               bool bPolar, double fMinMag) :
5305         mrInArray(rInArray),
5306         mrOutArray(rOutArray),
5307         mfMinMag(fMinMag),
5308         mbInverse(bInverse),
5309         mbPolar(bPolar)
5310     {}
5311 
5312     void Compute();
5313 
5314 private:
5315     std::vector<double>& mrInArray;
5316     std::vector<double>& mrOutArray;
5317     double mfMinMag;
5318     bool mbInverse:1;
5319     bool mbPolar:1;
5320 };
5321 
5322 }
5323 
5324 void ScRealFFT::Compute()
5325 {
5326     // input length has to be even to do this optimization.
5327     assert(mrInArray.size() % 2 == 0);
5328     assert(mrInArray.size()*2 == mrOutArray.size());
5329     // nN is the number of points in the complex-fft input
5330     // which will be half of the number of points in real array.
5331     const SCSIZE nN = mrInArray.size()/2;
5332     if (nN == 0)
5333     {
5334         mrOutArray[0] = mrInArray[0];
5335         mrOutArray[1] = 0.0;
5336         return;
5337     }
5338 
5339     // work array should be the same length as mrInArray
5340     std::vector<double> aWorkArray(nN*2);
5341     for (SCSIZE nIdx = 0; nIdx < nN; ++nIdx)
5342     {
5343         SCSIZE nDoubleIdx = 2*nIdx;
5344         // Use even elements as real part
5345         aWorkArray[nIdx] = mrInArray[nDoubleIdx];
5346         // and odd elements as imaginary part of the contrived complex sequence.
5347         aWorkArray[nN+nIdx] = mrInArray[nDoubleIdx+1];
5348     }
5349 
5350     ScTwiddleFactors aTFs(nN*2, mbInverse);
5351     aTFs.Compute();
5352     SCSIZE nNextPow2 = nN, nTmp = 0;
5353     lcl_roundUpNearestPow2(nNextPow2, nTmp);
5354 
5355     if (nNextPow2 == nN)
5356     {
5357         ScComplexFFT2 aFFT2(aWorkArray, mbInverse, false /*disable polar*/, 0.0 /* no clipping */,
5358                             aTFs, true /*subsample tf*/, true /*disable normalize*/);
5359         aFFT2.Compute();
5360     }
5361     else
5362     {
5363         ScComplexBluesteinFFT aFFT(aWorkArray, false /*complex input*/, mbInverse, false /*disable polar*/,
5364                                    0.0 /* no clipping */, true /*disable normalize*/);
5365         aFFT.Compute();
5366     }
5367 
5368     // Post process aWorkArray to populate mrOutArray
5369 
5370     const SCSIZE nTwoN = 2*nN, nThreeN = 3*nN;
5371     double fY1R, fY2R, fY1I, fY2I, fResR, fResI, fWR, fWI;
5372     for (SCSIZE nIdx = 0; nIdx < nN; ++nIdx)
5373     {
5374         const SCSIZE nIdxRev = nIdx ? (nN - nIdx) : 0;
5375         fY1R = aWorkArray[nIdx];
5376         fY2R = aWorkArray[nIdxRev];
5377         fY1I = aWorkArray[nN + nIdx];
5378         fY2I = aWorkArray[nN + nIdxRev];
5379         fWR  = aTFs.mfWReal[nIdx];
5380         fWI  = aTFs.mfWImag[nIdx];
5381 
5382         // mrOutArray has length = 4*nN
5383         // Real part of the final output (only half of the symmetry around Nyquist frequency)
5384         // Fills the first quarter.
5385         mrOutArray[nIdx] = fResR = 0.5*(
5386             fY1R + fY2R +
5387             fWR * (fY1I + fY2I) +
5388             fWI * (fY1R - fY2R) );
5389         // Imaginary part of the final output (only half of the symmetry around Nyquist frequency)
5390         // Fills the third quarter.
5391         mrOutArray[nTwoN + nIdx] = fResI = 0.5*(
5392             fY1I - fY2I +
5393             fWI * (fY1I + fY2I) -
5394             fWR * (fY1R - fY2R) );
5395 
5396         // Fill the missing 2 quarters using symmetry argument.
5397         if (nIdx)
5398         {
5399             // Fills the 2nd quarter.
5400             mrOutArray[nN + nIdxRev] = fResR;
5401             // Fills the 4th quarter.
5402             mrOutArray[nThreeN + nIdxRev] = -fResI;
5403         }
5404         else
5405         {
5406             mrOutArray[nN] = fY1R - fY1I;
5407             mrOutArray[nThreeN] = 0.0;
5408         }
5409     }
5410 
5411     // Normalize/Polar operations
5412     if (mbPolar)
5413         lcl_convertToPolar(mrOutArray, mfMinMag);
5414 
5415     // Normalize after converting to polar, so we have a chance to
5416     // save O(mnPoints) flops.
5417     if (mbInverse)
5418         lcl_normalize(mrOutArray, mbPolar);
5419 }
5420 
5421 using ScMatrixGenerator = ScMatrixRef(SCSIZE, SCSIZE, std::vector<double>&);
5422 
5423 namespace {
5424 
5425 // Generic FFT class that decides which FFT implementation to use.
5426 class ScFFT
5427 {
5428 public:
5429 
5430     ScFFT(ScMatrixRef& pMat, bool bReal, bool bInverse, bool bPolar, double fMinMag) :
5431         mpInputMat(pMat),
5432         mfMinMag(fMinMag),
5433         mbReal(bReal),
5434         mbInverse(bInverse),
5435         mbPolar(bPolar)
5436     {}
5437 
5438     ScMatrixRef Compute(const std::function<ScMatrixGenerator>& rMatGenFunc);
5439 
5440 private:
5441     ScMatrixRef& mpInputMat;
5442     double mfMinMag;
5443     bool mbReal:1;
5444     bool mbInverse:1;
5445     bool mbPolar:1;
5446 };
5447 
5448 }
5449 
5450 ScMatrixRef ScFFT::Compute(const std::function<ScMatrixGenerator>& rMatGenFunc)
5451 {
5452     std::vector<double> aArray;
5453     mpInputMat->GetDoubleArray(aArray);
5454     SCSIZE nPoints = mbReal ? aArray.size() : (aArray.size()/2);
5455     if (nPoints == 1)
5456     {
5457         std::vector<double> aOutArray(2);
5458         aOutArray[0] = aArray[0];
5459         aOutArray[1] = mbReal ? 0.0 : aArray[1];
5460         if (mbPolar)
5461             lcl_convertToPolar(aOutArray, mfMinMag);
5462         return rMatGenFunc(2, 1, aOutArray);
5463     }
5464 
5465     if (mbReal && (nPoints % 2) == 0)
5466     {
5467         std::vector<double> aOutArray(nPoints*2);
5468         ScRealFFT aFFT(aArray, aOutArray, mbInverse, mbPolar, mfMinMag);
5469         aFFT.Compute();
5470         return rMatGenFunc(2, nPoints, aOutArray);
5471     }
5472 
5473     SCSIZE nNextPow2 = nPoints, nTmp = 0;
5474     lcl_roundUpNearestPow2(nNextPow2, nTmp);
5475     if (nNextPow2 == nPoints && !mbReal)
5476     {
5477         ScTwiddleFactors aTF(nPoints, mbInverse);
5478         aTF.Compute();
5479         ScComplexFFT2 aFFT2(aArray, mbInverse, mbPolar, mfMinMag, aTF);
5480         aFFT2.Compute();
5481         return rMatGenFunc(2, nPoints, aArray);
5482     }
5483 
5484     if (mbReal)
5485         aArray.resize(nPoints*2, 0.0);
5486     ScComplexBluesteinFFT aFFT(aArray, mbReal, mbInverse, mbPolar, mfMinMag);
5487     aFFT.Compute();
5488     return rMatGenFunc(2, nPoints, aArray);
5489 }
5490 
5491 void ScInterpreter::ScFourier()
5492 {
5493     sal_uInt8 nParamCount = GetByte();
5494     if ( !MustHaveParamCount( nParamCount, 2, 5 ) )
5495         return;
5496 
5497     bool bInverse = false;
5498     bool bPolar = false;
5499     double fMinMag = 0.0;
5500 
5501     if (nParamCount == 5)
5502     {
5503         if (IsMissing())
5504             Pop();
5505         else
5506             fMinMag = GetDouble();
5507     }
5508 
5509     if (nParamCount >= 4)
5510     {
5511         if (IsMissing())
5512             Pop();
5513         else
5514             bPolar = GetBool();
5515     }
5516 
5517     if (nParamCount >= 3)
5518     {
5519         if (IsMissing())
5520             Pop();
5521         else
5522             bInverse = GetBool();
5523     }
5524 
5525     bool bGroupedByColumn = GetBool();
5526 
5527     ScMatrixRef pInputMat = GetMatrix();
5528     if (!pInputMat)
5529     {
5530         PushIllegalParameter();
5531         return;
5532     }
5533 
5534     SCSIZE nC, nR;
5535     pInputMat->GetDimensions(nC, nR);
5536 
5537     if ((bGroupedByColumn && nC > 2) || (!bGroupedByColumn && nR > 2))
5538     {
5539         // There can be no more than 2 columns (real, imaginary) if data grouped by columns.
5540         // and no more than 2 rows if data is grouped by rows.
5541         PushIllegalArgument();
5542         return;
5543     }
5544 
5545     if (!pInputMat->IsNumeric())
5546     {
5547         PushNoValue();
5548         return;
5549     }
5550 
5551     bool bRealInput = true;
5552     if (!bGroupedByColumn)
5553     {
5554         pInputMat->MatTrans(*pInputMat);
5555         bRealInput = (nR == 1);
5556     }
5557     else
5558     {
5559         bRealInput = (nC == 1);
5560     }
5561 
5562     ScFFT aFFT(pInputMat, bRealInput, bInverse, bPolar, fMinMag);
5563     std::function<ScMatrixGenerator> aFunc = [this](SCSIZE nCol, SCSIZE nRow, std::vector<double>& rVec) -> ScMatrixRef
5564     {
5565         return this->GetNewMat(nCol, nRow, rVec);
5566     };
5567     ScMatrixRef pOut = aFFT.Compute(aFunc);
5568     PushMatrix(pOut);
5569 }
5570 
5571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
5572