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
);
935 if (fB
< 1.0 && fX
== 1.0)
937 SetError(errIllegalArgument
);
943 // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
944 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
945 const double fLogDblMin
= log( ::std::numeric_limits
<double>::min());
946 double fLogY
= (fX
< 0.1) ? ::rtl::math::log1p(-fX
) : log(0.5-fX
+0.5);
947 double fLogX
= log(fX
);
948 double fAm1
= fA
-1.0;
949 double fBm1
= fB
-1.0;
950 double fLogBeta
= GetLogBeta(fA
,fB
);
951 // check whether parts over- or underflow
952 if ( fAm1
* fLogX
< fLogDblMax
&& fAm1
* fLogX
> fLogDblMin
953 && fBm1
* fLogY
< fLogDblMax
&& fBm1
* fLogY
> fLogDblMin
954 && fLogBeta
< fLogDblMax
&& fLogBeta
> fLogDblMin
)
955 return pow(fX
,fA
-1.0) * pow(0.5-fX
+0.5,fB
-1.0) / GetBeta(fA
,fB
);
956 else // need logarithm;
957 // might overflow as a whole, but seldom, not worth to pre-detect it
958 return exp((fA
-1.0)*fLogX
+ (fB
-1.0)* fLogY
- fLogBeta
);
964 I_x(a,b) = ---------------- * result of ContFrac
967 double lcl_GetBetaHelperContFrac(double fX
, double fA
, double fB
)
968 { // like old version
969 double a1
, b1
, a2
, b2
, fnorm
, apl2m
, d2m
, d2m1
, cfnew
, cf
;
971 b2
= 1.0 - (fA
+fB
)/(fA
+1.0)*fX
;
987 const double fMaxIter
= 50000.0;
988 // loop security, normal cases converge in less than 100 iterations.
989 // FIXME: You will get so much iteratons for fX near mean,
990 // I do not know a better algorithm.
991 bool bfinished
= false;
995 d2m
= rm
*(fB
-rm
)*fX
/((apl2m
-1.0)*apl2m
);
996 d2m1
= -(fA
+rm
)*(fA
+fB
+rm
)*fX
/(apl2m
*(apl2m
+1.0));
997 a1
= (a2
+d2m
*a1
)*fnorm
;
998 b1
= (b2
+d2m
*b1
)*fnorm
;
999 a2
= a1
+ d2m1
*a2
*fnorm
;
1000 b2
= b1
+ d2m1
*b2
*fnorm
;
1005 bfinished
= (fabs(cf
-cfnew
) < fabs(cf
)*fMachEps
);
1010 while (rm
< fMaxIter
&& !bfinished
);
1014 // cumulative distribution function, normalized
1015 double ScInterpreter::GetBetaDist(double fXin
, double fAlpha
, double fBeta
)
1018 if (fXin
<= 0.0) // values are valid, see spec
1020 if (fXin
>= 1.0) // values are valid, see spec
1023 return pow(fXin
, fAlpha
);
1025 // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
1026 return -::rtl::math::expm1(fBeta
* ::rtl::math::log1p(-fXin
));
1027 //FIXME: need special algorithm for fX near fP for large fA,fB
1029 // I use always continued fraction, power series are neither
1030 // faster nor more accurate.
1031 double fY
= (0.5-fXin
)+0.5;
1032 double flnY
= ::rtl::math::log1p(-fXin
);
1034 double flnX
= log(fXin
);
1037 bool bReflect
= fXin
> fAlpha
/(fAlpha
+fBeta
);
1047 fResult
= lcl_GetBetaHelperContFrac(fX
,fA
,fB
);
1048 fResult
= fResult
/fA
;
1049 double fP
= fA
/(fA
+fB
);
1050 double fQ
= fB
/(fA
+fB
);
1052 if (fA
> 1.0 && fB
> 1.0 && fP
< 0.97 && fQ
< 0.97) //found experimental
1053 fTemp
= GetBetaDistPDF(fX
,fA
,fB
)*fX
*fY
;
1055 fTemp
= exp(fA
*flnX
+ fB
*flnY
- GetLogBeta(fA
,fB
));
1058 fResult
= 0.5 - fResult
+ 0.5;
1059 if (fResult
> 1.0) // ensure valid range
1066 void ScInterpreter::ScBetaDist()
1068 BYTE nParamCount
= GetByte();
1069 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) ) // expanded, see #i91547#
1071 double fLowerBound
, fUpperBound
;
1072 double alpha
, beta
, x
;
1074 if (nParamCount
== 6)
1075 bIsCumulative
= GetBool();
1077 bIsCumulative
= true;
1078 if (nParamCount
>= 5)
1079 fUpperBound
= GetDouble();
1082 if (nParamCount
>= 4)
1083 fLowerBound
= GetDouble();
1087 alpha
= GetDouble();
1089 double fScale
= fUpperBound
- fLowerBound
;
1090 if (fScale
<= 0.0 || alpha
<= 0.0 || beta
<= 0.0)
1092 PushIllegalArgument();
1095 if (bIsCumulative
) // cumulative distribution function
1098 if (x
< fLowerBound
)
1100 PushDouble(0.0); return; //see spec
1102 if (x
> fUpperBound
)
1104 PushDouble(1.0); return; //see spec
1107 x
= (x
-fLowerBound
)/fScale
; // convert to standard form
1108 PushDouble(GetBetaDist(x
, alpha
, beta
));
1111 else // probability density function
1113 if (x
< fLowerBound
|| x
> fUpperBound
)
1118 x
= (x
-fLowerBound
)/fScale
;
1119 PushDouble(GetBetaDistPDF(x
, alpha
, beta
)/fScale
);
1124 void ScInterpreter::ScPhi()
1126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPhi" );
1127 PushDouble(phi(GetDouble()));
1130 void ScInterpreter::ScGauss()
1132 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGauss" );
1133 PushDouble(gauss(GetDouble()));
1136 void ScInterpreter::ScFisher()
1138 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFisher" );
1139 double fVal
= GetDouble();
1140 if (fabs(fVal
) >= 1.0)
1141 PushIllegalArgument();
1143 PushDouble( ::rtl::math::atanh( fVal
));
1146 void ScInterpreter::ScFisherInv()
1148 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFisherInv" );
1149 PushDouble( tanh( GetDouble()));
1152 void ScInterpreter::ScFact()
1154 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFact" );
1155 double nVal
= GetDouble();
1157 PushIllegalArgument();
1159 PushDouble(Fakultaet(nVal
));
1162 void ScInterpreter::ScKombin()
1164 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKombin" );
1165 if ( MustHaveParamCount( GetByte(), 2 ) )
1167 double k
= ::rtl::math::approxFloor(GetDouble());
1168 double n
= ::rtl::math::approxFloor(GetDouble());
1169 if (k
< 0.0 || n
< 0.0 || k
> n
)
1170 PushIllegalArgument();
1172 PushDouble(BinomKoeff(n
, k
));
1176 void ScInterpreter::ScKombin2()
1178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKombin2" );
1179 if ( MustHaveParamCount( GetByte(), 2 ) )
1181 double k
= ::rtl::math::approxFloor(GetDouble());
1182 double n
= ::rtl::math::approxFloor(GetDouble());
1183 if (k
< 0.0 || n
< 0.0 || k
> n
)
1184 PushIllegalArgument();
1186 PushDouble(BinomKoeff(n
+ k
- 1, k
));
1190 void ScInterpreter::ScVariationen()
1192 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVariationen" );
1193 if ( MustHaveParamCount( GetByte(), 2 ) )
1195 double k
= ::rtl::math::approxFloor(GetDouble());
1196 double n
= ::rtl::math::approxFloor(GetDouble());
1197 if (n
< 0.0 || k
< 0.0 || k
> n
)
1198 PushIllegalArgument();
1200 PushInt(1); // (n! / (n - 0)!) == 1
1204 for (ULONG i
= (ULONG
)k
-1; i
>= 1; i
--)
1205 nVal
*= n
-(double)i
;
1211 void ScInterpreter::ScVariationen2()
1213 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVariationen2" );
1214 if ( MustHaveParamCount( GetByte(), 2 ) )
1216 double k
= ::rtl::math::approxFloor(GetDouble());
1217 double n
= ::rtl::math::approxFloor(GetDouble());
1218 if (n
< 0.0 || k
< 0.0 || k
> n
)
1219 PushIllegalArgument();
1221 PushDouble(pow(n
,k
));
1225 void ScInterpreter::ScB()
1227 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScB" );
1228 BYTE nParamCount
= GetByte();
1229 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1231 if (nParamCount
== 3)
1233 double x
= ::rtl::math::approxFloor(GetDouble());
1234 double p
= GetDouble();
1235 double n
= ::rtl::math::approxFloor(GetDouble());
1236 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1237 PushIllegalArgument();
1241 double fFactor
= pow(q
, n
);
1244 fFactor
= pow(p
, n
);
1249 ULONG max
= (ULONG
) (n
- x
);
1250 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1251 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1252 PushDouble(fFactor
);
1257 ULONG max
= (ULONG
) x
;
1258 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1259 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1260 PushDouble(fFactor
);
1264 else if (nParamCount
== 4)
1266 double xe
= GetDouble();
1267 double xs
= GetDouble();
1268 double p
= GetDouble();
1269 double n
= GetDouble();
1270 // alter Stand 300-SC
1271 // if ((xs < n) && (xe < n) && (p < 1.0))
1273 // double Varianz = sqrt(n * p * (1.0 - p));
1274 // xs = fabs(xs - (n * p /* / 2.0 STE */ ));
1275 // xe = fabs(xe - (n * p /* / 2.0 STE */ ));
1276 //// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz);
1277 // double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz));
1278 // PushDouble(nVal);
1280 if (xe
<= n
&& xs
<= xe
&&
1281 p
< 1.0 && p
> 0.0 && n
>= 0.0 && xs
>= 0.0 )
1284 double fFactor
= pow(q
, n
);
1287 fFactor
= pow(p
, n
);
1295 max
= (ULONG
) (n
-xe
)-1;
1299 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1300 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1302 max
= (ULONG
) (n
-xs
);
1305 for (; i
< max
&& fFactor
> 0.0; i
++)
1307 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1317 if ( (ULONG
) xs
== 0)
1328 for (i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1329 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1330 if ((ULONG
)xe
== 0) // beide 0
1334 for (; i
< max
&& fFactor
> 0.0; i
++)
1336 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1343 PushIllegalArgument();
1347 void ScInterpreter::ScBinomDist()
1349 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBinomDist" );
1350 if ( MustHaveParamCount( GetByte(), 4 ) )
1352 double kum
= GetDouble(); // 0 oder 1
1353 double p
= GetDouble(); // p
1354 double n
= ::rtl::math::approxFloor(GetDouble()); // n
1355 double x
= ::rtl::math::approxFloor(GetDouble()); // x
1356 double fFactor
, q
, fSum
;
1357 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1358 PushIllegalArgument();
1359 else if (kum
== 0.0) // Dichte
1362 fFactor
= pow(q
, n
);
1365 fFactor
= pow(p
, n
);
1370 ULONG max
= (ULONG
) (n
- x
);
1371 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1372 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1373 PushDouble(fFactor
);
1378 ULONG max
= (ULONG
) x
;
1379 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1380 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1381 PushDouble(fFactor
);
1391 fFactor
= pow(q
, n
);
1394 fFactor
= pow(p
, n
);
1399 fSum
= 1.0 - fFactor
;
1400 ULONG max
= (ULONG
) (n
- x
) - 1;
1401 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1403 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1415 ULONG max
= (ULONG
) x
;
1416 for (ULONG i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1418 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1428 void ScInterpreter::ScCritBinom()
1430 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCritBinom" );
1431 if ( MustHaveParamCount( GetByte(), 3 ) )
1433 double alpha
= GetDouble(); // alpha
1434 double p
= GetDouble(); // p
1435 double n
= ::rtl::math::approxFloor(GetDouble());
1436 if (n
< 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || p
< 0.0 || p
> 1.0)
1437 PushIllegalArgument();
1441 double fFactor
= pow(q
,n
);
1444 fFactor
= pow(p
, n
);
1449 double fSum
= 1.0 - fFactor
; ULONG max
= (ULONG
) n
;
1452 for ( i
= 0; i
< max
&& fSum
>= alpha
; i
++)
1454 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1462 double fSum
= fFactor
; ULONG max
= (ULONG
) n
;
1465 for ( i
= 0; i
< max
&& fSum
< alpha
; i
++)
1467 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1476 void ScInterpreter::ScNegBinomDist()
1478 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNegBinomDist" );
1479 if ( MustHaveParamCount( GetByte(), 3 ) )
1481 double p
= GetDouble(); // p
1482 double r
= GetDouble(); // r
1483 double x
= GetDouble(); // x
1484 if (r
< 0.0 || x
< 0.0 || p
< 0.0 || p
> 1.0)
1485 PushIllegalArgument();
1489 double fFactor
= pow(p
,r
);
1490 for (double i
= 0.0; i
< x
; i
++)
1491 fFactor
*= (i
+r
)/(i
+1.0)*q
;
1492 PushDouble(fFactor
);
1497 void ScInterpreter::ScNormDist()
1499 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNormDist" );
1500 if ( MustHaveParamCount( GetByte(), 4 ) )
1502 double kum
= GetDouble(); // 0 oder 1
1503 double sigma
= GetDouble(); // Stdabw
1504 double mue
= GetDouble(); // Mittelwert
1505 double x
= GetDouble(); // x
1507 PushError( errIllegalArgument
);
1508 else if (sigma
== 0.0)
1509 PushError( errDivisionByZero
);
1510 else if (kum
== 0.0) // Dichte
1511 PushDouble(phi((x
-mue
)/sigma
)/sigma
);
1513 PushDouble(0.5 + gauss((x
-mue
)/sigma
));
1517 void ScInterpreter::ScLogNormDist()
1519 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLogNormDist" );
1520 if ( MustHaveParamCount( GetByte(), 3 ) )
1522 double sigma
= GetDouble(); // Stdabw
1523 double mue
= GetDouble(); // Mittelwert
1524 double x
= GetDouble(); // x
1526 PushError( errIllegalArgument
);
1527 else if (sigma
== 0.0)
1528 PushError( errDivisionByZero
);
1530 PushIllegalArgument();
1532 PushDouble(0.5 + gauss((log(x
)-mue
)/sigma
));
1536 void ScInterpreter::ScStdNormDist()
1538 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStdNormDist" );
1539 PushDouble(0.5 + gauss(GetDouble()));
1542 void ScInterpreter::ScExpDist()
1544 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExpDist" );
1545 if ( MustHaveParamCount( GetByte(), 3 ) )
1547 double kum
= GetDouble(); // 0 oder 1
1548 double lambda
= GetDouble(); // lambda
1549 double x
= GetDouble(); // x
1551 PushIllegalArgument();
1552 else if (kum
== 0.0) // Dichte
1555 PushDouble(lambda
* exp(-lambda
*x
));
1562 PushDouble(1.0 - exp(-lambda
*x
));
1569 void ScInterpreter::ScTDist()
1571 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTDist" );
1572 if ( !MustHaveParamCount( GetByte(), 3 ) )
1574 double fFlag
= ::rtl::math::approxFloor(GetDouble());
1575 double fDF
= ::rtl::math::approxFloor(GetDouble());
1576 double T
= GetDouble();
1577 if (fDF
< 1.0 || T
< 0.0 || (fFlag
!= 1.0 && fFlag
!= 2.0) )
1579 PushIllegalArgument();
1582 double R
= GetTDist(T
, fDF
);
1589 void ScInterpreter::ScFDist()
1591 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFDist" );
1592 if ( !MustHaveParamCount( GetByte(), 3 ) )
1594 double fF2
= ::rtl::math::approxFloor(GetDouble());
1595 double fF1
= ::rtl::math::approxFloor(GetDouble());
1596 double fF
= GetDouble();
1597 if (fF
< 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
)
1599 PushIllegalArgument();
1602 PushDouble(GetFDist(fF
, fF1
, fF2
));
1605 void ScInterpreter::ScChiDist()
1607 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiDist" );
1609 if ( !MustHaveParamCount( GetByte(), 2 ) )
1611 double fDF
= ::rtl::math::approxFloor(GetDouble());
1612 double fChi
= GetDouble();
1613 if (fDF
< 1.0) // x<=0 returns 1, see ODFF 6.17.10
1615 PushIllegalArgument();
1618 fResult
= GetChiDist( fChi
, fDF
);
1621 PushError( nGlobalError
);
1624 PushDouble(fResult
);
1627 void ScInterpreter::ScWeibull()
1629 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScWeibull" );
1630 if ( MustHaveParamCount( GetByte(), 4 ) )
1632 double kum
= GetDouble(); // 0 oder 1
1633 double beta
= GetDouble(); // beta
1634 double alpha
= GetDouble(); // alpha
1635 double x
= GetDouble(); // x
1636 if (alpha
<= 0.0 || beta
<= 0.0 || x
< 0.0)
1637 PushIllegalArgument();
1638 else if (kum
== 0.0) // Dichte
1639 PushDouble(alpha
/pow(beta
,alpha
)*pow(x
,alpha
-1.0)*
1640 exp(-pow(x
/beta
,alpha
)));
1642 PushDouble(1.0 - exp(-pow(x
/beta
,alpha
)));
1646 void ScInterpreter::ScPoissonDist()
1648 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPoissonDist" );
1649 BYTE nParamCount
= GetByte();
1650 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
1652 double kum
= (nParamCount
== 3 ? GetDouble() : 1); // 0 oder 1
1653 double lambda
= GetDouble(); // Mittelwert
1654 double x
= ::rtl::math::approxFloor(GetDouble()); // x
1655 if (lambda
< 0.0 || x
< 0.0)
1656 PushIllegalArgument();
1657 else if (kum
== 0.0) // Dichte
1663 double fPoissonVar
= 1.0;
1664 for ( double f
= 0.0; f
< x
; ++f
)
1665 fPoissonVar
*= lambda
/ ( f
+ 1.0 );
1666 PushDouble( fPoissonVar
*exp( -lambda
) );
1677 ULONG nEnd
= (ULONG
) x
;
1678 for (ULONG i
= 1; i
<= nEnd
; i
++)
1681 sum
+= pow( lambda
, (double)i
) / fFak
;
1683 sum
*= exp(-lambda
);
1690 /** Local function used in the calculation of the hypergeometric distribution.
1692 void lcl_PutFactorialElements( ::std::vector
< double >& cn
, double fLower
, double fUpper
, double fBase
)
1694 for ( double i
= fLower
; i
<= fUpper
; ++i
)
1696 double fVal
= fBase
- i
;
1698 cn
.push_back( fVal
);
1702 /** Calculates a value of the hypergeometric distribution.
1704 The algorithm is designed to avoid unnecessary multiplications and division
1705 by expanding all factorial elements (9 of them). It is done by excluding
1706 those ranges that overlap in the numerator and the denominator. This allows
1707 for a fast calculation for large values which would otherwise cause an overflow
1708 in the intermediate values.
1710 @author Kohei Yoshida <kohei@openoffice.org>
1715 void ScInterpreter::ScHypGeomDist()
1717 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHypGeomDist" );
1718 const size_t nMaxArraySize
= 500000; // arbitrary max array size
1720 if ( !MustHaveParamCount( GetByte(), 4 ) )
1723 double N
= ::rtl::math::approxFloor(GetDouble());
1724 double M
= ::rtl::math::approxFloor(GetDouble());
1725 double n
= ::rtl::math::approxFloor(GetDouble());
1726 double x
= ::rtl::math::approxFloor(GetDouble());
1728 if( (x
< 0.0) || (n
< x
) || (M
< x
) || (N
< n
) || (N
< M
) || (x
< n
- N
+ M
) )
1730 PushIllegalArgument();
1734 typedef ::std::vector
< double > HypContainer
;
1735 HypContainer cnNumer
, cnDenom
;
1737 size_t nEstContainerSize
= static_cast<size_t>( x
+ ::std::min( n
, M
) );
1738 size_t nMaxSize
= ::std::min( cnNumer
.max_size(), nMaxArraySize
);
1739 if ( nEstContainerSize
> nMaxSize
)
1744 cnNumer
.reserve( nEstContainerSize
+ 10 );
1745 cnDenom
.reserve( nEstContainerSize
+ 10 );
1747 // Trim coefficient C first
1748 double fCNumVarUpper
= N
- n
- M
+ x
- 1.0;
1749 double fCDenomVarLower
= 1.0;
1750 if ( N
- n
- M
+ x
>= M
- x
+ 1.0 )
1752 fCNumVarUpper
= M
- x
- 1.0;
1753 fCDenomVarLower
= N
- n
- 2.0*(M
- x
) + 1.0;
1757 double fCNumLower
= N
- n
- fCNumVarUpper
;
1759 double fCDenomUpper
= N
- n
- M
+ x
+ 1.0 - fCDenomVarLower
;
1761 double fDNumVarLower
= n
- M
;
1765 if ( N
- M
< n
+ 1.0 )
1769 if ( N
- n
< n
+ 1.0 )
1772 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1773 lcl_PutFactorialElements( cnDenom
, 0.0, N
- n
- 1.0, N
);
1778 DBG_ASSERT( fCNumLower
< n
+ 1.0, "ScHypGeomDist: wrong assertion" );
1779 lcl_PutFactorialElements( cnNumer
, N
- 2.0*n
, fCNumVarUpper
, N
- n
);
1780 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1783 DBG_ASSERT( fCDenomUpper
<= N
- M
, "ScHypGeomDist: wrong assertion" );
1785 if ( fCDenomUpper
< n
- x
+ 1.0 )
1787 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1791 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1793 fCDenomUpper
= n
- x
;
1794 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1804 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1805 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1809 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1810 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1813 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1815 if ( fCDenomUpper
< n
- x
+ 1.0 )
1817 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1820 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1821 fCDenomUpper
= n
- x
;
1822 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1826 DBG_ASSERT( fCDenomUpper
<= M
, "ScHypGeomDist: wrong assertion" );
1830 if ( N
- M
< M
+ 1.0 )
1834 if ( N
- n
< M
+ 1.0 )
1837 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1838 lcl_PutFactorialElements( cnDenom
, 0.0, N
- M
- 1.0, N
);
1842 lcl_PutFactorialElements( cnNumer
, N
- n
- M
, fCNumVarUpper
, N
- n
);
1843 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1846 if ( n
- x
+ 1.0 > fCDenomUpper
)
1848 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1852 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1854 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1855 fCDenomUpper
= n
- x
;
1862 DBG_ASSERT( M
>= n
- x
, "ScHypGeomDist: wrong assertion" );
1863 DBG_ASSERT( M
- x
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1865 if ( N
- n
< N
- M
+ 1.0 )
1868 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1869 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1874 DBG_ASSERT( fCNumLower
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
1876 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1877 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1880 if ( n
- x
+ 1.0 > fCDenomUpper
)
1882 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1883 else if ( M
>= fCDenomUpper
)
1885 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1887 fCDenomUpper
= n
- x
;
1888 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1892 DBG_ASSERT( M
<= fCDenomUpper
, "ScHypGeomDist: wrong assertion" );
1893 lcl_PutFactorialElements( cnDenom
, fCDenomVarLower
, N
- n
- 2.0*M
+ x
,
1894 N
- n
- M
+ x
+ 1.0 );
1896 fCDenomUpper
= n
- x
;
1897 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1901 DBG_ASSERT( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1903 fDNumVarLower
= 0.0;
1906 double nDNumVarUpper
= fCDenomUpper
< x
+ 1.0 ? n
- x
- 1.0 : n
- fCDenomUpper
- 1.0;
1907 double nDDenomVarLower
= fCDenomUpper
< x
+ 1.0 ? fCDenomVarLower
: N
- n
- M
+ 1.0;
1908 lcl_PutFactorialElements( cnNumer
, fDNumVarLower
, nDNumVarUpper
, n
);
1909 lcl_PutFactorialElements( cnDenom
, nDDenomVarLower
, N
- n
- M
+ x
, N
- n
- M
+ x
+ 1.0 );
1911 ::std::sort( cnNumer
.begin(), cnNumer
.end() );
1912 ::std::sort( cnDenom
.begin(), cnDenom
.end() );
1913 HypContainer::reverse_iterator it1
= cnNumer
.rbegin(), it1End
= cnNumer
.rend();
1914 HypContainer::reverse_iterator it2
= cnDenom
.rbegin(), it2End
= cnDenom
.rend();
1916 double fFactor
= 1.0;
1917 for ( ; it1
!= it1End
|| it2
!= it2End
; )
1919 double fEnum
= 1.0, fDenom
= 1.0;
1920 if ( it1
!= it1End
)
1922 if ( it2
!= it2End
)
1924 fFactor
*= fEnum
/ fDenom
;
1927 PushDouble(fFactor
);
1930 void ScInterpreter::ScGammaDist()
1932 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGammaDist" );
1933 BYTE nParamCount
= GetByte();
1934 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1937 if (nParamCount
== 4)
1938 bCumulative
= GetBool();
1941 double fBeta
= GetDouble(); // scale
1942 double fAlpha
= GetDouble(); // shape
1943 double fX
= GetDouble(); // x
1944 if (fAlpha
<= 0.0 || fBeta
<= 0.0)
1945 PushIllegalArgument();
1948 if (bCumulative
) // distribution
1949 PushDouble( GetGammaDist( fX
, fAlpha
, fBeta
));
1951 PushDouble( GetGammaDistPDF( fX
, fAlpha
, fBeta
));
1955 void ScInterpreter::ScNormInv()
1957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNormInv" );
1958 if ( MustHaveParamCount( GetByte(), 3 ) )
1960 double sigma
= GetDouble();
1961 double mue
= GetDouble();
1962 double x
= GetDouble();
1963 if (sigma
<= 0.0 || x
< 0.0 || x
> 1.0)
1964 PushIllegalArgument();
1965 else if (x
== 0.0 || x
== 1.0)
1968 PushDouble(gaussinv(x
)*sigma
+ mue
);
1972 void ScInterpreter::ScSNormInv()
1974 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSNormInv" );
1975 double x
= GetDouble();
1976 if (x
< 0.0 || x
> 1.0)
1977 PushIllegalArgument();
1978 else if (x
== 0.0 || x
== 1.0)
1981 PushDouble(gaussinv(x
));
1984 void ScInterpreter::ScLogNormInv()
1986 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLogNormInv" );
1987 if ( MustHaveParamCount( GetByte(), 3 ) )
1989 double sigma
= GetDouble(); // Stdabw
1990 double mue
= GetDouble(); // Mittelwert
1991 double y
= GetDouble(); // y
1992 if (sigma
<= 0.0 || y
<= 0.0 || y
>= 1.0)
1993 PushIllegalArgument();
1995 PushDouble(exp(mue
+sigma
*gaussinv(y
)));
1999 class ScGammaDistFunction
: public ScDistFunc
2001 ScInterpreter
& rInt
;
2002 double fp
, fAlpha
, fBeta
;
2005 ScGammaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2006 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2008 double GetValue( double x
) const { return fp
- rInt
.GetGammaDist(x
, fAlpha
, fBeta
); }
2011 void ScInterpreter::ScGammaInv()
2013 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGammaInv" );
2014 if ( !MustHaveParamCount( GetByte(), 3 ) )
2016 double fBeta
= GetDouble();
2017 double fAlpha
= GetDouble();
2018 double fP
= GetDouble();
2019 if (fAlpha
<= 0.0 || fBeta
<= 0.0 || fP
< 0.0 || fP
>= 1.0 )
2021 PushIllegalArgument();
2029 ScGammaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2030 double fStart
= fAlpha
* fBeta
;
2031 double fVal
= lcl_IterateInverse( aFunc
, fStart
*0.5, fStart
, bConvError
);
2033 SetError(errNoConvergence
);
2038 class ScBetaDistFunction
: public ScDistFunc
2040 ScInterpreter
& rInt
;
2041 double fp
, fAlpha
, fBeta
;
2044 ScBetaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2045 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2047 double GetValue( double x
) const { return fp
- rInt
.GetBetaDist(x
, fAlpha
, fBeta
); }
2050 void ScInterpreter::ScBetaInv()
2052 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScBetaInv" );
2053 BYTE nParamCount
= GetByte();
2054 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2056 double fP
, fA
, fB
, fAlpha
, fBeta
;
2057 if (nParamCount
== 5)
2061 if (nParamCount
>= 4)
2065 fBeta
= GetDouble();
2066 fAlpha
= GetDouble();
2068 if (fP
< 0.0 || fP
>= 1.0 || fA
== fB
|| fAlpha
<= 0.0 || fBeta
<= 0.0)
2070 PushIllegalArgument();
2078 ScBetaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2079 // 0..1 as range for iteration so it isn't extended beyond the valid range
2080 double fVal
= lcl_IterateInverse( aFunc
, 0.0, 1.0, bConvError
);
2082 PushError( errNoConvergence
);
2084 PushDouble(fA
+ fVal
*(fB
-fA
)); // scale to (A,B)
2088 // Achtung: T, F und Chi
2089 // sind monoton fallend,
2090 // deshalb 1-Dist als Funktion
2092 class ScTDistFunction
: public ScDistFunc
2094 ScInterpreter
& rInt
;
2098 ScTDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2099 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2101 double GetValue( double x
) const { return fp
- 2 * rInt
.GetTDist(x
, fDF
); }
2104 void ScInterpreter::ScTInv()
2106 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTInv" );
2107 if ( !MustHaveParamCount( GetByte(), 2 ) )
2109 double fDF
= ::rtl::math::approxFloor(GetDouble());
2110 double fP
= GetDouble();
2111 if (fDF
< 1.0 || fDF
>= 1.0E5
|| fP
<= 0.0 || fP
> 1.0 )
2113 PushIllegalArgument();
2118 ScTDistFunction
aFunc( *this, fP
, fDF
);
2119 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2121 SetError(errNoConvergence
);
2125 class ScFDistFunction
: public ScDistFunc
2127 ScInterpreter
& rInt
;
2128 double fp
, fF1
, fF2
;
2131 ScFDistFunction( ScInterpreter
& rI
, double fpVal
, double fF1Val
, double fF2Val
) :
2132 rInt(rI
), fp(fpVal
), fF1(fF1Val
), fF2(fF2Val
) {}
2134 double GetValue( double x
) const { return fp
- rInt
.GetFDist(x
, fF1
, fF2
); }
2137 void ScInterpreter::ScFInv()
2139 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFInv" );
2140 if ( !MustHaveParamCount( GetByte(), 3 ) )
2142 double fF2
= ::rtl::math::approxFloor(GetDouble());
2143 double fF1
= ::rtl::math::approxFloor(GetDouble());
2144 double fP
= GetDouble();
2145 if (fP
<= 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
|| fP
> 1.0)
2147 PushIllegalArgument();
2152 ScFDistFunction
aFunc( *this, fP
, fF1
, fF2
);
2153 double fVal
= lcl_IterateInverse( aFunc
, fF1
*0.5, fF1
, bConvError
);
2155 SetError(errNoConvergence
);
2159 class ScChiDistFunction
: public ScDistFunc
2161 ScInterpreter
& rInt
;
2165 ScChiDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2166 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2168 double GetValue( double x
) const { return fp
- rInt
.GetChiDist(x
, fDF
); }
2171 void ScInterpreter::ScChiInv()
2173 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiInv" );
2174 if ( !MustHaveParamCount( GetByte(), 2 ) )
2176 double fDF
= ::rtl::math::approxFloor(GetDouble());
2177 double fP
= GetDouble();
2178 if (fDF
< 1.0 || fP
<= 0.0 || fP
> 1.0 )
2180 PushIllegalArgument();
2185 ScChiDistFunction
aFunc( *this, fP
, fDF
);
2186 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2188 SetError(errNoConvergence
);
2192 /***********************************************/
2193 class ScChiSqDistFunction
: public ScDistFunc
2195 ScInterpreter
& rInt
;
2199 ScChiSqDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2200 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2202 double GetValue( double x
) const { return fp
- rInt
.GetChiSqDistCDF(x
, fDF
); }
2206 void ScInterpreter::ScChiSqInv()
2208 if ( !MustHaveParamCount( GetByte(), 2 ) )
2210 double fDF
= ::rtl::math::approxFloor(GetDouble());
2211 double fP
= GetDouble();
2212 if (fDF
< 1.0 || fP
< 0.0 || fP
>= 1.0 )
2214 PushIllegalArgument();
2219 ScChiSqDistFunction
aFunc( *this, fP
, fDF
);
2220 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2222 SetError(errNoConvergence
);
2227 void ScInterpreter::ScConfidence()
2229 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScConfidence" );
2230 if ( MustHaveParamCount( GetByte(), 3 ) )
2232 double n
= ::rtl::math::approxFloor(GetDouble());
2233 double sigma
= GetDouble();
2234 double alpha
= GetDouble();
2235 if (sigma
<= 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || n
< 1.0)
2236 PushIllegalArgument();
2238 PushDouble( gaussinv(1.0-alpha
/2.0) * sigma
/sqrt(n
) );
2242 void ScInterpreter::ScZTest()
2244 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScZTest" );
2245 BYTE nParamCount
= GetByte();
2246 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
2248 double sigma
= 0.0, mue
, x
;
2249 if (nParamCount
== 3)
2251 sigma
= GetDouble();
2254 PushIllegalArgument();
2261 double fSumSqr
= 0.0;
2263 double rValCount
= 0.0;
2264 switch (GetStackType())
2266 case formula::svDouble
:
2270 fSumSqr
+= fVal
*fVal
;
2277 PopSingleRef( aAdr
);
2278 ScBaseCell
* pCell
= GetCell( aAdr
);
2279 if (HasCellValueData(pCell
))
2281 fVal
= GetCellValue( aAdr
, pCell
);
2283 fSumSqr
+= fVal
*fVal
;
2289 case formula::svDoubleRef
:
2292 size_t nRefInList
= 0;
2293 while (nParam
-- > 0)
2297 PopDoubleRef( aRange
, nParam
, nRefInList
);
2298 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2299 if (aValIter
.GetFirst(fVal
, nErr
))
2302 fSumSqr
+= fVal
*fVal
;
2304 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
2307 fSumSqr
+= fVal
*fVal
;
2317 ScMatrixRef pMat
= PopMatrix();
2320 SCSIZE nCount
= pMat
->GetElementCount();
2321 if (pMat
->IsNumeric())
2323 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
2325 fVal
= pMat
->GetDouble(i
);
2327 fSumSqr
+= fVal
* fVal
;
2333 for (SCSIZE i
= 0; i
< nCount
; i
++)
2334 if (!pMat
->IsString(i
))
2336 fVal
= pMat
->GetDouble(i
);
2338 fSumSqr
+= fVal
* fVal
;
2345 default : SetError(errIllegalParameter
); break;
2347 if (rValCount
<= 1.0)
2348 PushError( errDivisionByZero
);
2351 mue
= fSum
/rValCount
;
2352 if (nParamCount
!= 3)
2353 sigma
= (fSumSqr
- fSum
*fSum
/rValCount
)/(rValCount
-1.0);
2355 PushDouble(0.5 - gauss((mue
-x
)/sqrt(sigma
/rValCount
)));
2358 bool ScInterpreter::CalculateTest(BOOL _bTemplin
2359 ,const SCSIZE nC1
, const SCSIZE nC2
,const SCSIZE nR1
,const SCSIZE nR2
2360 ,const ScMatrixRef
& pMat1
,const ScMatrixRef
& pMat2
2361 ,double& fT
,double& fF
)
2363 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateTest" );
2364 double fCount1
= 0.0;
2365 double fCount2
= 0.0;
2367 double fSumSqr1
= 0.0;
2369 double fSumSqr2
= 0.0;
2372 for (i
= 0; i
< nC1
; i
++)
2373 for (j
= 0; j
< nR1
; j
++)
2375 if (!pMat1
->IsString(i
,j
))
2377 fVal
= pMat1
->GetDouble(i
,j
);
2379 fSumSqr1
+= fVal
* fVal
;
2383 for (i
= 0; i
< nC2
; i
++)
2384 for (j
= 0; j
< nR2
; j
++)
2386 if (!pMat2
->IsString(i
,j
))
2388 fVal
= pMat2
->GetDouble(i
,j
);
2390 fSumSqr2
+= fVal
* fVal
;
2394 if (fCount1
< 2.0 || fCount2
< 2.0)
2398 } // if (fCount1 < 2.0 || fCount2 < 2.0)
2401 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0)/fCount1
;
2402 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0)/fCount2
;
2403 if (fS1
+ fS2
== 0.0)
2408 fT
= fabs(fSum1
/fCount1
- fSum2
/fCount2
)/sqrt(fS1
+fS2
);
2409 double c
= fS1
/(fS1
+fS2
);
2410 // s.u. fF = ::rtl::math::approxFloor(1.0/(c*c/(fCount1-1.0)+(1.0-c)*(1.0-c)/(fCount2-1.0)));
2411 // fF = ::rtl::math::approxFloor((fS1+fS2)*(fS1+fS2)/(fS1*fS1/(fCount1-1.0) + fS2*fS2/(fCount2-1.0)));
2413 // GetTDist wird mit GetBetaDist berechnet und kommt auch mit nicht ganzzahligen
2414 // Freiheitsgraden klar. Dann stimmt das Ergebnis auch mit Excel ueberein (#52406#):
2415 fF
= 1.0/(c
*c
/(fCount1
-1.0)+(1.0-c
)*(1.0-c
)/(fCount2
-1.0));
2419 // laut Bronstein-Semendjajew
2420 double fS1
= (fSumSqr1
- fSum1
*fSum1
/fCount1
) / (fCount1
- 1.0); // Varianz
2421 double fS2
= (fSumSqr2
- fSum2
*fSum2
/fCount2
) / (fCount2
- 1.0);
2422 fT
= fabs( fSum1
/fCount1
- fSum2
/fCount2
) /
2423 sqrt( (fCount1
-1.0)*fS1
+ (fCount2
-1.0)*fS2
) *
2424 sqrt( fCount1
*fCount2
*(fCount1
+fCount2
-2)/(fCount1
+fCount2
) );
2425 fF
= fCount1
+ fCount2
- 2;
2429 void ScInterpreter::ScTTest()
2431 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTTest" );
2432 if ( !MustHaveParamCount( GetByte(), 4 ) )
2434 double fTyp
= ::rtl::math::approxFloor(GetDouble());
2435 double fAnz
= ::rtl::math::approxFloor(GetDouble());
2436 if (fAnz
!= 1.0 && fAnz
!= 2.0)
2438 PushIllegalArgument();
2442 ScMatrixRef pMat2
= GetMatrix();
2443 ScMatrixRef pMat1
= GetMatrix();
2444 if (!pMat1
|| !pMat2
)
2446 PushIllegalParameter();
2453 pMat1
->GetDimensions(nC1
, nR1
);
2454 pMat2
->GetDimensions(nC2
, nR2
);
2457 if (nC1
!= nC2
|| nR1
!= nR2
)
2459 PushIllegalArgument();
2462 double fCount
= 0.0;
2465 double fSumSqrD
= 0.0;
2466 double fVal1
, fVal2
;
2467 for (i
= 0; i
< nC1
; i
++)
2468 for (j
= 0; j
< nR1
; j
++)
2470 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2472 fVal1
= pMat1
->GetDouble(i
,j
);
2473 fVal2
= pMat2
->GetDouble(i
,j
);
2476 fSumSqrD
+= (fVal1
- fVal2
)*(fVal1
- fVal2
);
2485 fT
= sqrt(fCount
-1.0) * fabs(fSum1
- fSum2
) /
2486 sqrt(fCount
* fSumSqrD
- (fSum1
-fSum2
)*(fSum1
-fSum2
));
2489 else if (fTyp
== 2.0)
2491 CalculateTest(FALSE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2493 else if (fTyp
== 3.0)
2495 CalculateTest(TRUE
,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
);
2500 PushIllegalArgument();
2504 PushDouble(GetTDist(fT
, fF
));
2506 PushDouble(2.0*GetTDist(fT
, fF
));
2509 void ScInterpreter::ScFTest()
2511 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFTest" );
2512 if ( !MustHaveParamCount( GetByte(), 2 ) )
2514 ScMatrixRef pMat2
= GetMatrix();
2515 ScMatrixRef pMat1
= GetMatrix();
2516 if (!pMat1
|| !pMat2
)
2518 PushIllegalParameter();
2524 pMat1
->GetDimensions(nC1
, nR1
);
2525 pMat2
->GetDimensions(nC2
, nR2
);
2526 double fCount1
= 0.0;
2527 double fCount2
= 0.0;
2529 double fSumSqr1
= 0.0;
2531 double fSumSqr2
= 0.0;
2533 for (i
= 0; i
< nC1
; i
++)
2534 for (j
= 0; j
< nR1
; j
++)
2536 if (!pMat1
->IsString(i
,j
))
2538 fVal
= pMat1
->GetDouble(i
,j
);
2540 fSumSqr1
+= fVal
* fVal
;
2544 for (i
= 0; i
< nC2
; i
++)
2545 for (j
= 0; j
< nR2
; j
++)
2547 if (!pMat2
->IsString(i
,j
))
2549 fVal
= pMat2
->GetDouble(i
,j
);
2551 fSumSqr2
+= fVal
* fVal
;
2555 if (fCount1
< 2.0 || fCount2
< 2.0)
2560 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
)/(fCount1
-1.0);
2561 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
)/(fCount2
-1.0);
2562 if (fS1
== 0.0 || fS2
== 0.0)
2567 double fF
, fF1
, fF2
;
2580 PushDouble(2.0*GetFDist(fF
, fF1
, fF2
));
2582 double Z = (pow(fF,1.0/3.0)*(1.0-2.0/(9.0*fF2)) - (1.0-2.0/(9.0*fF1))) /
2583 sqrt(2.0/(9.0*fF1) + pow(fF,2.0/3.0)*2.0/(9.0*fF2));
2584 PushDouble(1.0-2.0*gauss(Z));
2588 void ScInterpreter::ScChiTest()
2590 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChiTest" );
2591 if ( !MustHaveParamCount( GetByte(), 2 ) )
2593 ScMatrixRef pMat2
= GetMatrix();
2594 ScMatrixRef pMat1
= GetMatrix();
2595 if (!pMat1
|| !pMat2
)
2597 PushIllegalParameter();
2602 pMat1
->GetDimensions(nC1
, nR1
);
2603 pMat2
->GetDimensions(nC2
, nR2
);
2604 if (nR1
!= nR2
|| nC1
!= nC2
)
2606 PushIllegalArgument();
2610 for (SCSIZE i
= 0; i
< nC1
; i
++)
2612 for (SCSIZE j
= 0; j
< nR1
; j
++)
2614 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
2616 double fValX
= pMat1
->GetDouble(i
,j
);
2617 double fValE
= pMat2
->GetDouble(i
,j
);
2618 fChi
+= (fValX
- fValE
) * (fValX
- fValE
) / fValE
;
2622 PushIllegalArgument();
2628 if (nC1
== 1 || nR1
== 1)
2630 fDF
= (double)(nC1
*nR1
- 1);
2638 fDF
= (double)(nC1
-1)*(double)(nR1
-1);
2639 PushDouble(GetChiDist(fChi
, fDF
));
2641 double fX, fS, fT, fG;
2643 for (double fi = fDF; fi >= 2.0; fi -= 2.0)
2645 fX *= exp(-fChi/2.0);
2646 if (fmod(fDF, 2.0) != 0.0)
2647 fX *= sqrt(2.0*fChi/F_PI);
2651 while (fT >= 1.0E-7)
2657 PushDouble(1.0 - fX*fS);
2661 void ScInterpreter::ScKurt()
2663 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScKurt" );
2664 double fSum
,fCount
,vSum
;
2665 std::vector
<double> values
;
2666 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
2671 PushError( errDivisionByZero
);
2675 double fMean
= fSum
/ fCount
;
2677 for (size_t i
= 0; i
< values
.size(); i
++)
2678 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
2680 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
2682 double xpower4
= 0.0;
2686 PushError( errDivisionByZero
);
2690 for (size_t i
= 0; i
< values
.size(); i
++)
2692 dx
= (values
[i
] - fMean
) / fStdDev
;
2693 xpower4
= xpower4
+ (dx
* dx
* dx
* dx
);
2696 double k_d
= (fCount
- 2.0) * (fCount
- 3.0);
2697 double k_l
= fCount
* (fCount
+ 1.0) / ((fCount
- 1.0) * k_d
);
2698 double k_t
= 3.0 * (fCount
- 1.0) * (fCount
- 1.0) / k_d
;
2700 PushDouble(xpower4
* k_l
- k_t
);
2703 void ScInterpreter::ScHarMean()
2705 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHarMean" );
2706 short nParamCount
= GetByte();
2708 double nValCount
= 0.0;
2711 size_t nRefInList
= 0;
2712 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2714 switch (GetStackType())
2716 case formula::svDouble
:
2718 double x
= GetDouble();
2725 SetError( errIllegalArgument
);
2730 PopSingleRef( aAdr
);
2731 ScBaseCell
* pCell
= GetCell( aAdr
);
2732 if (HasCellValueData(pCell
))
2734 double x
= GetCellValue( aAdr
, pCell
);
2741 SetError( errIllegalArgument
);
2745 case formula::svDoubleRef
:
2749 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2751 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2752 if (aValIter
.GetFirst(nCellVal
, nErr
))
2756 nVal
+= 1.0/nCellVal
;
2760 SetError( errIllegalArgument
);
2762 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2766 nVal
+= 1.0/nCellVal
;
2770 SetError( errIllegalArgument
);
2778 ScMatrixRef pMat
= PopMatrix();
2781 SCSIZE nCount
= pMat
->GetElementCount();
2782 if (pMat
->IsNumeric())
2784 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2786 double x
= pMat
->GetDouble(nElem
);
2793 SetError( errIllegalArgument
);
2798 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2799 if (!pMat
->IsString(nElem
))
2801 double x
= pMat
->GetDouble(nElem
);
2808 SetError( errIllegalArgument
);
2814 default : SetError(errIllegalParameter
); break;
2817 if (nGlobalError
== 0)
2818 PushDouble((double)nValCount
/nVal
);
2820 PushError( nGlobalError
);
2823 void ScInterpreter::ScGeoMean()
2825 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGeoMean" );
2826 short nParamCount
= GetByte();
2828 double nValCount
= 0.0;
2832 size_t nRefInList
= 0;
2833 while ((nGlobalError
== 0) && (nParamCount
-- > 0))
2835 switch (GetStackType())
2837 case formula::svDouble
:
2839 double x
= GetDouble();
2846 SetError( errIllegalArgument
);
2851 PopSingleRef( aAdr
);
2852 ScBaseCell
* pCell
= GetCell( aAdr
);
2853 if (HasCellValueData(pCell
))
2855 double x
= GetCellValue( aAdr
, pCell
);
2862 SetError( errIllegalArgument
);
2866 case formula::svDoubleRef
:
2870 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2872 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
2873 if (aValIter
.GetFirst(nCellVal
, nErr
))
2877 nVal
+= log(nCellVal
);
2881 SetError( errIllegalArgument
);
2883 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
2887 nVal
+= log(nCellVal
);
2891 SetError( errIllegalArgument
);
2899 ScMatrixRef pMat
= PopMatrix();
2902 SCSIZE nCount
= pMat
->GetElementCount();
2903 if (pMat
->IsNumeric())
2905 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2907 double x
= pMat
->GetDouble(ui
);
2914 SetError( errIllegalArgument
);
2919 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
2920 if (!pMat
->IsString(ui
))
2922 double x
= pMat
->GetDouble(ui
);
2929 SetError( errIllegalArgument
);
2935 default : SetError(errIllegalParameter
); break;
2938 if (nGlobalError
== 0)
2939 PushDouble(exp(nVal
/ nValCount
));
2941 PushError( nGlobalError
);
2944 void ScInterpreter::ScStandard()
2946 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStandard" );
2947 if ( MustHaveParamCount( GetByte(), 3 ) )
2949 double sigma
= GetDouble();
2950 double mue
= GetDouble();
2951 double x
= GetDouble();
2953 PushError( errIllegalArgument
);
2954 else if (sigma
== 0.0)
2955 PushError( errDivisionByZero
);
2957 PushDouble((x
-mue
)/sigma
);
2960 bool ScInterpreter::CalculateSkew(double& fSum
,double& fCount
,double& vSum
,std::vector
<double>& values
)
2962 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSkew" );
2963 short nParamCount
= GetByte();
2964 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
2973 size_t nRefInList
= 0;
2974 while (nParamCount
-- > 0)
2976 switch (GetStackType())
2978 case formula::svDouble
:
2982 values
.push_back(fVal
);
2988 PopSingleRef( aAdr
);
2989 ScBaseCell
* pCell
= GetCell( aAdr
);
2990 if (HasCellValueData(pCell
))
2992 fVal
= GetCellValue( aAdr
, pCell
);
2994 values
.push_back(fVal
);
2999 case formula::svDoubleRef
:
3002 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3004 ScValueIterator
aValIter(pDok
, aRange
);
3005 if (aValIter
.GetFirst(fVal
, nErr
))
3008 values
.push_back(fVal
);
3011 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
))
3014 values
.push_back(fVal
);
3023 ScMatrixRef pMat
= PopMatrix();
3026 SCSIZE nCount
= pMat
->GetElementCount();
3027 if (pMat
->IsNumeric())
3029 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3031 fVal
= pMat
->GetDouble(nElem
);
3033 values
.push_back(fVal
);
3039 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3040 if (!pMat
->IsString(nElem
))
3042 fVal
= pMat
->GetDouble(nElem
);
3044 values
.push_back(fVal
);
3052 SetError(errIllegalParameter
);
3059 PushError( nGlobalError
);
3061 } // if (nGlobalError)
3065 void ScInterpreter::ScSkew()
3067 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSkew" );
3068 double fSum
,fCount
,vSum
;
3069 std::vector
<double> values
;
3070 if ( !CalculateSkew(fSum
,fCount
,vSum
,values
) )
3073 double fMean
= fSum
/ fCount
;
3075 for (size_t i
= 0; i
< values
.size(); i
++)
3076 vSum
+= (values
[i
] - fMean
) * (values
[i
] - fMean
);
3078 double fStdDev
= sqrt(vSum
/ (fCount
- 1.0));
3084 PushIllegalArgument();
3088 for (size_t i
= 0; i
< values
.size(); i
++)
3090 dx
= (values
[i
] - fMean
) / fStdDev
;
3091 xcube
= xcube
+ (dx
* dx
* dx
);
3094 PushDouble(((xcube
* fCount
) / (fCount
- 1.0)) / (fCount
- 2.0));
3097 double ScInterpreter::GetMedian( vector
<double> & rArray
)
3099 size_t nSize
= rArray
.size();
3100 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3102 SetError( errNoValue
);
3107 size_t nMid
= nSize
/ 2;
3108 vector
<double>::iterator iMid
= rArray
.begin() + nMid
;
3109 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3111 return *iMid
; // Lower and upper median are equal.
3116 iMid
= rArray
.begin() + nMid
- 1;
3117 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3118 return (fUp
+ *iMid
) / 2;
3122 void ScInterpreter::ScMedian()
3124 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMedian" );
3125 BYTE nParamCount
= GetByte();
3126 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3128 vector
<double> aArray
;
3129 GetNumberSequenceArray( nParamCount
, aArray
);
3130 PushDouble( GetMedian( aArray
));
3133 double ScInterpreter::GetPercentile( vector
<double> & rArray
, double fPercentile
)
3135 size_t nSize
= rArray
.size();
3136 if (rArray
.empty() || nSize
== 0 || nGlobalError
)
3138 SetError( errNoValue
);
3146 size_t nIndex
= (size_t)::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3147 double fDiff
= fPercentile
* (nSize
-1) - ::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3148 DBG_ASSERT(nIndex
< nSize
, "GetPercentile: wrong index(1)");
3149 vector
<double>::iterator iter
= rArray
.begin() + nIndex
;
3150 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3155 DBG_ASSERT(nIndex
< nSize
-1, "GetPercentile: wrong index(2)");
3156 double fVal
= *iter
;
3157 iter
= rArray
.begin() + nIndex
+1;
3158 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3159 return fVal
+ fDiff
* (*iter
- fVal
);
3164 void ScInterpreter::ScPercentile()
3166 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentile" );
3167 if ( !MustHaveParamCount( GetByte(), 2 ) )
3169 double alpha
= GetDouble();
3170 if (alpha
< 0.0 || alpha
> 1.0)
3172 PushIllegalArgument();
3175 vector
<double> aArray
;
3176 GetNumberSequenceArray( 1, aArray
);
3177 PushDouble( GetPercentile( aArray
, alpha
));
3180 void ScInterpreter::ScQuartile()
3182 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScQuartile" );
3183 if ( !MustHaveParamCount( GetByte(), 2 ) )
3185 double fFlag
= ::rtl::math::approxFloor(GetDouble());
3186 if (fFlag
< 0.0 || fFlag
> 4.0)
3188 PushIllegalArgument();
3191 vector
<double> aArray
;
3192 GetNumberSequenceArray( 1, aArray
);
3193 PushDouble( fFlag
== 2.0 ? GetMedian( aArray
) : GetPercentile( aArray
, 0.25 * fFlag
));
3196 void ScInterpreter::ScModalValue()
3198 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScModalValue" );
3199 BYTE nParamCount
= GetByte();
3200 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3202 vector
<double> aSortArray
;
3203 GetSortArray(nParamCount
, aSortArray
);
3204 SCSIZE nSize
= aSortArray
.size();
3205 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3209 SCSIZE nMaxIndex
= 0, nMax
= 1, nCount
= 1;
3210 double nOldVal
= aSortArray
[0];
3213 for ( i
= 1; i
< nSize
; i
++)
3215 if (aSortArray
[i
] == nOldVal
)
3219 nOldVal
= aSortArray
[i
];
3233 if (nMax
== 1 && nCount
== 1)
3236 PushDouble(nOldVal
);
3238 PushDouble(aSortArray
[nMaxIndex
]);
3242 void ScInterpreter::CalculateSmallLarge(BOOL bSmall
)
3244 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSmallLarge" );
3245 if ( !MustHaveParamCount( GetByte(), 2 ) )
3247 double f
= ::rtl::math::approxFloor(GetDouble());
3250 PushIllegalArgument();
3253 SCSIZE k
= static_cast<SCSIZE
>(f
);
3254 vector
<double> aSortArray
;
3255 /* TODO: using nth_element() is best for one single value, but LARGE/SMALL
3256 * actually are defined to return an array of values if an array of
3257 * positions was passed, in which case, depending on the number of values,
3258 * we may or will need a real sorted array again, see #i32345. */
3259 //GetSortArray(1, aSortArray);
3260 GetNumberSequenceArray(1, aSortArray
);
3261 SCSIZE nSize
= aSortArray
.size();
3262 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
|| nSize
< k
)
3266 // TODO: the sorted case for array: PushDouble( aSortArray[ bSmall ? k-1 : nSize-k ] );
3267 vector
<double>::iterator iPos
= aSortArray
.begin() + (bSmall
? k
-1 : nSize
-k
);
3268 ::std::nth_element( aSortArray
.begin(), iPos
, aSortArray
.end());
3273 void ScInterpreter::ScLarge()
3275 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLarge" );
3276 CalculateSmallLarge(FALSE
);
3279 void ScInterpreter::ScSmall()
3281 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSmall" );
3282 CalculateSmallLarge(TRUE
);
3285 void ScInterpreter::ScPercentrank()
3287 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentrank" );
3288 BYTE nParamCount
= GetByte();
3289 if ( !MustHaveParamCount( nParamCount
, 2 ) )
3292 /* wird nicht unterstuetzt
3294 if (nParamCount == 3)
3296 fPrec = ::rtl::math::approxFloor(GetDouble());
3299 PushIllegalArgument();
3307 double fNum
= GetDouble();
3308 vector
<double> aSortArray
;
3309 GetSortArray(1, aSortArray
);
3310 SCSIZE nSize
= aSortArray
.size();
3311 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3315 if (fNum
< aSortArray
[0] || fNum
> aSortArray
[nSize
-1])
3317 else if ( nSize
== 1 )
3318 PushDouble(1.0); // fNum == pSortArray[0], see test above
3322 SCSIZE nOldCount
= 0;
3323 double fOldVal
= aSortArray
[0];
3325 for (i
= 1; i
< nSize
&& aSortArray
[i
] < fNum
; i
++)
3327 if (aSortArray
[i
] != fOldVal
)
3330 fOldVal
= aSortArray
[i
];
3333 if (aSortArray
[i
] != fOldVal
)
3335 if (fNum
== aSortArray
[i
])
3336 fRes
= (double)nOldCount
/(double)(nSize
-1);
3339 // #75312# nOldCount is the count of smaller entries
3340 // fNum is between pSortArray[nOldCount-1] and pSortArray[nOldCount]
3341 // use linear interpolation to find a position between the entries
3343 if ( nOldCount
== 0 )
3345 DBG_ERROR("should not happen");
3350 double fFract
= ( fNum
- aSortArray
[nOldCount
-1] ) /
3351 ( aSortArray
[nOldCount
] - aSortArray
[nOldCount
-1] );
3352 fRes
= ( (double)(nOldCount
-1)+fFract
)/(double)(nSize
-1);
3360 void ScInterpreter::ScTrimMean()
3362 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrimMean" );
3363 if ( !MustHaveParamCount( GetByte(), 2 ) )
3365 double alpha
= GetDouble();
3366 if (alpha
< 0.0 || alpha
>= 1.0)
3368 PushIllegalArgument();
3371 vector
<double> aSortArray
;
3372 GetSortArray(1, aSortArray
);
3373 SCSIZE nSize
= aSortArray
.size();
3374 if (aSortArray
.empty() || nSize
== 0 || nGlobalError
)
3378 ULONG nIndex
= (ULONG
) ::rtl::math::approxFloor(alpha
*(double)nSize
);
3379 if (nIndex
% 2 != 0)
3382 DBG_ASSERT(nIndex
< nSize
, "ScTrimMean: falscher Index");
3384 for (SCSIZE i
= nIndex
; i
< nSize
-nIndex
; i
++)
3385 fSum
+= aSortArray
[i
];
3386 PushDouble(fSum
/(double)(nSize
-2*nIndex
));
3390 void ScInterpreter::GetNumberSequenceArray( BYTE nParamCount
, vector
<double>& rArray
)
3392 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetSortArray" );
3395 short nParam
= nParamCount
;
3396 size_t nRefInList
= 0;
3397 while (nParam
-- > 0)
3399 switch (GetStackType())
3401 case formula::svDouble
:
3402 rArray
.push_back( PopDouble());
3406 PopSingleRef( aAdr
);
3407 ScBaseCell
* pCell
= GetCell( aAdr
);
3408 if (HasCellValueData(pCell
))
3409 rArray
.push_back( GetCellValue( aAdr
, pCell
));
3412 case formula::svDoubleRef
:
3415 PopDoubleRef( aRange
, nParam
, nRefInList
);
3420 SCSIZE nCellCount
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
3421 nCellCount
*= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
3422 rArray
.reserve( rArray
.size() + nCellCount
);
3426 ScValueIterator
aValIter(pDok
, aRange
);
3427 if (aValIter
.GetFirst( fCellVal
, nErr
))
3429 rArray
.push_back( fCellVal
);
3431 while ((nErr
== 0) && aValIter
.GetNext( fCellVal
, nErr
))
3432 rArray
.push_back( fCellVal
);
3439 ScMatrixRef pMat
= PopMatrix();
3443 SCSIZE nCount
= pMat
->GetElementCount();
3444 rArray
.reserve( rArray
.size() + nCount
);
3445 if (pMat
->IsNumeric())
3447 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3448 rArray
.push_back( pMat
->GetDouble(i
));
3452 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3453 if (!pMat
->IsString(i
))
3454 rArray
.push_back( pMat
->GetDouble(i
));
3460 SetError( errIllegalParameter
);
3466 // nParam > 0 in case of error, clean stack environment and obtain earlier
3467 // error if there was one.
3468 while (nParam
-- > 0)
3472 void ScInterpreter::GetSortArray( BYTE nParamCount
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3474 GetNumberSequenceArray( nParamCount
, rSortArray
);
3476 if (rSortArray
.size() > MAX_ANZ_DOUBLE_FOR_SORT
)
3477 SetError( errStackOverflow
);
3478 else if (rSortArray
.empty())
3479 SetError( errNoValue
);
3481 if (nGlobalError
== 0)
3482 QuickSort( rSortArray
, pIndexOrder
);
3485 static void lcl_QuickSort( long nLo
, long nHi
, vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3487 // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
3493 if (rSortArray
[nLo
] > rSortArray
[nHi
])
3495 swap(rSortArray
[nLo
], rSortArray
[nHi
]);
3497 swap(pIndexOrder
->at(nLo
), pIndexOrder
->at(nHi
));
3506 double fLo
= rSortArray
[nLo
];
3507 while (ni
<= nHi
&& rSortArray
[ni
] < fLo
) ni
++;
3508 while (nj
>= nLo
&& fLo
< rSortArray
[nj
]) nj
--;
3513 swap(rSortArray
[ni
], rSortArray
[nj
]);
3515 swap(pIndexOrder
->at(ni
), pIndexOrder
->at(nj
));
3524 if ((nj
- nLo
) < (nHi
- ni
))
3526 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3527 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3531 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
3532 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
3536 void ScInterpreter::QuickSort( vector
<double>& rSortArray
, vector
<long>* pIndexOrder
)
3538 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::QuickSort" );
3539 long n
= static_cast<long>(rSortArray
.size());
3543 pIndexOrder
->clear();
3544 pIndexOrder
->reserve(n
);
3545 for (long i
= 0; i
< n
; ++i
)
3546 pIndexOrder
->push_back(i
);
3552 size_t nValCount
= rSortArray
.size();
3553 for (size_t i
= 0; (i
+ 4) <= nValCount
-1; i
+= 4)
3555 size_t nInd
= rand() % (int) (nValCount
-1);
3556 ::std::swap( rSortArray
[i
], rSortArray
[nInd
]);
3558 ::std::swap( pIndexOrder
->at(i
), pIndexOrder
->at(nInd
));
3561 lcl_QuickSort(0, n
-1, rSortArray
, pIndexOrder
);
3564 void ScInterpreter::ScRank()
3566 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRank" );
3567 BYTE nParamCount
= GetByte();
3568 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
3571 if (nParamCount
== 3)
3572 bDescending
= GetBool();
3574 bDescending
= FALSE
;
3575 double fCount
= 1.0;
3576 BOOL bValid
= FALSE
;
3577 switch (GetStackType())
3579 case formula::svDouble
:
3581 double x
= GetDouble();
3582 double fVal
= GetDouble();
3590 PopSingleRef( aAdr
);
3591 double fVal
= GetDouble();
3592 ScBaseCell
* pCell
= GetCell( aAdr
);
3593 if (HasCellValueData(pCell
))
3595 double x
= GetCellValue( aAdr
, pCell
);
3601 case formula::svDoubleRef
:
3606 size_t nRefInList
= 0;
3607 while (nParam
-- > 0)
3610 // Preserve stack until all RefList elements are done!
3611 USHORT nSaveSP
= sp
;
3612 PopDoubleRef( aRange
, nParam
, nRefInList
);
3614 --sp
; // simulate pop
3615 double fVal
= GetDouble();
3619 ScValueIterator
aValIter(pDok
, aRange
, glSubTotal
);
3620 if (aValIter
.GetFirst(nCellVal
, nErr
))
3622 if (nCellVal
== fVal
)
3624 else if ((!bDescending
&& nCellVal
> fVal
) ||
3625 (bDescending
&& nCellVal
< fVal
) )
3628 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3630 if (nCellVal
== fVal
)
3632 else if ((!bDescending
&& nCellVal
> fVal
) ||
3633 (bDescending
&& nCellVal
< fVal
) )
3643 ScMatrixRef pMat
= PopMatrix();
3644 double fVal
= GetDouble();
3647 SCSIZE nCount
= pMat
->GetElementCount();
3648 if (pMat
->IsNumeric())
3650 for (SCSIZE i
= 0; i
< nCount
; i
++)
3652 double x
= pMat
->GetDouble(i
);
3655 else if ((!bDescending
&& x
> fVal
) ||
3656 (bDescending
&& x
< fVal
) )
3662 for (SCSIZE i
= 0; i
< nCount
; i
++)
3663 if (!pMat
->IsString(i
))
3665 double x
= pMat
->GetDouble(i
);
3668 else if ((!bDescending
&& x
> fVal
) ||
3669 (bDescending
&& x
< fVal
) )
3676 default : SetError(errIllegalParameter
); break;
3684 void ScInterpreter::ScAveDev()
3686 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAveDev" );
3687 BYTE nParamCount
= GetByte();
3688 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3691 double nMiddle
= 0.0;
3693 double rValCount
= 0.0;
3696 short nParam
= nParamCount
;
3697 size_t nRefInList
= 0;
3698 while (nParam
-- > 0)
3700 switch (GetStackType())
3702 case formula::svDouble
:
3703 rVal
+= GetDouble();
3708 PopSingleRef( aAdr
);
3709 ScBaseCell
* pCell
= GetCell( aAdr
);
3710 if (HasCellValueData(pCell
))
3712 rVal
+= GetCellValue( aAdr
, pCell
);
3717 case formula::svDoubleRef
:
3722 PopDoubleRef( aRange
, nParam
, nRefInList
);
3723 ScValueIterator
aValIter(pDok
, aRange
);
3724 if (aValIter
.GetFirst(nCellVal
, nErr
))
3729 while ((nErr
== 0) && aValIter
.GetNext(nCellVal
, nErr
))
3740 ScMatrixRef pMat
= PopMatrix();
3743 SCSIZE nCount
= pMat
->GetElementCount();
3744 if (pMat
->IsNumeric())
3746 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3748 rVal
+= pMat
->GetDouble(nElem
);
3754 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3755 if (!pMat
->IsString(nElem
))
3757 rVal
+= pMat
->GetDouble(nElem
);
3765 SetError(errIllegalParameter
);
3771 PushError( nGlobalError
);
3774 nMiddle
= rVal
/ rValCount
;
3777 nParam
= nParamCount
;
3779 while (nParam
-- > 0)
3781 switch (GetStackType())
3783 case formula::svDouble
:
3784 rVal
+= fabs(GetDouble() - nMiddle
);
3788 PopSingleRef( aAdr
);
3789 ScBaseCell
* pCell
= GetCell( aAdr
);
3790 if (HasCellValueData(pCell
))
3791 rVal
+= fabs(GetCellValue( aAdr
, pCell
) - nMiddle
);
3794 case formula::svDoubleRef
:
3799 PopDoubleRef( aRange
, nParam
, nRefInList
);
3800 ScValueIterator
aValIter(pDok
, aRange
);
3801 if (aValIter
.GetFirst(nCellVal
, nErr
))
3803 rVal
+= (fabs(nCellVal
- nMiddle
));
3804 while (aValIter
.GetNext(nCellVal
, nErr
))
3805 rVal
+= fabs(nCellVal
- nMiddle
);
3811 ScMatrixRef pMat
= PopMatrix();
3814 SCSIZE nCount
= pMat
->GetElementCount();
3815 if (pMat
->IsNumeric())
3817 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3819 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3824 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3826 if (!pMat
->IsString(nElem
))
3827 rVal
+= fabs(pMat
->GetDouble(nElem
) - nMiddle
);
3833 default : SetError(errIllegalParameter
); break;
3836 PushDouble(rVal
/ rValCount
);
3839 void ScInterpreter::ScDevSq()
3841 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDevSq" );
3844 GetStVarParams(nVal
, nValCount
);
3848 void ScInterpreter::ScProbability()
3850 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScProbability" );
3851 BYTE nParamCount
= GetByte();
3852 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
3856 if (nParamCount
== 4)
3866 ScMatrixRef pMatP
= GetMatrix();
3867 ScMatrixRef pMatW
= GetMatrix();
3868 if (!pMatP
|| !pMatW
)
3869 PushIllegalParameter();
3874 pMatP
->GetDimensions(nC1
, nR1
);
3875 pMatW
->GetDimensions(nC2
, nR2
);
3876 if (nC1
!= nC2
|| nR1
!= nR2
|| nC1
== 0 || nR1
== 0 ||
3877 nC2
== 0 || nR2
== 0)
3885 SCSIZE nCount1
= nC1
* nR1
;
3886 for ( SCSIZE i
= 0; i
< nCount1
&& !bStop
; i
++ )
3888 if (pMatP
->IsValue(i
) && pMatW
->IsValue(i
))
3890 fP
= pMatP
->GetDouble(i
);
3891 fW
= pMatW
->GetDouble(i
);
3892 if (fP
< 0.0 || fP
> 1.0)
3897 if (fW
>= fLo
&& fW
<= fUp
)
3902 SetError( errIllegalArgument
);
3904 if (bStop
|| fabs(fSum
-1.0) > 1.0E-7)
3912 void ScInterpreter::ScCorrel()
3914 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCorrel" );
3915 // This is identical to ScPearson()
3919 void ScInterpreter::ScCovar()
3921 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCovar" );
3922 CalculatePearsonCovar(FALSE
,FALSE
);
3925 void ScInterpreter::ScPearson()
3927 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPearson" );
3928 CalculatePearsonCovar(TRUE
,FALSE
);
3930 void ScInterpreter::CalculatePearsonCovar(BOOL _bPearson
,BOOL _bStexy
)
3932 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculatePearsonCovar" );
3933 if ( !MustHaveParamCount( GetByte(), 2 ) )
3935 ScMatrixRef pMat1
= GetMatrix();
3936 ScMatrixRef pMat2
= GetMatrix();
3937 if (!pMat1
|| !pMat2
)
3939 PushIllegalParameter();
3944 pMat1
->GetDimensions(nC1
, nR1
);
3945 pMat2
->GetDimensions(nC2
, nR2
);
3946 if (nR1
!= nR2
|| nC1
!= nC2
)
3948 PushIllegalArgument();
3952 * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
3953 * but the latter produces wrong results if the absolute values are high,
3954 * for example above 10^8
3956 double fCount
= 0.0;
3959 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
3960 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
3961 double fSumSqrDeltaY
= 0.0; // sum of (ValY-MeanY)^2
3962 for (SCSIZE i
= 0; i
< nC1
; i
++)
3964 for (SCSIZE j
= 0; j
< nR1
; j
++)
3966 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
3968 double fValX
= pMat1
->GetDouble(i
,j
);
3969 double fValY
= pMat2
->GetDouble(i
,j
);
3976 if (fCount
< (_bStexy
? 3.0 : 1.0)) // fCount==1 is handled by checking denominator later on
3980 const double fMeanX
= fSumX
/ fCount
;
3981 const double fMeanY
= fSumY
/ fCount
;
3982 for (SCSIZE i
= 0; i
< nC1
; i
++)
3984 for (SCSIZE j
= 0; j
< nR1
; j
++)
3986 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
3988 const double fValX
= pMat1
->GetDouble(i
,j
);
3989 const double fValY
= pMat2
->GetDouble(i
,j
);
3990 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
3993 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
3994 fSumSqrDeltaY
+= (fValY
- fMeanY
) * (fValY
- fMeanY
);
3998 } // for (SCSIZE i = 0; i < nC1; i++)
4001 if (fSumSqrDeltaX
== 0.0 || ( !_bStexy
&& fSumSqrDeltaY
== 0.0) )
4002 PushError( errDivisionByZero
);
4004 PushDouble( sqrt( (fSumSqrDeltaY
- fSumDeltaXDeltaY
*
4005 fSumDeltaXDeltaY
/ fSumSqrDeltaX
) / (fCount
-2)));
4007 PushDouble( fSumDeltaXDeltaY
/ sqrt( fSumSqrDeltaX
* fSumSqrDeltaY
));
4008 } // if ( _bPearson )
4011 PushDouble( fSumDeltaXDeltaY
/ fCount
);
4016 void ScInterpreter::ScRSQ()
4018 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRSQ" );
4019 // Same as ScPearson()*ScPearson()
4023 switch (GetStackType())
4025 case formula::svDouble
:
4027 double fVal
= PopDouble();
4028 PushDouble( fVal
* fVal
);
4038 void ScInterpreter::ScSTEXY()
4040 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSTEXY" );
4041 CalculatePearsonCovar(TRUE
,TRUE
);
4043 void ScInterpreter::CalculateSlopeIntercept(BOOL bSlope
)
4045 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateSlopeIntercept" );
4046 if ( !MustHaveParamCount( GetByte(), 2 ) )
4048 ScMatrixRef pMat1
= GetMatrix();
4049 ScMatrixRef pMat2
= GetMatrix();
4050 if (!pMat1
|| !pMat2
)
4052 PushIllegalParameter();
4057 pMat1
->GetDimensions(nC1
, nR1
);
4058 pMat2
->GetDimensions(nC2
, nR2
);
4059 if (nR1
!= nR2
|| nC1
!= nC2
)
4061 PushIllegalArgument();
4064 // #i78250# numerical stability improved
4065 double fCount
= 0.0;
4068 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4069 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4070 for (SCSIZE i
= 0; i
< nC1
; i
++)
4072 for (SCSIZE j
= 0; j
< nR1
; j
++)
4074 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4076 double fValX
= pMat1
->GetDouble(i
,j
);
4077 double fValY
= pMat2
->GetDouble(i
,j
);
4088 double fMeanX
= fSumX
/ fCount
;
4089 double fMeanY
= fSumY
/ fCount
;
4090 for (SCSIZE i
= 0; i
< nC1
; i
++)
4092 for (SCSIZE j
= 0; j
< nR1
; j
++)
4094 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4096 double fValX
= pMat1
->GetDouble(i
,j
);
4097 double fValY
= pMat2
->GetDouble(i
,j
);
4098 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4099 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4103 if (fSumSqrDeltaX
== 0.0)
4104 PushError( errDivisionByZero
);
4108 PushDouble( fSumDeltaXDeltaY
/ fSumSqrDeltaX
);
4110 PushDouble( fMeanY
- fSumDeltaXDeltaY
/ fSumSqrDeltaX
* fMeanX
);
4115 void ScInterpreter::ScSlope()
4117 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSlope" );
4118 CalculateSlopeIntercept(TRUE
);
4121 void ScInterpreter::ScIntercept()
4123 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIntercept" );
4124 CalculateSlopeIntercept(FALSE
);
4127 void ScInterpreter::ScForecast()
4129 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScForecast" );
4130 if ( !MustHaveParamCount( GetByte(), 3 ) )
4132 ScMatrixRef pMat1
= GetMatrix();
4133 ScMatrixRef pMat2
= GetMatrix();
4134 if (!pMat1
|| !pMat2
)
4136 PushIllegalParameter();
4141 pMat1
->GetDimensions(nC1
, nR1
);
4142 pMat2
->GetDimensions(nC2
, nR2
);
4143 if (nR1
!= nR2
|| nC1
!= nC2
)
4145 PushIllegalArgument();
4148 double fVal
= GetDouble();
4149 // #i78250# numerical stability improved
4150 double fCount
= 0.0;
4153 double fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
4154 double fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
4155 for (SCSIZE i
= 0; i
< nC1
; i
++)
4157 for (SCSIZE j
= 0; j
< nR1
; j
++)
4159 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4161 double fValX
= pMat1
->GetDouble(i
,j
);
4162 double fValY
= pMat2
->GetDouble(i
,j
);
4173 double fMeanX
= fSumX
/ fCount
;
4174 double fMeanY
= fSumY
/ fCount
;
4175 for (SCSIZE i
= 0; i
< nC1
; i
++)
4177 for (SCSIZE j
= 0; j
< nR1
; j
++)
4179 if (!pMat1
->IsString(i
,j
) && !pMat2
->IsString(i
,j
))
4181 double fValX
= pMat1
->GetDouble(i
,j
);
4182 double fValY
= pMat2
->GetDouble(i
,j
);
4183 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
4184 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
4188 if (fSumSqrDeltaX
== 0.0)
4189 PushError( errDivisionByZero
);
4191 PushDouble( fMeanY
+ fSumDeltaXDeltaY
/ fSumSqrDeltaX
* (fVal
- fMeanX
));