1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr3.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <tools/solar.h>
39 #include <rtl/logfile.hxx>
41 #include "interpre.hxx"
43 #include "compiler.hxx"
45 #include "document.hxx"
46 #include "dociter.hxx"
47 #include "scmatrix.hxx"
48 #include "globstr.hrc"
55 using namespace formula
;
57 // STATIC DATA -----------------------------------------------------------
59 #define SCdEpsilon 1.0E-7
60 #define SC_MAX_ITERATION_COUNT 20
61 #define MAX_ANZ_DOUBLE_FOR_SORT 100000
62 // PI jetzt als F_PI aus solar.h
63 //#define PI 3.1415926535897932
65 const double ScInterpreter::fMaxGammaArgument
= 171.624376956302; // found experimental
66 const double fMachEps
= ::std::numeric_limits
<double>::epsilon();
68 //-----------------------------------------------------------------------------
73 virtual double GetValue(double x
) const = 0;
76 // iteration for inverse distributions
78 //template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError )
80 /** u*w<0.0 fails for values near zero */
81 inline bool lcl_HasChangeOfSign( double u
, double w
)
83 return (u
< 0.0 && w
> 0.0) || (u
> 0.0 && w
< 0.0);
86 double lcl_IterateInverse( const ScDistFunc
& rFunction
, double fAx
, double fBx
, bool& rConvError
)
89 const double fYEps
= 1.0E-307;
90 const double fXEps
= ::std::numeric_limits
<double>::epsilon();
92 DBG_ASSERT(fAx
<fBx
, "IterateInverse: wrong interval");
94 // find enclosing interval
96 double fAy
= rFunction
.GetValue(fAx
);
97 double fBy
= rFunction
.GetValue(fBx
);
99 unsigned short nCount
;
100 for (nCount
= 0; nCount
< 1000 && !lcl_HasChangeOfSign(fAy
,fBy
); nCount
++)
102 if (fabs(fAy
) <= fabs(fBy
))
105 fAx
+= 2.0 * (fAx
- fBx
);
110 fAy
= rFunction
.GetValue(fAx
);
115 fBx
+= 2.0 * (fBx
- fAx
);
118 fBy
= rFunction
.GetValue(fBx
);
126 if (!lcl_HasChangeOfSign( fAy
, fBy
))
131 // inverse quadric interpolation with additional brackets
139 double fSx
= 0.5 * (fAx
+ fBx
); // potential next point
140 bool bHasToInterpolate
= true;
142 while ( nCount
< 500 && fabs(fRy
) > fYEps
&&
143 (fBx
-fAx
) > ::std::max( fabs(fAx
), fabs(fBx
)) * fXEps
)
145 if (bHasToInterpolate
)
147 if (fPy
!=fQy
&& fQy
!=fRy
&& fRy
!=fPy
)
149 fSx
= fPx
* fRy
* fQy
/ (fRy
-fPy
) / (fQy
-fPy
)
150 + fRx
* fQy
* fPy
/ (fQy
-fRy
) / (fPy
-fRy
)
151 + fQx
* fPy
* fRy
/ (fPy
-fQy
) / (fRy
-fQy
);
152 bHasToInterpolate
= (fAx
< fSx
) && (fSx
< fBx
); // inside the brackets?
155 bHasToInterpolate
= false;
157 if(!bHasToInterpolate
)
159 fSx
= 0.5 * (fAx
+ fBx
);
161 fPx
= fAx
; fPy
= fAy
;
162 fQx
= fBx
; fQy
= fBy
;
163 bHasToInterpolate
= true;
165 // shift points for next interpolation
166 fPx
= fQx
; fQx
= fRx
; fRx
= fSx
;
167 fPy
= fQy
; fQy
= fRy
; fRy
= rFunction
.GetValue(fSx
);
169 if (lcl_HasChangeOfSign( fAy
, fRy
))
171 fBx
= fRx
; fBy
= fRy
;
175 fAx
= fRx
; fAy
= fRy
;
177 // if last interration brought to small advance, then do bisection next
179 bHasToInterpolate
= bHasToInterpolate
&& (fabs(fRy
) * 2.0 <= fabs(fQy
));
185 //-----------------------------------------------------------------------------
186 // Allgemeine Funktionen
187 //-----------------------------------------------------------------------------
189 void ScInterpreter::ScNoName()
191 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNoName" );
192 PushError(errNoName
);
195 void ScInterpreter::ScBadName()
197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScBadName" );
198 short nParamCount
= GetByte();
199 while (nParamCount
-- > 0)
203 PushError( errNoName
);
206 double ScInterpreter::phi(double x
)
208 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::phi" );
209 return 0.39894228040143268 * exp(-(x
* x
) / 2.0);
212 double ScInterpreter::integralPhi(double x
)
213 { // Using gauss(x)+0.5 has severe cancellation errors for x<-4
214 return 0.5 * ::rtl::math::erfc(-x
* 0.7071067811865475); // * 1/sqrt(2)
217 double ScInterpreter::taylor(double* pPolynom
, USHORT nMax
, double x
)
219 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::taylor" );
220 double nVal
= pPolynom
[nMax
];
221 for (short i
= nMax
-1; i
>= 0; i
--)
223 nVal
= pPolynom
[i
] + (nVal
* x
);
228 double ScInterpreter::gauss(double x
)
230 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::gauss" );
232 { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
233 -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
234 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
235 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
237 { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
238 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
239 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
240 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
241 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
242 -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
243 -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
244 -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
246 { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
247 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
248 -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
249 -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
250 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
251 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
252 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
253 double asympt
[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
255 double xAbs
= fabs(x
);
256 USHORT xShort
= (USHORT
)::rtl::math::approxFloor(xAbs
);
259 nVal
= taylor(t0
, 11, (xAbs
* xAbs
)) * xAbs
;
260 else if ((xShort
>= 1) && (xShort
<= 2))
261 nVal
= taylor(t2
, 23, (xAbs
- 2.0));
262 else if ((xShort
>= 3) && (xShort
<= 4))
263 nVal
= taylor(t4
, 20, (xAbs
- 4.0));
265 nVal
= 0.5 + phi(xAbs
) * taylor(asympt
, 4, 1.0 / (xAbs
* xAbs
)) / xAbs
;
273 // #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
276 double ScInterpreter::gaussinv(double x
)
278 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::gaussinv" );
296 t
*2509.0809287301226727+33430.575583588128105
298 *t
+67265.770927008700853
300 *t
+45921.953931549871457
302 *t
+13731.693765509461125
304 *t
+1971.5909503065514427
306 *t
+133.14166789178437745
308 *t
+3.387132872796366608
318 t
*5226.495278852854561+28729.085735721942674
320 *t
+39307.89580009271061
322 *t
+21213.794301586595867
324 *t
+5394.1960214247511077
326 *t
+687.1870074920579083
328 *t
+42.313330701600911252
353 t
*7.7454501427834140764e-4+0.0227238449892691845833
355 *t
+0.24178072517745061177
357 *t
+1.27045825245236838258
359 *t
+3.64784832476320460504
361 *t
+5.7694972214606914055
363 *t
+4.6303378461565452959
365 *t
+1.42343711074968357734
375 t
*1.05075007164441684324e-9+5.475938084995344946e-4
377 *t
+0.0151986665636164571966
379 *t
+0.14810397642748007459
381 *t
+0.68976733498510000455
383 *t
+1.6763848301838038494
385 *t
+2.05319162663775882187
403 t
*2.01033439929228813265e-7+2.71155556874348757815e-5
405 *t
+0.0012426609473880784386
407 *t
+0.026532189526576123093
409 *t
+0.29656057182850489123
411 *t
+1.7848265399172913358
413 *t
+5.4637849111641143699
415 *t
+6.6579046435011037772
425 t
*2.04426310338993978564e-15+1.4215117583164458887e-7
427 *t
+1.8463183175100546818e-5
429 *t
+7.868691311456132591e-4
431 *t
+0.0148753612908506148525
433 *t
+0.13692988092273580531
435 *t
+0.59983220655588793769
448 double ScInterpreter::Fakultaet(double x
)
450 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::Fakultaet" );
451 x
= ::rtl::math::approxFloor(x
);
466 SetError(errNoValue
);
467 /* // Stirlingsche Naeherung zu ungenau
469 x = pow(x/exp(1), x) * sqrt(x) * SQRT_2_PI * (1.0 + 1.0 / (12.0 * x));
474 double ScInterpreter::BinomKoeff(double n
, double k
)
476 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::BinomKoeff" );
478 k
= ::rtl::math::approxFloor(k
);
495 double f1 = n; // Zaehler
496 double f2 = k; // Nenner
513 // The algorithm is based on lanczos13m53 in lanczos.hpp
514 // in math library from http://www.boost.org
515 /** you must ensure fZ>0
516 Uses a variant of the Lanczos sum with a rational function. */
517 double lcl_getLanczosSum(double fZ
)
519 const double fNum
[13] ={
520 23531376880.41075968857200767445163675473,
521 42919803642.64909876895789904700198885093,
522 35711959237.35566804944018545154716670596,
523 17921034426.03720969991975575445893111267,
524 6039542586.35202800506429164430729792107,
525 1439720407.311721673663223072794912393972,
526 248874557.8620541565114603864132294232163,
527 31426415.58540019438061423162831820536287,
528 2876370.628935372441225409051620849613599,
529 186056.2653952234950402949897160456992822,
530 8071.672002365816210638002902272250613822,
531 210.8242777515793458725097339207133627117,
532 2.506628274631000270164908177133837338626
534 const double fDenom
[13] = {
557 fSumDenom
= fDenom
[12];
558 for (nI
= 11; nI
>= 0; --nI
)
563 fSumDenom
+= fDenom
[nI
];
567 // Cancel down with fZ^12; Horner scheme with reverse coefficients
571 fSumDenom
= fDenom
[0];
572 for (nI
= 1; nI
<=12; ++nI
)
577 fSumDenom
+= fDenom
[nI
];
580 return fSumNum
/fSumDenom
;
583 // The algorithm is based on tgamma in gamma.hpp
584 // in math library from http://www.boost.org
585 /** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
586 double lcl_GetGammaHelper(double fZ
)
588 double fGamma
= lcl_getLanczosSum(fZ
);
589 const double fg
= 6.024680040776729583740234375;
590 double fZgHelp
= fZ
+ fg
- 0.5;
591 // avoid intermediate overflow
592 double fHalfpower
= pow( fZgHelp
, fZ
/ 2 - 0.25);
593 fGamma
*= fHalfpower
;
594 fGamma
/= exp(fZgHelp
);
595 fGamma
*= fHalfpower
;
596 if (fZ
<= 20.0 && fZ
== ::rtl::math::approxFloor(fZ
))
597 fGamma
= ::rtl::math::round(fGamma
);
601 // The algorithm is based on tgamma in gamma.hpp
602 // in math library from http://www.boost.org
603 /** You must ensure fZ>0 */
604 double lcl_GetLogGammaHelper(double fZ
)
606 const double fg
= 6.024680040776729583740234375;
607 double fZgHelp
= fZ
+ fg
- 0.5;
608 return log( lcl_getLanczosSum(fZ
)) + (fZ
-0.5) * log(fZgHelp
) - fZgHelp
;
611 /** You must ensure non integer arguments for fZ<1 */
612 double ScInterpreter::GetGamma(double fZ
)
614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetGamma" );
615 const double fLogPi
= log(F_PI
);
616 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
618 if (fZ
> fMaxGammaArgument
)
620 SetError(errIllegalFPOperation
);
625 return lcl_GetGammaHelper(fZ
);
627 if (fZ
>= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
628 return lcl_GetGammaHelper(fZ
+1) / fZ
;
630 if (fZ
>= -0.5) // shift to x>=1, might overflow
632 double fLogTest
= lcl_GetLogGammaHelper(fZ
+2) - log(fZ
+1) - log( fabs(fZ
));
633 if (fLogTest
>= fLogDblMax
)
635 SetError( errIllegalFPOperation
);
638 return lcl_GetGammaHelper(fZ
+2) / (fZ
+1) / fZ
;
641 // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
642 double fLogDivisor
= lcl_GetLogGammaHelper(1-fZ
) + log( fabs( ::rtl::math::sin( F_PI
*fZ
)));
643 if (fLogDivisor
- fLogPi
>= fLogDblMax
) // underflow
647 if (fLogPi
- fLogDivisor
> fLogDblMax
) // overflow
649 SetError(errIllegalFPOperation
);
653 return exp( fLogPi
- fLogDivisor
) * ((::rtl::math::sin( F_PI
*fZ
) < 0.0) ? -1.0 : 1.0);
657 /** You must ensure fZ>0 */
658 double ScInterpreter::GetLogGamma(double fZ
)
660 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetLogGamma" );
661 if (fZ
>= fMaxGammaArgument
)
662 return lcl_GetLogGammaHelper(fZ
);
664 return log(lcl_GetGammaHelper(fZ
));
666 return log( lcl_GetGammaHelper(fZ
+1) / fZ
);
667 return lcl_GetLogGammaHelper(fZ
+2) - log(fZ
+1) - log(fZ
);
670 double ScInterpreter::GetFDist(double x
, double fF1
, double fF2
)
672 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetFDist" );
673 double arg
= fF2
/(fF2
+fF1
*x
);
674 double alpha
= fF2
/2.0;
675 double beta
= fF1
/2.0;
676 return (GetBetaDist(arg
, alpha
, beta
));
678 double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
679 sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
680 return (0.5-gauss(Z));
684 double ScInterpreter::GetTDist(double T
, double fDF
)
686 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetTDist" );
687 return 0.5 * GetBetaDist(fDF
/(fDF
+T
*T
), fDF
/2.0, 0.5);
689 USHORT DF = (USHORT) fDF;
690 double A = T / sqrt(DF);
691 double B = 1.0 + A*A;
694 R = 0.5 + atan(A)/F_PI;
695 else if (DF % 2 == 0)
697 double S0 = A/(2.0 * sqrt(B));
699 for (USHORT i = 2; i <= DF-2; i+=2)
701 C0 *= (1.0 - 1.0/(double)i)/B;
708 double S1 = A / (B * F_PI);
710 for (USHORT i = 3; i <= DF-2; i+=2)
712 C1 *= (1.0 - 1.0/(double)i)/B;
715 R = 0.5 + atan(A)/F_PI + S1;
721 // for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
722 /** You must ensure fDF>0.0 */
723 double ScInterpreter::GetChiDist(double fX
, double fDF
)
725 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetChiDist" );
727 return 1.0; // see ODFF
729 return GetUpRegIGamma( fDF
/2.0, fX
/2.0);
733 // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
735 /** You must ensure fDF>0.0 */
736 double ScInterpreter::GetChiSqDistCDF(double fX
, double fDF
)
738 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetChiSqDistCDF" );
740 return 0.0; // see ODFF
742 return GetLowRegIGamma( fDF
/2.0, fX
/2.0);
745 double ScInterpreter::GetChiSqDistPDF(double fX
, double fDF
)
747 // you must ensure fDF is positive integer
751 return 0.0; // see ODFF
752 if (fDF
*fX
> 1391000.0)
754 // intermediate invalid values, use log
755 fValue
= exp((0.5*fDF
- 1) * log(fX
*0.5) - 0.5 * fX
- log(2.0) - GetLogGamma(0.5*fDF
));
757 else // fDF is small in most cases, we can iterate
759 if (fmod(fDF
,2.0)<0.5)
767 fValue
= 1/sqrt(fX
*2*F_PI
);
770 while ( fCount
< fDF
)
772 fValue
*= (fX
/ fCount
);
775 if (fX
>=1425.0) // underflow in e^(-x/2)
776 fValue
= exp(log(fValue
)-fX
/2);
778 fValue
*= exp(-fX
/2);
783 void ScInterpreter::ScChiSqDist()
785 BYTE nParamCount
= GetByte();
786 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
790 if (nParamCount
== 3)
791 bCumulative
= GetBool();
794 double fDF
= ::rtl::math::approxFloor(GetDouble());
796 PushIllegalArgument();
801 PushDouble(GetChiSqDistCDF(fX
,fDF
));
803 PushDouble(GetChiSqDistPDF(fX
,fDF
));
807 void ScInterpreter::ScGamma()
809 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGamma" );
810 double x
= GetDouble();
812 if (x
<= 0.0 && x
== ::rtl::math::approxFloor(x
))
813 PushIllegalArgument();
816 fResult
= GetGamma(x
);
819 PushError( nGlobalError
);
827 void ScInterpreter::ScLogGamma()
829 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLogGamma" );
830 double x
= GetDouble();
831 if (x
> 0.0) // constraint from ODFF
832 PushDouble( GetLogGamma(x
));
834 PushIllegalArgument();
837 double ScInterpreter::GetBeta(double fAlpha
, double fBeta
)
843 fA
= fAlpha
; fB
= fBeta
;
847 fA
= fBeta
; fB
= fAlpha
;
849 if (fA
+fB
< fMaxGammaArgument
) // simple case
850 return GetGamma(fA
)/GetGamma(fA
+fB
)*GetGamma(fB
);
852 // GetLogGamma is not accurate enough, back to Lanczos for all three
853 // GetGamma and arrange factors newly.
854 const double fg
= 6.024680040776729583740234375; //see GetGamma
855 double fgm
= fg
- 0.5;
856 double fLanczos
= lcl_getLanczosSum(fA
);
857 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
858 fLanczos
*= lcl_getLanczosSum(fB
);
859 double fABgm
= fA
+fB
+fgm
;
860 fLanczos
*= sqrt((fABgm
/(fA
+fgm
))/(fB
+fgm
));
861 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
862 double fTempB
= fA
/(fB
+fgm
);
863 double fResult
= exp(-fA
* ::rtl::math::log1p(fTempA
)
864 -fB
* ::rtl::math::log1p(fTempB
)-fgm
);
869 // Same as GetBeta but with logarithm
870 double ScInterpreter::GetLogBeta(double fAlpha
, double fBeta
)
876 fA
= fAlpha
; fB
= fBeta
;
880 fA
= fBeta
; fB
= fAlpha
;
882 const double fg
= 6.024680040776729583740234375; //see GetGamma
883 double fgm
= fg
- 0.5;
884 double fLanczos
= lcl_getLanczosSum(fA
);
885 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
886 fLanczos
*= lcl_getLanczosSum(fB
);
887 double fLogLanczos
= log(fLanczos
);
888 double fABgm
= fA
+fB
+fgm
;
889 fLogLanczos
+= 0.5*(log(fABgm
)-log(fA
+fgm
)-log(fB
+fgm
));
890 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
891 double fTempB
= fA
/(fB
+fgm
);
892 double fResult
= -fA
* ::rtl::math::log1p(fTempA
)
893 -fB
* ::rtl::math::log1p(fTempB
)-fgm
;
894 fResult
+= fLogLanczos
;
898 // beta distribution probability density function
899 double ScInterpreter::GetBetaDistPDF(double fX
, double fA
, double fB
)
902 if (fA
== 1.0) // result b*(1-x)^(b-1)
907 return -2.0*fX
+ 2.0;
908 if (fX
== 1.0 && fB
< 1.0)
910 SetError(errIllegalArgument
);
914 return fB
+ fB
* ::rtl::math::expm1((fB
-1.0) * ::rtl::math::log1p(-fX
));
916 return fB
* pow(0.5-fX
+0.5,fB
-1.0);
918 if (fB
== 1.0) // result a*x^(a-1)
922 if (fX
== 0.0 && fA
< 1.0)
924 SetError(errIllegalArgument
);
927 return fA
* pow(fX
,fA
-1);
931 if (fA
< 1.0 && fX
== 0.0)
933 SetError(errIllegalArgument
);
941 if (fB
< 1.0 && fX
== 1.0)
943 SetError(errIllegalArgument
);
950 // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
951 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
952 const double fLogDblMin
= log( ::std::numeric_limits
<double>::min());
953 double fLogY
= (fX
< 0.1) ? ::rtl::math::log1p(-fX
) : log(0.5-fX
+0.5);
954 double fLogX
= log(fX
);
955 double fAm1
= fA
-1.0;
956 double fBm1
= fB
-1.0;
957 double fLogBeta
= GetLogBeta(fA
,fB
);
958 // check whether parts over- or underflow
959 if ( fAm1
* fLogX
< fLogDblMax
&& fAm1
* fLogX
> fLogDblMin
960 && fBm1
* fLogY
< fLogDblMax
&& fBm1
* fLogY
> fLogDblMin
961 && fLogBeta
< fLogDblMax
&& fLogBeta
> fLogDblMin
)
962 return pow(fX
,fA
-1.0) * pow(0.5-fX
+0.5,fB
-1.0) / GetBeta(fA
,fB
);
963 else // need logarithm;
964 // might overflow as a whole, but seldom, not worth to pre-detect it
965 return exp((fA
-1.0)*fLogX
+ (fB
-1.0)* fLogY
- fLogBeta
);
971 I_x(a,b) = ---------------- * result of ContFrac
974 double lcl_GetBetaHelperContFrac(double fX
, double fA
, double fB
)
975 { // like old version
976 double a1
, b1
, a2
, b2
, fnorm
, apl2m
, d2m
, d2m1
, cfnew
, cf
;
978 b2
= 1.0 - (fA
+fB
)/(fA
+1.0)*fX
;
994 const double fMaxIter
= 50000.0;
995 // loop security, normal cases converge in less than 100 iterations.
996 // FIXME: You will get so much iteratons for fX near mean,
997 // I do not know a better algorithm.
998 bool bfinished
= false;
1001 apl2m
= fA
+ 2.0*rm
;
1002 d2m
= rm
*(fB
-rm
)*fX
/((apl2m
-1.0)*apl2m
);
1003 d2m1
= -(fA
+rm
)*(fA
+fB
+rm
)*fX
/(apl2m
*(apl2m
+1.0));
1004 a1
= (a2
+d2m
*a1
)*fnorm
;
1005 b1
= (b2
+d2m
*b1
)*fnorm
;
1006 a2
= a1
+ d2m1
*a2
*fnorm
;
1007 b2
= b1
+ d2m1
*b2
*fnorm
;
1012 bfinished
= (fabs(cf
-cfnew
) < fabs(cf
)*fMachEps
);
1017 while (rm
< fMaxIter
&& !bfinished
);
1021 // cumulative distribution function, normalized
1022 double ScInterpreter::GetBetaDist(double fXin
, double fAlpha
, double fBeta
)
1025 if (fXin
<= 0.0) // values are valid, see spec
1027 if (fXin
>= 1.0) // values are valid, see spec
1030 return pow(fXin
, fAlpha
);
1032 // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
1033 return -::rtl::math::expm1(fBeta
* ::rtl::math::log1p(-fXin
));
1034 //FIXME: need special algorithm for fX near fP for large fA,fB
1036 // I use always continued fraction, power series are neither
1037 // faster nor more accurate.
1038 double fY
= (0.5-fXin
)+0.5;
1039 double flnY
= ::rtl::math::log1p(-fXin
);
1041 double flnX
= log(fXin
);
1044 bool bReflect
= fXin
> fAlpha
/(fAlpha
+fBeta
);
1054 fResult
= lcl_GetBetaHelperContFrac(fX
,fA
,fB
);
1055 fResult
= fResult
/fA
;
1056 double fP
= fA
/(fA
+fB
);
1057 double fQ
= fB
/(fA
+fB
);
1059 if (fA
> 1.0 && fB
> 1.0 && fP
< 0.97 && fQ
< 0.97) //found experimental
1060 fTemp
= GetBetaDistPDF(fX
,fA
,fB
)*fX
*fY
;
1062 fTemp
= exp(fA
*flnX
+ fB
*flnY
- GetLogBeta(fA
,fB
));
1065 fResult
= 0.5 - fResult
+ 0.5;
1066 if (fResult
> 1.0) // ensure valid range
1073 void ScInterpreter::ScBetaDist()
1075 BYTE nParamCount
= GetByte();
1076 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) ) // expanded, see #i91547#
1078 double fLowerBound
, fUpperBound
;
1079 double alpha
, beta
, x
;
1081 if (nParamCount
== 6)
1082 bIsCumulative
= GetBool();
1084 bIsCumulative
= true;
1085 if (nParamCount
>= 5)
1086 fUpperBound
= GetDouble();
1089 if (nParamCount
>= 4)
1090 fLowerBound
= GetDouble();
1094 alpha
= GetDouble();
1096 double fScale
= fUpperBound
- fLowerBound
;
1097 if (fScale
<= 0.0 || alpha
<= 0.0 || beta
<= 0.0)
1099 PushIllegalArgument();
1102 if (bIsCumulative
) // cumulative distribution function
1105 if (x
< fLowerBound
)
1107 PushDouble(0.0); return; //see spec
1109 if (x
> fUpperBound
)
1111 PushDouble(1.0); return; //see spec
1114 x
= (x
-fLowerBound
)/fScale
; // convert to standard form
1115 PushDouble(GetBetaDist(x
, alpha
, beta
));
1118 else // probability density function
1120 if (x
< fLowerBound
|| x
> fUpperBound
)
1125 x
= (x
-fLowerBound
)/fScale
;
1126 PushDouble(GetBetaDistPDF(x
, alpha
, beta
)/fScale
);
1131 void ScInterpreter::ScPhi()
1133 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPhi" );
1134 PushDouble(phi(GetDouble()));
1137 void ScInterpreter::ScGauss()
1139 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGauss" );
1140 PushDouble(gauss(GetDouble()));
1143 void ScInterpreter::ScFisher()
1145 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFisher" );
1146 double fVal
= GetDouble();
1147 if (fabs(fVal
) >= 1.0)
1148 PushIllegalArgument();
1150 PushDouble( ::rtl::math::atanh( fVal
));
1153 void ScInterpreter::ScFisherInv()
1155 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFisherInv" );
1156 PushDouble( tanh( GetDouble()));
1159 void ScInterpreter::ScFact()
1161 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFact" );
1162 double nVal
= GetDouble();
1164 PushIllegalArgument();
1166 PushDouble(Fakultaet(nVal
));
1169 void ScInterpreter::ScKombin()
1171 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScKombin" );
1172 if ( MustHaveParamCount( GetByte(), 2 ) )
1174 double k
= ::rtl::math::approxFloor(GetDouble());
1175 double n
= ::rtl::math::approxFloor(GetDouble());
1176 if (k
< 0.0 || n
< 0.0 || k
> n
)
1177 PushIllegalArgument();
1179 PushDouble(BinomKoeff(n
, k
));
1183 void ScInterpreter::ScKombin2()
1185 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScKombin2" );
1186 if ( MustHaveParamCount( GetByte(), 2 ) )
1188 double k
= ::rtl::math::approxFloor(GetDouble());
1189 double n
= ::rtl::math::approxFloor(GetDouble());
1190 if (k
< 0.0 || n
< 0.0 || k
> n
)
1191 PushIllegalArgument();
1193 PushDouble(BinomKoeff(n
+ k
- 1, k
));
1197 void ScInterpreter::ScVariationen()
1199 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScVariationen" );
1200 if ( MustHaveParamCount( GetByte(), 2 ) )
1202 double k
= ::rtl::math::approxFloor(GetDouble());
1203 double n
= ::rtl::math::approxFloor(GetDouble());
1204 if (n
< 0.0 || k
< 0.0 || k
> n
)
1205 PushIllegalArgument();
1207 PushInt(1); // (n! / (n - 0)!) == 1
1211 for (ULONG i
= (ULONG
)k
-1; i
>= 1; i
--)
1212 nVal
*= n
-(double)i
;
1218 void ScInterpreter::ScVariationen2()
1220 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScVariationen2" );
1221 if ( MustHaveParamCount( GetByte(), 2 ) )
1223 double k
= ::rtl::math::approxFloor(GetDouble());
1224 double n
= ::rtl::math::approxFloor(GetDouble());
1225 if (n
< 0.0 || k
< 0.0 || k
> n
)
1226 PushIllegalArgument();
1228 PushDouble(pow(n
,k
));
1232 void ScInterpreter::ScB()
1234 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScB" );
1235 BYTE nParamCount
= GetByte();
1236 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1238 if (nParamCount
== 3)
1240 double x
= ::rtl::math::approxFloor(GetDouble());
1241 double p
= GetDouble();
1242 double n
= ::rtl::math::approxFloor(GetDouble());
1243 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1244 PushIllegalArgument();
1248 double fFactor
= pow(q
, n
);
1251 fFactor
= pow(p
, n
);
1256 ULONG max
= (ULONG
) (n
- x
);
1257 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1258 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1259 PushDouble(fFactor
);
1264 ULONG max
= (ULONG
) x
;
1265 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1266 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1267 PushDouble(fFactor
);
1271 else if (nParamCount
== 4)
1273 double xe
= GetDouble();
1274 double xs
= GetDouble();
1275 double p
= GetDouble();
1276 double n
= GetDouble();
1277 // alter Stand 300-SC
1278 // if ((xs < n) && (xe < n) && (p < 1.0))
1280 // double Varianz = sqrt(n * p * (1.0 - p));
1281 // xs = fabs(xs - (n * p /* / 2.0 STE */ ));
1282 // xe = fabs(xe - (n * p /* / 2.0 STE */ ));
1283 //// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz);
1284 // double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz));
1285 // PushDouble(nVal);
1287 bool bIsValidX
= ( 0.0 <= xs
&& xs
<= xe
&& xe
<= n
);
1288 if ( bIsValidX
&& 0.0 < p
&& p
< 1.0 )
1291 double fFactor
= pow(q
, n
);
1294 fFactor
= pow(p
, n
);
1302 max
= (ULONG
) (n
-xe
)-1;
1306 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1307 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1309 max
= (ULONG
) (n
-xs
);
1312 for (; i
< max
&& fFactor
> 0.0; i
++)
1314 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1324 if ( (ULONG
) xs
== 0)
1335 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1336 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1337 if ((ULONG
)xe
== 0) // beide 0
1341 for (; i
< max
&& fFactor
> 0.0; i
++)
1343 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1351 if ( bIsValidX
) // not(0<p<1)
1354 PushDouble( (xs
== 0.0) ? 1.0 : 0.0 );
1355 else if ( p
== 1.0 )
1356 PushDouble( (xe
== n
) ? 1.0 : 0.0 );
1358 PushIllegalArgument();
1361 PushIllegalArgument();
1366 void ScInterpreter::ScBinomDist()
1368 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScBinomDist" );
1369 if ( MustHaveParamCount( GetByte(), 4 ) )
1371 double kum
= GetDouble(); // 0 oder 1
1372 double p
= GetDouble(); // p
1373 double n
= ::rtl::math::approxFloor(GetDouble()); // n
1374 double x
= ::rtl::math::approxFloor(GetDouble()); // x
1375 double fFactor
, q
, fSum
;
1376 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1377 PushIllegalArgument();
1378 else if (kum
== 0.0) // Dichte
1381 fFactor
= pow(q
, n
);
1384 fFactor
= pow(p
, n
);
1389 ULONG max
= (ULONG
) (n
- x
);
1390 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1391 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1392 PushDouble(fFactor
);
1397 ULONG max
= (ULONG
) x
;
1398 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1399 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1400 PushDouble(fFactor
);
1410 fFactor
= pow(q
, n
);
1413 fFactor
= pow(p
, n
);
1418 fSum
= 1.0 - fFactor
;
1419 ULONG max
= (ULONG
) (n
- x
) - 1;
1420 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1422 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1434 ULONG max
= (ULONG
) x
;
1435 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1437 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1447 void ScInterpreter::ScCritBinom()
1449 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCritBinom" );
1450 if ( MustHaveParamCount( GetByte(), 3 ) )
1452 double alpha
= GetDouble(); // alpha
1453 double p
= GetDouble(); // p
1454 double n
= ::rtl::math::approxFloor(GetDouble());
1455 if (n
< 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || p
< 0.0 || p
> 1.0)
1456 PushIllegalArgument();
1460 double fFactor
= pow(q
,n
);
1463 fFactor
= pow(p
, n
);
1468 double fSum
= 1.0 - fFactor
; ULONG max
= (ULONG
) n
;
1471 for ( i
= 0; i
< max
&& fSum
>= alpha
; i
++)
1473 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1481 double fSum
= fFactor
; ULONG max
= (ULONG
) n
;
1484 for ( i
= 0; i
< max
&& fSum
< alpha
; i
++)
1486 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1495 void ScInterpreter::ScNegBinomDist()
1497 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNegBinomDist" );
1498 if ( MustHaveParamCount( GetByte(), 3 ) )
1500 double p
= GetDouble(); // p
1501 double r
= GetDouble(); // r
1502 double x
= GetDouble(); // x
1503 if (r
< 0.0 || x
< 0.0 || p
< 0.0 || p
> 1.0)
1504 PushIllegalArgument();
1508 double fFactor
= pow(p
,r
);
1509 for (double i
= 0.0; i
< x
; i
++)
1510 fFactor
*= (i
+r
)/(i
+1.0)*q
;
1511 PushDouble(fFactor
);
1516 void ScInterpreter::ScNormDist()
1518 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNormDist" );
1519 BYTE nParamCount
= GetByte();
1520 if ( !MustHaveParamCount( nParamCount
, 3, 4))
1522 bool bCumulative
= nParamCount
== 4 ? GetBool() : true;
1523 double sigma
= GetDouble(); // standard deviation
1524 double mue
= GetDouble(); // mean
1525 double x
= GetDouble(); // x
1528 PushIllegalArgument();
1532 PushDouble(integralPhi((x
-mue
)/sigma
));
1534 PushDouble(phi((x
-mue
)/sigma
)/sigma
);
1537 void ScInterpreter::ScLogNormDist() //expanded, see #i100119#
1539 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLogNormDist" );
1540 BYTE nParamCount
= GetByte();
1541 if ( !MustHaveParamCount( nParamCount
, 1, 4))
1543 bool bCumulative
= nParamCount
== 4 ? GetBool() : true; // cumulative
1544 double sigma
= nParamCount
>= 3 ? GetDouble() : 1.0; // standard deviation
1545 double mue
= nParamCount
>= 2 ? GetDouble() : 0.0; // mean
1546 double x
= GetDouble(); // x
1549 PushIllegalArgument();
1557 PushDouble(integralPhi((log(x
)-mue
)/sigma
));
1562 PushIllegalArgument();
1564 PushDouble(phi((log(x
)-mue
)/sigma
)/sigma
/x
);
1568 void ScInterpreter::ScStdNormDist()
1570 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScStdNormDist" );
1571 PushDouble(integralPhi(GetDouble()));
1574 void ScInterpreter::ScExpDist()
1576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScExpDist" );
1577 if ( MustHaveParamCount( GetByte(), 3 ) )
1579 double kum
= GetDouble(); // 0 oder 1
1580 double lambda
= GetDouble(); // lambda
1581 double x
= GetDouble(); // x
1583 PushIllegalArgument();
1584 else if (kum
== 0.0) // Dichte
1587 PushDouble(lambda
* exp(-lambda
*x
));
1594 PushDouble(1.0 - exp(-lambda
*x
));
1601 void ScInterpreter::ScTDist()
1603 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTDist" );
1604 if ( !MustHaveParamCount( GetByte(), 3 ) )
1606 double fFlag
= ::rtl::math::approxFloor(GetDouble());
1607 double fDF
= ::rtl::math::approxFloor(GetDouble());
1608 double T
= GetDouble();
1609 if (fDF
< 1.0 || T
< 0.0 || (fFlag
!= 1.0 && fFlag
!= 2.0) )
1611 PushIllegalArgument();
1614 double R
= GetTDist(T
, fDF
);
1621 void ScInterpreter::ScFDist()
1623 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFDist" );
1624 if ( !MustHaveParamCount( GetByte(), 3 ) )
1626 double fF2
= ::rtl::math::approxFloor(GetDouble());
1627 double fF1
= ::rtl::math::approxFloor(GetDouble());
1628 double fF
= GetDouble();
1629 if (fF
< 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
)
1631 PushIllegalArgument();
1634 PushDouble(GetFDist(fF
, fF1
, fF2
));
1637 void ScInterpreter::ScChiDist()
1639 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScChiDist" );
1641 if ( !MustHaveParamCount( GetByte(), 2 ) )
1643 double fDF
= ::rtl::math::approxFloor(GetDouble());
1644 double fChi
= GetDouble();
1645 if (fDF
< 1.0) // x<=0 returns 1, see ODFF 6.17.10
1647 PushIllegalArgument();
1650 fResult
= GetChiDist( fChi
, fDF
);
1653 PushError( nGlobalError
);
1656 PushDouble(fResult
);
1659 void ScInterpreter::ScWeibull()
1661 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScWeibull" );
1662 if ( MustHaveParamCount( GetByte(), 4 ) )
1664 double kum
= GetDouble(); // 0 oder 1
1665 double beta
= GetDouble(); // beta
1666 double alpha
= GetDouble(); // alpha
1667 double x
= GetDouble(); // x
1668 if (alpha
<= 0.0 || beta
<= 0.0 || x
< 0.0)
1669 PushIllegalArgument();
1670 else if (kum
== 0.0) // Dichte
1671 PushDouble(alpha
/pow(beta
,alpha
)*pow(x
,alpha
-1.0)*
1672 exp(-pow(x
/beta
,alpha
)));
1674 PushDouble(1.0 - exp(-pow(x
/beta
,alpha
)));
1678 void ScInterpreter::ScPoissonDist()
1680 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPoissonDist" );
1681 BYTE nParamCount
= GetByte();
1682 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
1684 bool bCumulative
= (nParamCount
== 3 ? GetBool() : true); // default cumulative
1685 double lambda
= GetDouble(); // Mean
1686 double x
= ::rtl::math::approxFloor(GetDouble()); // discrete distribution
1687 if (lambda
< 0.0 || x
< 0.0)
1688 PushIllegalArgument();
1689 else if (!bCumulative
) // Probability mass function
1695 if (lambda
>712) // underflow in exp(-lambda)
1696 { // accuracy 11 Digits
1697 PushDouble( exp(x
*log(lambda
)-lambda
-GetLogGamma(x
+1.0)));
1701 double fPoissonVar
= 1.0;
1702 for ( double f
= 0.0; f
< x
; ++f
)
1703 fPoissonVar
*= lambda
/ ( f
+ 1.0 );
1704 PushDouble( fPoissonVar
* exp( -lambda
) );
1708 else // Cumulative distribution function
1714 if (lambda
> 712 ) // underflow in exp(-lambda)
1715 { // accuracy 12 Digits
1716 PushDouble(GetUpRegIGamma(x
+1.0,lambda
));
1720 if (x
>= 936.0) // result is always undistinghable from 1
1724 double fSummand
= exp(-lambda
);
1725 double fSum
= fSummand
;
1726 int nEnd
= sal::static_int_cast
<int>( x
);
1727 for (int i
= 1; i
<= nEnd
; i
++)
1729 fSummand
= (fSummand
* lambda
)/(double)i
;
1740 /** Local function used in the calculation of the hypergeometric distribution.
1742 void lcl_PutFactorialElements( ::std::vector
< double >& cn
, double fLower
, double fUpper
, double fBase
)
1744 for ( double i
= fLower
; i
<= fUpper
; ++i
)
1746 double fVal
= fBase
- i
;
1748 cn
.push_back( fVal
);
1752 /** Calculates a value of the hypergeometric distribution.
1754 The algorithm is designed to avoid unnecessary multiplications and division
1755 by expanding all factorial elements (9 of them). It is done by excluding
1756 those ranges that overlap in the numerator and the denominator. This allows
1757 for a fast calculation for large values which would otherwise cause an overflow
1758 in the intermediate values.
1760 @author Kohei Yoshida <kohei@openoffice.org>
1765 void ScInterpreter::ScHypGeomDist()
1767 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScHypGeomDist" );
1768 const size_t nMaxArraySize
= 500000; // arbitrary max array size
1770 if ( !MustHaveParamCount( GetByte(), 4 ) )
1773 double N
= ::rtl::math::approxFloor(GetDouble());
1774 double M
= ::rtl::math::approxFloor(GetDouble());
1775 double n
= ::rtl::math::approxFloor(GetDouble());
1776 double x
= ::rtl::math::approxFloor(GetDouble());
1778 if( (x
< 0.0) || (n
< x
) || (M
< x
) || (N
< n
) || (N
< M
) || (x
< n
- N
+ M
) )
1780 PushIllegalArgument();
1784 typedef ::std::vector
< double > HypContainer
;
1785 HypContainer cnNumer
, cnDenom
;
1787 size_t nEstContainerSize
= static_cast<size_t>( x
+ ::std::min( n
, M
) );
1788 size_t nMaxSize
= ::std::min( cnNumer
.max_size(), nMaxArraySize
);
1789 if ( nEstContainerSize
> nMaxSize
)
1794 cnNumer
.reserve( nEstContainerSize
+ 10 );
1795 cnDenom
.reserve( nEstContainerSize
+ 10 );
1797 // Trim coefficient C first
1798 double fCNumVarUpper
= N
- n
- M
+ x
- 1.0;
1799 double fCDenomVarLower
= 1.0;
1800 if ( N
- n
- M
+ x
>= M
- x
+ 1.0 )
1802 fCNumVarUpper
= M
- x
- 1.0;
1803 fCDenomVarLower
= N
- n
- 2.0*(M
- x
) + 1.0;
1807 double fCNumLower
= N
- n
- fCNumVarUpper
;
1809 double fCDenomUpper
= N
- n
- M
+ x
+ 1.0 - fCDenomVarLower
;
1811 double fDNumVarLower
= n
- M
;
1815 if ( N
- M
< n
+ 1.0 )
1819 if ( N
- n
< n
+ 1.0 )
1822 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1823 lcl_PutFactorialElements( cnDenom
, 0.0, N
- n
- 1.0, N
);
1828 DBG_ASSERT( fCNumLower
< n
+ 1.0, "ScHypGeomDist: wrong assertion" );
1829 lcl_PutFactorialElements( cnNumer
, N
- 2.0*n
, fCNumVarUpper
, N
- n
);
1830 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1833 DBG_ASSERT( fCDenomUpper
<= N
- M
, "ScHypGeomDist: wrong assertion" );
1835 if ( fCDenomUpper
< n
- x
+ 1.0 )
1837 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1841 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1843 fCDenomUpper
= n
- x
;
1844 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1854 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1855 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1859 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1860 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1863 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1865 if ( fCDenomUpper
< n
- x
+ 1.0 )
1867 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1870 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1871 fCDenomUpper
= n
- x
;
1872 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1876 DBG_ASSERT( fCDenomUpper
<= M
, "ScHypGeomDist: wrong assertion" );
1880 if ( N
- M
< M
+ 1.0 )
1884 if ( N
- n
< M
+ 1.0 )
1887 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1888 lcl_PutFactorialElements( cnDenom
, 0.0, N
- M
- 1.0, N
);
1892 lcl_PutFactorialElements( cnNumer
, N
- n
- M
, fCNumVarUpper
, N
- n
);
1893 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1896 if ( n
- x
+ 1.0 > fCDenomUpper
)
1898 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1902 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1904 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1905 fCDenomUpper
= n
- x
;
1912 DBG_ASSERT( M
>= n
- x
, "ScHypGeomDist: wrong assertion" );
1913 DBG_ASSERT( M
- x
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1915 if ( N
- n
< N
- M
+ 1.0 )
1918 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1919 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1924 DBG_ASSERT( fCNumLower
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1926 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1927 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1930 if ( n
- x
+ 1.0 > fCDenomUpper
)
1932 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1933 else if ( M
>= fCDenomUpper
)
1935 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1937 fCDenomUpper
= n
- x
;
1938 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1942 DBG_ASSERT( M
<= fCDenomUpper
, "ScHypGeomDist: wrong assertion" );
1943 lcl_PutFactorialElements( cnDenom
, fCDenomVarLower
, N
- n
- 2.0*M
+ x
,
1944 N
- n
- M
+ x
+ 1.0 );
1946 fCDenomUpper
= n
- x
;
1947 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1951 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1953 fDNumVarLower
= 0.0;
1956 double nDNumVarUpper
= fCDenomUpper
< x
+ 1.0 ? n
- x
- 1.0 : n
- fCDenomUpper
- 1.0;
1957 double nDDenomVarLower
= fCDenomUpper
< x
+ 1.0 ? fCDenomVarLower
: N
- n
- M
+ 1.0;
1958 lcl_PutFactorialElements( cnNumer
, fDNumVarLower
, nDNumVarUpper
, n
);
1959 lcl_PutFactorialElements( cnDenom
, nDDenomVarLower
, N
- n
- M
+ x
, N
- n
- M
+ x
+ 1.0 );
1961 ::std::sort( cnNumer
.begin(), cnNumer
.end() );
1962 ::std::sort( cnDenom
.begin(), cnDenom
.end() );
1963 HypContainer::reverse_iterator it1
= cnNumer
.rbegin(), it1End
= cnNumer
.rend();
1964 HypContainer::reverse_iterator it2
= cnDenom
.rbegin(), it2End
= cnDenom
.rend();
1966 double fFactor
= 1.0;
1967 for ( ; it1
!= it1End
|| it2
!= it2End
; )
1969 double fEnum
= 1.0, fDenom
= 1.0;
1970 if ( it1
!= it1End
)
1972 if ( it2
!= it2End
)
1974 fFactor
*= fEnum
/ fDenom
;
1977 PushDouble(fFactor
);
1980 void ScInterpreter::ScGammaDist()
1982 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGammaDist" );
1983 BYTE nParamCount
= GetByte();
1984 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1987 if (nParamCount
== 4)
1988 bCumulative
= GetBool();
1991 double fBeta
= GetDouble(); // scale
1992 double fAlpha
= GetDouble(); // shape
1993 double fX
= GetDouble(); // x
1994 if (fAlpha
<= 0.0 || fBeta
<= 0.0)
1995 PushIllegalArgument();
1998 if (bCumulative
) // distribution
1999 PushDouble( GetGammaDist( fX
, fAlpha
, fBeta
));
2001 PushDouble( GetGammaDistPDF( fX
, fAlpha
, fBeta
));
2005 void ScInterpreter::ScNormInv()
2007 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNormInv" );
2008 if ( MustHaveParamCount( GetByte(), 3 ) )
2010 double sigma
= GetDouble();
2011 double mue
= GetDouble();
2012 double x
= GetDouble();
2013 if (sigma
<= 0.0 || x
< 0.0 || x
> 1.0)
2014 PushIllegalArgument();
2015 else if (x
== 0.0 || x
== 1.0)
2018 PushDouble(gaussinv(x
)*sigma
+ mue
);
2022 void ScInterpreter::ScSNormInv()
2024 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSNormInv" );
2025 double x
= GetDouble();
2026 if (x
< 0.0 || x
> 1.0)
2027 PushIllegalArgument();
2028 else if (x
== 0.0 || x
== 1.0)
2031 PushDouble(gaussinv(x
));
2034 void ScInterpreter::ScLogNormInv()
2036 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLogNormInv" );
2037 if ( MustHaveParamCount( GetByte(), 3 ) )
2039 double sigma
= GetDouble(); // Stdabw
2040 double mue
= GetDouble(); // Mittelwert
2041 double y
= GetDouble(); // y
2042 if (sigma
<= 0.0 || y
<= 0.0 || y
>= 1.0)
2043 PushIllegalArgument();
2045 PushDouble(exp(mue
+sigma
*gaussinv(y
)));
2049 class ScGammaDistFunction
: public ScDistFunc
2051 ScInterpreter
& rInt
;
2052 double fp
, fAlpha
, fBeta
;
2055 ScGammaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2056 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2058 double GetValue( double x
) const { return fp
- rInt
.GetGammaDist(x
, fAlpha
, fBeta
); }
2061 void ScInterpreter::ScGammaInv()
2063 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGammaInv" );
2064 if ( !MustHaveParamCount( GetByte(), 3 ) )
2066 double fBeta
= GetDouble();
2067 double fAlpha
= GetDouble();
2068 double fP
= GetDouble();
2069 if (fAlpha
<= 0.0 || fBeta
<= 0.0 || fP
< 0.0 || fP
>= 1.0 )
2071 PushIllegalArgument();
2079 ScGammaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2080 double fStart
= fAlpha
* fBeta
;
2081 double fVal
= lcl_IterateInverse( aFunc
, fStart
*0.5, fStart
, bConvError
);
2083 SetError(errNoConvergence
);
2088 class ScBetaDistFunction
: public ScDistFunc
2090 ScInterpreter
& rInt
;
2091 double fp
, fAlpha
, fBeta
;
2094 ScBetaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2095 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2097 double GetValue( double x
) const { return fp
- rInt
.GetBetaDist(x
, fAlpha
, fBeta
); }
2100 void ScInterpreter::ScBetaInv()
2102 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScBetaInv" );
2103 BYTE nParamCount
= GetByte();
2104 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2106 double fP
, fA
, fB
, fAlpha
, fBeta
;
2107 if (nParamCount
== 5)
2111 if (nParamCount
>= 4)
2115 fBeta
= GetDouble();
2116 fAlpha
= GetDouble();
2118 if (fP
< 0.0 || fP
>= 1.0 || fA
== fB
|| fAlpha
<= 0.0 || fBeta
<= 0.0)
2120 PushIllegalArgument();
2128 ScBetaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2129 // 0..1 as range for iteration so it isn't extended beyond the valid range
2130 double fVal
= lcl_IterateInverse( aFunc
, 0.0, 1.0, bConvError
);
2132 PushError( errNoConvergence
);
2134 PushDouble(fA
+ fVal
*(fB
-fA
)); // scale to (A,B)
2138 // Achtung: T, F und Chi
2139 // sind monoton fallend,
2140 // deshalb 1-Dist als Funktion
2142 class ScTDistFunction
: public ScDistFunc
2144 ScInterpreter
& rInt
;
2148 ScTDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2149 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2151 double GetValue( double x
) const { return fp
- 2 * rInt
.GetTDist(x
, fDF
); }
2154 void ScInterpreter::ScTInv()
2156 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTInv" );
2157 if ( !MustHaveParamCount( GetByte(), 2 ) )
2159 double fDF
= ::rtl::math::approxFloor(GetDouble());
2160 double fP
= GetDouble();
2161 if (fDF
< 1.0 || fDF
>= 1.0E5
|| fP
<= 0.0 || fP
> 1.0 )
2163 PushIllegalArgument();
2168 ScTDistFunction
aFunc( *this, fP
, fDF
);
2169 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2171 SetError(errNoConvergence
);
2175 class ScFDistFunction
: public ScDistFunc
2177 ScInterpreter
& rInt
;
2178 double fp
, fF1
, fF2
;
2181 ScFDistFunction( ScInterpreter
& rI
, double fpVal
, double fF1Val
, double fF2Val
) :
2182 rInt(rI
), fp(fpVal
), fF1(fF1Val
), fF2(fF2Val
) {}
2184 double GetValue( double x
) const { return fp
- rInt
.GetFDist(x
, fF1
, fF2
); }
2187 void ScInterpreter::ScFInv()
2189 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFInv" );
2190 if ( !MustHaveParamCount( GetByte(), 3 ) )
2192 double fF2
= ::rtl::math::approxFloor(GetDouble());
2193 double fF1
= ::rtl::math::approxFloor(GetDouble());
2194 double fP
= GetDouble();
2195 if (fP
<= 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
|| fP
> 1.0)
2197 PushIllegalArgument();
2202 ScFDistFunction
aFunc( *this, fP
, fF1
, fF2
);
2203 double fVal
= lcl_IterateInverse( aFunc
, fF1
*0.5, fF1
, bConvError
);
2205 SetError(errNoConvergence
);
2209 class ScChiDistFunction
: public ScDistFunc
2211 ScInterpreter
& rInt
;
2215 ScChiDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2216 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2218 double GetValue( double x
) const { return fp
- rInt
.GetChiDist(x
, fDF
); }
2221 void ScInterpreter::ScChiInv()
2223 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScChiInv" );
2224 if ( !MustHaveParamCount( GetByte(), 2 ) )
2226 double fDF
= ::rtl::math::approxFloor(GetDouble());
2227 double fP
= GetDouble();
2228 if (fDF
< 1.0 || fP
<= 0.0 || fP
> 1.0 )
2230 PushIllegalArgument();
2235 ScChiDistFunction
aFunc( *this, fP
, fDF
);
2236 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2238 SetError(errNoConvergence
);
2242 /***********************************************/
2243 class ScChiSqDistFunction
: public ScDistFunc
2245 ScInterpreter
& rInt
;
2249 ScChiSqDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2250 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2252 double GetValue( double x
) const { return fp
- rInt
.GetChiSqDistCDF(x
, fDF
); }
2256 void ScInterpreter::ScChiSqInv()
2258 if ( !MustHaveParamCount( GetByte(), 2 ) )
2260 double fDF
= ::rtl::math::approxFloor(GetDouble());
2261 double fP
= GetDouble();
2262 if (fDF
< 1.0 || fP
< 0.0 || fP
>= 1.0 )
2264 PushIllegalArgument();
2269 ScChiSqDistFunction
aFunc( *this, fP
, fDF
);
2270 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2272 SetError(errNoConvergence
);
2277 void ScInterpreter::ScConfidence()
2279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScConfidence" );
2280 if ( MustHaveParamCount( GetByte(), 3 ) )
2282 double n
= ::rtl::math::approxFloor(GetDouble());
2283 double sigma
= GetDouble();
2284 double alpha
= GetDouble();
2285 if (sigma
<= 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || n
< 1.0)
2286 PushIllegalArgument();
2288 PushDouble( gaussinv(1.0-alpha
/2.0) * sigma
/sqrt(n
) );
2292 void ScInterpreter::ScZTest()
2294 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScZTest" );
2295 BYTE nParamCount
= GetByte();
2296 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
2298 double sigma
= 0.0, mue
, x
;
2299 if (nParamCount
== 3)
2301 sigma
= GetDouble();
2304 PushIllegalArgument();
2311 double fSumSqr
= 0.0;
2313 double rValCount
= 0.0;
2314 switch (GetStackType())
2316 case formula::svDouble
:
2320 fSumSqr
+= fVal
*fVal
;
2327 PopSingleRef( aAdr
);
2328 ScBaseCell
* pCell
= GetCell( aAdr
);
2329 if (HasCellValueData(pCell
))
2331 fVal
= GetCellValue( aAdr
, pCell
);
2333 fSumSqr
+= fVal
*fVal
;
2339 case formula::svDoubleRef
:
2342 size_t nRefInList
= 0;
2343 while (nParam
-- > 0)
2347 PopDoubleRef( aRange
, nParam
, nRefInList
);
2348 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2349 if (aValIter
.GetFirst(fVal
, nErr
))
2352 fSumSqr
+= fVal
*fVal
;
2354 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
2357 fSumSqr
+= fVal
*fVal
;
2367 ScMatrixRef pMat
= PopMatrix();
2370 SCSIZE nCount
= pMat
->GetElementCount();
2371 if (pMat
->IsNumeric())
2373 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
2375 fVal
= pMat
->GetDouble(i
);
2377 fSumSqr
+= fVal
* fVal
;
2383 for (SCSIZE i
= 0; i
< nCount
; i
++)
2384 if (!pMat
->IsString(i
))
2386 fVal
= pMat
->GetDouble(i
);
2388 fSumSqr
+= fVal
* fVal
;
2395 default : SetError(errIllegalParameter
); break;
2397 if (rValCount
<= 1.0)
2398 PushError( errDivisionByZero
);
2401 mue
= fSum
/rValCount
;
2402 if (nParamCount
!= 3)
2404 sigma
= (fSumSqr
- fSum
*fSum
/rValCount
)/(rValCount
-1.0);
2405 PushDouble(0.5 - gauss((mue
-x
)/sqrt(sigma
/rValCount
)));
2408 PushDouble(0.5 - gauss((mue
-x
)*sqrt(rValCount
)/sigma
));
2411 bool ScInterpreter::CalculateTest(BOOL _bTemplin
2412 ,const SCSIZE nC1
, const SCSIZE nC2
,const SCSIZE nR1
,const SCSIZE nR2
2413 ,const ScMatrixRef
& pMat1
,const ScMatrixRef
& pMat2
2414 ,double& fT
,double& fF
)
2416 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculateTest" );
2417 double fCount1
= 0.0;
2418 double fCount2
= 0.0;
2420 double fSumSqr1
= 0.0;
2422 double fSumSqr2
= 0.0;
2425 for (i
= 0; i
< nC1
; i
++)
2426 for (j
= 0; j
< nR1
; j
++)
2428 if (!pMat1
->IsString(i
,j
))
2430 fVal
= pMat1
->GetDouble(i
,j
);
2432 fSumSqr1
+= fVal
* fVal
;
2436 for (i
= 0; i
< nC2
; i
++)
2437 for (j
= 0; j
< nR2
; j
++)
2439 if (!pMat2
->IsString(i
,j
))
2441 fVal
= pMat2
->GetDouble(i
,j
);
2443 fSumSqr2
+= fVal
* fVal
;
2447 if (fCount1
< 2.0 || fCount2
< 2.0)
2451 } // if (fCount1 < 2.0 || fCount2 < 2.0)
2454 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0)/fCount1
;
2455 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0)/fCount2
;
2456 if (fS1
+ fS2
== 0.0)
2461 fT
= fabs(fSum1
/fCount1
- fSum2
/fCount2
)/sqrt(fS1
+fS2
);
2462 double c
= fS1
/(fS1
+fS2
);
2463 // s.u. fF = ::rtl::math::approxFloor(1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0)));
2464 // fF = ::rtl::math::approxFloor((fS1+fS2)*(fS1+fS2)/(fS1*fS1/(fCount1-1.0) + fS2*fS2/(fCount2-1.0)));
2466 // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen
2467 // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#):
2468 fF
= 1.0/(c
*c
/(fCount1
-1.0)+(1.0-c
)*(1.0-c
)/(fCount2
-1.0));
2472 // laut Bronstein-Semendjajew
2473 double fS1
= (fSumSqr1
- fSum1
*fSum1
/fCount1
) / (fCount1
- 1.0); // Varianz
2474 double fS2
= (fSumSqr2
- fSum2
*fSum2
/fCount2
) / (fCount2
- 1.0);
2475 fT
= fabs( fSum1
/fCount1
- fSum2
/fCount2
) /
2476 sqrt( (fCount1
-1.0)*fS1
+ (fCount2
-1.0)*fS2
) *
2477 sqrt( fCount1
*fCount2
*(fCount1
+fCount2
-2)/(fCount1
+fCount2
) );
2478 fF
= fCount1
+ fCount2
- 2;
2482 void ScInterpreter::ScTTest()
2484 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTTest" );
2485 if ( !MustHaveParamCount( GetByte(), 4 ) )
2487 double fTyp
= ::rtl::math::approxFloor(GetDouble());
2488 double fAnz
= ::rtl::math::approxFloor(GetDouble());
2489 if (fAnz
!= 1.0 && fAnz
!= 2.0)
2491 PushIllegalArgument();
2495 ScMatrixRef pMat2
= GetMatrix();
2496 ScMatrixRef pMat1
= GetMatrix();
2497 if (!pMat1
|| !pMat2
)
2499 PushIllegalParameter();
2506 pMat1
->GetDimensions(nC1
, nR1
);
2507 pMat2
->GetDimensions(nC2
, nR2
);
2510 if (nC1
!= nC2
|| nR1
!= nR2
)
2512 PushIllegalArgument();
2515 double fCount
= 0.0;
2518 double fSumSqrD
= 0.0;
2519 double fVal1
, fVal2
;
2520 for (i
= 0; i
< nC1
; i
++)
2521 for (j
= 0; j
< nR1
; j
++)
2523 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2525 fVal1
= pMat1
->GetDouble(i
,j
);
2526 fVal2
= pMat2
->GetDouble(i
,j
);
2529 fSumSqrD
+= (fVal1
- fVal2
)*(fVal1
- fVal2
);
2538 fT
= sqrt(fCount
-1.0) * fabs(fSum1
- fSum2
) /
2539 sqrt(fCount
* fSumSqrD
- (fSum1
-fSum2
)*(fSum1
-fSum2
));
2542 else if (fTyp
== 2.0)
2544 CalculateTest(FALSE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2546 else if (fTyp
== 3.0)
2548 CalculateTest(TRUE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2553 PushIllegalArgument();
2557 PushDouble(GetTDist(fT
, fF
));
2559 PushDouble(2.0*GetTDist(fT
, fF
));
2562 void ScInterpreter::ScFTest()
2564 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFTest" );
2565 if ( !MustHaveParamCount( GetByte(), 2 ) )
2567 ScMatrixRef pMat2
= GetMatrix();
2568 ScMatrixRef pMat1
= GetMatrix();
2569 if (!pMat1
|| !pMat2
)
2571 PushIllegalParameter();
2577 pMat1
->GetDimensions(nC1
, nR1
);
2578 pMat2
->GetDimensions(nC2
, nR2
);
2579 double fCount1
= 0.0;
2580 double fCount2
= 0.0;
2582 double fSumSqr1
= 0.0;
2584 double fSumSqr2
= 0.0;
2586 for (i
= 0; i
< nC1
; i
++)
2587 for (j
= 0; j
< nR1
; j
++)
2589 if (!pMat1
->IsString(i
,j
))
2591 fVal
= pMat1
->GetDouble(i
,j
);
2593 fSumSqr1
+= fVal
* fVal
;
2597 for (i
= 0; i
< nC2
; i
++)
2598 for (j
= 0; j
< nR2
; j
++)
2600 if (!pMat2
->IsString(i
,j
))
2602 fVal
= pMat2
->GetDouble(i
,j
);
2604 fSumSqr2
+= fVal
* fVal
;
2608 if (fCount1
< 2.0 || fCount2
< 2.0)
2613 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0);
2614 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0);
2615 if (fS1
== 0.0 || fS2
== 0.0)
2620 double fF
, fF1
, fF2
;
2633 PushDouble(2.0*GetFDist(fF
, fF1
, fF2
));
2635 double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
2636 sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
2637 PushDouble(1.0-2.0*gauss(Z));
2641 void ScInterpreter::ScChiTest()
2643 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScChiTest" );
2644 if ( !MustHaveParamCount( GetByte(), 2 ) )
2646 ScMatrixRef pMat2
= GetMatrix();
2647 ScMatrixRef pMat1
= GetMatrix();
2648 if (!pMat1
|| !pMat2
)
2650 PushIllegalParameter();
2655 pMat1
->GetDimensions(nC1
, nR1
);
2656 pMat2
->GetDimensions(nC2
, nR2
);
2657 if (nR1
!= nR2
|| nC1
!= nC2
)
2659 PushIllegalArgument();
2663 for (SCSIZE i
= 0; i
< nC1
; i
++)
2665 for (SCSIZE j
= 0; j
< nR1
; j
++)
2667 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2669 double fValX
= pMat1
->GetDouble(i
,j
);
2670 double fValE
= pMat2
->GetDouble(i
,j
);
2671 fChi
+= (fValX
- fValE
) * (fValX
- fValE
) / fValE
;
2675 PushIllegalArgument();
2681 if (nC1
== 1 || nR1
== 1)
2683 fDF
= (double)(nC1
*nR1
- 1);
2691 fDF
= (double)(nC1
-1)*(double)(nR1
-1);
2692 PushDouble(GetChiDist(fChi
, fDF
));
2694 double fX, fS, fT, fG;
2696 for (double fi = fDF; fi >= 2.0; fi -= 2.0)
2698 fX *= exp(-fChi/2.0);
2699 if (fmod(fDF, 2.0) != 0.0)
2700 fX *= sqrt(2.0*fChi/F_PI);
2704 while (fT >= 1.0E-7)
2710 PushDouble(1.0 - fX*fS);
2714 void ScInterpreter::ScKurt()
2716 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScKurt" );
2717 double fSum
,fCount
,vSum
;
2718 std::vector
<double> values
;
2719 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
2724 PushError( errDivisionByZero
);
2728 double fMean
= fSum
/ fCount
;
2730 for (size_t i
= 0; i
< values
.size(); i
++)
2731 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
2733 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
2735 double xpower4
= 0.0;
2739 PushError( errDivisionByZero
);
2743 for (size_t i
= 0; i
< values
.size(); i
++)
2745 dx
= (values
[i
] - fMean
) / fStdDev
;
2746 xpower4
= xpower4
+ (dx
* dx
* dx
* dx
);
2749 double k_d
= (fCount
- 2.0) * (fCount
- 3.0);
2750 double k_l
= fCount
* (fCount
+ 1.0) / ((fCount
- 1.0) * k_d
);
2751 double k_t
= 3.0 * (fCount
- 1.0) * (fCount
- 1.0) / k_d
;
2753 PushDouble(xpower4
* k_l
- k_t
);
2756 void ScInterpreter::ScHarMean()
2758 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScHarMean" );
2759 short nParamCount
= GetByte();
2761 double nValCount
= 0.0;
2764 size_t nRefInList
= 0;
2765 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2767 switch (GetStackType())
2769 case formula::svDouble
:
2771 double x
= GetDouble();
2778 SetError( errIllegalArgument
);
2783 PopSingleRef( aAdr
);
2784 ScBaseCell
* pCell
= GetCell( aAdr
);
2785 if (HasCellValueData(pCell
))
2787 double x
= GetCellValue( aAdr
, pCell
);
2794 SetError( errIllegalArgument
);
2798 case formula::svDoubleRef
:
2802 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2804 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2805 if (aValIter
.GetFirst(nCellVal
, nErr
))
2809 nVal
+= 1.0/nCellVal
;
2813 SetError( errIllegalArgument
);
2815 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2819 nVal
+= 1.0/nCellVal
;
2823 SetError( errIllegalArgument
);
2831 ScMatrixRef pMat
= PopMatrix();
2834 SCSIZE nCount
= pMat
->GetElementCount();
2835 if (pMat
->IsNumeric())
2837 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2839 double x
= pMat
->GetDouble(nElem
);
2846 SetError( errIllegalArgument
);
2851 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2852 if (!pMat
->IsString(nElem
))
2854 double x
= pMat
->GetDouble(nElem
);
2861 SetError( errIllegalArgument
);
2867 default : SetError(errIllegalParameter
); break;
2870 if (nGlobalError
== 0)
2871 PushDouble((double)nValCount
/nVal
);
2873 PushError( nGlobalError
);
2876 void ScInterpreter::ScGeoMean()
2878 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGeoMean" );
2879 short nParamCount
= GetByte();
2881 double nValCount
= 0.0;
2885 size_t nRefInList
= 0;
2886 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2888 switch (GetStackType())
2890 case formula::svDouble
:
2892 double x
= GetDouble();
2899 SetError( errIllegalArgument
);
2904 PopSingleRef( aAdr
);
2905 ScBaseCell
* pCell
= GetCell( aAdr
);
2906 if (HasCellValueData(pCell
))
2908 double x
= GetCellValue( aAdr
, pCell
);
2915 SetError( errIllegalArgument
);
2919 case formula::svDoubleRef
:
2923 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2925 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2926 if (aValIter
.GetFirst(nCellVal
, nErr
))
2930 nVal
+= log(nCellVal
);
2934 SetError( errIllegalArgument
);
2936 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2940 nVal
+= log(nCellVal
);
2944 SetError( errIllegalArgument
);
2952 ScMatrixRef pMat
= PopMatrix();
2955 SCSIZE nCount
= pMat
->GetElementCount();
2956 if (pMat
->IsNumeric())
2958 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2960 double x
= pMat
->GetDouble(ui
);
2967 SetError( errIllegalArgument
);
2972 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2973 if (!pMat
->IsString(ui
))
2975 double x
= pMat
->GetDouble(ui
);
2982 SetError( errIllegalArgument
);
2988 default : SetError(errIllegalParameter
); break;
2991 if (nGlobalError
== 0)
2992 PushDouble(exp(nVal
/ nValCount
));
2994 PushError( nGlobalError
);
2997 void ScInterpreter::ScStandard()
2999 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScStandard" );
3000 if ( MustHaveParamCount( GetByte(), 3 ) )
3002 double sigma
= GetDouble();
3003 double mue
= GetDouble();
3004 double x
= GetDouble();
3006 PushError( errIllegalArgument
);
3007 else if (sigma
== 0.0)
3008 PushError( errDivisionByZero
);
3010 PushDouble((x
-mue
)/sigma
);
3013 bool ScInterpreter::CalculateSkew(double& fSum
,double& fCount
,double& vSum
,std::vector
<double>& values
)
3015 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculateSkew" );
3016 short nParamCount
= GetByte();
3017 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3026 size_t nRefInList
= 0;
3027 while (nParamCount
-- > 0)
3029 switch (GetStackType())
3031 case formula::svDouble
:
3035 values
.push_back(fVal
);
3041 PopSingleRef( aAdr
);
3042 ScBaseCell
* pCell
= GetCell( aAdr
);
3043 if (HasCellValueData(pCell
))
3045 fVal
= GetCellValue( aAdr
, pCell
);
3047 values
.push_back(fVal
);
3052 case formula::svDoubleRef
:
3055 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3057 ScValueIterator
aValIter(pDok
, aRange
);
3058 if (aValIter
.GetFirst(fVal
, nErr
))
3061 values
.push_back(fVal
);
3064 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
3067 values
.push_back(fVal
);
3076 ScMatrixRef pMat
= PopMatrix();
3079 SCSIZE nCount
= pMat
->GetElementCount();
3080 if (pMat
->IsNumeric())
3082 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3084 fVal
= pMat
->GetDouble(nElem
);
3086 values
.push_back(fVal
);
3092 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3093 if (!pMat
->IsString(nElem
))
3095 fVal
= pMat
->GetDouble(nElem
);
3097 values
.push_back(fVal
);
3105 SetError(errIllegalParameter
);
3112 PushError( nGlobalError
);
3114 } // if (nGlobalError)
3118 void ScInterpreter::ScSkew()
3120 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSkew" );
3121 double fSum
,fCount
,vSum
;
3122 std::vector
<double> values
;
3123 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
3126 double fMean
= fSum
/ fCount
;
3128 for (size_t i
= 0; i
< values
.size(); i
++)
3129 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
3131 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
3137 PushIllegalArgument();
3141 for (size_t i
= 0; i
< values
.size(); i
++)
3143 dx
= (values
[i
] - fMean
) / fStdDev
;
3144 xcube
= xcube
+ (dx
* dx
* dx
);
3147 PushDouble(((xcube
* fCount
) / (fCount
- 1.0)) / (fCount
- 2.0));
3150 double ScInterpreter::GetMedian( vector
<double> & rArray
)
3152 size_t nSize
= rArray
.size();
3153 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3155 SetError( errNoValue
);
3160 size_t nMid
= nSize
/ 2;
3161 vector
<double>::iterator iMid
= rArray
.begin() + nMid
;
3162 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3164 return *iMid
; // Lower and upper median are equal.
3169 iMid
= rArray
.begin() + nMid
- 1;
3170 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3171 return (fUp
+ *iMid
) / 2;
3175 void ScInterpreter::ScMedian()
3177 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMedian" );
3178 BYTE nParamCount
= GetByte();
3179 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3181 vector
<double> aArray
;
3182 GetNumberSequenceArray( nParamCount
, aArray
);
3183 PushDouble( GetMedian( aArray
));
3186 double ScInterpreter::GetPercentile( vector
<double> & rArray
, double fPercentile
)
3188 size_t nSize
= rArray
.size();
3189 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3191 SetError( errNoValue
);
3199 size_t nIndex
= (size_t)::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3200 double fDiff
= fPercentile
* (nSize
-1) - ::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3201 DBG_ASSERT(nIndex
< nSize
, "GetPercentile: wrong index(1)");
3202 vector
<double>::iterator iter
= rArray
.begin() + nIndex
;
3203 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3208 DBG_ASSERT(nIndex
< nSize
-1, "GetPercentile: wrong index(2)");
3209 double fVal
= *iter
;
3210 iter
= rArray
.begin() + nIndex
+1;
3211 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3212 return fVal
+ fDiff
* (*iter
- fVal
);
3217 void ScInterpreter::ScPercentile()
3219 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPercentile" );
3220 if ( !MustHaveParamCount( GetByte(), 2 ) )
3222 double alpha
= GetDouble();
3223 if (alpha
< 0.0 || alpha
> 1.0)
3225 PushIllegalArgument();
3228 vector
<double> aArray
;
3229 GetNumberSequenceArray( 1, aArray
);
3230 PushDouble( GetPercentile( aArray
, alpha
));
3233 void ScInterpreter::ScQuartile()
3235 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScQuartile" );
3236 if ( !MustHaveParamCount( GetByte(), 2 ) )
3238 double fFlag
= ::rtl::math::approxFloor(GetDouble());
3239 if (fFlag
< 0.0 || fFlag
> 4.0)
3241 PushIllegalArgument();
3244 vector
<double> aArray
;
3245 GetNumberSequenceArray( 1, aArray
);
3246 PushDouble( fFlag
== 2.0 ? GetMedian( aArray
) : GetPercentile( aArray
, 0.25 * fFlag
));
3249 void ScInterpreter::ScModalValue()
3251 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScModalValue" );
3252 BYTE nParamCount
= GetByte();
3253 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3255 vector
<double> aSortArray
;
3256 GetSortArray(nParamCount
, aSortArray
);
3257 SCSIZE nSize
= aSortArray
.size();
3258 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3262 SCSIZE nMaxIndex
= 0, nMax
= 1, nCount
= 1;
3263 double nOldVal
= aSortArray
[0];
3266 for ( i
= 1; i
< nSize
; i
++)
3268 if (aSortArray
[i
] == nOldVal
)
3272 nOldVal
= aSortArray
[i
];
3286 if (nMax
== 1 && nCount
== 1)
3289 PushDouble(nOldVal
);
3291 PushDouble(aSortArray
[nMaxIndex
]);
3295 void ScInterpreter::CalculateSmallLarge(BOOL bSmall
)
3297 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculateSmallLarge" );
3298 if ( !MustHaveParamCount( GetByte(), 2 ) )
3300 double f
= ::rtl::math::approxFloor(GetDouble());
3303 PushIllegalArgument();
3306 SCSIZE k
= static_cast<SCSIZE
>(f
);
3307 vector
<double> aSortArray
;
3308 /* TODO: using nth_element() is best for one single value, but LARGE/SMALL
3309 * actually are defined to return an array of values if an array of
3310 * positions was passed, in which case, depending on the number of values,
3311 * we may or will need a real sorted array again, see #i32345. */
3312 //GetSortArray(1, aSortArray);
3313 GetNumberSequenceArray(1, aSortArray
);
3314 SCSIZE nSize
= aSortArray
.size();
3315 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
|| nSize
< k
)
3319 // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] );
3320 vector
<double>::iterator iPos
= aSortArray
.begin() + (bSmall
? k
-1 : nSize
-k
);
3321 ::std::nth_element( aSortArray
.begin(), iPos
, aSortArray
.end());
3326 void ScInterpreter::ScLarge()
3328 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLarge" );
3329 CalculateSmallLarge(FALSE
);
3332 void ScInterpreter::ScSmall()
3334 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSmall" );
3335 CalculateSmallLarge(TRUE
);
3338 void ScInterpreter::ScPercentrank()
3340 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPercentrank" );
3341 BYTE nParamCount
= GetByte();
3342 if ( !MustHaveParamCount( nParamCount
, 2 ) )
3345 /* wird nicht unterstuetzt
3347 if (nParamCount == 3)
3349 fPrec = ::rtl::math::approxFloor(GetDouble());
3352 PushIllegalArgument();
3360 double fNum
= GetDouble();
3361 vector
<double> aSortArray
;
3362 GetSortArray(1, aSortArray
);
3363 SCSIZE nSize
= aSortArray
.size();
3364 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3368 if (fNum
< aSortArray
[0] || fNum
> aSortArray
[nSize
-1])
3370 else if ( nSize
== 1 )
3371 PushDouble(1.0); // fNum == pSortArray[0], see test above
3375 SCSIZE nOldCount
= 0;
3376 double fOldVal
= aSortArray
[0];
3378 for (i
= 1; i
< nSize
&& aSortArray
[i
] < fNum
; i
++)
3380 if (aSortArray
[i
] != fOldVal
)
3383 fOldVal
= aSortArray
[i
];
3386 if (aSortArray
[i
] != fOldVal
)
3388 if (fNum
== aSortArray
[i
])
3389 fRes
= (double)nOldCount
/(double)(nSize
-1);
3392 // #75312# nOldCount is the count of smaller entries
3393 // fNum is between pSortArray[nOldCount-1] and pSortArray[nOldCount]
3394 // use linear interpolation to find a position between the entries
3396 if ( nOldCount
== 0 )
3398 DBG_ERROR("should not happen");
3403 double fFract
= ( fNum
- aSortArray
[nOldCount
-1] ) /
3404 ( aSortArray
[nOldCount
] - aSortArray
[nOldCount
-1] );
3405 fRes
= ( (double)(nOldCount
-1)+fFract
)/(double)(nSize
-1);
3413 void ScInterpreter::ScTrimMean()
3415 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTrimMean" );
3416 if ( !MustHaveParamCount( GetByte(), 2 ) )
3418 double alpha
= GetDouble();
3419 if (alpha
< 0.0 || alpha
>= 1.0)
3421 PushIllegalArgument();
3424 vector
<double> aSortArray
;
3425 GetSortArray(1, aSortArray
);
3426 SCSIZE nSize
= aSortArray
.size();
3427 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3431 ULONG nIndex
= (ULONG
) ::rtl::math::approxFloor(alpha
*(double)nSize
);
3432 if (nIndex
% 2 != 0)
3435 DBG_ASSERT(nIndex
< nSize
, "ScTrimMean: falscher Index");
3437 for (SCSIZE i
= nIndex
; i
< nSize
-nIndex
; i
++)
3438 fSum
+= aSortArray
[i
];
3439 PushDouble(fSum
/(double)(nSize
-2*nIndex
));
3443 void ScInterpreter::GetNumberSequenceArray( BYTE nParamCount
, vector
<double>& rArray
)
3445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetSortArray" );
3448 short nParam
= nParamCount
;
3449 size_t nRefInList
= 0;
3450 while (nParam
-- > 0)
3452 switch (GetStackType())
3454 case formula::svDouble
:
3455 rArray
.push_back( PopDouble());
3459 PopSingleRef( aAdr
);
3460 ScBaseCell
* pCell
= GetCell( aAdr
);
3461 if (HasCellValueData(pCell
))
3462 rArray
.push_back( GetCellValue( aAdr
, pCell
));
3465 case formula::svDoubleRef
:
3468 PopDoubleRef( aRange
, nParam
, nRefInList
);
3473 SCSIZE nCellCount
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
3474 nCellCount
*= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
3475 rArray
.reserve( rArray
.size() + nCellCount
);
3479 ScValueIterator
aValIter(pDok
, aRange
);
3480 if (aValIter
.GetFirst( fCellVal
, nErr
))
3482 rArray
.push_back( fCellVal
);
3484 while ((nErr
== 0) && aValIter
.GetNext( fCellVal
, nErr
))
3485 rArray
.push_back( fCellVal
);
3492 ScMatrixRef pMat
= PopMatrix();
3496 SCSIZE nCount
= pMat
->GetElementCount();
3497 rArray
.reserve( rArray
.size() + nCount
);
3498 if (pMat
->IsNumeric())
3500 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3501 rArray
.push_back( pMat
->GetDouble(i
));
3505 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3506 if (!pMat
->IsString(i
))
3507 rArray
.push_back( pMat
->GetDouble(i
));
3513 SetError( errIllegalParameter
);
3519 // nParam > 0 in case of error, clean stack environment and obtain earlier
3520 // error if there was one.
3521 while (nParam
-- > 0)
3525 void ScInterpreter::GetSortArray( BYTE nParamCount
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3527 GetNumberSequenceArray( nParamCount
, rSortArray
);
3529 if (rSortArray
.size() > MAX_ANZ_DOUBLE_FOR_SORT
)
3530 SetError( errStackOverflow
);
3531 else if (rSortArray
.empty())
3532 SetError( errNoValue
);
3534 if (nGlobalError
== 0)
3535 QuickSort( rSortArray
, pIndexOrder
);
3538 static void lcl_QuickSort( long nLo
, long nHi
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3540 // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
3546 if (rSortArray
[nLo
] > rSortArray
[nHi
])
3548 swap(rSortArray
[nLo
], rSortArray
[nHi
]);
3550 swap(pIndexOrder
->at(nLo
), pIndexOrder
->at(nHi
));
3559 double fLo
= rSortArray
[nLo
];
3560 while (ni
<= nHi
&& rSortArray
[ni
] < fLo
) ni
++;
3561 while (nj
>= nLo
&& fLo
< rSortArray
[nj
]) nj
--;
3566 swap(rSortArray
[ni
], rSortArray
[nj
]);
3568 swap(pIndexOrder
->at(ni
), pIndexOrder
->at(nj
));
3577 if ((nj
- nLo
) < (nHi
- ni
))
3579 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3580 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3584 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3585 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3589 void ScInterpreter::QuickSort( vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3591 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::QuickSort" );
3592 long n
= static_cast<long>(rSortArray
.size());
3596 pIndexOrder
->clear();
3597 pIndexOrder
->reserve(n
);
3598 for (long i
= 0; i
< n
; ++i
)
3599 pIndexOrder
->push_back(i
);
3605 size_t nValCount
= rSortArray
.size();
3606 for (size_t i
= 0; (i
+ 4) <= nValCount
-1; i
+= 4)
3608 size_t nInd
= rand() % (int) (nValCount
-1);
3609 ::std::swap( rSortArray
[i
], rSortArray
[nInd
]);
3611 ::std::swap( pIndexOrder
->at(i
), pIndexOrder
->at(nInd
));
3614 lcl_QuickSort(0, n
-1, rSortArray
, pIndexOrder
);
3617 void ScInterpreter::ScRank()
3619 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRank" );
3620 BYTE nParamCount
= GetByte();
3621 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
3624 if (nParamCount
== 3)
3625 bDescending
= GetBool();
3627 bDescending
= FALSE
;
3628 double fCount
= 1.0;
3629 BOOL bValid
= FALSE
;
3630 switch (GetStackType())
3632 case formula::svDouble
:
3634 double x
= GetDouble();
3635 double fVal
= GetDouble();
3643 PopSingleRef( aAdr
);
3644 double fVal
= GetDouble();
3645 ScBaseCell
* pCell
= GetCell( aAdr
);
3646 if (HasCellValueData(pCell
))
3648 double x
= GetCellValue( aAdr
, pCell
);
3654 case formula::svDoubleRef
:
3659 size_t nRefInList
= 0;
3660 while (nParam
-- > 0)
3663 // Preserve stack until all RefList elements are done!
3664 USHORT nSaveSP
= sp
;
3665 PopDoubleRef( aRange
, nParam
, nRefInList
);
3667 --sp
; // simulate pop
3668 double fVal
= GetDouble();
3672 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
3673 if (aValIter
.GetFirst(nCellVal
, nErr
))
3675 if (nCellVal
== fVal
)
3677 else if ((!bDescending
&& nCellVal
> fVal
) ||
3678 (bDescending
&& nCellVal
< fVal
) )
3681 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3683 if (nCellVal
== fVal
)
3685 else if ((!bDescending
&& nCellVal
> fVal
) ||
3686 (bDescending
&& nCellVal
< fVal
) )
3696 ScMatrixRef pMat
= PopMatrix();
3697 double fVal
= GetDouble();
3700 SCSIZE nCount
= pMat
->GetElementCount();
3701 if (pMat
->IsNumeric())
3703 for (SCSIZE i
= 0; i
< nCount
; i
++)
3705 double x
= pMat
->GetDouble(i
);
3708 else if ((!bDescending
&& x
> fVal
) ||
3709 (bDescending
&& x
< fVal
) )
3715 for (SCSIZE i
= 0; i
< nCount
; i
++)
3716 if (!pMat
->IsString(i
))
3718 double x
= pMat
->GetDouble(i
);
3721 else if ((!bDescending
&& x
> fVal
) ||
3722 (bDescending
&& x
< fVal
) )
3729 default : SetError(errIllegalParameter
); break;
3737 void ScInterpreter::ScAveDev()
3739 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAveDev" );
3740 BYTE nParamCount
= GetByte();
3741 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3744 double nMiddle
= 0.0;
3746 double rValCount
= 0.0;
3749 short nParam
= nParamCount
;
3750 size_t nRefInList
= 0;
3751 while (nParam
-- > 0)
3753 switch (GetStackType())
3755 case formula::svDouble
:
3756 rVal
+= GetDouble();
3761 PopSingleRef( aAdr
);
3762 ScBaseCell
* pCell
= GetCell( aAdr
);
3763 if (HasCellValueData(pCell
))
3765 rVal
+= GetCellValue( aAdr
, pCell
);
3770 case formula::svDoubleRef
:
3775 PopDoubleRef( aRange
, nParam
, nRefInList
);
3776 ScValueIterator
aValIter(pDok
, aRange
);
3777 if (aValIter
.GetFirst(nCellVal
, nErr
))
3782 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3793 ScMatrixRef pMat
= PopMatrix();
3796 SCSIZE nCount
= pMat
->GetElementCount();
3797 if (pMat
->IsNumeric())
3799 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3801 rVal
+= pMat
->GetDouble(nElem
);
3807 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3808 if (!pMat
->IsString(nElem
))
3810 rVal
+= pMat
->GetDouble(nElem
);
3818 SetError(errIllegalParameter
);
3824 PushError( nGlobalError
);
3827 nMiddle
= rVal
/ rValCount
;
3830 nParam
= nParamCount
;
3832 while (nParam
-- > 0)
3834 switch (GetStackType())
3836 case formula::svDouble
:
3837 rVal
+= fabs(GetDouble() - nMiddle
);
3841 PopSingleRef( aAdr
);
3842 ScBaseCell
* pCell
= GetCell( aAdr
);
3843 if (HasCellValueData(pCell
))
3844 rVal
+= fabs(GetCellValue( aAdr
, pCell
) - nMiddle
);
3847 case formula::svDoubleRef
:
3852 PopDoubleRef( aRange
, nParam
, nRefInList
);
3853 ScValueIterator
aValIter(pDok
, aRange
);
3854 if (aValIter
.GetFirst(nCellVal
, nErr
))
3856 rVal
+= (fabs(nCellVal
- nMiddle
));
3857 while (aValIter
.GetNext(nCellVal
, nErr
))
3858 rVal
+= fabs(nCellVal
- nMiddle
);
3864 ScMatrixRef pMat
= PopMatrix();
3867 SCSIZE nCount
= pMat
->GetElementCount();
3868 if (pMat
->IsNumeric())
3870 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3872 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3877 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3879 if (!pMat
->IsString(nElem
))
3880 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3886 default : SetError(errIllegalParameter
); break;
3889 PushDouble(rVal
/ rValCount
);
3892 void ScInterpreter::ScDevSq()
3894 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDevSq" );
3897 GetStVarParams(nVal
, nValCount
);
3901 void ScInterpreter::ScProbability()
3903 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScProbability" );
3904 BYTE nParamCount
= GetByte();
3905 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
3909 if (nParamCount
== 4)
3919 ScMatrixRef pMatP
= GetMatrix();
3920 ScMatrixRef pMatW
= GetMatrix();
3921 if (!pMatP
|| !pMatW
)
3922 PushIllegalParameter();
3927 pMatP
->GetDimensions(nC1
, nR1
);
3928 pMatW
->GetDimensions(nC2
, nR2
);
3929 if (nC1
!= nC2
|| nR1
!= nR2
|| nC1
== 0 || nR1
== 0 ||
3930 nC2
== 0 || nR2
== 0)
3938 SCSIZE nCount1
= nC1
* nR1
;
3939 for ( SCSIZE i
= 0; i
< nCount1
&& !bStop
; i
++ )
3941 if (pMatP
->IsValue(i
) && pMatW
->IsValue(i
))
3943 fP
= pMatP
->GetDouble(i
);
3944 fW
= pMatW
->GetDouble(i
);
3945 if (fP
< 0.0 || fP
> 1.0)
3950 if (fW
>= fLo
&& fW
<= fUp
)
3955 SetError( errIllegalArgument
);
3957 if (bStop
|| fabs(fSum
-1.0) > 1.0E-7)
3965 void ScInterpreter::ScCorrel()
3967 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCorrel" );
3968 // This is identical to ScPearson()
3972 void ScInterpreter::ScCovar()
3974 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCovar" );
3975 CalculatePearsonCovar(FALSE
,FALSE
);
3978 void ScInterpreter::ScPearson()
3980 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPearson" );
3981 CalculatePearsonCovar(TRUE
,FALSE
);
3983 void ScInterpreter::CalculatePearsonCovar(BOOL _bPearson
,BOOL _bStexy
)
3985 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculatePearsonCovar" );
3986 if ( !MustHaveParamCount( GetByte(), 2 ) )
3988 ScMatrixRef pMat1
= GetMatrix();
3989 ScMatrixRef pMat2
= GetMatrix();
3990 if (!pMat1
|| !pMat2
)
3992 PushIllegalParameter();
3997 pMat1
->GetDimensions(nC1
, nR1
);
3998 pMat2
->GetDimensions(nC2
, nR2
);
3999 if (nR1
!= nR2
|| nC1
!= nC2
)
4001 PushIllegalArgument();
4005 * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
4006 * but the latter produces wrong results if the absolute values are high,
4007 * for example above 10^8
4009 double fCount
= 0.0;
4012 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4013 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4014 double fSumSqrDeltaY
= 0.0; // sum of (ValY-MeanY)^2
4015 for (SCSIZE i
= 0; i
< nC1
; i
++)
4017 for (SCSIZE j
= 0; j
< nR1
; j
++)
4019 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4021 double fValX
= pMat1
->GetDouble(i
,j
);
4022 double fValY
= pMat2
->GetDouble(i
,j
);
4029 if (fCount
< (_bStexy
? 3.0 : 1.0)) // fCount==1 is handled by checking denominator later on
4033 const double fMeanX
= fSumX
/ fCount
;
4034 const double fMeanY
= fSumY
/ fCount
;
4035 for (SCSIZE i
= 0; i
< nC1
; i
++)
4037 for (SCSIZE j
= 0; j
< nR1
; j
++)
4039 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4041 const double fValX
= pMat1
->GetDouble(i
,j
);
4042 const double fValY
= pMat2
->GetDouble(i
,j
);
4043 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4046 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4047 fSumSqrDeltaY
+= (fValY
- fMeanY
) * (fValY
- fMeanY
);
4051 } // for (SCSIZE i = 0; i < nC1; i++)
4054 if (fSumSqrDeltaX
== 0.0 || ( !_bStexy
&& fSumSqrDeltaY
== 0.0) )
4055 PushError( errDivisionByZero
);
4057 PushDouble( sqrt( (fSumSqrDeltaY
- fSumDeltaXDeltaY
*
4058 fSumDeltaXDeltaY
/ fSumSqrDeltaX
) / (fCount
-2)));
4060 PushDouble( fSumDeltaXDeltaY
/ sqrt( fSumSqrDeltaX
* fSumSqrDeltaY
));
4061 } // if ( _bPearson )
4064 PushDouble( fSumDeltaXDeltaY
/ fCount
);
4069 void ScInterpreter::ScRSQ()
4071 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRSQ" );
4072 // Same as ScPearson()*ScPearson()
4076 switch (GetStackType())
4078 case formula::svDouble
:
4080 double fVal
= PopDouble();
4081 PushDouble( fVal
* fVal
);
4091 void ScInterpreter::ScSTEXY()
4093 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSTEXY" );
4094 CalculatePearsonCovar(TRUE
,TRUE
);
4096 void ScInterpreter::CalculateSlopeIntercept(BOOL bSlope
)
4098 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculateSlopeIntercept" );
4099 if ( !MustHaveParamCount( GetByte(), 2 ) )
4101 ScMatrixRef pMat1
= GetMatrix();
4102 ScMatrixRef pMat2
= GetMatrix();
4103 if (!pMat1
|| !pMat2
)
4105 PushIllegalParameter();
4110 pMat1
->GetDimensions(nC1
, nR1
);
4111 pMat2
->GetDimensions(nC2
, nR2
);
4112 if (nR1
!= nR2
|| nC1
!= nC2
)
4114 PushIllegalArgument();
4117 // #i78250# numerical stability improved
4118 double fCount
= 0.0;
4121 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4122 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4123 for (SCSIZE i
= 0; i
< nC1
; i
++)
4125 for (SCSIZE j
= 0; j
< nR1
; j
++)
4127 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4129 double fValX
= pMat1
->GetDouble(i
,j
);
4130 double fValY
= pMat2
->GetDouble(i
,j
);
4141 double fMeanX
= fSumX
/ fCount
;
4142 double fMeanY
= fSumY
/ fCount
;
4143 for (SCSIZE i
= 0; i
< nC1
; i
++)
4145 for (SCSIZE j
= 0; j
< nR1
; j
++)
4147 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4149 double fValX
= pMat1
->GetDouble(i
,j
);
4150 double fValY
= pMat2
->GetDouble(i
,j
);
4151 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4152 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4156 if (fSumSqrDeltaX
== 0.0)
4157 PushError( errDivisionByZero
);
4161 PushDouble( fSumDeltaXDeltaY
/ fSumSqrDeltaX
);
4163 PushDouble( fMeanY
- fSumDeltaXDeltaY
/ fSumSqrDeltaX
* fMeanX
);
4168 void ScInterpreter::ScSlope()
4170 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSlope" );
4171 CalculateSlopeIntercept(TRUE
);
4174 void ScInterpreter::ScIntercept()
4176 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIntercept" );
4177 CalculateSlopeIntercept(FALSE
);
4180 void ScInterpreter::ScForecast()
4182 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScForecast" );
4183 if ( !MustHaveParamCount( GetByte(), 3 ) )
4185 ScMatrixRef pMat1
= GetMatrix();
4186 ScMatrixRef pMat2
= GetMatrix();
4187 if (!pMat1
|| !pMat2
)
4189 PushIllegalParameter();
4194 pMat1
->GetDimensions(nC1
, nR1
);
4195 pMat2
->GetDimensions(nC2
, nR2
);
4196 if (nR1
!= nR2
|| nC1
!= nC2
)
4198 PushIllegalArgument();
4201 double fVal
= GetDouble();
4202 // #i78250# numerical stability improved
4203 double fCount
= 0.0;
4206 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4207 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4208 for (SCSIZE i
= 0; i
< nC1
; i
++)
4210 for (SCSIZE j
= 0; j
< nR1
; j
++)
4212 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4214 double fValX
= pMat1
->GetDouble(i
,j
);
4215 double fValY
= pMat2
->GetDouble(i
,j
);
4226 double fMeanX
= fSumX
/ fCount
;
4227 double fMeanY
= fSumY
/ fCount
;
4228 for (SCSIZE i
= 0; i
< nC1
; i
++)
4230 for (SCSIZE j
= 0; j
< nR1
; j
++)
4232 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4234 double fValX
= pMat1
->GetDouble(i
,j
);
4235 double fValY
= pMat2
->GetDouble(i
,j
);
4236 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4237 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4241 if (fSumSqrDeltaX
== 0.0)
4242 PushError( errDivisionByZero
);
4244 PushDouble( fMeanY
+ fSumDeltaXDeltaY
/ fSumSqrDeltaX
* (fVal
- fMeanX
));