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", "Eike.Rathke@sun.com", "ScInterpreter::ScNoName" );
192 PushError(errNoName
);
195 void ScInterpreter::ScBadName()
197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "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", "Eike.Rathke@sun.com", "ScInterpreter::phi" );
209 return 0.39894228040143268 * exp(-(x
* x
) / 2.0);
212 double ScInterpreter::taylor(double* pPolynom
, USHORT nMax
, double x
)
214 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::taylor" );
215 double nVal
= pPolynom
[nMax
];
216 for (short i
= nMax
-1; i
>= 0; i
--)
218 nVal
= pPolynom
[i
] + (nVal
* x
);
223 double ScInterpreter::gauss(double x
)
225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::gauss" );
227 { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
228 -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
229 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
230 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
232 { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
233 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
234 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
235 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
236 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
237 -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
238 -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
239 -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
241 { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
242 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
243 -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
244 -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
245 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
246 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
247 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
248 double asympt
[] = { -1.0, 1.0, -3.0, 15.0, -105.0 };
250 double xAbs
= fabs(x
);
251 USHORT xShort
= (USHORT
)::rtl::math::approxFloor(xAbs
);
254 nVal
= taylor(t0
, 11, (xAbs
* xAbs
)) * xAbs
;
255 else if ((xShort
>= 1) && (xShort
<= 2))
256 nVal
= taylor(t2
, 23, (xAbs
- 2.0));
257 else if ((xShort
>= 3) && (xShort
<= 4))
258 nVal
= taylor(t4
, 20, (xAbs
- 4.0));
260 nVal
= 0.5 + phi(xAbs
) * taylor(asympt
, 4, 1.0 / (xAbs
* xAbs
)) / xAbs
;
268 // #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
271 double ScInterpreter::gaussinv(double x
)
273 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::gaussinv" );
291 t
*2509.0809287301226727+33430.575583588128105
293 *t
+67265.770927008700853
295 *t
+45921.953931549871457
297 *t
+13731.693765509461125
299 *t
+1971.5909503065514427
301 *t
+133.14166789178437745
303 *t
+3.387132872796366608
313 t
*5226.495278852854561+28729.085735721942674
315 *t
+39307.89580009271061
317 *t
+21213.794301586595867
319 *t
+5394.1960214247511077
321 *t
+687.1870074920579083
323 *t
+42.313330701600911252
348 t
*7.7454501427834140764e-4+0.0227238449892691845833
350 *t
+0.24178072517745061177
352 *t
+1.27045825245236838258
354 *t
+3.64784832476320460504
356 *t
+5.7694972214606914055
358 *t
+4.6303378461565452959
360 *t
+1.42343711074968357734
370 t
*1.05075007164441684324e-9+5.475938084995344946e-4
372 *t
+0.0151986665636164571966
374 *t
+0.14810397642748007459
376 *t
+0.68976733498510000455
378 *t
+1.6763848301838038494
380 *t
+2.05319162663775882187
398 t
*2.01033439929228813265e-7+2.71155556874348757815e-5
400 *t
+0.0012426609473880784386
402 *t
+0.026532189526576123093
404 *t
+0.29656057182850489123
406 *t
+1.7848265399172913358
408 *t
+5.4637849111641143699
410 *t
+6.6579046435011037772
420 t
*2.04426310338993978564e-15+1.4215117583164458887e-7
422 *t
+1.8463183175100546818e-5
424 *t
+7.868691311456132591e-4
426 *t
+0.0148753612908506148525
428 *t
+0.13692988092273580531
430 *t
+0.59983220655588793769
443 double ScInterpreter::Fakultaet(double x
)
445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Fakultaet" );
446 x
= ::rtl::math::approxFloor(x
);
461 SetError(errNoValue
);
462 /* // Stirlingsche Naeherung zu ungenau
464 x = pow(x/exp(1), x) * sqrt(x) * SQRT_2_PI * (1.0 + 1.0 / (12.0 * x));
469 double ScInterpreter::BinomKoeff(double n
, double k
)
471 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::BinomKoeff" );
473 k
= ::rtl::math::approxFloor(k
);
490 double f1 = n; // Zaehler
491 double f2 = k; // Nenner
508 // The algorithm is based on lanczos13m53 in lanczos.hpp
509 // in math library from http://www.boost.org
510 /** you must ensure fZ>0
511 Uses a variant of the Lanczos sum with a rational function. */
512 double lcl_getLanczosSum(double fZ
)
514 const double fNum
[13] ={
515 23531376880.41075968857200767445163675473,
516 42919803642.64909876895789904700198885093,
517 35711959237.35566804944018545154716670596,
518 17921034426.03720969991975575445893111267,
519 6039542586.35202800506429164430729792107,
520 1439720407.311721673663223072794912393972,
521 248874557.8620541565114603864132294232163,
522 31426415.58540019438061423162831820536287,
523 2876370.628935372441225409051620849613599,
524 186056.2653952234950402949897160456992822,
525 8071.672002365816210638002902272250613822,
526 210.8242777515793458725097339207133627117,
527 2.506628274631000270164908177133837338626
529 const double fDenom
[13] = {
552 fSumDenom
= fDenom
[12];
553 for (nI
= 11; nI
>= 0; --nI
)
558 fSumDenom
+= fDenom
[nI
];
562 // Cancel down with fZ^12; Horner scheme with reverse coefficients
566 fSumDenom
= fDenom
[0];
567 for (nI
= 1; nI
<=12; ++nI
)
572 fSumDenom
+= fDenom
[nI
];
575 return fSumNum
/fSumDenom
;
578 // The algorithm is based on tgamma in gamma.hpp
579 // in math library from http://www.boost.org
580 /** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
581 double lcl_GetGammaHelper(double fZ
)
583 double fGamma
= lcl_getLanczosSum(fZ
);
584 const double fg
= 6.024680040776729583740234375;
585 double fZgHelp
= fZ
+ fg
- 0.5;
586 // avoid intermediate overflow
587 double fHalfpower
= pow( fZgHelp
, fZ
/ 2 - 0.25);
588 fGamma
*= fHalfpower
;
589 fGamma
/= exp(fZgHelp
);
590 fGamma
*= fHalfpower
;
591 if (fZ
<= 20.0 && fZ
== ::rtl::math::approxFloor(fZ
))
592 fGamma
= ::rtl::math::round(fGamma
);
596 // The algorithm is based on tgamma in gamma.hpp
597 // in math library from http://www.boost.org
598 /** You must ensure fZ>0 */
599 double lcl_GetLogGammaHelper(double fZ
)
601 const double fg
= 6.024680040776729583740234375;
602 double fZgHelp
= fZ
+ fg
- 0.5;
603 return log( lcl_getLanczosSum(fZ
)) + (fZ
-0.5) * log(fZgHelp
) - fZgHelp
;
606 /** You must ensure non integer arguments for fZ<1 */
607 double ScInterpreter::GetGamma(double fZ
)
609 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetGamma" );
610 const double fLogPi
= log(F_PI
);
611 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
613 if (fZ
> fMaxGammaArgument
)
615 SetError(errIllegalFPOperation
);
620 return lcl_GetGammaHelper(fZ
);
622 if (fZ
>= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
623 return lcl_GetGammaHelper(fZ
+1) / fZ
;
625 if (fZ
>= -0.5) // shift to x>=1, might overflow
627 double fLogTest
= lcl_GetLogGammaHelper(fZ
+2) - log(fZ
+1) - log( fabs(fZ
));
628 if (fLogTest
>= fLogDblMax
)
630 SetError( errIllegalFPOperation
);
633 return lcl_GetGammaHelper(fZ
+2) / (fZ
+1) / fZ
;
636 // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
637 double fLogDivisor
= lcl_GetLogGammaHelper(1-fZ
) + log( fabs( ::rtl::math::sin( F_PI
*fZ
)));
638 if (fLogDivisor
- fLogPi
>= fLogDblMax
) // underflow
642 if (fLogPi
- fLogDivisor
> fLogDblMax
) // overflow
644 SetError(errIllegalFPOperation
);
648 return exp( fLogPi
- fLogDivisor
) * ((::rtl::math::sin( F_PI
*fZ
) < 0.0) ? -1.0 : 1.0);
652 /** You must ensure fZ>0 */
653 double ScInterpreter::GetLogGamma(double fZ
)
655 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetLogGamma" );
656 if (fZ
>= fMaxGammaArgument
)
657 return lcl_GetLogGammaHelper(fZ
);
659 return log(lcl_GetGammaHelper(fZ
));
661 return log( lcl_GetGammaHelper(fZ
+1) / fZ
);
662 return lcl_GetLogGammaHelper(fZ
+2) - log(fZ
+1) - log(fZ
);
665 double ScInterpreter::GetFDist(double x
, double fF1
, double fF2
)
667 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetFDist" );
668 double arg
= fF2
/(fF2
+fF1
*x
);
669 double alpha
= fF2
/2.0;
670 double beta
= fF1
/2.0;
671 return (GetBetaDist(arg
, alpha
, beta
));
673 double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
674 sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
675 return (0.5-gauss(Z));
679 double ScInterpreter::GetTDist(double T
, double fDF
)
681 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetTDist" );
682 return 0.5 * GetBetaDist(fDF
/(fDF
+T
*T
), fDF
/2.0, 0.5);
684 USHORT DF = (USHORT) fDF;
685 double A = T / sqrt(DF);
686 double B = 1.0 + A*A;
689 R = 0.5 + atan(A)/F_PI;
690 else if (DF % 2 == 0)
692 double S0 = A/(2.0 * sqrt(B));
694 for (USHORT i = 2; i <= DF-2; i+=2)
696 C0 *= (1.0 - 1.0/(double)i)/B;
703 double S1 = A / (B * F_PI);
705 for (USHORT i = 3; i <= DF-2; i+=2)
707 C1 *= (1.0 - 1.0/(double)i)/B;
710 R = 0.5 + atan(A)/F_PI + S1;
716 // for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
717 /** You must ensure fDF>0.0 */
718 double ScInterpreter::GetChiDist(double fX
, double fDF
)
720 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetChiDist" );
722 return 1.0; // see ODFF
724 return GetUpRegIGamma( fDF
/2.0, fX
/2.0);
728 // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
730 /** You must ensure fDF>0.0 */
731 double ScInterpreter::GetChiSqDistCDF(double fX
, double fDF
)
733 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetChiSqDistCDF" );
735 return 0.0; // see ODFF
737 return GetLowRegIGamma( fDF
/2.0, fX
/2.0);
740 double ScInterpreter::GetChiSqDistPDF(double fX
, double fDF
)
742 // you must ensure fDF is positive integer
746 return 0.0; // see ODFF
747 if (fDF
*fX
> 1391000.0)
749 // intermediate invalid values, use log
750 fValue
= exp((0.5*fDF
- 1) * log(fX
*0.5) - 0.5 * fX
- log(2.0) - GetLogGamma(0.5*fDF
));
752 else // fDF is small in most cases, we can iterate
754 if (fmod(fDF
,2.0)<0.5)
762 fValue
= 1/sqrt(fX
*2*F_PI
);
765 while ( fCount
< fDF
)
767 fValue
*= (fX
/ fCount
);
770 if (fX
>=1425.0) // underflow in e^(-x/2)
771 fValue
= exp(log(fValue
)-fX
/2);
773 fValue
*= exp(-fX
/2);
778 void ScInterpreter::ScChiSqDist()
780 BYTE nParamCount
= GetByte();
781 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
785 if (nParamCount
== 3)
786 bCumulative
= GetBool();
789 double fDF
= ::rtl::math::approxFloor(GetDouble());
791 PushIllegalArgument();
796 PushDouble(GetChiSqDistCDF(fX
,fDF
));
798 PushDouble(GetChiSqDistPDF(fX
,fDF
));
802 void ScInterpreter::ScGamma()
804 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGamma" );
805 double x
= GetDouble();
807 if (x
<= 0.0 && x
== ::rtl::math::approxFloor(x
))
808 PushIllegalArgument();
811 fResult
= GetGamma(x
);
814 PushError( nGlobalError
);
822 void ScInterpreter::ScLogGamma()
824 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLogGamma" );
825 double x
= GetDouble();
826 if (x
> 0.0) // constraint from ODFF
827 PushDouble( GetLogGamma(x
));
829 PushIllegalArgument();
832 double ScInterpreter::GetBeta(double fAlpha
, double fBeta
)
838 fA
= fAlpha
; fB
= fBeta
;
842 fA
= fBeta
; fB
= fAlpha
;
844 if (fA
+fB
< fMaxGammaArgument
) // simple case
845 return GetGamma(fA
)/GetGamma(fA
+fB
)*GetGamma(fB
);
847 // GetLogGamma is not accurate enough, back to Lanczos for all three
848 // GetGamma and arrange factors newly.
849 const double fg
= 6.024680040776729583740234375; //see GetGamma
850 double fgm
= fg
- 0.5;
851 double fLanczos
= lcl_getLanczosSum(fA
);
852 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
853 fLanczos
*= lcl_getLanczosSum(fB
);
854 double fABgm
= fA
+fB
+fgm
;
855 fLanczos
*= sqrt((fABgm
/(fA
+fgm
))/(fB
+fgm
));
856 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
857 double fTempB
= fA
/(fB
+fgm
);
858 double fResult
= exp(-fA
* ::rtl::math::log1p(fTempA
)
859 -fB
* ::rtl::math::log1p(fTempB
)-fgm
);
864 // Same as GetBeta but with logarithm
865 double ScInterpreter::GetLogBeta(double fAlpha
, double fBeta
)
871 fA
= fAlpha
; fB
= fBeta
;
875 fA
= fBeta
; fB
= fAlpha
;
877 const double fg
= 6.024680040776729583740234375; //see GetGamma
878 double fgm
= fg
- 0.5;
879 double fLanczos
= lcl_getLanczosSum(fA
);
880 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
881 fLanczos
*= lcl_getLanczosSum(fB
);
882 double fLogLanczos
= log(fLanczos
);
883 double fABgm
= fA
+fB
+fgm
;
884 fLogLanczos
+= 0.5*(log(fABgm
)-log(fA
+fgm
)-log(fB
+fgm
));
885 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
886 double fTempB
= fA
/(fB
+fgm
);
887 double fResult
= -fA
* ::rtl::math::log1p(fTempA
)
888 -fB
* ::rtl::math::log1p(fTempB
)-fgm
;
889 fResult
+= fLogLanczos
;
893 // beta distribution probability density function
894 double ScInterpreter::GetBetaDistPDF(double fX
, double fA
, double fB
)
897 if (fA
== 1.0) // result b*(1-x)^(b-1)
902 return -2.0*fX
+ 2.0;
903 if (fX
== 1.0 && fB
< 1.0)
905 SetError(errIllegalArgument
);
909 return fB
+ fB
* ::rtl::math::expm1((fB
-1.0) * ::rtl::math::log1p(-fX
));
911 return fB
* pow(0.5-fX
+0.5,fB
-1.0);
913 if (fB
== 1.0) // result a*x^(a-1)
917 if (fX
== 0.0 && fA
< 1.0)
919 SetError(errIllegalArgument
);
922 return fA
* pow(fX
,fA
-1);
926 if (fA
< 1.0 && fX
== 0.0)
928 SetError(errIllegalArgument
);
936 if (fB
< 1.0 && fX
== 1.0)
938 SetError(errIllegalArgument
);
945 // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
946 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
947 const double fLogDblMin
= log( ::std::numeric_limits
<double>::min());
948 double fLogY
= (fX
< 0.1) ? ::rtl::math::log1p(-fX
) : log(0.5-fX
+0.5);
949 double fLogX
= log(fX
);
950 double fAm1
= fA
-1.0;
951 double fBm1
= fB
-1.0;
952 double fLogBeta
= GetLogBeta(fA
,fB
);
953 // check whether parts over- or underflow
954 if ( fAm1
* fLogX
< fLogDblMax
&& fAm1
* fLogX
> fLogDblMin
955 && fBm1
* fLogY
< fLogDblMax
&& fBm1
* fLogY
> fLogDblMin
956 && fLogBeta
< fLogDblMax
&& fLogBeta
> fLogDblMin
)
957 return pow(fX
,fA
-1.0) * pow(0.5-fX
+0.5,fB
-1.0) / GetBeta(fA
,fB
);
958 else // need logarithm;
959 // might overflow as a whole, but seldom, not worth to pre-detect it
960 return exp((fA
-1.0)*fLogX
+ (fB
-1.0)* fLogY
- fLogBeta
);
966 I_x(a,b) = ---------------- * result of ContFrac
969 double lcl_GetBetaHelperContFrac(double fX
, double fA
, double fB
)
970 { // like old version
971 double a1
, b1
, a2
, b2
, fnorm
, apl2m
, d2m
, d2m1
, cfnew
, cf
;
973 b2
= 1.0 - (fA
+fB
)/(fA
+1.0)*fX
;
989 const double fMaxIter
= 50000.0;
990 // loop security, normal cases converge in less than 100 iterations.
991 // FIXME: You will get so much iteratons for fX near mean,
992 // I do not know a better algorithm.
993 bool bfinished
= false;
997 d2m
= rm
*(fB
-rm
)*fX
/((apl2m
-1.0)*apl2m
);
998 d2m1
= -(fA
+rm
)*(fA
+fB
+rm
)*fX
/(apl2m
*(apl2m
+1.0));
999 a1
= (a2
+d2m
*a1
)*fnorm
;
1000 b1
= (b2
+d2m
*b1
)*fnorm
;
1001 a2
= a1
+ d2m1
*a2
*fnorm
;
1002 b2
= b1
+ d2m1
*b2
*fnorm
;
1007 bfinished
= (fabs(cf
-cfnew
) < fabs(cf
)*fMachEps
);
1012 while (rm
< fMaxIter
&& !bfinished
);
1016 // cumulative distribution function, normalized
1017 double ScInterpreter::GetBetaDist(double fXin
, double fAlpha
, double fBeta
)
1020 if (fXin
<= 0.0) // values are valid, see spec
1022 if (fXin
>= 1.0) // values are valid, see spec
1025 return pow(fXin
, fAlpha
);
1027 // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
1028 return -::rtl::math::expm1(fBeta
* ::rtl::math::log1p(-fXin
));
1029 //FIXME: need special algorithm for fX near fP for large fA,fB
1031 // I use always continued fraction, power series are neither
1032 // faster nor more accurate.
1033 double fY
= (0.5-fXin
)+0.5;
1034 double flnY
= ::rtl::math::log1p(-fXin
);
1036 double flnX
= log(fXin
);
1039 bool bReflect
= fXin
> fAlpha
/(fAlpha
+fBeta
);
1049 fResult
= lcl_GetBetaHelperContFrac(fX
,fA
,fB
);
1050 fResult
= fResult
/fA
;
1051 double fP
= fA
/(fA
+fB
);
1052 double fQ
= fB
/(fA
+fB
);
1054 if (fA
> 1.0 && fB
> 1.0 && fP
< 0.97 && fQ
< 0.97) //found experimental
1055 fTemp
= GetBetaDistPDF(fX
,fA
,fB
)*fX
*fY
;
1057 fTemp
= exp(fA
*flnX
+ fB
*flnY
- GetLogBeta(fA
,fB
));
1060 fResult
= 0.5 - fResult
+ 0.5;
1061 if (fResult
> 1.0) // ensure valid range
1068 void ScInterpreter::ScBetaDist()
1070 BYTE nParamCount
= GetByte();
1071 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) ) // expanded, see #i91547#
1073 double fLowerBound
, fUpperBound
;
1074 double alpha
, beta
, x
;
1076 if (nParamCount
== 6)
1077 bIsCumulative
= GetBool();
1079 bIsCumulative
= true;
1080 if (nParamCount
>= 5)
1081 fUpperBound
= GetDouble();
1084 if (nParamCount
>= 4)
1085 fLowerBound
= GetDouble();
1089 alpha
= GetDouble();
1091 double fScale
= fUpperBound
- fLowerBound
;
1092 if (fScale
<= 0.0 || alpha
<= 0.0 || beta
<= 0.0)
1094 PushIllegalArgument();
1097 if (bIsCumulative
) // cumulative distribution function
1100 if (x
< fLowerBound
)
1102 PushDouble(0.0); return; //see spec
1104 if (x
> fUpperBound
)
1106 PushDouble(1.0); return; //see spec
1109 x
= (x
-fLowerBound
)/fScale
; // convert to standard form
1110 PushDouble(GetBetaDist(x
, alpha
, beta
));
1113 else // probability density function
1115 if (x
< fLowerBound
|| x
> fUpperBound
)
1120 x
= (x
-fLowerBound
)/fScale
;
1121 PushDouble(GetBetaDistPDF(x
, alpha
, beta
)/fScale
);
1126 void ScInterpreter::ScPhi()
1128 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPhi" );
1129 PushDouble(phi(GetDouble()));
1132 void ScInterpreter::ScGauss()
1134 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGauss" );
1135 PushDouble(gauss(GetDouble()));
1138 void ScInterpreter::ScFisher()
1140 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFisher" );
1141 double fVal
= GetDouble();
1142 if (fabs(fVal
) >= 1.0)
1143 PushIllegalArgument();
1145 PushDouble( ::rtl::math::atanh( fVal
));
1148 void ScInterpreter::ScFisherInv()
1150 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFisherInv" );
1151 PushDouble( tanh( GetDouble()));
1154 void ScInterpreter::ScFact()
1156 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFact" );
1157 double nVal
= GetDouble();
1159 PushIllegalArgument();
1161 PushDouble(Fakultaet(nVal
));
1164 void ScInterpreter::ScKombin()
1166 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKombin" );
1167 if ( MustHaveParamCount( GetByte(), 2 ) )
1169 double k
= ::rtl::math::approxFloor(GetDouble());
1170 double n
= ::rtl::math::approxFloor(GetDouble());
1171 if (k
< 0.0 || n
< 0.0 || k
> n
)
1172 PushIllegalArgument();
1174 PushDouble(BinomKoeff(n
, k
));
1178 void ScInterpreter::ScKombin2()
1180 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKombin2" );
1181 if ( MustHaveParamCount( GetByte(), 2 ) )
1183 double k
= ::rtl::math::approxFloor(GetDouble());
1184 double n
= ::rtl::math::approxFloor(GetDouble());
1185 if (k
< 0.0 || n
< 0.0 || k
> n
)
1186 PushIllegalArgument();
1188 PushDouble(BinomKoeff(n
+ k
- 1, k
));
1192 void ScInterpreter::ScVariationen()
1194 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVariationen" );
1195 if ( MustHaveParamCount( GetByte(), 2 ) )
1197 double k
= ::rtl::math::approxFloor(GetDouble());
1198 double n
= ::rtl::math::approxFloor(GetDouble());
1199 if (n
< 0.0 || k
< 0.0 || k
> n
)
1200 PushIllegalArgument();
1202 PushInt(1); // (n! / (n - 0)!) == 1
1206 for (ULONG i
= (ULONG
)k
-1; i
>= 1; i
--)
1207 nVal
*= n
-(double)i
;
1213 void ScInterpreter::ScVariationen2()
1215 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVariationen2" );
1216 if ( MustHaveParamCount( GetByte(), 2 ) )
1218 double k
= ::rtl::math::approxFloor(GetDouble());
1219 double n
= ::rtl::math::approxFloor(GetDouble());
1220 if (n
< 0.0 || k
< 0.0 || k
> n
)
1221 PushIllegalArgument();
1223 PushDouble(pow(n
,k
));
1227 void ScInterpreter::ScB()
1229 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScB" );
1230 BYTE nParamCount
= GetByte();
1231 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1233 if (nParamCount
== 3)
1235 double x
= ::rtl::math::approxFloor(GetDouble());
1236 double p
= GetDouble();
1237 double n
= ::rtl::math::approxFloor(GetDouble());
1238 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1239 PushIllegalArgument();
1243 double fFactor
= pow(q
, n
);
1246 fFactor
= pow(p
, n
);
1251 ULONG max
= (ULONG
) (n
- x
);
1252 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1253 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1254 PushDouble(fFactor
);
1259 ULONG max
= (ULONG
) x
;
1260 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1261 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1262 PushDouble(fFactor
);
1266 else if (nParamCount
== 4)
1268 double xe
= GetDouble();
1269 double xs
= GetDouble();
1270 double p
= GetDouble();
1271 double n
= GetDouble();
1272 // alter Stand 300-SC
1273 // if ((xs < n) && (xe < n) && (p < 1.0))
1275 // double Varianz = sqrt(n * p * (1.0 - p));
1276 // xs = fabs(xs - (n * p /* / 2.0 STE */ ));
1277 // xe = fabs(xe - (n * p /* / 2.0 STE */ ));
1278 //// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz);
1279 // double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz));
1280 // PushDouble(nVal);
1282 if (xe
<= n
&& xs
<= xe
&&
1283 p
< 1.0 && p
> 0.0 && n
>= 0.0 && xs
>= 0.0 )
1286 double fFactor
= pow(q
, n
);
1289 fFactor
= pow(p
, n
);
1297 max
= (ULONG
) (n
-xe
)-1;
1301 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1302 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1304 max
= (ULONG
) (n
-xs
);
1307 for (; i
< max
&& fFactor
> 0.0; i
++)
1309 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1319 if ( (ULONG
) xs
== 0)
1330 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1331 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1332 if ((ULONG
)xe
== 0) // beide 0
1336 for (; i
< max
&& fFactor
> 0.0; i
++)
1338 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1345 PushIllegalArgument();
1349 void ScInterpreter::ScBinomDist()
1351 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBinomDist" );
1352 if ( MustHaveParamCount( GetByte(), 4 ) )
1354 double kum
= GetDouble(); // 0 oder 1
1355 double p
= GetDouble(); // p
1356 double n
= ::rtl::math::approxFloor(GetDouble()); // n
1357 double x
= ::rtl::math::approxFloor(GetDouble()); // x
1358 double fFactor
, q
, fSum
;
1359 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1360 PushIllegalArgument();
1361 else if (kum
== 0.0) // Dichte
1364 fFactor
= pow(q
, n
);
1367 fFactor
= pow(p
, n
);
1372 ULONG max
= (ULONG
) (n
- x
);
1373 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1374 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1375 PushDouble(fFactor
);
1380 ULONG max
= (ULONG
) x
;
1381 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1382 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1383 PushDouble(fFactor
);
1393 fFactor
= pow(q
, n
);
1396 fFactor
= pow(p
, n
);
1401 fSum
= 1.0 - fFactor
;
1402 ULONG max
= (ULONG
) (n
- x
) - 1;
1403 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1405 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1417 ULONG max
= (ULONG
) x
;
1418 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1420 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1430 void ScInterpreter::ScCritBinom()
1432 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCritBinom" );
1433 if ( MustHaveParamCount( GetByte(), 3 ) )
1435 double alpha
= GetDouble(); // alpha
1436 double p
= GetDouble(); // p
1437 double n
= ::rtl::math::approxFloor(GetDouble());
1438 if (n
< 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || p
< 0.0 || p
> 1.0)
1439 PushIllegalArgument();
1443 double fFactor
= pow(q
,n
);
1446 fFactor
= pow(p
, n
);
1451 double fSum
= 1.0 - fFactor
; ULONG max
= (ULONG
) n
;
1454 for ( i
= 0; i
< max
&& fSum
>= alpha
; i
++)
1456 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1464 double fSum
= fFactor
; ULONG max
= (ULONG
) n
;
1467 for ( i
= 0; i
< max
&& fSum
< alpha
; i
++)
1469 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1478 void ScInterpreter::ScNegBinomDist()
1480 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNegBinomDist" );
1481 if ( MustHaveParamCount( GetByte(), 3 ) )
1483 double p
= GetDouble(); // p
1484 double r
= GetDouble(); // r
1485 double x
= GetDouble(); // x
1486 if (r
< 0.0 || x
< 0.0 || p
< 0.0 || p
> 1.0)
1487 PushIllegalArgument();
1491 double fFactor
= pow(p
,r
);
1492 for (double i
= 0.0; i
< x
; i
++)
1493 fFactor
*= (i
+r
)/(i
+1.0)*q
;
1494 PushDouble(fFactor
);
1499 void ScInterpreter::ScNormDist()
1501 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNormDist" );
1502 if ( MustHaveParamCount( GetByte(), 4 ) )
1504 double kum
= GetDouble(); // 0 oder 1
1505 double sigma
= GetDouble(); // Stdabw
1506 double mue
= GetDouble(); // Mittelwert
1507 double x
= GetDouble(); // x
1509 PushError( errIllegalArgument
);
1510 else if (sigma
== 0.0)
1511 PushError( errDivisionByZero
);
1512 else if (kum
== 0.0) // Dichte
1513 PushDouble(phi((x
-mue
)/sigma
)/sigma
);
1515 PushDouble(0.5 + gauss((x
-mue
)/sigma
));
1519 void ScInterpreter::ScLogNormDist()
1521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLogNormDist" );
1522 if ( MustHaveParamCount( GetByte(), 3 ) )
1524 double sigma
= GetDouble(); // Stdabw
1525 double mue
= GetDouble(); // Mittelwert
1526 double x
= GetDouble(); // x
1528 PushError( errIllegalArgument
);
1529 else if (sigma
== 0.0)
1530 PushError( errDivisionByZero
);
1532 PushIllegalArgument();
1534 PushDouble(0.5 + gauss((log(x
)-mue
)/sigma
));
1538 void ScInterpreter::ScStdNormDist()
1540 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStdNormDist" );
1541 PushDouble(0.5 + gauss(GetDouble()));
1544 void ScInterpreter::ScExpDist()
1546 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExpDist" );
1547 if ( MustHaveParamCount( GetByte(), 3 ) )
1549 double kum
= GetDouble(); // 0 oder 1
1550 double lambda
= GetDouble(); // lambda
1551 double x
= GetDouble(); // x
1553 PushIllegalArgument();
1554 else if (kum
== 0.0) // Dichte
1557 PushDouble(lambda
* exp(-lambda
*x
));
1564 PushDouble(1.0 - exp(-lambda
*x
));
1571 void ScInterpreter::ScTDist()
1573 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTDist" );
1574 if ( !MustHaveParamCount( GetByte(), 3 ) )
1576 double fFlag
= ::rtl::math::approxFloor(GetDouble());
1577 double fDF
= ::rtl::math::approxFloor(GetDouble());
1578 double T
= GetDouble();
1579 if (fDF
< 1.0 || T
< 0.0 || (fFlag
!= 1.0 && fFlag
!= 2.0) )
1581 PushIllegalArgument();
1584 double R
= GetTDist(T
, fDF
);
1591 void ScInterpreter::ScFDist()
1593 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFDist" );
1594 if ( !MustHaveParamCount( GetByte(), 3 ) )
1596 double fF2
= ::rtl::math::approxFloor(GetDouble());
1597 double fF1
= ::rtl::math::approxFloor(GetDouble());
1598 double fF
= GetDouble();
1599 if (fF
< 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
)
1601 PushIllegalArgument();
1604 PushDouble(GetFDist(fF
, fF1
, fF2
));
1607 void ScInterpreter::ScChiDist()
1609 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiDist" );
1611 if ( !MustHaveParamCount( GetByte(), 2 ) )
1613 double fDF
= ::rtl::math::approxFloor(GetDouble());
1614 double fChi
= GetDouble();
1615 if (fDF
< 1.0) // x<=0 returns 1, see ODFF 6.17.10
1617 PushIllegalArgument();
1620 fResult
= GetChiDist( fChi
, fDF
);
1623 PushError( nGlobalError
);
1626 PushDouble(fResult
);
1629 void ScInterpreter::ScWeibull()
1631 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScWeibull" );
1632 if ( MustHaveParamCount( GetByte(), 4 ) )
1634 double kum
= GetDouble(); // 0 oder 1
1635 double beta
= GetDouble(); // beta
1636 double alpha
= GetDouble(); // alpha
1637 double x
= GetDouble(); // x
1638 if (alpha
<= 0.0 || beta
<= 0.0 || x
< 0.0)
1639 PushIllegalArgument();
1640 else if (kum
== 0.0) // Dichte
1641 PushDouble(alpha
/pow(beta
,alpha
)*pow(x
,alpha
-1.0)*
1642 exp(-pow(x
/beta
,alpha
)));
1644 PushDouble(1.0 - exp(-pow(x
/beta
,alpha
)));
1648 void ScInterpreter::ScPoissonDist()
1650 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPoissonDist" );
1651 BYTE nParamCount
= GetByte();
1652 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
1654 double kum
= (nParamCount
== 3 ? GetDouble() : 1); // 0 oder 1
1655 double lambda
= GetDouble(); // Mittelwert
1656 double x
= ::rtl::math::approxFloor(GetDouble()); // x
1657 if (lambda
< 0.0 || x
< 0.0)
1658 PushIllegalArgument();
1659 else if (kum
== 0.0) // Dichte
1665 double fPoissonVar
= 1.0;
1666 for ( double f
= 0.0; f
< x
; ++f
)
1667 fPoissonVar
*= lambda
/ ( f
+ 1.0 );
1668 PushDouble( fPoissonVar
*exp( -lambda
) );
1679 ULONG nEnd
= (ULONG
) x
;
1680 for (ULONG i
= 1; i
<= nEnd
; i
++)
1683 sum
+= pow( lambda
, (double)i
) / fFak
;
1685 sum
*= exp(-lambda
);
1692 /** Local function used in the calculation of the hypergeometric distribution.
1694 void lcl_PutFactorialElements( ::std::vector
< double >& cn
, double fLower
, double fUpper
, double fBase
)
1696 for ( double i
= fLower
; i
<= fUpper
; ++i
)
1698 double fVal
= fBase
- i
;
1700 cn
.push_back( fVal
);
1704 /** Calculates a value of the hypergeometric distribution.
1706 The algorithm is designed to avoid unnecessary multiplications and division
1707 by expanding all factorial elements (9 of them). It is done by excluding
1708 those ranges that overlap in the numerator and the denominator. This allows
1709 for a fast calculation for large values which would otherwise cause an overflow
1710 in the intermediate values.
1712 @author Kohei Yoshida <kohei@openoffice.org>
1717 void ScInterpreter::ScHypGeomDist()
1719 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHypGeomDist" );
1720 const size_t nMaxArraySize
= 500000; // arbitrary max array size
1722 if ( !MustHaveParamCount( GetByte(), 4 ) )
1725 double N
= ::rtl::math::approxFloor(GetDouble());
1726 double M
= ::rtl::math::approxFloor(GetDouble());
1727 double n
= ::rtl::math::approxFloor(GetDouble());
1728 double x
= ::rtl::math::approxFloor(GetDouble());
1730 if( (x
< 0.0) || (n
< x
) || (M
< x
) || (N
< n
) || (N
< M
) || (x
< n
- N
+ M
) )
1732 PushIllegalArgument();
1736 typedef ::std::vector
< double > HypContainer
;
1737 HypContainer cnNumer
, cnDenom
;
1739 size_t nEstContainerSize
= static_cast<size_t>( x
+ ::std::min( n
, M
) );
1740 size_t nMaxSize
= ::std::min( cnNumer
.max_size(), nMaxArraySize
);
1741 if ( nEstContainerSize
> nMaxSize
)
1746 cnNumer
.reserve( nEstContainerSize
+ 10 );
1747 cnDenom
.reserve( nEstContainerSize
+ 10 );
1749 // Trim coefficient C first
1750 double fCNumVarUpper
= N
- n
- M
+ x
- 1.0;
1751 double fCDenomVarLower
= 1.0;
1752 if ( N
- n
- M
+ x
>= M
- x
+ 1.0 )
1754 fCNumVarUpper
= M
- x
- 1.0;
1755 fCDenomVarLower
= N
- n
- 2.0*(M
- x
) + 1.0;
1759 double fCNumLower
= N
- n
- fCNumVarUpper
;
1761 double fCDenomUpper
= N
- n
- M
+ x
+ 1.0 - fCDenomVarLower
;
1763 double fDNumVarLower
= n
- M
;
1767 if ( N
- M
< n
+ 1.0 )
1771 if ( N
- n
< n
+ 1.0 )
1774 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1775 lcl_PutFactorialElements( cnDenom
, 0.0, N
- n
- 1.0, N
);
1780 DBG_ASSERT( fCNumLower
< n
+ 1.0, "ScHypGeomDist: wrong assertion" );
1781 lcl_PutFactorialElements( cnNumer
, N
- 2.0*n
, fCNumVarUpper
, N
- n
);
1782 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1785 DBG_ASSERT( fCDenomUpper
<= N
- M
, "ScHypGeomDist: wrong assertion" );
1787 if ( fCDenomUpper
< n
- x
+ 1.0 )
1789 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1793 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1795 fCDenomUpper
= n
- x
;
1796 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1806 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1807 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1811 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1812 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1815 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1817 if ( fCDenomUpper
< n
- x
+ 1.0 )
1819 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1822 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1823 fCDenomUpper
= n
- x
;
1824 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1828 DBG_ASSERT( fCDenomUpper
<= M
, "ScHypGeomDist: wrong assertion" );
1832 if ( N
- M
< M
+ 1.0 )
1836 if ( N
- n
< M
+ 1.0 )
1839 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1840 lcl_PutFactorialElements( cnDenom
, 0.0, N
- M
- 1.0, N
);
1844 lcl_PutFactorialElements( cnNumer
, N
- n
- M
, fCNumVarUpper
, N
- n
);
1845 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1848 if ( n
- x
+ 1.0 > fCDenomUpper
)
1850 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1854 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1856 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1857 fCDenomUpper
= n
- x
;
1864 DBG_ASSERT( M
>= n
- x
, "ScHypGeomDist: wrong assertion" );
1865 DBG_ASSERT( M
- x
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1867 if ( N
- n
< N
- M
+ 1.0 )
1870 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1871 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1876 DBG_ASSERT( fCNumLower
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1878 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1879 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1882 if ( n
- x
+ 1.0 > fCDenomUpper
)
1884 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1885 else if ( M
>= fCDenomUpper
)
1887 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1889 fCDenomUpper
= n
- x
;
1890 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1894 DBG_ASSERT( M
<= fCDenomUpper
, "ScHypGeomDist: wrong assertion" );
1895 lcl_PutFactorialElements( cnDenom
, fCDenomVarLower
, N
- n
- 2.0*M
+ x
,
1896 N
- n
- M
+ x
+ 1.0 );
1898 fCDenomUpper
= n
- x
;
1899 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1903 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1905 fDNumVarLower
= 0.0;
1908 double nDNumVarUpper
= fCDenomUpper
< x
+ 1.0 ? n
- x
- 1.0 : n
- fCDenomUpper
- 1.0;
1909 double nDDenomVarLower
= fCDenomUpper
< x
+ 1.0 ? fCDenomVarLower
: N
- n
- M
+ 1.0;
1910 lcl_PutFactorialElements( cnNumer
, fDNumVarLower
, nDNumVarUpper
, n
);
1911 lcl_PutFactorialElements( cnDenom
, nDDenomVarLower
, N
- n
- M
+ x
, N
- n
- M
+ x
+ 1.0 );
1913 ::std::sort( cnNumer
.begin(), cnNumer
.end() );
1914 ::std::sort( cnDenom
.begin(), cnDenom
.end() );
1915 HypContainer::reverse_iterator it1
= cnNumer
.rbegin(), it1End
= cnNumer
.rend();
1916 HypContainer::reverse_iterator it2
= cnDenom
.rbegin(), it2End
= cnDenom
.rend();
1918 double fFactor
= 1.0;
1919 for ( ; it1
!= it1End
|| it2
!= it2End
; )
1921 double fEnum
= 1.0, fDenom
= 1.0;
1922 if ( it1
!= it1End
)
1924 if ( it2
!= it2End
)
1926 fFactor
*= fEnum
/ fDenom
;
1929 PushDouble(fFactor
);
1932 void ScInterpreter::ScGammaDist()
1934 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGammaDist" );
1935 BYTE nParamCount
= GetByte();
1936 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1939 if (nParamCount
== 4)
1940 bCumulative
= GetBool();
1943 double fBeta
= GetDouble(); // scale
1944 double fAlpha
= GetDouble(); // shape
1945 double fX
= GetDouble(); // x
1946 if (fAlpha
<= 0.0 || fBeta
<= 0.0)
1947 PushIllegalArgument();
1950 if (bCumulative
) // distribution
1951 PushDouble( GetGammaDist( fX
, fAlpha
, fBeta
));
1953 PushDouble( GetGammaDistPDF( fX
, fAlpha
, fBeta
));
1957 void ScInterpreter::ScNormInv()
1959 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNormInv" );
1960 if ( MustHaveParamCount( GetByte(), 3 ) )
1962 double sigma
= GetDouble();
1963 double mue
= GetDouble();
1964 double x
= GetDouble();
1965 if (sigma
<= 0.0 || x
< 0.0 || x
> 1.0)
1966 PushIllegalArgument();
1967 else if (x
== 0.0 || x
== 1.0)
1970 PushDouble(gaussinv(x
)*sigma
+ mue
);
1974 void ScInterpreter::ScSNormInv()
1976 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSNormInv" );
1977 double x
= GetDouble();
1978 if (x
< 0.0 || x
> 1.0)
1979 PushIllegalArgument();
1980 else if (x
== 0.0 || x
== 1.0)
1983 PushDouble(gaussinv(x
));
1986 void ScInterpreter::ScLogNormInv()
1988 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLogNormInv" );
1989 if ( MustHaveParamCount( GetByte(), 3 ) )
1991 double sigma
= GetDouble(); // Stdabw
1992 double mue
= GetDouble(); // Mittelwert
1993 double y
= GetDouble(); // y
1994 if (sigma
<= 0.0 || y
<= 0.0 || y
>= 1.0)
1995 PushIllegalArgument();
1997 PushDouble(exp(mue
+sigma
*gaussinv(y
)));
2001 class ScGammaDistFunction
: public ScDistFunc
2003 ScInterpreter
& rInt
;
2004 double fp
, fAlpha
, fBeta
;
2007 ScGammaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2008 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2010 double GetValue( double x
) const { return fp
- rInt
.GetGammaDist(x
, fAlpha
, fBeta
); }
2013 void ScInterpreter::ScGammaInv()
2015 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGammaInv" );
2016 if ( !MustHaveParamCount( GetByte(), 3 ) )
2018 double fBeta
= GetDouble();
2019 double fAlpha
= GetDouble();
2020 double fP
= GetDouble();
2021 if (fAlpha
<= 0.0 || fBeta
<= 0.0 || fP
< 0.0 || fP
>= 1.0 )
2023 PushIllegalArgument();
2031 ScGammaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2032 double fStart
= fAlpha
* fBeta
;
2033 double fVal
= lcl_IterateInverse( aFunc
, fStart
*0.5, fStart
, bConvError
);
2035 SetError(errNoConvergence
);
2040 class ScBetaDistFunction
: public ScDistFunc
2042 ScInterpreter
& rInt
;
2043 double fp
, fAlpha
, fBeta
;
2046 ScBetaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2047 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2049 double GetValue( double x
) const { return fp
- rInt
.GetBetaDist(x
, fAlpha
, fBeta
); }
2052 void ScInterpreter::ScBetaInv()
2054 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBetaInv" );
2055 BYTE nParamCount
= GetByte();
2056 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2058 double fP
, fA
, fB
, fAlpha
, fBeta
;
2059 if (nParamCount
== 5)
2063 if (nParamCount
>= 4)
2067 fBeta
= GetDouble();
2068 fAlpha
= GetDouble();
2070 if (fP
< 0.0 || fP
>= 1.0 || fA
== fB
|| fAlpha
<= 0.0 || fBeta
<= 0.0)
2072 PushIllegalArgument();
2080 ScBetaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2081 // 0..1 as range for iteration so it isn't extended beyond the valid range
2082 double fVal
= lcl_IterateInverse( aFunc
, 0.0, 1.0, bConvError
);
2084 PushError( errNoConvergence
);
2086 PushDouble(fA
+ fVal
*(fB
-fA
)); // scale to (A,B)
2090 // Achtung: T, F und Chi
2091 // sind monoton fallend,
2092 // deshalb 1-Dist als Funktion
2094 class ScTDistFunction
: public ScDistFunc
2096 ScInterpreter
& rInt
;
2100 ScTDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2101 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2103 double GetValue( double x
) const { return fp
- 2 * rInt
.GetTDist(x
, fDF
); }
2106 void ScInterpreter::ScTInv()
2108 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTInv" );
2109 if ( !MustHaveParamCount( GetByte(), 2 ) )
2111 double fDF
= ::rtl::math::approxFloor(GetDouble());
2112 double fP
= GetDouble();
2113 if (fDF
< 1.0 || fDF
>= 1.0E5
|| fP
<= 0.0 || fP
> 1.0 )
2115 PushIllegalArgument();
2120 ScTDistFunction
aFunc( *this, fP
, fDF
);
2121 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2123 SetError(errNoConvergence
);
2127 class ScFDistFunction
: public ScDistFunc
2129 ScInterpreter
& rInt
;
2130 double fp
, fF1
, fF2
;
2133 ScFDistFunction( ScInterpreter
& rI
, double fpVal
, double fF1Val
, double fF2Val
) :
2134 rInt(rI
), fp(fpVal
), fF1(fF1Val
), fF2(fF2Val
) {}
2136 double GetValue( double x
) const { return fp
- rInt
.GetFDist(x
, fF1
, fF2
); }
2139 void ScInterpreter::ScFInv()
2141 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFInv" );
2142 if ( !MustHaveParamCount( GetByte(), 3 ) )
2144 double fF2
= ::rtl::math::approxFloor(GetDouble());
2145 double fF1
= ::rtl::math::approxFloor(GetDouble());
2146 double fP
= GetDouble();
2147 if (fP
<= 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
|| fP
> 1.0)
2149 PushIllegalArgument();
2154 ScFDistFunction
aFunc( *this, fP
, fF1
, fF2
);
2155 double fVal
= lcl_IterateInverse( aFunc
, fF1
*0.5, fF1
, bConvError
);
2157 SetError(errNoConvergence
);
2161 class ScChiDistFunction
: public ScDistFunc
2163 ScInterpreter
& rInt
;
2167 ScChiDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2168 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2170 double GetValue( double x
) const { return fp
- rInt
.GetChiDist(x
, fDF
); }
2173 void ScInterpreter::ScChiInv()
2175 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiInv" );
2176 if ( !MustHaveParamCount( GetByte(), 2 ) )
2178 double fDF
= ::rtl::math::approxFloor(GetDouble());
2179 double fP
= GetDouble();
2180 if (fDF
< 1.0 || fP
<= 0.0 || fP
> 1.0 )
2182 PushIllegalArgument();
2187 ScChiDistFunction
aFunc( *this, fP
, fDF
);
2188 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2190 SetError(errNoConvergence
);
2194 /***********************************************/
2195 class ScChiSqDistFunction
: public ScDistFunc
2197 ScInterpreter
& rInt
;
2201 ScChiSqDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2202 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2204 double GetValue( double x
) const { return fp
- rInt
.GetChiSqDistCDF(x
, fDF
); }
2208 void ScInterpreter::ScChiSqInv()
2210 if ( !MustHaveParamCount( GetByte(), 2 ) )
2212 double fDF
= ::rtl::math::approxFloor(GetDouble());
2213 double fP
= GetDouble();
2214 if (fDF
< 1.0 || fP
< 0.0 || fP
>= 1.0 )
2216 PushIllegalArgument();
2221 ScChiSqDistFunction
aFunc( *this, fP
, fDF
);
2222 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2224 SetError(errNoConvergence
);
2229 void ScInterpreter::ScConfidence()
2231 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScConfidence" );
2232 if ( MustHaveParamCount( GetByte(), 3 ) )
2234 double n
= ::rtl::math::approxFloor(GetDouble());
2235 double sigma
= GetDouble();
2236 double alpha
= GetDouble();
2237 if (sigma
<= 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || n
< 1.0)
2238 PushIllegalArgument();
2240 PushDouble( gaussinv(1.0-alpha
/2.0) * sigma
/sqrt(n
) );
2244 void ScInterpreter::ScZTest()
2246 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZTest" );
2247 BYTE nParamCount
= GetByte();
2248 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
2250 double sigma
= 0.0, mue
, x
;
2251 if (nParamCount
== 3)
2253 sigma
= GetDouble();
2256 PushIllegalArgument();
2263 double fSumSqr
= 0.0;
2265 double rValCount
= 0.0;
2266 switch (GetStackType())
2268 case formula::svDouble
:
2272 fSumSqr
+= fVal
*fVal
;
2279 PopSingleRef( aAdr
);
2280 ScBaseCell
* pCell
= GetCell( aAdr
);
2281 if (HasCellValueData(pCell
))
2283 fVal
= GetCellValue( aAdr
, pCell
);
2285 fSumSqr
+= fVal
*fVal
;
2291 case formula::svDoubleRef
:
2294 size_t nRefInList
= 0;
2295 while (nParam
-- > 0)
2299 PopDoubleRef( aRange
, nParam
, nRefInList
);
2300 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2301 if (aValIter
.GetFirst(fVal
, nErr
))
2304 fSumSqr
+= fVal
*fVal
;
2306 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
2309 fSumSqr
+= fVal
*fVal
;
2319 ScMatrixRef pMat
= PopMatrix();
2322 SCSIZE nCount
= pMat
->GetElementCount();
2323 if (pMat
->IsNumeric())
2325 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
2327 fVal
= pMat
->GetDouble(i
);
2329 fSumSqr
+= fVal
* fVal
;
2335 for (SCSIZE i
= 0; i
< nCount
; i
++)
2336 if (!pMat
->IsString(i
))
2338 fVal
= pMat
->GetDouble(i
);
2340 fSumSqr
+= fVal
* fVal
;
2347 default : SetError(errIllegalParameter
); break;
2349 if (rValCount
<= 1.0)
2350 PushError( errDivisionByZero
);
2353 mue
= fSum
/rValCount
;
2354 if (nParamCount
!= 3)
2355 sigma
= (fSumSqr
- fSum
*fSum
/rValCount
)/(rValCount
-1.0);
2357 PushDouble(0.5 - gauss((mue
-x
)/sqrt(sigma
/rValCount
)));
2360 bool ScInterpreter::CalculateTest(BOOL _bTemplin
2361 ,const SCSIZE nC1
, const SCSIZE nC2
,const SCSIZE nR1
,const SCSIZE nR2
2362 ,const ScMatrixRef
& pMat1
,const ScMatrixRef
& pMat2
2363 ,double& fT
,double& fF
)
2365 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateTest" );
2366 double fCount1
= 0.0;
2367 double fCount2
= 0.0;
2369 double fSumSqr1
= 0.0;
2371 double fSumSqr2
= 0.0;
2374 for (i
= 0; i
< nC1
; i
++)
2375 for (j
= 0; j
< nR1
; j
++)
2377 if (!pMat1
->IsString(i
,j
))
2379 fVal
= pMat1
->GetDouble(i
,j
);
2381 fSumSqr1
+= fVal
* fVal
;
2385 for (i
= 0; i
< nC2
; i
++)
2386 for (j
= 0; j
< nR2
; j
++)
2388 if (!pMat2
->IsString(i
,j
))
2390 fVal
= pMat2
->GetDouble(i
,j
);
2392 fSumSqr2
+= fVal
* fVal
;
2396 if (fCount1
< 2.0 || fCount2
< 2.0)
2400 } // if (fCount1 < 2.0 || fCount2 < 2.0)
2403 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0)/fCount1
;
2404 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0)/fCount2
;
2405 if (fS1
+ fS2
== 0.0)
2410 fT
= fabs(fSum1
/fCount1
- fSum2
/fCount2
)/sqrt(fS1
+fS2
);
2411 double c
= fS1
/(fS1
+fS2
);
2412 // s.u. fF = ::rtl::math::approxFloor(1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0)));
2413 // fF = ::rtl::math::approxFloor((fS1+fS2)*(fS1+fS2)/(fS1*fS1/(fCount1-1.0) + fS2*fS2/(fCount2-1.0)));
2415 // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen
2416 // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#):
2417 fF
= 1.0/(c
*c
/(fCount1
-1.0)+(1.0-c
)*(1.0-c
)/(fCount2
-1.0));
2421 // laut Bronstein-Semendjajew
2422 double fS1
= (fSumSqr1
- fSum1
*fSum1
/fCount1
) / (fCount1
- 1.0); // Varianz
2423 double fS2
= (fSumSqr2
- fSum2
*fSum2
/fCount2
) / (fCount2
- 1.0);
2424 fT
= fabs( fSum1
/fCount1
- fSum2
/fCount2
) /
2425 sqrt( (fCount1
-1.0)*fS1
+ (fCount2
-1.0)*fS2
) *
2426 sqrt( fCount1
*fCount2
*(fCount1
+fCount2
-2)/(fCount1
+fCount2
) );
2427 fF
= fCount1
+ fCount2
- 2;
2431 void ScInterpreter::ScTTest()
2433 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTTest" );
2434 if ( !MustHaveParamCount( GetByte(), 4 ) )
2436 double fTyp
= ::rtl::math::approxFloor(GetDouble());
2437 double fAnz
= ::rtl::math::approxFloor(GetDouble());
2438 if (fAnz
!= 1.0 && fAnz
!= 2.0)
2440 PushIllegalArgument();
2444 ScMatrixRef pMat2
= GetMatrix();
2445 ScMatrixRef pMat1
= GetMatrix();
2446 if (!pMat1
|| !pMat2
)
2448 PushIllegalParameter();
2455 pMat1
->GetDimensions(nC1
, nR1
);
2456 pMat2
->GetDimensions(nC2
, nR2
);
2459 if (nC1
!= nC2
|| nR1
!= nR2
)
2461 PushIllegalArgument();
2464 double fCount
= 0.0;
2467 double fSumSqrD
= 0.0;
2468 double fVal1
, fVal2
;
2469 for (i
= 0; i
< nC1
; i
++)
2470 for (j
= 0; j
< nR1
; j
++)
2472 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2474 fVal1
= pMat1
->GetDouble(i
,j
);
2475 fVal2
= pMat2
->GetDouble(i
,j
);
2478 fSumSqrD
+= (fVal1
- fVal2
)*(fVal1
- fVal2
);
2487 fT
= sqrt(fCount
-1.0) * fabs(fSum1
- fSum2
) /
2488 sqrt(fCount
* fSumSqrD
- (fSum1
-fSum2
)*(fSum1
-fSum2
));
2491 else if (fTyp
== 2.0)
2493 CalculateTest(FALSE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2495 else if (fTyp
== 3.0)
2497 CalculateTest(TRUE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2502 PushIllegalArgument();
2506 PushDouble(GetTDist(fT
, fF
));
2508 PushDouble(2.0*GetTDist(fT
, fF
));
2511 void ScInterpreter::ScFTest()
2513 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFTest" );
2514 if ( !MustHaveParamCount( GetByte(), 2 ) )
2516 ScMatrixRef pMat2
= GetMatrix();
2517 ScMatrixRef pMat1
= GetMatrix();
2518 if (!pMat1
|| !pMat2
)
2520 PushIllegalParameter();
2526 pMat1
->GetDimensions(nC1
, nR1
);
2527 pMat2
->GetDimensions(nC2
, nR2
);
2528 double fCount1
= 0.0;
2529 double fCount2
= 0.0;
2531 double fSumSqr1
= 0.0;
2533 double fSumSqr2
= 0.0;
2535 for (i
= 0; i
< nC1
; i
++)
2536 for (j
= 0; j
< nR1
; j
++)
2538 if (!pMat1
->IsString(i
,j
))
2540 fVal
= pMat1
->GetDouble(i
,j
);
2542 fSumSqr1
+= fVal
* fVal
;
2546 for (i
= 0; i
< nC2
; i
++)
2547 for (j
= 0; j
< nR2
; j
++)
2549 if (!pMat2
->IsString(i
,j
))
2551 fVal
= pMat2
->GetDouble(i
,j
);
2553 fSumSqr2
+= fVal
* fVal
;
2557 if (fCount1
< 2.0 || fCount2
< 2.0)
2562 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0);
2563 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0);
2564 if (fS1
== 0.0 || fS2
== 0.0)
2569 double fF
, fF1
, fF2
;
2582 PushDouble(2.0*GetFDist(fF
, fF1
, fF2
));
2584 double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
2585 sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
2586 PushDouble(1.0-2.0*gauss(Z));
2590 void ScInterpreter::ScChiTest()
2592 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiTest" );
2593 if ( !MustHaveParamCount( GetByte(), 2 ) )
2595 ScMatrixRef pMat2
= GetMatrix();
2596 ScMatrixRef pMat1
= GetMatrix();
2597 if (!pMat1
|| !pMat2
)
2599 PushIllegalParameter();
2604 pMat1
->GetDimensions(nC1
, nR1
);
2605 pMat2
->GetDimensions(nC2
, nR2
);
2606 if (nR1
!= nR2
|| nC1
!= nC2
)
2608 PushIllegalArgument();
2612 for (SCSIZE i
= 0; i
< nC1
; i
++)
2614 for (SCSIZE j
= 0; j
< nR1
; j
++)
2616 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2618 double fValX
= pMat1
->GetDouble(i
,j
);
2619 double fValE
= pMat2
->GetDouble(i
,j
);
2620 fChi
+= (fValX
- fValE
) * (fValX
- fValE
) / fValE
;
2624 PushIllegalArgument();
2630 if (nC1
== 1 || nR1
== 1)
2632 fDF
= (double)(nC1
*nR1
- 1);
2640 fDF
= (double)(nC1
-1)*(double)(nR1
-1);
2641 PushDouble(GetChiDist(fChi
, fDF
));
2643 double fX, fS, fT, fG;
2645 for (double fi = fDF; fi >= 2.0; fi -= 2.0)
2647 fX *= exp(-fChi/2.0);
2648 if (fmod(fDF, 2.0) != 0.0)
2649 fX *= sqrt(2.0*fChi/F_PI);
2653 while (fT >= 1.0E-7)
2659 PushDouble(1.0 - fX*fS);
2663 void ScInterpreter::ScKurt()
2665 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKurt" );
2666 double fSum
,fCount
,vSum
;
2667 std::vector
<double> values
;
2668 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
2673 PushError( errDivisionByZero
);
2677 double fMean
= fSum
/ fCount
;
2679 for (size_t i
= 0; i
< values
.size(); i
++)
2680 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
2682 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
2684 double xpower4
= 0.0;
2688 PushError( errDivisionByZero
);
2692 for (size_t i
= 0; i
< values
.size(); i
++)
2694 dx
= (values
[i
] - fMean
) / fStdDev
;
2695 xpower4
= xpower4
+ (dx
* dx
* dx
* dx
);
2698 double k_d
= (fCount
- 2.0) * (fCount
- 3.0);
2699 double k_l
= fCount
* (fCount
+ 1.0) / ((fCount
- 1.0) * k_d
);
2700 double k_t
= 3.0 * (fCount
- 1.0) * (fCount
- 1.0) / k_d
;
2702 PushDouble(xpower4
* k_l
- k_t
);
2705 void ScInterpreter::ScHarMean()
2707 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHarMean" );
2708 short nParamCount
= GetByte();
2710 double nValCount
= 0.0;
2713 size_t nRefInList
= 0;
2714 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2716 switch (GetStackType())
2718 case formula::svDouble
:
2720 double x
= GetDouble();
2727 SetError( errIllegalArgument
);
2732 PopSingleRef( aAdr
);
2733 ScBaseCell
* pCell
= GetCell( aAdr
);
2734 if (HasCellValueData(pCell
))
2736 double x
= GetCellValue( aAdr
, pCell
);
2743 SetError( errIllegalArgument
);
2747 case formula::svDoubleRef
:
2751 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2753 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2754 if (aValIter
.GetFirst(nCellVal
, nErr
))
2758 nVal
+= 1.0/nCellVal
;
2762 SetError( errIllegalArgument
);
2764 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2768 nVal
+= 1.0/nCellVal
;
2772 SetError( errIllegalArgument
);
2780 ScMatrixRef pMat
= PopMatrix();
2783 SCSIZE nCount
= pMat
->GetElementCount();
2784 if (pMat
->IsNumeric())
2786 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2788 double x
= pMat
->GetDouble(nElem
);
2795 SetError( errIllegalArgument
);
2800 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2801 if (!pMat
->IsString(nElem
))
2803 double x
= pMat
->GetDouble(nElem
);
2810 SetError( errIllegalArgument
);
2816 default : SetError(errIllegalParameter
); break;
2819 if (nGlobalError
== 0)
2820 PushDouble((double)nValCount
/nVal
);
2822 PushError( nGlobalError
);
2825 void ScInterpreter::ScGeoMean()
2827 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGeoMean" );
2828 short nParamCount
= GetByte();
2830 double nValCount
= 0.0;
2834 size_t nRefInList
= 0;
2835 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2837 switch (GetStackType())
2839 case formula::svDouble
:
2841 double x
= GetDouble();
2848 SetError( errIllegalArgument
);
2853 PopSingleRef( aAdr
);
2854 ScBaseCell
* pCell
= GetCell( aAdr
);
2855 if (HasCellValueData(pCell
))
2857 double x
= GetCellValue( aAdr
, pCell
);
2864 SetError( errIllegalArgument
);
2868 case formula::svDoubleRef
:
2872 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2874 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2875 if (aValIter
.GetFirst(nCellVal
, nErr
))
2879 nVal
+= log(nCellVal
);
2883 SetError( errIllegalArgument
);
2885 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2889 nVal
+= log(nCellVal
);
2893 SetError( errIllegalArgument
);
2901 ScMatrixRef pMat
= PopMatrix();
2904 SCSIZE nCount
= pMat
->GetElementCount();
2905 if (pMat
->IsNumeric())
2907 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2909 double x
= pMat
->GetDouble(ui
);
2916 SetError( errIllegalArgument
);
2921 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2922 if (!pMat
->IsString(ui
))
2924 double x
= pMat
->GetDouble(ui
);
2931 SetError( errIllegalArgument
);
2937 default : SetError(errIllegalParameter
); break;
2940 if (nGlobalError
== 0)
2941 PushDouble(exp(nVal
/ nValCount
));
2943 PushError( nGlobalError
);
2946 void ScInterpreter::ScStandard()
2948 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStandard" );
2949 if ( MustHaveParamCount( GetByte(), 3 ) )
2951 double sigma
= GetDouble();
2952 double mue
= GetDouble();
2953 double x
= GetDouble();
2955 PushError( errIllegalArgument
);
2956 else if (sigma
== 0.0)
2957 PushError( errDivisionByZero
);
2959 PushDouble((x
-mue
)/sigma
);
2962 bool ScInterpreter::CalculateSkew(double& fSum
,double& fCount
,double& vSum
,std::vector
<double>& values
)
2964 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSkew" );
2965 short nParamCount
= GetByte();
2966 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
2975 size_t nRefInList
= 0;
2976 while (nParamCount
-- > 0)
2978 switch (GetStackType())
2980 case formula::svDouble
:
2984 values
.push_back(fVal
);
2990 PopSingleRef( aAdr
);
2991 ScBaseCell
* pCell
= GetCell( aAdr
);
2992 if (HasCellValueData(pCell
))
2994 fVal
= GetCellValue( aAdr
, pCell
);
2996 values
.push_back(fVal
);
3001 case formula::svDoubleRef
:
3004 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3006 ScValueIterator
aValIter(pDok
, aRange
);
3007 if (aValIter
.GetFirst(fVal
, nErr
))
3010 values
.push_back(fVal
);
3013 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
3016 values
.push_back(fVal
);
3025 ScMatrixRef pMat
= PopMatrix();
3028 SCSIZE nCount
= pMat
->GetElementCount();
3029 if (pMat
->IsNumeric())
3031 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3033 fVal
= pMat
->GetDouble(nElem
);
3035 values
.push_back(fVal
);
3041 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3042 if (!pMat
->IsString(nElem
))
3044 fVal
= pMat
->GetDouble(nElem
);
3046 values
.push_back(fVal
);
3054 SetError(errIllegalParameter
);
3061 PushError( nGlobalError
);
3063 } // if (nGlobalError)
3067 void ScInterpreter::ScSkew()
3069 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSkew" );
3070 double fSum
,fCount
,vSum
;
3071 std::vector
<double> values
;
3072 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
3075 double fMean
= fSum
/ fCount
;
3077 for (size_t i
= 0; i
< values
.size(); i
++)
3078 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
3080 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
3086 PushIllegalArgument();
3090 for (size_t i
= 0; i
< values
.size(); i
++)
3092 dx
= (values
[i
] - fMean
) / fStdDev
;
3093 xcube
= xcube
+ (dx
* dx
* dx
);
3096 PushDouble(((xcube
* fCount
) / (fCount
- 1.0)) / (fCount
- 2.0));
3099 double ScInterpreter::GetMedian( vector
<double> & rArray
)
3101 size_t nSize
= rArray
.size();
3102 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3104 SetError( errNoValue
);
3109 size_t nMid
= nSize
/ 2;
3110 vector
<double>::iterator iMid
= rArray
.begin() + nMid
;
3111 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3113 return *iMid
; // Lower and upper median are equal.
3118 iMid
= rArray
.begin() + nMid
- 1;
3119 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3120 return (fUp
+ *iMid
) / 2;
3124 void ScInterpreter::ScMedian()
3126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMedian" );
3127 BYTE nParamCount
= GetByte();
3128 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3130 vector
<double> aArray
;
3131 GetNumberSequenceArray( nParamCount
, aArray
);
3132 PushDouble( GetMedian( aArray
));
3135 double ScInterpreter::GetPercentile( vector
<double> & rArray
, double fPercentile
)
3137 size_t nSize
= rArray
.size();
3138 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3140 SetError( errNoValue
);
3148 size_t nIndex
= (size_t)::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3149 double fDiff
= fPercentile
* (nSize
-1) - ::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3150 DBG_ASSERT(nIndex
< nSize
, "GetPercentile: wrong index(1)");
3151 vector
<double>::iterator iter
= rArray
.begin() + nIndex
;
3152 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3157 DBG_ASSERT(nIndex
< nSize
-1, "GetPercentile: wrong index(2)");
3158 double fVal
= *iter
;
3159 iter
= rArray
.begin() + nIndex
+1;
3160 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3161 return fVal
+ fDiff
* (*iter
- fVal
);
3166 void ScInterpreter::ScPercentile()
3168 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentile" );
3169 if ( !MustHaveParamCount( GetByte(), 2 ) )
3171 double alpha
= GetDouble();
3172 if (alpha
< 0.0 || alpha
> 1.0)
3174 PushIllegalArgument();
3177 vector
<double> aArray
;
3178 GetNumberSequenceArray( 1, aArray
);
3179 PushDouble( GetPercentile( aArray
, alpha
));
3182 void ScInterpreter::ScQuartile()
3184 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScQuartile" );
3185 if ( !MustHaveParamCount( GetByte(), 2 ) )
3187 double fFlag
= ::rtl::math::approxFloor(GetDouble());
3188 if (fFlag
< 0.0 || fFlag
> 4.0)
3190 PushIllegalArgument();
3193 vector
<double> aArray
;
3194 GetNumberSequenceArray( 1, aArray
);
3195 PushDouble( fFlag
== 2.0 ? GetMedian( aArray
) : GetPercentile( aArray
, 0.25 * fFlag
));
3198 void ScInterpreter::ScModalValue()
3200 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScModalValue" );
3201 BYTE nParamCount
= GetByte();
3202 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3204 vector
<double> aSortArray
;
3205 GetSortArray(nParamCount
, aSortArray
);
3206 SCSIZE nSize
= aSortArray
.size();
3207 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3211 SCSIZE nMaxIndex
= 0, nMax
= 1, nCount
= 1;
3212 double nOldVal
= aSortArray
[0];
3215 for ( i
= 1; i
< nSize
; i
++)
3217 if (aSortArray
[i
] == nOldVal
)
3221 nOldVal
= aSortArray
[i
];
3235 if (nMax
== 1 && nCount
== 1)
3238 PushDouble(nOldVal
);
3240 PushDouble(aSortArray
[nMaxIndex
]);
3244 void ScInterpreter::CalculateSmallLarge(BOOL bSmall
)
3246 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSmallLarge" );
3247 if ( !MustHaveParamCount( GetByte(), 2 ) )
3249 double f
= ::rtl::math::approxFloor(GetDouble());
3252 PushIllegalArgument();
3255 SCSIZE k
= static_cast<SCSIZE
>(f
);
3256 vector
<double> aSortArray
;
3257 /* TODO: using nth_element() is best for one single value, but LARGE/SMALL
3258 * actually are defined to return an array of values if an array of
3259 * positions was passed, in which case, depending on the number of values,
3260 * we may or will need a real sorted array again, see #i32345. */
3261 //GetSortArray(1, aSortArray);
3262 GetNumberSequenceArray(1, aSortArray
);
3263 SCSIZE nSize
= aSortArray
.size();
3264 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
|| nSize
< k
)
3268 // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] );
3269 vector
<double>::iterator iPos
= aSortArray
.begin() + (bSmall
? k
-1 : nSize
-k
);
3270 ::std::nth_element( aSortArray
.begin(), iPos
, aSortArray
.end());
3275 void ScInterpreter::ScLarge()
3277 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLarge" );
3278 CalculateSmallLarge(FALSE
);
3281 void ScInterpreter::ScSmall()
3283 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSmall" );
3284 CalculateSmallLarge(TRUE
);
3287 void ScInterpreter::ScPercentrank()
3289 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentrank" );
3290 BYTE nParamCount
= GetByte();
3291 if ( !MustHaveParamCount( nParamCount
, 2 ) )
3294 /* wird nicht unterstuetzt
3296 if (nParamCount == 3)
3298 fPrec = ::rtl::math::approxFloor(GetDouble());
3301 PushIllegalArgument();
3309 double fNum
= GetDouble();
3310 vector
<double> aSortArray
;
3311 GetSortArray(1, aSortArray
);
3312 SCSIZE nSize
= aSortArray
.size();
3313 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3317 if (fNum
< aSortArray
[0] || fNum
> aSortArray
[nSize
-1])
3319 else if ( nSize
== 1 )
3320 PushDouble(1.0); // fNum == pSortArray[0], see test above
3324 SCSIZE nOldCount
= 0;
3325 double fOldVal
= aSortArray
[0];
3327 for (i
= 1; i
< nSize
&& aSortArray
[i
] < fNum
; i
++)
3329 if (aSortArray
[i
] != fOldVal
)
3332 fOldVal
= aSortArray
[i
];
3335 if (aSortArray
[i
] != fOldVal
)
3337 if (fNum
== aSortArray
[i
])
3338 fRes
= (double)nOldCount
/(double)(nSize
-1);
3341 // #75312# nOldCount is the count of smaller entries
3342 // fNum is between pSortArray[nOldCount-1] and pSortArray[nOldCount]
3343 // use linear interpolation to find a position between the entries
3345 if ( nOldCount
== 0 )
3347 DBG_ERROR("should not happen");
3352 double fFract
= ( fNum
- aSortArray
[nOldCount
-1] ) /
3353 ( aSortArray
[nOldCount
] - aSortArray
[nOldCount
-1] );
3354 fRes
= ( (double)(nOldCount
-1)+fFract
)/(double)(nSize
-1);
3362 void ScInterpreter::ScTrimMean()
3364 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrimMean" );
3365 if ( !MustHaveParamCount( GetByte(), 2 ) )
3367 double alpha
= GetDouble();
3368 if (alpha
< 0.0 || alpha
>= 1.0)
3370 PushIllegalArgument();
3373 vector
<double> aSortArray
;
3374 GetSortArray(1, aSortArray
);
3375 SCSIZE nSize
= aSortArray
.size();
3376 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3380 ULONG nIndex
= (ULONG
) ::rtl::math::approxFloor(alpha
*(double)nSize
);
3381 if (nIndex
% 2 != 0)
3384 DBG_ASSERT(nIndex
< nSize
, "ScTrimMean: falscher Index");
3386 for (SCSIZE i
= nIndex
; i
< nSize
-nIndex
; i
++)
3387 fSum
+= aSortArray
[i
];
3388 PushDouble(fSum
/(double)(nSize
-2*nIndex
));
3392 void ScInterpreter::GetNumberSequenceArray( BYTE nParamCount
, vector
<double>& rArray
)
3394 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetSortArray" );
3397 short nParam
= nParamCount
;
3398 size_t nRefInList
= 0;
3399 while (nParam
-- > 0)
3401 switch (GetStackType())
3403 case formula::svDouble
:
3404 rArray
.push_back( PopDouble());
3408 PopSingleRef( aAdr
);
3409 ScBaseCell
* pCell
= GetCell( aAdr
);
3410 if (HasCellValueData(pCell
))
3411 rArray
.push_back( GetCellValue( aAdr
, pCell
));
3414 case formula::svDoubleRef
:
3417 PopDoubleRef( aRange
, nParam
, nRefInList
);
3422 SCSIZE nCellCount
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
3423 nCellCount
*= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
3424 rArray
.reserve( rArray
.size() + nCellCount
);
3428 ScValueIterator
aValIter(pDok
, aRange
);
3429 if (aValIter
.GetFirst( fCellVal
, nErr
))
3431 rArray
.push_back( fCellVal
);
3433 while ((nErr
== 0) && aValIter
.GetNext( fCellVal
, nErr
))
3434 rArray
.push_back( fCellVal
);
3441 ScMatrixRef pMat
= PopMatrix();
3445 SCSIZE nCount
= pMat
->GetElementCount();
3446 rArray
.reserve( rArray
.size() + nCount
);
3447 if (pMat
->IsNumeric())
3449 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3450 rArray
.push_back( pMat
->GetDouble(i
));
3454 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3455 if (!pMat
->IsString(i
))
3456 rArray
.push_back( pMat
->GetDouble(i
));
3462 SetError( errIllegalParameter
);
3468 // nParam > 0 in case of error, clean stack environment and obtain earlier
3469 // error if there was one.
3470 while (nParam
-- > 0)
3474 void ScInterpreter::GetSortArray( BYTE nParamCount
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3476 GetNumberSequenceArray( nParamCount
, rSortArray
);
3478 if (rSortArray
.size() > MAX_ANZ_DOUBLE_FOR_SORT
)
3479 SetError( errStackOverflow
);
3480 else if (rSortArray
.empty())
3481 SetError( errNoValue
);
3483 if (nGlobalError
== 0)
3484 QuickSort( rSortArray
, pIndexOrder
);
3487 static void lcl_QuickSort( long nLo
, long nHi
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3489 // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
3495 if (rSortArray
[nLo
] > rSortArray
[nHi
])
3497 swap(rSortArray
[nLo
], rSortArray
[nHi
]);
3499 swap(pIndexOrder
->at(nLo
), pIndexOrder
->at(nHi
));
3508 double fLo
= rSortArray
[nLo
];
3509 while (ni
<= nHi
&& rSortArray
[ni
] < fLo
) ni
++;
3510 while (nj
>= nLo
&& fLo
< rSortArray
[nj
]) nj
--;
3515 swap(rSortArray
[ni
], rSortArray
[nj
]);
3517 swap(pIndexOrder
->at(ni
), pIndexOrder
->at(nj
));
3526 if ((nj
- nLo
) < (nHi
- ni
))
3528 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3529 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3533 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3534 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3538 void ScInterpreter::QuickSort( vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3540 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::QuickSort" );
3541 long n
= static_cast<long>(rSortArray
.size());
3545 pIndexOrder
->clear();
3546 pIndexOrder
->reserve(n
);
3547 for (long i
= 0; i
< n
; ++i
)
3548 pIndexOrder
->push_back(i
);
3554 size_t nValCount
= rSortArray
.size();
3555 for (size_t i
= 0; (i
+ 4) <= nValCount
-1; i
+= 4)
3557 size_t nInd
= rand() % (int) (nValCount
-1);
3558 ::std::swap( rSortArray
[i
], rSortArray
[nInd
]);
3560 ::std::swap( pIndexOrder
->at(i
), pIndexOrder
->at(nInd
));
3563 lcl_QuickSort(0, n
-1, rSortArray
, pIndexOrder
);
3566 void ScInterpreter::ScRank()
3568 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRank" );
3569 BYTE nParamCount
= GetByte();
3570 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
3573 if (nParamCount
== 3)
3574 bDescending
= GetBool();
3576 bDescending
= FALSE
;
3577 double fCount
= 1.0;
3578 BOOL bValid
= FALSE
;
3579 switch (GetStackType())
3581 case formula::svDouble
:
3583 double x
= GetDouble();
3584 double fVal
= GetDouble();
3592 PopSingleRef( aAdr
);
3593 double fVal
= GetDouble();
3594 ScBaseCell
* pCell
= GetCell( aAdr
);
3595 if (HasCellValueData(pCell
))
3597 double x
= GetCellValue( aAdr
, pCell
);
3603 case formula::svDoubleRef
:
3608 size_t nRefInList
= 0;
3609 while (nParam
-- > 0)
3612 // Preserve stack until all RefList elements are done!
3613 USHORT nSaveSP
= sp
;
3614 PopDoubleRef( aRange
, nParam
, nRefInList
);
3616 --sp
; // simulate pop
3617 double fVal
= GetDouble();
3621 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
3622 if (aValIter
.GetFirst(nCellVal
, nErr
))
3624 if (nCellVal
== fVal
)
3626 else if ((!bDescending
&& nCellVal
> fVal
) ||
3627 (bDescending
&& nCellVal
< fVal
) )
3630 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3632 if (nCellVal
== fVal
)
3634 else if ((!bDescending
&& nCellVal
> fVal
) ||
3635 (bDescending
&& nCellVal
< fVal
) )
3645 ScMatrixRef pMat
= PopMatrix();
3646 double fVal
= GetDouble();
3649 SCSIZE nCount
= pMat
->GetElementCount();
3650 if (pMat
->IsNumeric())
3652 for (SCSIZE i
= 0; i
< nCount
; i
++)
3654 double x
= pMat
->GetDouble(i
);
3657 else if ((!bDescending
&& x
> fVal
) ||
3658 (bDescending
&& x
< fVal
) )
3664 for (SCSIZE i
= 0; i
< nCount
; i
++)
3665 if (!pMat
->IsString(i
))
3667 double x
= pMat
->GetDouble(i
);
3670 else if ((!bDescending
&& x
> fVal
) ||
3671 (bDescending
&& x
< fVal
) )
3678 default : SetError(errIllegalParameter
); break;
3686 void ScInterpreter::ScAveDev()
3688 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAveDev" );
3689 BYTE nParamCount
= GetByte();
3690 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3693 double nMiddle
= 0.0;
3695 double rValCount
= 0.0;
3698 short nParam
= nParamCount
;
3699 size_t nRefInList
= 0;
3700 while (nParam
-- > 0)
3702 switch (GetStackType())
3704 case formula::svDouble
:
3705 rVal
+= GetDouble();
3710 PopSingleRef( aAdr
);
3711 ScBaseCell
* pCell
= GetCell( aAdr
);
3712 if (HasCellValueData(pCell
))
3714 rVal
+= GetCellValue( aAdr
, pCell
);
3719 case formula::svDoubleRef
:
3724 PopDoubleRef( aRange
, nParam
, nRefInList
);
3725 ScValueIterator
aValIter(pDok
, aRange
);
3726 if (aValIter
.GetFirst(nCellVal
, nErr
))
3731 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3742 ScMatrixRef pMat
= PopMatrix();
3745 SCSIZE nCount
= pMat
->GetElementCount();
3746 if (pMat
->IsNumeric())
3748 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3750 rVal
+= pMat
->GetDouble(nElem
);
3756 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3757 if (!pMat
->IsString(nElem
))
3759 rVal
+= pMat
->GetDouble(nElem
);
3767 SetError(errIllegalParameter
);
3773 PushError( nGlobalError
);
3776 nMiddle
= rVal
/ rValCount
;
3779 nParam
= nParamCount
;
3781 while (nParam
-- > 0)
3783 switch (GetStackType())
3785 case formula::svDouble
:
3786 rVal
+= fabs(GetDouble() - nMiddle
);
3790 PopSingleRef( aAdr
);
3791 ScBaseCell
* pCell
= GetCell( aAdr
);
3792 if (HasCellValueData(pCell
))
3793 rVal
+= fabs(GetCellValue( aAdr
, pCell
) - nMiddle
);
3796 case formula::svDoubleRef
:
3801 PopDoubleRef( aRange
, nParam
, nRefInList
);
3802 ScValueIterator
aValIter(pDok
, aRange
);
3803 if (aValIter
.GetFirst(nCellVal
, nErr
))
3805 rVal
+= (fabs(nCellVal
- nMiddle
));
3806 while (aValIter
.GetNext(nCellVal
, nErr
))
3807 rVal
+= fabs(nCellVal
- nMiddle
);
3813 ScMatrixRef pMat
= PopMatrix();
3816 SCSIZE nCount
= pMat
->GetElementCount();
3817 if (pMat
->IsNumeric())
3819 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3821 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3826 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3828 if (!pMat
->IsString(nElem
))
3829 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3835 default : SetError(errIllegalParameter
); break;
3838 PushDouble(rVal
/ rValCount
);
3841 void ScInterpreter::ScDevSq()
3843 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDevSq" );
3846 GetStVarParams(nVal
, nValCount
);
3850 void ScInterpreter::ScProbability()
3852 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScProbability" );
3853 BYTE nParamCount
= GetByte();
3854 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
3858 if (nParamCount
== 4)
3868 ScMatrixRef pMatP
= GetMatrix();
3869 ScMatrixRef pMatW
= GetMatrix();
3870 if (!pMatP
|| !pMatW
)
3871 PushIllegalParameter();
3876 pMatP
->GetDimensions(nC1
, nR1
);
3877 pMatW
->GetDimensions(nC2
, nR2
);
3878 if (nC1
!= nC2
|| nR1
!= nR2
|| nC1
== 0 || nR1
== 0 ||
3879 nC2
== 0 || nR2
== 0)
3887 SCSIZE nCount1
= nC1
* nR1
;
3888 for ( SCSIZE i
= 0; i
< nCount1
&& !bStop
; i
++ )
3890 if (pMatP
->IsValue(i
) && pMatW
->IsValue(i
))
3892 fP
= pMatP
->GetDouble(i
);
3893 fW
= pMatW
->GetDouble(i
);
3894 if (fP
< 0.0 || fP
> 1.0)
3899 if (fW
>= fLo
&& fW
<= fUp
)
3904 SetError( errIllegalArgument
);
3906 if (bStop
|| fabs(fSum
-1.0) > 1.0E-7)
3914 void ScInterpreter::ScCorrel()
3916 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCorrel" );
3917 // This is identical to ScPearson()
3921 void ScInterpreter::ScCovar()
3923 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCovar" );
3924 CalculatePearsonCovar(FALSE
,FALSE
);
3927 void ScInterpreter::ScPearson()
3929 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPearson" );
3930 CalculatePearsonCovar(TRUE
,FALSE
);
3932 void ScInterpreter::CalculatePearsonCovar(BOOL _bPearson
,BOOL _bStexy
)
3934 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculatePearsonCovar" );
3935 if ( !MustHaveParamCount( GetByte(), 2 ) )
3937 ScMatrixRef pMat1
= GetMatrix();
3938 ScMatrixRef pMat2
= GetMatrix();
3939 if (!pMat1
|| !pMat2
)
3941 PushIllegalParameter();
3946 pMat1
->GetDimensions(nC1
, nR1
);
3947 pMat2
->GetDimensions(nC2
, nR2
);
3948 if (nR1
!= nR2
|| nC1
!= nC2
)
3950 PushIllegalArgument();
3954 * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
3955 * but the latter produces wrong results if the absolute values are high,
3956 * for example above 10^8
3958 double fCount
= 0.0;
3961 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
3962 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
3963 double fSumSqrDeltaY
= 0.0; // sum of (ValY-MeanY)^2
3964 for (SCSIZE i
= 0; i
< nC1
; i
++)
3966 for (SCSIZE j
= 0; j
< nR1
; j
++)
3968 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
3970 double fValX
= pMat1
->GetDouble(i
,j
);
3971 double fValY
= pMat2
->GetDouble(i
,j
);
3978 if (fCount
< (_bStexy
? 3.0 : 1.0)) // fCount==1 is handled by checking denominator later on
3982 const double fMeanX
= fSumX
/ fCount
;
3983 const double fMeanY
= fSumY
/ fCount
;
3984 for (SCSIZE i
= 0; i
< nC1
; i
++)
3986 for (SCSIZE j
= 0; j
< nR1
; j
++)
3988 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
3990 const double fValX
= pMat1
->GetDouble(i
,j
);
3991 const double fValY
= pMat2
->GetDouble(i
,j
);
3992 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
3995 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
3996 fSumSqrDeltaY
+= (fValY
- fMeanY
) * (fValY
- fMeanY
);
4000 } // for (SCSIZE i = 0; i < nC1; i++)
4003 if (fSumSqrDeltaX
== 0.0 || ( !_bStexy
&& fSumSqrDeltaY
== 0.0) )
4004 PushError( errDivisionByZero
);
4006 PushDouble( sqrt( (fSumSqrDeltaY
- fSumDeltaXDeltaY
*
4007 fSumDeltaXDeltaY
/ fSumSqrDeltaX
) / (fCount
-2)));
4009 PushDouble( fSumDeltaXDeltaY
/ sqrt( fSumSqrDeltaX
* fSumSqrDeltaY
));
4010 } // if ( _bPearson )
4013 PushDouble( fSumDeltaXDeltaY
/ fCount
);
4018 void ScInterpreter::ScRSQ()
4020 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRSQ" );
4021 // Same as ScPearson()*ScPearson()
4025 switch (GetStackType())
4027 case formula::svDouble
:
4029 double fVal
= PopDouble();
4030 PushDouble( fVal
* fVal
);
4040 void ScInterpreter::ScSTEXY()
4042 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSTEXY" );
4043 CalculatePearsonCovar(TRUE
,TRUE
);
4045 void ScInterpreter::CalculateSlopeIntercept(BOOL bSlope
)
4047 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSlopeIntercept" );
4048 if ( !MustHaveParamCount( GetByte(), 2 ) )
4050 ScMatrixRef pMat1
= GetMatrix();
4051 ScMatrixRef pMat2
= GetMatrix();
4052 if (!pMat1
|| !pMat2
)
4054 PushIllegalParameter();
4059 pMat1
->GetDimensions(nC1
, nR1
);
4060 pMat2
->GetDimensions(nC2
, nR2
);
4061 if (nR1
!= nR2
|| nC1
!= nC2
)
4063 PushIllegalArgument();
4066 // #i78250# numerical stability improved
4067 double fCount
= 0.0;
4070 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4071 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4072 for (SCSIZE i
= 0; i
< nC1
; i
++)
4074 for (SCSIZE j
= 0; j
< nR1
; j
++)
4076 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4078 double fValX
= pMat1
->GetDouble(i
,j
);
4079 double fValY
= pMat2
->GetDouble(i
,j
);
4090 double fMeanX
= fSumX
/ fCount
;
4091 double fMeanY
= fSumY
/ fCount
;
4092 for (SCSIZE i
= 0; i
< nC1
; i
++)
4094 for (SCSIZE j
= 0; j
< nR1
; j
++)
4096 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4098 double fValX
= pMat1
->GetDouble(i
,j
);
4099 double fValY
= pMat2
->GetDouble(i
,j
);
4100 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4101 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4105 if (fSumSqrDeltaX
== 0.0)
4106 PushError( errDivisionByZero
);
4110 PushDouble( fSumDeltaXDeltaY
/ fSumSqrDeltaX
);
4112 PushDouble( fMeanY
- fSumDeltaXDeltaY
/ fSumSqrDeltaX
* fMeanX
);
4117 void ScInterpreter::ScSlope()
4119 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSlope" );
4120 CalculateSlopeIntercept(TRUE
);
4123 void ScInterpreter::ScIntercept()
4125 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIntercept" );
4126 CalculateSlopeIntercept(FALSE
);
4129 void ScInterpreter::ScForecast()
4131 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScForecast" );
4132 if ( !MustHaveParamCount( GetByte(), 3 ) )
4134 ScMatrixRef pMat1
= GetMatrix();
4135 ScMatrixRef pMat2
= GetMatrix();
4136 if (!pMat1
|| !pMat2
)
4138 PushIllegalParameter();
4143 pMat1
->GetDimensions(nC1
, nR1
);
4144 pMat2
->GetDimensions(nC2
, nR2
);
4145 if (nR1
!= nR2
|| nC1
!= nC2
)
4147 PushIllegalArgument();
4150 double fVal
= GetDouble();
4151 // #i78250# numerical stability improved
4152 double fCount
= 0.0;
4155 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4156 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4157 for (SCSIZE i
= 0; i
< nC1
; i
++)
4159 for (SCSIZE j
= 0; j
< nR1
; j
++)
4161 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4163 double fValX
= pMat1
->GetDouble(i
,j
);
4164 double fValY
= pMat2
->GetDouble(i
,j
);
4175 double fMeanX
= fSumX
/ fCount
;
4176 double fMeanY
= fSumY
/ fCount
;
4177 for (SCSIZE i
= 0; i
< nC1
; i
++)
4179 for (SCSIZE j
= 0; j
< nR1
; j
++)
4181 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4183 double fValX
= pMat1
->GetDouble(i
,j
);
4184 double fValY
= pMat2
->GetDouble(i
,j
);
4185 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4186 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4190 if (fSumSqrDeltaX
== 0.0)
4191 PushError( errDivisionByZero
);
4193 PushDouble( fMeanY
+ fSumDeltaXDeltaY
/ fSumSqrDeltaX
* (fVal
- fMeanX
));