LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/tool - interpr3.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 77 2085 3.7 %
Date: 2012-12-27 Functions: 5 133 3.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10