diff options
Diffstat (limited to 'sc/source/core/tool/interpr3.cxx')
-rw-r--r-- | sc/source/core/tool/interpr3.cxx | 4157 |
1 files changed, 0 insertions, 4157 deletions
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx deleted file mode 100644 index 62d670d65..000000000 --- a/sc/source/core/tool/interpr3.cxx +++ /dev/null @@ -1,4157 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sc.hxx" - -// INCLUDE --------------------------------------------------------------- - -#include <tools/solar.h> -#include <stdlib.h> -#include <string.h> -#include <rtl/logfile.hxx> - -#include "interpre.hxx" -#include "global.hxx" -#include "compiler.hxx" -#include "cell.hxx" -#include "document.hxx" -#include "dociter.hxx" -#include "scmatrix.hxx" -#include "globstr.hrc" - -#include <math.h> -#include <vector> -#include <algorithm> - -using ::std::vector; -using namespace formula; - -// STATIC DATA ----------------------------------------------------------- - -#define SCdEpsilon 1.0E-7 -#define SC_MAX_ITERATION_COUNT 20 -#define MAX_ANZ_DOUBLE_FOR_SORT 100000 - -const double ScInterpreter::fMaxGammaArgument = 171.624376956302; // found experimental -const double fMachEps = ::std::numeric_limits<double>::epsilon(); - -//----------------------------------------------------------------------------- - -class ScDistFunc -{ -public: - virtual double GetValue(double x) const = 0; -}; - -// iteration for inverse distributions - -//template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError ) - -/** u*w<0.0 fails for values near zero */ -inline bool lcl_HasChangeOfSign( double u, double w ) -{ - return (u < 0.0 && w > 0.0) || (u > 0.0 && w < 0.0); -} - -double lcl_IterateInverse( const ScDistFunc& rFunction, double fAx, double fBx, bool& rConvError ) -{ - rConvError = false; - const double fYEps = 1.0E-307; - const double fXEps = ::std::numeric_limits<double>::epsilon(); - - OSL_ENSURE(fAx<fBx, "IterateInverse: wrong interval"); - - // find enclosing interval - - double fAy = rFunction.GetValue(fAx); - double fBy = rFunction.GetValue(fBx); - double fTemp; - unsigned short nCount; - for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++) - { - if (fabs(fAy) <= fabs(fBy)) - { - fTemp = fAx; - fAx += 2.0 * (fAx - fBx); - if (fAx < 0.0) - fAx = 0.0; - fBx = fTemp; - fBy = fAy; - fAy = rFunction.GetValue(fAx); - } - else - { - fTemp = fBx; - fBx += 2.0 * (fBx - fAx); - fAx = fTemp; - fAy = fBy; - fBy = rFunction.GetValue(fBx); - } - } - - if (fAy == 0.0) - return fAx; - if (fBy == 0.0) - return fBx; - if (!lcl_HasChangeOfSign( fAy, fBy)) - { - rConvError = true; - return 0.0; - } - // inverse quadric interpolation with additional brackets - // set three points - double fPx = fAx; - double fPy = fAy; - double fQx = fBx; - double fQy = fBy; - double fRx = fAx; - double fRy = fAy; - double fSx = 0.5 * (fAx + fBx); // potential next point - bool bHasToInterpolate = true; - nCount = 0; - while ( nCount < 500 && fabs(fRy) > fYEps && - (fBx-fAx) > ::std::max( fabs(fAx), fabs(fBx)) * fXEps ) - { - if (bHasToInterpolate) - { - if (fPy!=fQy && fQy!=fRy && fRy!=fPy) - { - fSx = fPx * fRy * fQy / (fRy-fPy) / (fQy-fPy) - + fRx * fQy * fPy / (fQy-fRy) / (fPy-fRy) - + fQx * fPy * fRy / (fPy-fQy) / (fRy-fQy); - bHasToInterpolate = (fAx < fSx) && (fSx < fBx); // inside the brackets? - } - else - bHasToInterpolate = false; - } - if(!bHasToInterpolate) - { - fSx = 0.5 * (fAx + fBx); - // reset points - fPx = fAx; fPy = fAy; - fQx = fBx; fQy = fBy; - bHasToInterpolate = true; - } - // shift points for next interpolation - fPx = fQx; fQx = fRx; fRx = fSx; - fPy = fQy; fQy = fRy; fRy = rFunction.GetValue(fSx); - // update brackets - if (lcl_HasChangeOfSign( fAy, fRy)) - { - fBx = fRx; fBy = fRy; - } - else - { - fAx = fRx; fAy = fRy; - } - // if last interration brought to small advance, then do bisection next - // time, for safety - bHasToInterpolate = bHasToInterpolate && (fabs(fRy) * 2.0 <= fabs(fQy)); - ++nCount; - } - return fRx; -} - -//----------------------------------------------------------------------------- -// Allgemeine Funktionen -//----------------------------------------------------------------------------- - -void ScInterpreter::ScNoName() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNoName" ); - PushError(errNoName); -} - -void ScInterpreter::ScBadName() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBadName" ); - short nParamCount = GetByte(); - while (nParamCount-- > 0) - { - PopError(); - } - PushError( errNoName); -} - -double ScInterpreter::phi(double x) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::phi" ); - return 0.39894228040143268 * exp(-(x * x) / 2.0); -} - -double ScInterpreter::integralPhi(double x) -{ // Using gauss(x)+0.5 has severe cancellation errors for x<-4 - return 0.5 * ::rtl::math::erfc(-x * 0.7071067811865475); // * 1/sqrt(2) -} - -double ScInterpreter::taylor(double* pPolynom, sal_uInt16 nMax, double x) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::taylor" ); - double nVal = pPolynom[nMax]; - for (short i = nMax-1; i >= 0; i--) - { - nVal = pPolynom[i] + (nVal * x); - } - return nVal; -} - -double ScInterpreter::gauss(double x) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::gauss" ); - double t0[] = - { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582, - -0.00118732821548045, 0.00011543468761616, -0.00000944465625950, - 0.00000066596935163, -0.00000004122667415, 0.00000000227352982, - 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 }; - double t2[] = - { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805, - 0.02699548325659403, -0.00449924720943234, -0.00224962360471617, - 0.00134977416282970, -0.00011783742691370, -0.00011515930357476, - 0.00003704737285544, 0.00000282690796889, -0.00000354513195524, - 0.00000037669563126, 0.00000019202407921, -0.00000005226908590, - -0.00000000491799345, 0.00000000366377919, -0.00000000015981997, - -0.00000000017381238, 0.00000000002624031, 0.00000000000560919, - -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 }; - double t4[] = - { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977, - 0.00033457556441221, -0.00028996548915725, 0.00018178605666397, - -0.00008252863922168, 0.00002551802519049, -0.00000391665839292, - -0.00000074018205222, 0.00000064422023359, -0.00000017370155340, - 0.00000000909595465, 0.00000000944943118, -0.00000000329957075, - 0.00000000029492075, 0.00000000011874477, -0.00000000004420396, - 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 }; - double asympt[] = { -1.0, 1.0, -3.0, 15.0, -105.0 }; - - double xAbs = fabs(x); - sal_uInt16 xShort = (sal_uInt16)::rtl::math::approxFloor(xAbs); - double nVal = 0.0; - if (xShort == 0) - nVal = taylor(t0, 11, (xAbs * xAbs)) * xAbs; - else if ((xShort >= 1) && (xShort <= 2)) - nVal = taylor(t2, 23, (xAbs - 2.0)); - else if ((xShort >= 3) && (xShort <= 4)) - nVal = taylor(t4, 20, (xAbs - 4.0)); - else - nVal = 0.5 + phi(xAbs) * taylor(asympt, 4, 1.0 / (xAbs * xAbs)) / xAbs; - if (x < 0.0) - return -nVal; - else - return nVal; -} - -// -// #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net> -// - -double ScInterpreter::gaussinv(double x) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::gaussinv" ); - double q,t,z; - - q=x-0.5; - - if(fabs(q)<=.425) - { - t=0.180625-q*q; - - z= - q* - ( - ( - ( - ( - ( - ( - ( - t*2509.0809287301226727+33430.575583588128105 - ) - *t+67265.770927008700853 - ) - *t+45921.953931549871457 - ) - *t+13731.693765509461125 - ) - *t+1971.5909503065514427 - ) - *t+133.14166789178437745 - ) - *t+3.387132872796366608 - ) - / - ( - ( - ( - ( - ( - ( - ( - t*5226.495278852854561+28729.085735721942674 - ) - *t+39307.89580009271061 - ) - *t+21213.794301586595867 - ) - *t+5394.1960214247511077 - ) - *t+687.1870074920579083 - ) - *t+42.313330701600911252 - ) - *t+1.0 - ); - - } - else - { - if(q>0) t=1-x; - else t=x; - - t=sqrt(-log(t)); - - if(t<=5.0) - { - t+=-1.6; - - z= - ( - ( - ( - ( - ( - ( - ( - t*7.7454501427834140764e-4+0.0227238449892691845833 - ) - *t+0.24178072517745061177 - ) - *t+1.27045825245236838258 - ) - *t+3.64784832476320460504 - ) - *t+5.7694972214606914055 - ) - *t+4.6303378461565452959 - ) - *t+1.42343711074968357734 - ) - / - ( - ( - ( - ( - ( - ( - ( - t*1.05075007164441684324e-9+5.475938084995344946e-4 - ) - *t+0.0151986665636164571966 - ) - *t+0.14810397642748007459 - ) - *t+0.68976733498510000455 - ) - *t+1.6763848301838038494 - ) - *t+2.05319162663775882187 - ) - *t+1.0 - ); - - } - else - { - t+=-5.0; - - z= - ( - ( - ( - ( - ( - ( - ( - t*2.01033439929228813265e-7+2.71155556874348757815e-5 - ) - *t+0.0012426609473880784386 - ) - *t+0.026532189526576123093 - ) - *t+0.29656057182850489123 - ) - *t+1.7848265399172913358 - ) - *t+5.4637849111641143699 - ) - *t+6.6579046435011037772 - ) - / - ( - ( - ( - ( - ( - ( - ( - t*2.04426310338993978564e-15+1.4215117583164458887e-7 - ) - *t+1.8463183175100546818e-5 - ) - *t+7.868691311456132591e-4 - ) - *t+0.0148753612908506148525 - ) - *t+0.13692988092273580531 - ) - *t+0.59983220655588793769 - ) - *t+1.0 - ); - - } - - if(q<0.0) z=-z; - } - - return z; -} - -double ScInterpreter::Fakultaet(double x) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Fakultaet" ); - x = ::rtl::math::approxFloor(x); - if (x < 0.0) - return 0.0; - else if (x == 0.0) - return 1.0; - else if (x <= 170.0) - { - double fTemp = x; - while (fTemp > 2.0) - { - fTemp--; - x *= fTemp; - } - } - else - SetError(errNoValue); - return x; -} - -double ScInterpreter::BinomKoeff(double n, double k) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::BinomKoeff" ); - double nVal = 0.0; - k = ::rtl::math::approxFloor(k); - if (n < k) - nVal = 0.0; - else if (k == 0.0) - nVal = 1.0; - else - { - nVal = n/k; - n--; - k--; - while (k > 0.0) - { - nVal *= n/k; - k--; - n--; - } - - } - return nVal; -} - -// The algorithm is based on lanczos13m53 in lanczos.hpp -// in math library from http://www.boost.org -/** you must ensure fZ>0 - Uses a variant of the Lanczos sum with a rational function. */ -double lcl_getLanczosSum(double fZ) -{ - const double fNum[13] ={ - 23531376880.41075968857200767445163675473, - 42919803642.64909876895789904700198885093, - 35711959237.35566804944018545154716670596, - 17921034426.03720969991975575445893111267, - 6039542586.35202800506429164430729792107, - 1439720407.311721673663223072794912393972, - 248874557.8620541565114603864132294232163, - 31426415.58540019438061423162831820536287, - 2876370.628935372441225409051620849613599, - 186056.2653952234950402949897160456992822, - 8071.672002365816210638002902272250613822, - 210.8242777515793458725097339207133627117, - 2.506628274631000270164908177133837338626 - }; - const double fDenom[13] = { - 0, - 39916800, - 120543840, - 150917976, - 105258076, - 45995730, - 13339535, - 2637558, - 357423, - 32670, - 1925, - 66, - 1 - }; - // Horner scheme - double fSumNum; - double fSumDenom; - int nI; - if (fZ<=1.0) - { - fSumNum = fNum[12]; - fSumDenom = fDenom[12]; - for (nI = 11; nI >= 0; --nI) - { - fSumNum *= fZ; - fSumNum += fNum[nI]; - fSumDenom *= fZ; - fSumDenom += fDenom[nI]; - } - } - else - // Cancel down with fZ^12; Horner scheme with reverse coefficients - { - double fZInv = 1/fZ; - fSumNum = fNum[0]; - fSumDenom = fDenom[0]; - for (nI = 1; nI <=12; ++nI) - { - fSumNum *= fZInv; - fSumNum += fNum[nI]; - fSumDenom *= fZInv; - fSumDenom += fDenom[nI]; - } - } - return fSumNum/fSumDenom; -} - -// The algorithm is based on tgamma in gamma.hpp -// in math library from http://www.boost.org -/** You must ensure fZ>0; fZ>171.624376956302 will overflow. */ -double lcl_GetGammaHelper(double fZ) -{ - double fGamma = lcl_getLanczosSum(fZ); - const double fg = 6.024680040776729583740234375; - double fZgHelp = fZ + fg - 0.5; - // avoid intermediate overflow - double fHalfpower = pow( fZgHelp, fZ / 2 - 0.25); - fGamma *= fHalfpower; - fGamma /= exp(fZgHelp); - fGamma *= fHalfpower; - if (fZ <= 20.0 && fZ == ::rtl::math::approxFloor(fZ)) - fGamma = ::rtl::math::round(fGamma); - return fGamma; -} - -// The algorithm is based on tgamma in gamma.hpp -// in math library from http://www.boost.org -/** You must ensure fZ>0 */ -double lcl_GetLogGammaHelper(double fZ) -{ - const double fg = 6.024680040776729583740234375; - double fZgHelp = fZ + fg - 0.5; - return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp; -} - -/** You must ensure non integer arguments for fZ<1 */ -double ScInterpreter::GetGamma(double fZ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGamma" ); - const double fLogPi = log(F_PI); - const double fLogDblMax = log( ::std::numeric_limits<double>::max()); - - if (fZ > fMaxGammaArgument) - { - SetError(errIllegalFPOperation); - return HUGE_VAL; - } - - if (fZ >= 1.0) - return lcl_GetGammaHelper(fZ); - - if (fZ >= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x - return lcl_GetGammaHelper(fZ+1) / fZ; - - if (fZ >= -0.5) // shift to x>=1, might overflow - { - double fLogTest = lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log( fabs(fZ)); - if (fLogTest >= fLogDblMax) - { - SetError( errIllegalFPOperation); - return HUGE_VAL; - } - return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ; - } - // fZ<-0.5 - // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) ) - double fLogDivisor = lcl_GetLogGammaHelper(1-fZ) + log( fabs( ::rtl::math::sin( F_PI*fZ))); - if (fLogDivisor - fLogPi >= fLogDblMax) // underflow - return 0.0; - - if (fLogDivisor<0.0) - if (fLogPi - fLogDivisor > fLogDblMax) // overflow - { - SetError(errIllegalFPOperation); - return HUGE_VAL; - } - - return exp( fLogPi - fLogDivisor) * ((::rtl::math::sin( F_PI*fZ) < 0.0) ? -1.0 : 1.0); -} - -/** You must ensure fZ>0 */ -double ScInterpreter::GetLogGamma(double fZ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetLogGamma" ); - if (fZ >= fMaxGammaArgument) - return lcl_GetLogGammaHelper(fZ); - if (fZ >= 1.0) - return log(lcl_GetGammaHelper(fZ)); - if (fZ >= 0.5) - return log( lcl_GetGammaHelper(fZ+1) / fZ); - return lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log(fZ); -} - -double ScInterpreter::GetFDist(double x, double fF1, double fF2) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetFDist" ); - double arg = fF2/(fF2+fF1*x); - double alpha = fF2/2.0; - double beta = fF1/2.0; - return (GetBetaDist(arg, alpha, beta)); -} - -double ScInterpreter::GetTDist(double T, double fDF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetTDist" ); - return 0.5 * GetBetaDist(fDF/(fDF+T*T), fDF/2.0, 0.5); -} - -// for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom -/** You must ensure fDF>0.0 */ -double ScInterpreter::GetChiDist(double fX, double fDF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetChiDist" ); - if (fX <= 0.0) - return 1.0; // see ODFF - else - return GetUpRegIGamma( fDF/2.0, fX/2.0); -} - -// ready for ODF 1.2 -// for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom -// returns left tail -/** You must ensure fDF>0.0 */ -double ScInterpreter::GetChiSqDistCDF(double fX, double fDF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetChiSqDistCDF" ); - if (fX <= 0.0) - return 0.0; // see ODFF - else - return GetLowRegIGamma( fDF/2.0, fX/2.0); -} - -double ScInterpreter::GetChiSqDistPDF(double fX, double fDF) -{ - // you must ensure fDF is positive integer - double fValue; - if (fX <= 0.0) - return 0.0; // see ODFF - if (fDF*fX > 1391000.0) - { - // intermediate invalid values, use log - fValue = exp((0.5*fDF - 1) * log(fX*0.5) - 0.5 * fX - log(2.0) - GetLogGamma(0.5*fDF)); - } - else // fDF is small in most cases, we can iterate - { - double fCount; - if (fmod(fDF,2.0)<0.5) - { - // even - fValue = 0.5; - fCount = 2.0; - } - else - { - fValue = 1/sqrt(fX*2*F_PI); - fCount = 1.0; - } - while ( fCount < fDF) - { - fValue *= (fX / fCount); - fCount += 2.0; - } - if (fX>=1425.0) // underflow in e^(-x/2) - fValue = exp(log(fValue)-fX/2); - else - fValue *= exp(-fX/2); - } - return fValue; -} - -void ScInterpreter::ScChiSqDist() -{ - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 2, 3 ) ) - return; - bool bCumulative; - if (nParamCount == 3) - bCumulative = GetBool(); - else - bCumulative = true; - double fDF = ::rtl::math::approxFloor(GetDouble()); - if (fDF < 1.0) - PushIllegalArgument(); - else - { - double fX = GetDouble(); - if (bCumulative) - PushDouble(GetChiSqDistCDF(fX,fDF)); - else - PushDouble(GetChiSqDistPDF(fX,fDF)); - } -} - -void ScInterpreter::ScGamma() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGamma" ); - double x = GetDouble(); - if (x <= 0.0 && x == ::rtl::math::approxFloor(x)) - PushIllegalArgument(); - else - { - double fResult = GetGamma(x); - if (nGlobalError) - { - PushError( nGlobalError); - return; - } - PushDouble(fResult); - } -} - -void ScInterpreter::ScLogGamma() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogGamma" ); - double x = GetDouble(); - if (x > 0.0) // constraint from ODFF - PushDouble( GetLogGamma(x)); - else - PushIllegalArgument(); -} - -double ScInterpreter::GetBeta(double fAlpha, double fBeta) -{ - double fA; - double fB; - if (fAlpha > fBeta) - { - fA = fAlpha; fB = fBeta; - } - else - { - fA = fBeta; fB = fAlpha; - } - if (fA+fB < fMaxGammaArgument) // simple case - return GetGamma(fA)/GetGamma(fA+fB)*GetGamma(fB); - // need logarithm - // GetLogGamma is not accurate enough, back to Lanczos for all three - // GetGamma and arrange factors newly. - const double fg = 6.024680040776729583740234375; //see GetGamma - double fgm = fg - 0.5; - double fLanczos = lcl_getLanczosSum(fA); - fLanczos /= lcl_getLanczosSum(fA+fB); - fLanczos *= lcl_getLanczosSum(fB); - double fABgm = fA+fB+fgm; - fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm)); - double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) - double fTempB = fA/(fB+fgm); - double fResult = exp(-fA * ::rtl::math::log1p(fTempA) - -fB * ::rtl::math::log1p(fTempB)-fgm); - fResult *= fLanczos; - return fResult; -} - -// Same as GetBeta but with logarithm -double ScInterpreter::GetLogBeta(double fAlpha, double fBeta) -{ - double fA; - double fB; - if (fAlpha > fBeta) - { - fA = fAlpha; fB = fBeta; - } - else - { - fA = fBeta; fB = fAlpha; - } - const double fg = 6.024680040776729583740234375; //see GetGamma - double fgm = fg - 0.5; - double fLanczos = lcl_getLanczosSum(fA); - fLanczos /= lcl_getLanczosSum(fA+fB); - fLanczos *= lcl_getLanczosSum(fB); - double fLogLanczos = log(fLanczos); - double fABgm = fA+fB+fgm; - fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm)); - double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) - double fTempB = fA/(fB+fgm); - double fResult = -fA * ::rtl::math::log1p(fTempA) - -fB * ::rtl::math::log1p(fTempB)-fgm; - fResult += fLogLanczos; - return fResult; -} - -// beta distribution probability density function -double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB) -{ - // special cases - if (fA == 1.0) // result b*(1-x)^(b-1) - { - if (fB == 1.0) - return 1.0; - if (fB == 2.0) - return -2.0*fX + 2.0; - if (fX == 1.0 && fB < 1.0) - { - SetError(errIllegalArgument); - return HUGE_VAL; - } - if (fX <= 0.01) - return fB + fB * ::rtl::math::expm1((fB-1.0) * ::rtl::math::log1p(-fX)); - else - return fB * pow(0.5-fX+0.5,fB-1.0); - } - if (fB == 1.0) // result a*x^(a-1) - { - if (fA == 2.0) - return fA * fX; - if (fX == 0.0 && fA < 1.0) - { - SetError(errIllegalArgument); - return HUGE_VAL; - } - return fA * pow(fX,fA-1); - } - if (fX <= 0.0) - { - if (fA < 1.0 && fX == 0.0) - { - SetError(errIllegalArgument); - return HUGE_VAL; - } - else - return 0.0; - } - if (fX >= 1.0) - { - if (fB < 1.0 && fX == 1.0) - { - SetError(errIllegalArgument); - return HUGE_VAL; - } - else - return 0.0; - } - - // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b) - const double fLogDblMax = log( ::std::numeric_limits<double>::max()); - const double fLogDblMin = log( ::std::numeric_limits<double>::min()); - double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5); - double fLogX = log(fX); - double fAm1 = fA-1.0; - double fBm1 = fB-1.0; - double fLogBeta = GetLogBeta(fA,fB); - // check whether parts over- or underflow - if ( fAm1 * fLogX < fLogDblMax && fAm1 * fLogX > fLogDblMin - && fBm1 * fLogY < fLogDblMax && fBm1* fLogY > fLogDblMin - && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin ) - return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB); - else // need logarithm; - // might overflow as a whole, but seldom, not worth to pre-detect it - return exp((fA-1.0)*fLogX + (fB-1.0)* fLogY - fLogBeta); -} - -/* - x^a * (1-x)^b - I_x(a,b) = ---------------- * result of ContFrac - a * Beta(a,b) -*/ -double lcl_GetBetaHelperContFrac(double fX, double fA, double fB) -{ // like old version - double a1, b1, a2, b2, fnorm, apl2m, d2m, d2m1, cfnew, cf; - a1 = 1.0; b1 = 1.0; - b2 = 1.0 - (fA+fB)/(fA+1.0)*fX; - if (b2 == 0.0) - { - a2 = 0.0; - fnorm = 1.0; - cf = 1.0; - } - else - { - a2 = 1.0; - fnorm = 1.0/b2; - cf = a2*fnorm; - } - cfnew = 1.0; - double rm = 1.0; - - const double fMaxIter = 50000.0; - // loop security, normal cases converge in less than 100 iterations. - // FIXME: You will get so much iteratons for fX near mean, - // I do not know a better algorithm. - bool bfinished = false; - do - { - apl2m = fA + 2.0*rm; - d2m = rm*(fB-rm)*fX/((apl2m-1.0)*apl2m); - d2m1 = -(fA+rm)*(fA+fB+rm)*fX/(apl2m*(apl2m+1.0)); - a1 = (a2+d2m*a1)*fnorm; - b1 = (b2+d2m*b1)*fnorm; - a2 = a1 + d2m1*a2*fnorm; - b2 = b1 + d2m1*b2*fnorm; - if (b2 != 0.0) - { - fnorm = 1.0/b2; - cfnew = a2*fnorm; - bfinished = (fabs(cf-cfnew) < fabs(cf)*fMachEps); - } - cf = cfnew; - rm += 1.0; - } - while (rm < fMaxIter && !bfinished); - return cf; -} - -// cumulative distribution function, normalized -double ScInterpreter::GetBetaDist(double fXin, double fAlpha, double fBeta) -{ -// special cases - if (fXin <= 0.0) // values are valid, see spec - return 0.0; - if (fXin >= 1.0) // values are valid, see spec - return 1.0; - if (fBeta == 1.0) - return pow(fXin, fAlpha); - if (fAlpha == 1.0) - // 1.0 - pow(1.0-fX,fBeta) is not accurate enough - return -::rtl::math::expm1(fBeta * ::rtl::math::log1p(-fXin)); - //FIXME: need special algorithm for fX near fP for large fA,fB - double fResult; - // I use always continued fraction, power series are neither - // faster nor more accurate. - double fY = (0.5-fXin)+0.5; - double flnY = ::rtl::math::log1p(-fXin); - double fX = fXin; - double flnX = log(fXin); - double fA = fAlpha; - double fB = fBeta; - bool bReflect = fXin > fAlpha/(fAlpha+fBeta); - if (bReflect) - { - fA = fBeta; - fB = fAlpha; - fX = fY; - fY = fXin; - flnX = flnY; - flnY = log(fXin); - } - fResult = lcl_GetBetaHelperContFrac(fX,fA,fB); - fResult = fResult/fA; - double fP = fA/(fA+fB); - double fQ = fB/(fA+fB); - double fTemp; - if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97) //found experimental - fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY; - else - fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB)); - fResult *= fTemp; - if (bReflect) - fResult = 0.5 - fResult + 0.5; - if (fResult > 1.0) // ensure valid range - fResult = 1.0; - if (fResult < 0.0) - fResult = 0.0; - return fResult; -} - - void ScInterpreter::ScBetaDist() - { - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) // expanded, see #i91547# - return; - double fLowerBound, fUpperBound; - double alpha, beta, x; - bool bIsCumulative; - if (nParamCount == 6) - bIsCumulative = GetBool(); - else - bIsCumulative = true; - if (nParamCount >= 5) - fUpperBound = GetDouble(); - else - fUpperBound = 1.0; - if (nParamCount >= 4) - fLowerBound = GetDouble(); - else - fLowerBound = 0.0; - beta = GetDouble(); - alpha = GetDouble(); - x = GetDouble(); - double fScale = fUpperBound - fLowerBound; - if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0) - { - PushIllegalArgument(); - return; - } - if (bIsCumulative) // cumulative distribution function - { - // special cases - if (x < fLowerBound) - { - PushDouble(0.0); return; //see spec - } - if (x > fUpperBound) - { - PushDouble(1.0); return; //see spec - } - // normal cases - x = (x-fLowerBound)/fScale; // convert to standard form - PushDouble(GetBetaDist(x, alpha, beta)); - return; - } - else // probability density function - { - if (x < fLowerBound || x > fUpperBound) - { - PushDouble(0.0); - return; - } - x = (x-fLowerBound)/fScale; - PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale); - return; - } -} - -void ScInterpreter::ScPhi() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPhi" ); - PushDouble(phi(GetDouble())); -} - -void ScInterpreter::ScGauss() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGauss" ); - PushDouble(gauss(GetDouble())); -} - -void ScInterpreter::ScFisher() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFisher" ); - double fVal = GetDouble(); - if (fabs(fVal) >= 1.0) - PushIllegalArgument(); - else - PushDouble( ::rtl::math::atanh( fVal)); -} - -void ScInterpreter::ScFisherInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFisherInv" ); - PushDouble( tanh( GetDouble())); -} - -void ScInterpreter::ScFact() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFact" ); - double nVal = GetDouble(); - if (nVal < 0.0) - PushIllegalArgument(); - else - PushDouble(Fakultaet(nVal)); -} - -void ScInterpreter::ScKombin() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKombin" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double k = ::rtl::math::approxFloor(GetDouble()); - double n = ::rtl::math::approxFloor(GetDouble()); - if (k < 0.0 || n < 0.0 || k > n) - PushIllegalArgument(); - else - PushDouble(BinomKoeff(n, k)); - } -} - -void ScInterpreter::ScKombin2() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKombin2" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double k = ::rtl::math::approxFloor(GetDouble()); - double n = ::rtl::math::approxFloor(GetDouble()); - if (k < 0.0 || n < 0.0 || k > n) - PushIllegalArgument(); - else - PushDouble(BinomKoeff(n + k - 1, k)); - } -} - -void ScInterpreter::ScVariationen() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVariationen" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double k = ::rtl::math::approxFloor(GetDouble()); - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || k < 0.0 || k > n) - PushIllegalArgument(); - else if (k == 0.0) - PushInt(1); // (n! / (n - 0)!) == 1 - else - { - double nVal = n; - for (sal_uLong i = (sal_uLong)k-1; i >= 1; i--) - nVal *= n-(double)i; - PushDouble(nVal); - } - } -} - -void ScInterpreter::ScVariationen2() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVariationen2" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double k = ::rtl::math::approxFloor(GetDouble()); - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || k < 0.0 || k > n) - PushIllegalArgument(); - else - PushDouble(pow(n,k)); - } -} - -void ScInterpreter::ScB() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) - return ; - if (nParamCount == 3) - { - double x = ::rtl::math::approxFloor(GetDouble()); - double p = GetDouble(); - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else - { - double q = 1.0 - p; - double fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); - } - } - else - { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); - } - } - } - else if (nParamCount == 4) - { - double xe = GetDouble(); - double xs = GetDouble(); - double p = GetDouble(); - double n = GetDouble(); -// alter Stand 300-SC -// if ((xs < n) && (xe < n) && (p < 1.0)) -// { -// double Varianz = sqrt(n * p * (1.0 - p)); -// xs = fabs(xs - (n * p /* / 2.0 STE */ )); -// xe = fabs(xe - (n * p /* / 2.0 STE */ )); -//// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz); -// double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz)); -// PushDouble(nVal); -// } - bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n); - if ( bIsValidX && 0.0 < p && p < 1.0 ) - { - double q = 1.0 - p; - double fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - double fSum = 0.0; - sal_uLong max; - if (xe < (sal_uLong) n) - max = (sal_uLong) (n-xe)-1; - else - max = 0; - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - if (xs < (sal_uLong) n) - max = (sal_uLong) (n-xs); - else - fSum = fFactor; - for (; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*q/p; - fSum += fFactor; - } - PushDouble(fSum); - } - } - else - { - sal_uLong max; - double fSum; - if ( (sal_uLong) xs == 0) - { - fSum = fFactor; - max = 0; - } - else - { - max = (sal_uLong) xs-1; - fSum = 0.0; - } - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - if ((sal_uLong)xe == 0) // beide 0 - fSum = fFactor; - else - max = (sal_uLong) xe; - for (; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; - } - PushDouble(fSum); - } - } - else - { - if ( bIsValidX ) // not(0<p<1) - { - if ( p == 0.0 ) - PushDouble( (xs == 0.0) ? 1.0 : 0.0 ); - else if ( p == 1.0 ) - PushDouble( (xe == n) ? 1.0 : 0.0 ); - else - PushIllegalArgument(); - } - else - PushIllegalArgument(); - } - } -} - -void ScInterpreter::ScBinomDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" ); - if ( MustHaveParamCount( GetByte(), 4 ) ) - { - double kum = GetDouble(); // 0 oder 1 - double p = GetDouble(); // p - double n = ::rtl::math::approxFloor(GetDouble()); // n - double x = ::rtl::math::approxFloor(GetDouble()); // x - double fFactor, q; - if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else if (kum == 0.0) // Dichte - { - q = 1.0 - p; - fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); - } - } - else - { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); - } - } - else // Verteilung - { - if (n == x) - PushDouble(1.0); - else - { - double fSum; - q = 1.0 - p; - fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - fSum = 1.0 - fFactor; - sal_uLong max = (sal_uLong) (n - x) - 1; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*q/p; - fSum -= fFactor; - } - if (fSum < 0.0) - PushDouble(0.0); - else - PushDouble(fSum); - } - } - else - { - fSum = fFactor; - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; - } - PushDouble(fSum); - } - } - } - } -} - -void ScInterpreter::ScCritBinom() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCritBinom" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double alpha = GetDouble(); // alpha - double p = GetDouble(); // p - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || alpha <= 0.0 || alpha >= 1.0 || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else - { - double q = 1.0 - p; - double fFactor = pow(q,n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - double fSum = 1.0 - fFactor; sal_uLong max = (sal_uLong) n; - sal_uLong i; - - for ( i = 0; i < max && fSum >= alpha; i++) - { - fFactor *= (n-i)/(i+1)*q/p; - fSum -= fFactor; - } - PushDouble(n-i); - } - } - else - { - double fSum = fFactor; sal_uLong max = (sal_uLong) n; - sal_uLong i; - - for ( i = 0; i < max && fSum < alpha; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; - } - PushDouble(i); - } - } - } -} - -void ScInterpreter::ScNegBinomDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNegBinomDist" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double p = GetDouble(); // p - double r = GetDouble(); // r - double x = GetDouble(); // x - if (r < 0.0 || x < 0.0 || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else - { - double q = 1.0 - p; - double fFactor = pow(p,r); - for (double i = 0.0; i < x; i++) - fFactor *= (i+r)/(i+1.0)*q; - PushDouble(fFactor); - } - } -} - -void ScInterpreter::ScNormDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNormDist" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4)) - return; - bool bCumulative = nParamCount == 4 ? GetBool() : true; - double sigma = GetDouble(); // standard deviation - double mue = GetDouble(); // mean - double x = GetDouble(); // x - if (sigma <= 0.0) - { - PushIllegalArgument(); - return; - } - if (bCumulative) - PushDouble(integralPhi((x-mue)/sigma)); - else - PushDouble(phi((x-mue)/sigma)/sigma); -} - -void ScInterpreter::ScLogNormDist() //expanded, see #i100119# -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogNormDist" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 1, 4)) - return; - bool bCumulative = nParamCount == 4 ? GetBool() : true; // cumulative - double sigma = nParamCount >= 3 ? GetDouble() : 1.0; // standard deviation - double mue = nParamCount >= 2 ? GetDouble() : 0.0; // mean - double x = GetDouble(); // x - if (sigma <= 0.0) - { - PushIllegalArgument(); - return; - } - if (bCumulative) - { // cumulative - if (x <= 0.0) - PushDouble(0.0); - else - PushDouble(integralPhi((log(x)-mue)/sigma)); - } - else - { // density - if (x <= 0.0) - PushIllegalArgument(); - else - PushDouble(phi((log(x)-mue)/sigma)/sigma/x); - } -} - -void ScInterpreter::ScStdNormDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStdNormDist" ); - PushDouble(integralPhi(GetDouble())); -} - -void ScInterpreter::ScExpDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExpDist" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double kum = GetDouble(); // 0 oder 1 - double lambda = GetDouble(); // lambda - double x = GetDouble(); // x - if (lambda <= 0.0) - PushIllegalArgument(); - else if (kum == 0.0) // Dichte - { - if (x >= 0.0) - PushDouble(lambda * exp(-lambda*x)); - else - PushInt(0); - } - else // Verteilung - { - if (x > 0.0) - PushDouble(1.0 - exp(-lambda*x)); - else - PushInt(0); - } - } -} - -void ScInterpreter::ScTDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTDist" ); - if ( !MustHaveParamCount( GetByte(), 3 ) ) - return; - double fFlag = ::rtl::math::approxFloor(GetDouble()); - double fDF = ::rtl::math::approxFloor(GetDouble()); - double T = GetDouble(); - if (fDF < 1.0 || T < 0.0 || (fFlag != 1.0 && fFlag != 2.0) ) - { - PushIllegalArgument(); - return; - } - double R = GetTDist(T, fDF); - if (fFlag == 1.0) - PushDouble(R); - else - PushDouble(2.0*R); -} - -void ScInterpreter::ScFDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFDist" ); - if ( !MustHaveParamCount( GetByte(), 3 ) ) - return; - double fF2 = ::rtl::math::approxFloor(GetDouble()); - double fF1 = ::rtl::math::approxFloor(GetDouble()); - double fF = GetDouble(); - if (fF < 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10) - { - PushIllegalArgument(); - return; - } - PushDouble(GetFDist(fF, fF1, fF2)); -} - -void ScInterpreter::ScChiDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiDist" ); - double fResult; - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double fDF = ::rtl::math::approxFloor(GetDouble()); - double fChi = GetDouble(); - if (fDF < 1.0) // x<=0 returns 1, see ODFF 6.17.10 - { - PushIllegalArgument(); - return; - } - fResult = GetChiDist( fChi, fDF); - if (nGlobalError) - { - PushError( nGlobalError); - return; - } - PushDouble(fResult); -} - -void ScInterpreter::ScWeibull() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScWeibull" ); - if ( MustHaveParamCount( GetByte(), 4 ) ) - { - double kum = GetDouble(); // 0 oder 1 - double beta = GetDouble(); // beta - double alpha = GetDouble(); // alpha - double x = GetDouble(); // x - if (alpha <= 0.0 || beta <= 0.0 || x < 0.0) - PushIllegalArgument(); - else if (kum == 0.0) // Dichte - PushDouble(alpha/pow(beta,alpha)*pow(x,alpha-1.0)* - exp(-pow(x/beta,alpha))); - else // Verteilung - PushDouble(1.0 - exp(-pow(x/beta,alpha))); - } -} - -void ScInterpreter::ScPoissonDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPoissonDist" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 3 ) ) - { - bool bCumulative = (nParamCount == 3 ? GetBool() : true); // default cumulative - double lambda = GetDouble(); // Mean - double x = ::rtl::math::approxFloor(GetDouble()); // discrete distribution - if (lambda < 0.0 || x < 0.0) - PushIllegalArgument(); - else if (!bCumulative) // Probability mass function - { - if (lambda == 0.0) - PushInt(0); - else - { - if (lambda >712) // underflow in exp(-lambda) - { // accuracy 11 Digits - PushDouble( exp(x*log(lambda)-lambda-GetLogGamma(x+1.0))); - } - else - { - double fPoissonVar = 1.0; - for ( double f = 0.0; f < x; ++f ) - fPoissonVar *= lambda / ( f + 1.0 ); - PushDouble( fPoissonVar * exp( -lambda ) ); - } - } - } - else // Cumulative distribution function - { - if (lambda == 0.0) - PushInt(1); - else - { - if (lambda > 712 ) // underflow in exp(-lambda) - { // accuracy 12 Digits - PushDouble(GetUpRegIGamma(x+1.0,lambda)); - } - else - { - if (x >= 936.0) // result is always undistinghable from 1 - PushDouble (1.0); - else - { - double fSummand = exp(-lambda); - double fSum = fSummand; - int nEnd = sal::static_int_cast<int>( x ); - for (int i = 1; i <= nEnd; i++) - { - fSummand = (fSummand * lambda)/(double)i; - fSum += fSummand; - } - PushDouble(fSum); - } - } - } - } - } -} - -/** Local function used in the calculation of the hypergeometric distribution. - */ -void lcl_PutFactorialElements( ::std::vector< double >& cn, double fLower, double fUpper, double fBase ) -{ - for ( double i = fLower; i <= fUpper; ++i ) - { - double fVal = fBase - i; - if ( fVal > 1.0 ) - cn.push_back( fVal ); - } -} - -/** Calculates a value of the hypergeometric distribution. - - The algorithm is designed to avoid unnecessary multiplications and division - by expanding all factorial elements (9 of them). It is done by excluding - those ranges that overlap in the numerator and the denominator. This allows - for a fast calculation for large values which would otherwise cause an overflow - in the intermediate values. - - @author Kohei Yoshida <kohei@openoffice.org> - - @see #i47296# - - */ -void ScInterpreter::ScHypGeomDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHypGeomDist" ); - const size_t nMaxArraySize = 500000; // arbitrary max array size - - if ( !MustHaveParamCount( GetByte(), 4 ) ) - return; - - double N = ::rtl::math::approxFloor(GetDouble()); - double M = ::rtl::math::approxFloor(GetDouble()); - double n = ::rtl::math::approxFloor(GetDouble()); - double x = ::rtl::math::approxFloor(GetDouble()); - - if( (x < 0.0) || (n < x) || (M < x) || (N < n) || (N < M) || (x < n - N + M) ) - { - PushIllegalArgument(); - return; - } - - typedef ::std::vector< double > HypContainer; - HypContainer cnNumer, cnDenom; - - size_t nEstContainerSize = static_cast<size_t>( x + ::std::min( n, M ) ); - size_t nMaxSize = ::std::min( cnNumer.max_size(), nMaxArraySize ); - if ( nEstContainerSize > nMaxSize ) - { - PushNoValue(); - return; - } - cnNumer.reserve( nEstContainerSize + 10 ); - cnDenom.reserve( nEstContainerSize + 10 ); - - // Trim coefficient C first - double fCNumVarUpper = N - n - M + x - 1.0; - double fCDenomVarLower = 1.0; - if ( N - n - M + x >= M - x + 1.0 ) - { - fCNumVarUpper = M - x - 1.0; - fCDenomVarLower = N - n - 2.0*(M - x) + 1.0; - } - -#if OSL_DEBUG_LEVEL > 0 - double fCNumLower = N - n - fCNumVarUpper; -#endif - double fCDenomUpper = N - n - M + x + 1.0 - fCDenomVarLower; - - double fDNumVarLower = n - M; - - if ( n >= M + 1.0 ) - { - if ( N - M < n + 1.0 ) - { - // Case 1 - - if ( N - n < n + 1.0 ) - { - // no overlap - lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, N - n - 1.0, N ); - } - else - { - // overlap - OSL_ENSURE( fCNumLower < n + 1.0, "ScHypGeomDist: wrong assertion" ); - lcl_PutFactorialElements( cnNumer, N - 2.0*n, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N ); - } - - OSL_ENSURE( fCDenomUpper <= N - M, "ScHypGeomDist: wrong assertion" ); - - if ( fCDenomUpper < n - x + 1.0 ) - // no overlap - lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 ); - else - { - // overlap - lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 ); - - fCDenomUpper = n - x; - fCDenomVarLower = N - M - 2.0*(n - x) + 1.0; - } - } - else - { - // Case 2 - - if ( n > M - 1.0 ) - { - // no overlap - lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N ); - } - else - { - lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N ); - } - - OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" ); - - if ( fCDenomUpper < n - x + 1.0 ) - // no overlap - lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - n + x, N - M + 1.0 ); - else - { - lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - fCDenomUpper, N - M + 1.0 ); - fCDenomUpper = n - x; - fCDenomVarLower = N - M - 2.0*(n - x) + 1.0; - } - } - - OSL_ENSURE( fCDenomUpper <= M, "ScHypGeomDist: wrong assertion" ); - } - else - { - if ( N - M < M + 1.0 ) - { - // Case 3 - - if ( N - n < M + 1.0 ) - { - // No overlap - lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, N - M - 1.0, N ); - } - else - { - lcl_PutFactorialElements( cnNumer, N - n - M, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N ); - } - - if ( n - x + 1.0 > fCDenomUpper ) - // No overlap - lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 ); - else - { - // Overlap - lcl_PutFactorialElements( cnNumer, 1.0, N - M - fCDenomUpper, N - M + 1.0 ); - - fCDenomVarLower = N - M - 2.0*(n - x) + 1.0; - fCDenomUpper = n - x; - } - } - else - { - // Case 4 - - OSL_ENSURE( M >= n - x, "ScHypGeomDist: wrong assertion" ); - OSL_ENSURE( M - x <= N - M + 1.0, "ScHypGeomDist: wrong assertion" ); - - if ( N - n < N - M + 1.0 ) - { - // No overlap - lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N ); - } - else - { - // Overlap - OSL_ENSURE( fCNumLower <= N - M + 1.0, "ScHypGeomDist: wrong assertion" ); - lcl_PutFactorialElements( cnNumer, M - n, fCNumVarUpper, N - n ); - lcl_PutFactorialElements( cnDenom, 0.0, n - 1.0, N ); - } - - if ( n - x + 1.0 > fCDenomUpper ) - // No overlap - lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - n + x, N - M + 1.0 ); - else if ( M >= fCDenomUpper ) - { - lcl_PutFactorialElements( cnNumer, N - 2.0*M + 1.0, N - M - fCDenomUpper, N - M + 1.0 ); - - fCDenomUpper = n - x; - fCDenomVarLower = N - M - 2.0*(n - x) + 1.0; - } - else - { - OSL_ENSURE( M <= fCDenomUpper, "ScHypGeomDist: wrong assertion" ); - lcl_PutFactorialElements( cnDenom, fCDenomVarLower, N - n - 2.0*M + x, - N - n - M + x + 1.0 ); - - fCDenomUpper = n - x; - fCDenomVarLower = N - M - 2.0*(n - x) + 1.0; - } - } - - OSL_ENSURE( fCDenomUpper <= n, "ScHypGeomDist: wrong assertion" ); - - fDNumVarLower = 0.0; - } - - double nDNumVarUpper = fCDenomUpper < x + 1.0 ? n - x - 1.0 : n - fCDenomUpper - 1.0; - double nDDenomVarLower = fCDenomUpper < x + 1.0 ? fCDenomVarLower : N - n - M + 1.0; - lcl_PutFactorialElements( cnNumer, fDNumVarLower, nDNumVarUpper, n ); - lcl_PutFactorialElements( cnDenom, nDDenomVarLower, N - n - M + x, N - n - M + x + 1.0 ); - - ::std::sort( cnNumer.begin(), cnNumer.end() ); - ::std::sort( cnDenom.begin(), cnDenom.end() ); - HypContainer::reverse_iterator it1 = cnNumer.rbegin(), it1End = cnNumer.rend(); - HypContainer::reverse_iterator it2 = cnDenom.rbegin(), it2End = cnDenom.rend(); - - double fFactor = 1.0; - for ( ; it1 != it1End || it2 != it2End; ) - { - double fEnum = 1.0, fDenom = 1.0; - if ( it1 != it1End ) - fEnum = *it1++; - if ( it2 != it2End ) - fDenom = *it2++; - fFactor *= fEnum / fDenom; - } - - PushDouble(fFactor); -} - -void ScInterpreter::ScGammaDist() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGammaDist" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) - return; - double bCumulative; - if (nParamCount == 4) - bCumulative = GetBool(); - else - bCumulative = true; - double fBeta = GetDouble(); // scale - double fAlpha = GetDouble(); // shape - double fX = GetDouble(); // x - if (fAlpha <= 0.0 || fBeta <= 0.0) - PushIllegalArgument(); - else - { - if (bCumulative) // distribution - PushDouble( GetGammaDist( fX, fAlpha, fBeta)); - else // density - PushDouble( GetGammaDistPDF( fX, fAlpha, fBeta)); - } -} - -void ScInterpreter::ScNormInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNormInv" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double sigma = GetDouble(); - double mue = GetDouble(); - double x = GetDouble(); - if (sigma <= 0.0 || x < 0.0 || x > 1.0) - PushIllegalArgument(); - else if (x == 0.0 || x == 1.0) - PushNoValue(); - else - PushDouble(gaussinv(x)*sigma + mue); - } -} - -void ScInterpreter::ScSNormInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSNormInv" ); - double x = GetDouble(); - if (x < 0.0 || x > 1.0) - PushIllegalArgument(); - else if (x == 0.0 || x == 1.0) - PushNoValue(); - else - PushDouble(gaussinv(x)); -} - -void ScInterpreter::ScLogNormInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLogNormInv" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double sigma = GetDouble(); // Stdabw - double mue = GetDouble(); // Mittelwert - double y = GetDouble(); // y - if (sigma <= 0.0 || y <= 0.0 || y >= 1.0) - PushIllegalArgument(); - else - PushDouble(exp(mue+sigma*gaussinv(y))); - } -} - -class ScGammaDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fAlpha, fBeta; - -public: - ScGammaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) : - rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {} - - double GetValue( double x ) const { return fp - rInt.GetGammaDist(x, fAlpha, fBeta); } -}; - -void ScInterpreter::ScGammaInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGammaInv" ); - if ( !MustHaveParamCount( GetByte(), 3 ) ) - return; - double fBeta = GetDouble(); - double fAlpha = GetDouble(); - double fP = GetDouble(); - if (fAlpha <= 0.0 || fBeta <= 0.0 || fP < 0.0 || fP >= 1.0 ) - { - PushIllegalArgument(); - return; - } - if (fP == 0.0) - PushInt(0); - else - { - bool bConvError; - ScGammaDistFunction aFunc( *this, fP, fAlpha, fBeta ); - double fStart = fAlpha * fBeta; - double fVal = lcl_IterateInverse( aFunc, fStart*0.5, fStart, bConvError ); - if (bConvError) - SetError(errNoConvergence); - PushDouble(fVal); - } -} - -class ScBetaDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fAlpha, fBeta; - -public: - ScBetaDistFunction( ScInterpreter& rI, double fpVal, double fAlphaVal, double fBetaVal ) : - rInt(rI), fp(fpVal), fAlpha(fAlphaVal), fBeta(fBetaVal) {} - - double GetValue( double x ) const { return fp - rInt.GetBetaDist(x, fAlpha, fBeta); } -}; - -void ScInterpreter::ScBetaInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBetaInv" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 5 ) ) - return; - double fP, fA, fB, fAlpha, fBeta; - if (nParamCount == 5) - fB = GetDouble(); - else - fB = 1.0; - if (nParamCount >= 4) - fA = GetDouble(); - else - fA = 0.0; - fBeta = GetDouble(); - fAlpha = GetDouble(); - fP = GetDouble(); - if (fP < 0.0 || fP >= 1.0 || fA == fB || fAlpha <= 0.0 || fBeta <= 0.0) - { - PushIllegalArgument(); - return; - } - if (fP == 0.0) - PushInt(0); - else - { - bool bConvError; - ScBetaDistFunction aFunc( *this, fP, fAlpha, fBeta ); - // 0..1 as range for iteration so it isn't extended beyond the valid range - double fVal = lcl_IterateInverse( aFunc, 0.0, 1.0, bConvError ); - if (bConvError) - PushError( errNoConvergence); - else - PushDouble(fA + fVal*(fB-fA)); // scale to (A,B) - } -} - - // Achtung: T, F und Chi - // sind monoton fallend, - // deshalb 1-Dist als Funktion - -class ScTDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fDF; - -public: - ScTDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) : - rInt(rI), fp(fpVal), fDF(fDFVal) {} - - double GetValue( double x ) const { return fp - 2 * rInt.GetTDist(x, fDF); } -}; - -void ScInterpreter::ScTInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTInv" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double fDF = ::rtl::math::approxFloor(GetDouble()); - double fP = GetDouble(); - if (fDF < 1.0 || fDF > 1.0E10 || fP <= 0.0 || fP > 1.0 ) - { - PushIllegalArgument(); - return; - } - - bool bConvError; - ScTDistFunction aFunc( *this, fP, fDF ); - double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError ); - if (bConvError) - SetError(errNoConvergence); - PushDouble(fVal); -} - -class ScFDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fF1, fF2; - -public: - ScFDistFunction( ScInterpreter& rI, double fpVal, double fF1Val, double fF2Val ) : - rInt(rI), fp(fpVal), fF1(fF1Val), fF2(fF2Val) {} - - double GetValue( double x ) const { return fp - rInt.GetFDist(x, fF1, fF2); } -}; - -void ScInterpreter::ScFInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFInv" ); - if ( !MustHaveParamCount( GetByte(), 3 ) ) - return; - double fF2 = ::rtl::math::approxFloor(GetDouble()); - double fF1 = ::rtl::math::approxFloor(GetDouble()); - double fP = GetDouble(); - if (fP <= 0.0 || fF1 < 1.0 || fF2 < 1.0 || fF1 >= 1.0E10 || fF2 >= 1.0E10 || fP > 1.0) - { - PushIllegalArgument(); - return; - } - - bool bConvError; - ScFDistFunction aFunc( *this, fP, fF1, fF2 ); - double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError ); - if (bConvError) - SetError(errNoConvergence); - PushDouble(fVal); -} - -class ScChiDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fDF; - -public: - ScChiDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) : - rInt(rI), fp(fpVal), fDF(fDFVal) {} - - double GetValue( double x ) const { return fp - rInt.GetChiDist(x, fDF); } -}; - -void ScInterpreter::ScChiInv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiInv" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double fDF = ::rtl::math::approxFloor(GetDouble()); - double fP = GetDouble(); - if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 ) - { - PushIllegalArgument(); - return; - } - - bool bConvError; - ScChiDistFunction aFunc( *this, fP, fDF ); - double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError ); - if (bConvError) - SetError(errNoConvergence); - PushDouble(fVal); -} - -/***********************************************/ -class ScChiSqDistFunction : public ScDistFunc -{ - ScInterpreter& rInt; - double fp, fDF; - -public: - ScChiSqDistFunction( ScInterpreter& rI, double fpVal, double fDFVal ) : - rInt(rI), fp(fpVal), fDF(fDFVal) {} - - double GetValue( double x ) const { return fp - rInt.GetChiSqDistCDF(x, fDF); } -}; - -void ScInterpreter::ScChiSqInv() -{ - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double fDF = ::rtl::math::approxFloor(GetDouble()); - double fP = GetDouble(); - if (fDF < 1.0 || fP < 0.0 || fP >= 1.0 ) - { - PushIllegalArgument(); - return; - } - - bool bConvError; - ScChiSqDistFunction aFunc( *this, fP, fDF ); - double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError ); - if (bConvError) - SetError(errNoConvergence); - PushDouble(fVal); -} - -void ScInterpreter::ScConfidence() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConfidence" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double n = ::rtl::math::approxFloor(GetDouble()); - double sigma = GetDouble(); - double alpha = GetDouble(); - if (sigma <= 0.0 || alpha <= 0.0 || alpha >= 1.0 || n < 1.0) - PushIllegalArgument(); - else - PushDouble( gaussinv(1.0-alpha/2.0) * sigma/sqrt(n) ); - } -} - -void ScInterpreter::ScZTest() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZTest" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 2, 3 ) ) - return; - double sigma = 0.0, mue, x; - if (nParamCount == 3) - { - sigma = GetDouble(); - if (sigma <= 0.0) - { - PushIllegalArgument(); - return; - } - } - x = GetDouble(); - - double fSum = 0.0; - double fSumSqr = 0.0; - double fVal; - double rValCount = 0.0; - switch (GetStackType()) - { - case formula::svDouble : - { - fVal = GetDouble(); - fSum += fVal; - fSumSqr += fVal*fVal; - rValCount++; - } - break; - case svSingleRef : - { - ScAddress aAdr; - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - fVal = GetCellValue( aAdr, pCell ); - fSum += fVal; - fSumSqr += fVal*fVal; - rValCount++; - } - } - break; - case svRefList : - case formula::svDoubleRef : - { - short nParam = 1; - size_t nRefInList = 0; - while (nParam-- > 0) - { - ScRange aRange; - sal_uInt16 nErr = 0; - PopDoubleRef( aRange, nParam, nRefInList); - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(fVal, nErr)) - { - fSum += fVal; - fSumSqr += fVal*fVal; - rValCount++; - while ((nErr == 0) && aValIter.GetNext(fVal, nErr)) - { - fSum += fVal; - fSumSqr += fVal*fVal; - rValCount++; - } - SetError(nErr); - } - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for ( SCSIZE i = 0; i < nCount; i++ ) - { - fVal= pMat->GetDouble(i); - fSum += fVal; - fSumSqr += fVal * fVal; - rValCount++; - } - } - else - { - for (SCSIZE i = 0; i < nCount; i++) - if (!pMat->IsString(i)) - { - fVal= pMat->GetDouble(i); - fSum += fVal; - fSumSqr += fVal * fVal; - rValCount++; - } - } - } - } - break; - default : SetError(errIllegalParameter); break; - } - if (rValCount <= 1.0) - PushError( errDivisionByZero); - else - { - mue = fSum/rValCount; - if (nParamCount != 3) - { - sigma = (fSumSqr - fSum*fSum/rValCount)/(rValCount-1.0); - PushDouble(0.5 - gauss((mue-x)/sqrt(sigma/rValCount))); - } - else - PushDouble(0.5 - gauss((mue-x)*sqrt(rValCount)/sigma)); - } -} -bool ScInterpreter::CalculateTest(sal_Bool _bTemplin - ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2 - ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2 - ,double& fT,double& fF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateTest" ); - double fCount1 = 0.0; - double fCount2 = 0.0; - double fSum1 = 0.0; - double fSumSqr1 = 0.0; - double fSum2 = 0.0; - double fSumSqr2 = 0.0; - double fVal; - SCSIZE i,j; - for (i = 0; i < nC1; i++) - for (j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j)) - { - fVal = pMat1->GetDouble(i,j); - fSum1 += fVal; - fSumSqr1 += fVal * fVal; - fCount1++; - } - } - for (i = 0; i < nC2; i++) - for (j = 0; j < nR2; j++) - { - if (!pMat2->IsString(i,j)) - { - fVal = pMat2->GetDouble(i,j); - fSum2 += fVal; - fSumSqr2 += fVal * fVal; - fCount2++; - } - } - if (fCount1 < 2.0 || fCount2 < 2.0) - { - PushNoValue(); - return false; - } // if (fCount1 < 2.0 || fCount2 < 2.0) - if ( _bTemplin ) - { - double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0)/fCount1; - double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0)/fCount2; - if (fS1 + fS2 == 0.0) - { - PushNoValue(); - return false; - } - fT = fabs(fSum1/fCount1 - fSum2/fCount2)/sqrt(fS1+fS2); - double c = fS1/(fS1+fS2); - // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen - // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#): - fF = 1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0)); - } - else - { - // laut Bronstein-Semendjajew - double fS1 = (fSumSqr1 - fSum1*fSum1/fCount1) / (fCount1 - 1.0); // Varianz - double fS2 = (fSumSqr2 - fSum2*fSum2/fCount2) / (fCount2 - 1.0); - fT = fabs( fSum1/fCount1 - fSum2/fCount2 ) / - sqrt( (fCount1-1.0)*fS1 + (fCount2-1.0)*fS2 ) * - sqrt( fCount1*fCount2*(fCount1+fCount2-2)/(fCount1+fCount2) ); - fF = fCount1 + fCount2 - 2; - } - return true; -} -void ScInterpreter::ScTTest() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTTest" ); - if ( !MustHaveParamCount( GetByte(), 4 ) ) - return; - double fTyp = ::rtl::math::approxFloor(GetDouble()); - double fAnz = ::rtl::math::approxFloor(GetDouble()); - if (fAnz != 1.0 && fAnz != 2.0) - { - PushIllegalArgument(); - return; - } - - ScMatrixRef pMat2 = GetMatrix(); - ScMatrixRef pMat1 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - double fT, fF; - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - SCSIZE i, j; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - if (fTyp == 1.0) - { - if (nC1 != nC2 || nR1 != nR2) - { - PushIllegalArgument(); - return; - } - double fCount = 0.0; - double fSum1 = 0.0; - double fSum2 = 0.0; - double fSumSqrD = 0.0; - double fVal1, fVal2; - for (i = 0; i < nC1; i++) - for (j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - fVal1 = pMat1->GetDouble(i,j); - fVal2 = pMat2->GetDouble(i,j); - fSum1 += fVal1; - fSum2 += fVal2; - fSumSqrD += (fVal1 - fVal2)*(fVal1 - fVal2); - fCount++; - } - } - if (fCount < 1.0) - { - PushNoValue(); - return; - } - fT = sqrt(fCount-1.0) * fabs(fSum1 - fSum2) / - sqrt(fCount * fSumSqrD - (fSum1-fSum2)*(fSum1-fSum2)); - fF = fCount - 1.0; - } - else if (fTyp == 2.0) - { - CalculateTest(false,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF); - } - else if (fTyp == 3.0) - { - CalculateTest(sal_True,nC1, nC2,nR1, nR2,pMat1,pMat2,fT,fF); - } - - else - { - PushIllegalArgument(); - return; - } - if (fAnz == 1.0) - PushDouble(GetTDist(fT, fF)); - else - PushDouble(2.0*GetTDist(fT, fF)); -} - -void ScInterpreter::ScFTest() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFTest" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - ScMatrixRef pMat2 = GetMatrix(); - ScMatrixRef pMat1 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - SCSIZE i, j; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - double fCount1 = 0.0; - double fCount2 = 0.0; - double fSum1 = 0.0; - double fSumSqr1 = 0.0; - double fSum2 = 0.0; - double fSumSqr2 = 0.0; - double fVal; - for (i = 0; i < nC1; i++) - for (j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j)) - { - fVal = pMat1->GetDouble(i,j); - fSum1 += fVal; - fSumSqr1 += fVal * fVal; - fCount1++; - } - } - for (i = 0; i < nC2; i++) - for (j = 0; j < nR2; j++) - { - if (!pMat2->IsString(i,j)) - { - fVal = pMat2->GetDouble(i,j); - fSum2 += fVal; - fSumSqr2 += fVal * fVal; - fCount2++; - } - } - if (fCount1 < 2.0 || fCount2 < 2.0) - { - PushNoValue(); - return; - } - double fS1 = (fSumSqr1-fSum1*fSum1/fCount1)/(fCount1-1.0); - double fS2 = (fSumSqr2-fSum2*fSum2/fCount2)/(fCount2-1.0); - if (fS1 == 0.0 || fS2 == 0.0) - { - PushNoValue(); - return; - } - double fF, fF1, fF2; - if (fS1 > fS2) - { - fF = fS1/fS2; - fF1 = fCount1-1.0; - fF2 = fCount2-1.0; - } - else - { - fF = fS2/fS1; - fF1 = fCount2-1.0; - fF2 = fCount1-1.0; - } - PushDouble(2.0*GetFDist(fF, fF1, fF2)); -} - -void ScInterpreter::ScChiTest() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChiTest" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - ScMatrixRef pMat2 = GetMatrix(); - ScMatrixRef pMat1 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - if (nR1 != nR2 || nC1 != nC2) - { - PushIllegalArgument(); - return; - } - double fChi = 0.0; - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValE = pMat2->GetDouble(i,j); - fChi += (fValX - fValE) * (fValX - fValE) / fValE; - } - else - { - PushIllegalArgument(); - return; - } - } - } - double fDF; - if (nC1 == 1 || nR1 == 1) - { - fDF = (double)(nC1*nR1 - 1); - if (fDF == 0.0) - { - PushNoValue(); - return; - } - } - else - fDF = (double)(nC1-1)*(double)(nR1-1); - PushDouble(GetChiDist(fChi, fDF)); -} - -void ScInterpreter::ScKurt() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKurt" ); - double fSum,fCount,vSum; - std::vector<double> values; - if ( !CalculateSkew(fSum,fCount,vSum,values) ) - return; - - if (fCount == 0.0) - { - PushError( errDivisionByZero); - return; - } - - double fMean = fSum / fCount; - - for (size_t i = 0; i < values.size(); i++) - vSum += (values[i] - fMean) * (values[i] - fMean); - - double fStdDev = sqrt(vSum / (fCount - 1.0)); - double dx = 0.0; - double xpower4 = 0.0; - - if (fStdDev == 0.0) - { - PushError( errDivisionByZero); - return; - } - - for (size_t i = 0; i < values.size(); i++) - { - dx = (values[i] - fMean) / fStdDev; - xpower4 = xpower4 + (dx * dx * dx * dx); - } - - double k_d = (fCount - 2.0) * (fCount - 3.0); - double k_l = fCount * (fCount + 1.0) / ((fCount - 1.0) * k_d); - double k_t = 3.0 * (fCount - 1.0) * (fCount - 1.0) / k_d; - - PushDouble(xpower4 * k_l - k_t); -} - -void ScInterpreter::ScHarMean() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHarMean" ); - short nParamCount = GetByte(); - double nVal = 0.0; - double nValCount = 0.0; - ScAddress aAdr; - ScRange aRange; - size_t nRefInList = 0; - while ((nGlobalError == 0) && (nParamCount-- > 0)) - { - switch (GetStackType()) - { - case formula::svDouble : - { - double x = GetDouble(); - if (x > 0.0) - { - nVal += 1.0/x; - nValCount++; - } - else - SetError( errIllegalArgument); - break; - } - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - double x = GetCellValue( aAdr, pCell ); - if (x > 0.0) - { - nVal += 1.0/x; - nValCount++; - } - else - SetError( errIllegalArgument); - } - break; - } - case formula::svDoubleRef : - case svRefList : - { - sal_uInt16 nErr = 0; - PopDoubleRef( aRange, nParamCount, nRefInList); - double nCellVal; - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(nCellVal, nErr)) - { - if (nCellVal > 0.0) - { - nVal += 1.0/nCellVal; - nValCount++; - } - else - SetError( errIllegalArgument); - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr)) - { - if (nCellVal > 0.0) - { - nVal += 1.0/nCellVal; - nValCount++; - } - else - SetError( errIllegalArgument); - } - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - { - double x = pMat->GetDouble(nElem); - if (x > 0.0) - { - nVal += 1.0/x; - nValCount++; - } - else - SetError( errIllegalArgument); - } - } - else - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - if (!pMat->IsString(nElem)) - { - double x = pMat->GetDouble(nElem); - if (x > 0.0) - { - nVal += 1.0/x; - nValCount++; - } - else - SetError( errIllegalArgument); - } - } - } - } - break; - default : SetError(errIllegalParameter); break; - } - } - if (nGlobalError == 0) - PushDouble((double)nValCount/nVal); - else - PushError( nGlobalError); -} - -void ScInterpreter::ScGeoMean() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGeoMean" ); - short nParamCount = GetByte(); - double nVal = 0.0; - double nValCount = 0.0; - ScAddress aAdr; - ScRange aRange; - - size_t nRefInList = 0; - while ((nGlobalError == 0) && (nParamCount-- > 0)) - { - switch (GetStackType()) - { - case formula::svDouble : - { - double x = GetDouble(); - if (x > 0.0) - { - nVal += log(x); - nValCount++; - } - else - SetError( errIllegalArgument); - break; - } - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - double x = GetCellValue( aAdr, pCell ); - if (x > 0.0) - { - nVal += log(x); - nValCount++; - } - else - SetError( errIllegalArgument); - } - break; - } - case formula::svDoubleRef : - case svRefList : - { - sal_uInt16 nErr = 0; - PopDoubleRef( aRange, nParamCount, nRefInList); - double nCellVal; - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(nCellVal, nErr)) - { - if (nCellVal > 0.0) - { - nVal += log(nCellVal); - nValCount++; - } - else - SetError( errIllegalArgument); - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr)) - { - if (nCellVal > 0.0) - { - nVal += log(nCellVal); - nValCount++; - } - else - SetError( errIllegalArgument); - } - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE ui = 0; ui < nCount; ui++) - { - double x = pMat->GetDouble(ui); - if (x > 0.0) - { - nVal += log(x); - nValCount++; - } - else - SetError( errIllegalArgument); - } - } - else - { - for (SCSIZE ui = 0; ui < nCount; ui++) - if (!pMat->IsString(ui)) - { - double x = pMat->GetDouble(ui); - if (x > 0.0) - { - nVal += log(x); - nValCount++; - } - else - SetError( errIllegalArgument); - } - } - } - } - break; - default : SetError(errIllegalParameter); break; - } - } - if (nGlobalError == 0) - PushDouble(exp(nVal / nValCount)); - else - PushError( nGlobalError); -} - -void ScInterpreter::ScStandard() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStandard" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double sigma = GetDouble(); - double mue = GetDouble(); - double x = GetDouble(); - if (sigma < 0.0) - PushError( errIllegalArgument); - else if (sigma == 0.0) - PushError( errDivisionByZero); - else - PushDouble((x-mue)/sigma); - } -} -bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::vector<double>& values) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSkew" ); - short nParamCount = GetByte(); - if ( !MustHaveParamCountMin( nParamCount, 1 ) ) - return false; - - fSum = 0.0; - fCount = 0.0; - vSum = 0.0; - double fVal = 0.0; - ScAddress aAdr; - ScRange aRange; - size_t nRefInList = 0; - while (nParamCount-- > 0) - { - switch (GetStackType()) - { - case formula::svDouble : - { - fVal = GetDouble(); - fSum += fVal; - values.push_back(fVal); - fCount++; - } - break; - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - fVal = GetCellValue( aAdr, pCell ); - fSum += fVal; - values.push_back(fVal); - fCount++; - } - } - break; - case formula::svDoubleRef : - case svRefList : - { - PopDoubleRef( aRange, nParamCount, nRefInList); - sal_uInt16 nErr = 0; - ScValueIterator aValIter(pDok, aRange); - if (aValIter.GetFirst(fVal, nErr)) - { - fSum += fVal; - values.push_back(fVal); - fCount++; - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext(fVal, nErr)) - { - fSum += fVal; - values.push_back(fVal); - fCount++; - } - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - { - fVal = pMat->GetDouble(nElem); - fSum += fVal; - values.push_back(fVal); - fCount++; - } - } - else - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - if (!pMat->IsString(nElem)) - { - fVal = pMat->GetDouble(nElem); - fSum += fVal; - values.push_back(fVal); - fCount++; - } - } - } - } - break; - default : - SetError(errIllegalParameter); - break; - } - } - - if (nGlobalError) - { - PushError( nGlobalError); - return false; - } // if (nGlobalError) - return true; -} - -void ScInterpreter::ScSkew() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSkew" ); - double fSum,fCount,vSum; - std::vector<double> values; - if ( !CalculateSkew(fSum,fCount,vSum,values) ) - return; - - double fMean = fSum / fCount; - - for (size_t i = 0; i < values.size(); i++) - vSum += (values[i] - fMean) * (values[i] - fMean); - - double fStdDev = sqrt(vSum / (fCount - 1.0)); - double dx = 0.0; - double xcube = 0.0; - - if (fStdDev == 0) - { - PushIllegalArgument(); - return; - } - - for (size_t i = 0; i < values.size(); i++) - { - dx = (values[i] - fMean) / fStdDev; - xcube = xcube + (dx * dx * dx); - } - - PushDouble(((xcube * fCount) / (fCount - 1.0)) / (fCount - 2.0)); -} - -double ScInterpreter::GetMedian( vector<double> & rArray ) -{ - size_t nSize = rArray.size(); - if (rArray.empty() || nSize == 0 || nGlobalError) - { - SetError( errNoValue); - return 0.0; - } - - // Upper median. - size_t nMid = nSize / 2; - vector<double>::iterator iMid = rArray.begin() + nMid; - ::std::nth_element( rArray.begin(), iMid, rArray.end()); - if (nSize & 1) - return *iMid; // Lower and upper median are equal. - else - { - double fUp = *iMid; - // Lower median. - iMid = rArray.begin() + nMid - 1; - ::std::nth_element( rArray.begin(), iMid, rArray.end()); - return (fUp + *iMid) / 2; - } -} - -void ScInterpreter::ScMedian() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMedian" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCountMin( nParamCount, 1 ) ) - return; - vector<double> aArray; - GetNumberSequenceArray( nParamCount, aArray); - PushDouble( GetMedian( aArray)); -} - -double ScInterpreter::GetPercentile( vector<double> & rArray, double fPercentile ) -{ - size_t nSize = rArray.size(); - if (rArray.empty() || nSize == 0 || nGlobalError) - { - SetError( errNoValue); - return 0.0; - } - - if (nSize == 1) - return rArray[0]; - else - { - size_t nIndex = (size_t)::rtl::math::approxFloor( fPercentile * (nSize-1)); - double fDiff = fPercentile * (nSize-1) - ::rtl::math::approxFloor( fPercentile * (nSize-1)); - OSL_ENSURE(nIndex < nSize, "GetPercentile: wrong index(1)"); - vector<double>::iterator iter = rArray.begin() + nIndex; - ::std::nth_element( rArray.begin(), iter, rArray.end()); - if (fDiff == 0.0) - return *iter; - else - { - OSL_ENSURE(nIndex < nSize-1, "GetPercentile: wrong index(2)"); - double fVal = *iter; - iter = rArray.begin() + nIndex+1; - ::std::nth_element( rArray.begin(), iter, rArray.end()); - return fVal + fDiff * (*iter - fVal); - } - } -} - -void ScInterpreter::ScPercentile() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentile" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double alpha = GetDouble(); - if (alpha < 0.0 || alpha > 1.0) - { - PushIllegalArgument(); - return; - } - vector<double> aArray; - GetNumberSequenceArray( 1, aArray); - PushDouble( GetPercentile( aArray, alpha)); -} - -void ScInterpreter::ScQuartile() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScQuartile" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double fFlag = ::rtl::math::approxFloor(GetDouble()); - if (fFlag < 0.0 || fFlag > 4.0) - { - PushIllegalArgument(); - return; - } - vector<double> aArray; - GetNumberSequenceArray( 1, aArray); - PushDouble( fFlag == 2.0 ? GetMedian( aArray) : GetPercentile( aArray, 0.25 * fFlag)); -} - -void ScInterpreter::ScModalValue() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScModalValue" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCountMin( nParamCount, 1 ) ) - return; - vector<double> aSortArray; - GetSortArray(nParamCount, aSortArray); - SCSIZE nSize = aSortArray.size(); - if (aSortArray.empty() || nSize == 0 || nGlobalError) - PushNoValue(); - else - { - SCSIZE nMaxIndex = 0, nMax = 1, nCount = 1; - double nOldVal = aSortArray[0]; - SCSIZE i; - - for ( i = 1; i < nSize; i++) - { - if (aSortArray[i] == nOldVal) - nCount++; - else - { - nOldVal = aSortArray[i]; - if (nCount > nMax) - { - nMax = nCount; - nMaxIndex = i-1; - } - nCount = 1; - } - } - if (nCount > nMax) - { - nMax = nCount; - nMaxIndex = i-1; - } - if (nMax == 1 && nCount == 1) - PushNoValue(); - else if (nMax == 1) - PushDouble(nOldVal); - else - PushDouble(aSortArray[nMaxIndex]); - } -} - -void ScInterpreter::CalculateSmallLarge(sal_Bool bSmall) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSmallLarge" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double f = ::rtl::math::approxFloor(GetDouble()); - if (f < 1.0) - { - PushIllegalArgument(); - return; - } - SCSIZE k = static_cast<SCSIZE>(f); - vector<double> aSortArray; - /* TODO: using nth_element() is best for one single value, but LARGE/SMALL - * actually are defined to return an array of values if an array of - * positions was passed, in which case, depending on the number of values, - * we may or will need a real sorted array again, see #i32345. */ - GetNumberSequenceArray(1, aSortArray); - SCSIZE nSize = aSortArray.size(); - if (aSortArray.empty() || nSize == 0 || nGlobalError || nSize < k) - PushNoValue(); - else - { - // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] ); - vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k); - ::std::nth_element( aSortArray.begin(), iPos, aSortArray.end()); - PushDouble( *iPos); - } -} - -void ScInterpreter::ScLarge() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLarge" ); - CalculateSmallLarge(false); -} - -void ScInterpreter::ScSmall() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSmall" ); - CalculateSmallLarge(sal_True); -} - -void ScInterpreter::ScPercentrank() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentrank" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 2 ) ) - return; - - double fNum = GetDouble(); - vector<double> aSortArray; - GetSortArray(1, aSortArray); - SCSIZE nSize = aSortArray.size(); - if (aSortArray.empty() || nSize == 0 || nGlobalError) - PushNoValue(); - else - { - if (fNum < aSortArray[0] || fNum > aSortArray[nSize-1]) - PushNoValue(); - else if ( nSize == 1 ) - PushDouble(1.0); // fNum == pSortArray[0], see test above - else - { - double fRes; - SCSIZE nOldCount = 0; - double fOldVal = aSortArray[0]; - SCSIZE i; - for (i = 1; i < nSize && aSortArray[i] < fNum; i++) - { - if (aSortArray[i] != fOldVal) - { - nOldCount = i; - fOldVal = aSortArray[i]; - } - } - if (aSortArray[i] != fOldVal) - nOldCount = i; - if (fNum == aSortArray[i]) - fRes = (double)nOldCount/(double)(nSize-1); - else - { - // nOldCount is the count of smaller entries - // fNum is between pSortArray[nOldCount-1] and pSortArray[nOldCount] - // use linear interpolation to find a position between the entries - - if ( nOldCount == 0 ) - { - OSL_FAIL("should not happen"); - fRes = 0.0; - } - else - { - double fFract = ( fNum - aSortArray[nOldCount-1] ) / - ( aSortArray[nOldCount] - aSortArray[nOldCount-1] ); - fRes = ( (double)(nOldCount-1)+fFract )/(double)(nSize-1); - } - } - PushDouble(fRes); - } - } -} - -void ScInterpreter::ScTrimMean() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrimMean" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - double alpha = GetDouble(); - if (alpha < 0.0 || alpha >= 1.0) - { - PushIllegalArgument(); - return; - } - vector<double> aSortArray; - GetSortArray(1, aSortArray); - SCSIZE nSize = aSortArray.size(); - if (aSortArray.empty() || nSize == 0 || nGlobalError) - PushNoValue(); - else - { - sal_uLong nIndex = (sal_uLong) ::rtl::math::approxFloor(alpha*(double)nSize); - if (nIndex % 2 != 0) - nIndex--; - nIndex /= 2; - OSL_ENSURE(nIndex < nSize, "ScTrimMean: falscher Index"); - double fSum = 0.0; - for (SCSIZE i = nIndex; i < nSize-nIndex; i++) - fSum += aSortArray[i]; - PushDouble(fSum/(double)(nSize-2*nIndex)); - } -} - -void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetSortArray" ); - ScAddress aAdr; - ScRange aRange; - short nParam = nParamCount; - size_t nRefInList = 0; - while (nParam-- > 0) - { - switch (GetStackType()) - { - case formula::svDouble : - rArray.push_back( PopDouble()); - break; - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - rArray.push_back( GetCellValue( aAdr, pCell)); - } - break; - case formula::svDoubleRef : - case svRefList : - { - PopDoubleRef( aRange, nParam, nRefInList); - if (nGlobalError) - break; - - aRange.Justify(); - SCSIZE nCellCount = aRange.aEnd.Col() - aRange.aStart.Col() + 1; - nCellCount *= aRange.aEnd.Row() - aRange.aStart.Row() + 1; - rArray.reserve( rArray.size() + nCellCount); - - sal_uInt16 nErr = 0; - double fCellVal; - ScValueIterator aValIter(pDok, aRange); - if (aValIter.GetFirst( fCellVal, nErr)) - { - rArray.push_back( fCellVal); - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext( fCellVal, nErr)) - rArray.push_back( fCellVal); - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (!pMat) - break; - - SCSIZE nCount = pMat->GetElementCount(); - rArray.reserve( rArray.size() + nCount); - if (pMat->IsNumeric()) - { - for (SCSIZE i = 0; i < nCount; ++i) - rArray.push_back( pMat->GetDouble(i)); - } - else - { - for (SCSIZE i = 0; i < nCount; ++i) - if (!pMat->IsString(i)) - rArray.push_back( pMat->GetDouble(i)); - } - } - break; - default : - PopError(); - SetError( errIllegalParameter); - break; - } - if (nGlobalError) - break; // while - } - // nParam > 0 in case of error, clean stack environment and obtain earlier - // error if there was one. - while (nParam-- > 0) - PopError(); -} - -void ScInterpreter::GetSortArray( sal_uInt8 nParamCount, vector<double>& rSortArray, vector<long>* pIndexOrder ) -{ - GetNumberSequenceArray( nParamCount, rSortArray); - - if (rSortArray.size() > MAX_ANZ_DOUBLE_FOR_SORT) - SetError( errStackOverflow); - else if (rSortArray.empty()) - SetError( errNoValue); - - if (nGlobalError == 0) - QuickSort( rSortArray, pIndexOrder); -} - -static void lcl_QuickSort( long nLo, long nHi, vector<double>& rSortArray, vector<long>* pIndexOrder ) -{ - // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size(). - - using ::std::swap; - - if (nHi - nLo == 1) - { - if (rSortArray[nLo] > rSortArray[nHi]) - { - swap(rSortArray[nLo], rSortArray[nHi]); - if (pIndexOrder) - swap(pIndexOrder->at(nLo), pIndexOrder->at(nHi)); - } - return; - } - - long ni = nLo; - long nj = nHi; - do - { - double fLo = rSortArray[nLo]; - while (ni <= nHi && rSortArray[ni] < fLo) ni++; - while (nj >= nLo && fLo < rSortArray[nj]) nj--; - if (ni <= nj) - { - if (ni != nj) - { - swap(rSortArray[ni], rSortArray[nj]); - if (pIndexOrder) - swap(pIndexOrder->at(ni), pIndexOrder->at(nj)); - } - - ++ni; - --nj; - } - } - while (ni < nj); - - if ((nj - nLo) < (nHi - ni)) - { - if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder); - if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder); - } - else - { - if (ni < nHi) lcl_QuickSort(ni, nHi, rSortArray, pIndexOrder); - if (nLo < nj) lcl_QuickSort(nLo, nj, rSortArray, pIndexOrder); - } -} - -void ScInterpreter::QuickSort( vector<double>& rSortArray, vector<long>* pIndexOrder ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::QuickSort" ); - long n = static_cast<long>(rSortArray.size()); - - if (pIndexOrder) - { - pIndexOrder->clear(); - pIndexOrder->reserve(n); - for (long i = 0; i < n; ++i) - pIndexOrder->push_back(i); - } - - if (n < 2) - return; - - size_t nValCount = rSortArray.size(); - for (size_t i = 0; (i + 4) <= nValCount-1; i += 4) - { - size_t nInd = rand() % (int) (nValCount-1); - ::std::swap( rSortArray[i], rSortArray[nInd]); - if (pIndexOrder) - ::std::swap( pIndexOrder->at(i), pIndexOrder->at(nInd)); - } - - lcl_QuickSort(0, n-1, rSortArray, pIndexOrder); -} - -void ScInterpreter::ScRank() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRank" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 2, 3 ) ) - return; - sal_Bool bDescending; - if (nParamCount == 3) - bDescending = GetBool(); - else - bDescending = false; - double fCount = 1.0; - sal_Bool bValid = false; - switch (GetStackType()) - { - case formula::svDouble : - { - double x = GetDouble(); - double fVal = GetDouble(); - if (x == fVal) - bValid = sal_True; - break; - } - case svSingleRef : - { - ScAddress aAdr; - PopSingleRef( aAdr ); - double fVal = GetDouble(); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - double x = GetCellValue( aAdr, pCell ); - if (x == fVal) - bValid = sal_True; - } - break; - } - case formula::svDoubleRef : - case svRefList : - { - ScRange aRange; - short nParam = 1; - size_t nRefInList = 0; - while (nParam-- > 0) - { - sal_uInt16 nErr = 0; - // Preserve stack until all RefList elements are done! - sal_uInt16 nSaveSP = sp; - PopDoubleRef( aRange, nParam, nRefInList); - if (nParam) - --sp; // simulate pop - double fVal = GetDouble(); - if (nParam) - sp = nSaveSP; - double nCellVal; - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(nCellVal, nErr)) - { - if (nCellVal == fVal) - bValid = sal_True; - else if ((!bDescending && nCellVal > fVal) || - (bDescending && nCellVal < fVal) ) - fCount++; - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr)) - { - if (nCellVal == fVal) - bValid = sal_True; - else if ((!bDescending && nCellVal > fVal) || - (bDescending && nCellVal < fVal) ) - fCount++; - } - } - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - double fVal = GetDouble(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE i = 0; i < nCount; i++) - { - double x = pMat->GetDouble(i); - if (x == fVal) - bValid = sal_True; - else if ((!bDescending && x > fVal) || - (bDescending && x < fVal) ) - fCount++; - } - } - else - { - for (SCSIZE i = 0; i < nCount; i++) - if (!pMat->IsString(i)) - { - double x = pMat->GetDouble(i); - if (x == fVal) - bValid = sal_True; - else if ((!bDescending && x > fVal) || - (bDescending && x < fVal) ) - fCount++; - } - } - } - } - break; - default : SetError(errIllegalParameter); break; - } - if (bValid) - PushDouble(fCount); - else - PushNoValue(); -} - -void ScInterpreter::ScAveDev() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAveDev" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCountMin( nParamCount, 1 ) ) - return; - sal_uInt16 SaveSP = sp; - double nMiddle = 0.0; - double rVal = 0.0; - double rValCount = 0.0; - ScAddress aAdr; - ScRange aRange; - short nParam = nParamCount; - size_t nRefInList = 0; - while (nParam-- > 0) - { - switch (GetStackType()) - { - case formula::svDouble : - rVal += GetDouble(); - rValCount++; - break; - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - { - rVal += GetCellValue( aAdr, pCell ); - rValCount++; - } - } - break; - case formula::svDoubleRef : - case svRefList : - { - sal_uInt16 nErr = 0; - double nCellVal; - PopDoubleRef( aRange, nParam, nRefInList); - ScValueIterator aValIter(pDok, aRange); - if (aValIter.GetFirst(nCellVal, nErr)) - { - rVal += nCellVal; - rValCount++; - SetError(nErr); - while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr)) - { - rVal += nCellVal; - rValCount++; - } - SetError(nErr); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - { - rVal += pMat->GetDouble(nElem); - rValCount++; - } - } - else - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - if (!pMat->IsString(nElem)) - { - rVal += pMat->GetDouble(nElem); - rValCount++; - } - } - } - } - break; - default : - SetError(errIllegalParameter); - break; - } - } - if (nGlobalError) - { - PushError( nGlobalError); - return; - } - nMiddle = rVal / rValCount; - sp = SaveSP; - rVal = 0.0; - nParam = nParamCount; - nRefInList = 0; - while (nParam-- > 0) - { - switch (GetStackType()) - { - case formula::svDouble : - rVal += fabs(GetDouble() - nMiddle); - break; - case svSingleRef : - { - PopSingleRef( aAdr ); - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - rVal += fabs(GetCellValue( aAdr, pCell ) - nMiddle); - } - break; - case formula::svDoubleRef : - case svRefList : - { - sal_uInt16 nErr = 0; - double nCellVal; - PopDoubleRef( aRange, nParam, nRefInList); - ScValueIterator aValIter(pDok, aRange); - if (aValIter.GetFirst(nCellVal, nErr)) - { - rVal += (fabs(nCellVal - nMiddle)); - while (aValIter.GetNext(nCellVal, nErr)) - rVal += fabs(nCellVal - nMiddle); - } - } - break; - case svMatrix : - case svExternalSingleRef: - case svExternalDoubleRef: - { - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nCount = pMat->GetElementCount(); - if (pMat->IsNumeric()) - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - { - rVal += fabs(pMat->GetDouble(nElem) - nMiddle); - } - } - else - { - for (SCSIZE nElem = 0; nElem < nCount; nElem++) - { - if (!pMat->IsString(nElem)) - rVal += fabs(pMat->GetDouble(nElem) - nMiddle); - } - } - } - } - break; - default : SetError(errIllegalParameter); break; - } - } - PushDouble(rVal / rValCount); -} - -void ScInterpreter::ScDevSq() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDevSq" ); - double nVal; - double nValCount; - GetStVarParams(nVal, nValCount); - PushDouble(nVal); -} - -void ScInterpreter::ScProbability() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProbability" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) - return; - double fUp, fLo; - fUp = GetDouble(); - if (nParamCount == 4) - fLo = GetDouble(); - else - fLo = fUp; - if (fLo > fUp) - { - double fTemp = fLo; - fLo = fUp; - fUp = fTemp; - } - ScMatrixRef pMatP = GetMatrix(); - ScMatrixRef pMatW = GetMatrix(); - if (!pMatP || !pMatW) - PushIllegalParameter(); - else - { - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - pMatP->GetDimensions(nC1, nR1); - pMatW->GetDimensions(nC2, nR2); - if (nC1 != nC2 || nR1 != nR2 || nC1 == 0 || nR1 == 0 || - nC2 == 0 || nR2 == 0) - PushNA(); - else - { - double fSum = 0.0; - double fRes = 0.0; - sal_Bool bStop = false; - double fP, fW; - for ( SCSIZE i = 0; i < nC1 && !bStop; i++ ) - { - for (SCSIZE j = 0; j < nR1 && !bStop; ++j ) - { - if (pMatP->IsValue(i,j) && pMatW->IsValue(i,j)) - { - fP = pMatP->GetDouble(i,j); - fW = pMatW->GetDouble(i,j); - if (fP < 0.0 || fP > 1.0) - bStop = true; - else - { - fSum += fP; - if (fW >= fLo && fW <= fUp) - fRes += fP; - } - } - else - SetError( errIllegalArgument); - } - } - if (bStop || fabs(fSum -1.0) > 1.0E-7) - PushNoValue(); - else - PushDouble(fRes); - } - } -} - -void ScInterpreter::ScCorrel() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCorrel" ); - // This is identical to ScPearson() - ScPearson(); -} - -void ScInterpreter::ScCovar() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCovar" ); - CalculatePearsonCovar(false,false); -} - -void ScInterpreter::ScPearson() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPearson" ); - CalculatePearsonCovar(sal_True,false); -} -void ScInterpreter::CalculatePearsonCovar(sal_Bool _bPearson,sal_Bool _bStexy) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculatePearsonCovar" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - ScMatrixRef pMat1 = GetMatrix(); - ScMatrixRef pMat2 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - if (nR1 != nR2 || nC1 != nC2) - { - PushIllegalArgument(); - return; - } - /* #i78250# - * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically, - * but the latter produces wrong results if the absolute values are high, - * for example above 10^8 - */ - double fCount = 0.0; - double fSumX = 0.0; - double fSumY = 0.0; - double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY) - double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2 - double fSumSqrDeltaY = 0.0; // sum of (ValY-MeanY)^2 - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValY = pMat2->GetDouble(i,j); - fSumX += fValX; - fSumY += fValY; - fCount++; - } - } - } - if (fCount < (_bStexy ? 3.0 : 1.0)) // fCount==1 is handled by checking denominator later on - PushNoValue(); - else - { - const double fMeanX = fSumX / fCount; - const double fMeanY = fSumY / fCount; - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - const double fValX = pMat1->GetDouble(i,j); - const double fValY = pMat2->GetDouble(i,j); - fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY); - if ( _bPearson ) - { - fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX); - fSumSqrDeltaY += (fValY - fMeanY) * (fValY - fMeanY); - } - } - } - } // for (SCSIZE i = 0; i < nC1; i++) - if ( _bPearson ) - { - if (fSumSqrDeltaX == 0.0 || ( !_bStexy && fSumSqrDeltaY == 0.0) ) - PushError( errDivisionByZero); - else if ( _bStexy ) - PushDouble( sqrt( (fSumSqrDeltaY - fSumDeltaXDeltaY * - fSumDeltaXDeltaY / fSumSqrDeltaX) / (fCount-2))); - else - PushDouble( fSumDeltaXDeltaY / sqrt( fSumSqrDeltaX * fSumSqrDeltaY)); - } // if ( _bPearson ) - else - { - PushDouble( fSumDeltaXDeltaY / fCount); - } - } -} - -void ScInterpreter::ScRSQ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRSQ" ); - // Same as ScPearson()*ScPearson() - ScPearson(); - if (!nGlobalError) - { - switch (GetStackType()) - { - case formula::svDouble: - { - double fVal = PopDouble(); - PushDouble( fVal * fVal); - } - break; - default: - PopError(); - PushNoValue(); - } - } -} - -void ScInterpreter::ScSTEXY() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSTEXY" ); - CalculatePearsonCovar(true,true); -} -void ScInterpreter::CalculateSlopeIntercept(sal_Bool bSlope) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateSlopeIntercept" ); - if ( !MustHaveParamCount( GetByte(), 2 ) ) - return; - ScMatrixRef pMat1 = GetMatrix(); - ScMatrixRef pMat2 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - if (nR1 != nR2 || nC1 != nC2) - { - PushIllegalArgument(); - return; - } - // #i78250# numerical stability improved - double fCount = 0.0; - double fSumX = 0.0; - double fSumY = 0.0; - double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY) - double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2 - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValY = pMat2->GetDouble(i,j); - fSumX += fValX; - fSumY += fValY; - fCount++; - } - } - } - if (fCount < 1.0) - PushNoValue(); - else - { - double fMeanX = fSumX / fCount; - double fMeanY = fSumY / fCount; - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValY = pMat2->GetDouble(i,j); - fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY); - fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX); - } - } - } - if (fSumSqrDeltaX == 0.0) - PushError( errDivisionByZero); - else - { - if ( bSlope ) - PushDouble( fSumDeltaXDeltaY / fSumSqrDeltaX); - else - PushDouble( fMeanY - fSumDeltaXDeltaY / fSumSqrDeltaX * fMeanX); - } - } -} - -void ScInterpreter::ScSlope() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSlope" ); - CalculateSlopeIntercept(sal_True); -} - -void ScInterpreter::ScIntercept() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntercept" ); - CalculateSlopeIntercept(false); -} - -void ScInterpreter::ScForecast() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScForecast" ); - if ( !MustHaveParamCount( GetByte(), 3 ) ) - return; - ScMatrixRef pMat1 = GetMatrix(); - ScMatrixRef pMat2 = GetMatrix(); - if (!pMat1 || !pMat2) - { - PushIllegalParameter(); - return; - } - SCSIZE nC1, nC2; - SCSIZE nR1, nR2; - pMat1->GetDimensions(nC1, nR1); - pMat2->GetDimensions(nC2, nR2); - if (nR1 != nR2 || nC1 != nC2) - { - PushIllegalArgument(); - return; - } - double fVal = GetDouble(); - // #i78250# numerical stability improved - double fCount = 0.0; - double fSumX = 0.0; - double fSumY = 0.0; - double fSumDeltaXDeltaY = 0.0; // sum of (ValX-MeanX)*(ValY-MeanY) - double fSumSqrDeltaX = 0.0; // sum of (ValX-MeanX)^2 - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValY = pMat2->GetDouble(i,j); - fSumX += fValX; - fSumY += fValY; - fCount++; - } - } - } - if (fCount < 1.0) - PushNoValue(); - else - { - double fMeanX = fSumX / fCount; - double fMeanY = fSumY / fCount; - for (SCSIZE i = 0; i < nC1; i++) - { - for (SCSIZE j = 0; j < nR1; j++) - { - if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j)) - { - double fValX = pMat1->GetDouble(i,j); - double fValY = pMat2->GetDouble(i,j); - fSumDeltaXDeltaY += (fValX - fMeanX) * (fValY - fMeanY); - fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX); - } - } - } - if (fSumSqrDeltaX == 0.0) - PushError( errDivisionByZero); - else - PushDouble( fMeanY + fSumDeltaXDeltaY / fSumSqrDeltaX * (fVal - fMeanX)); - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |