1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/solar.h>
23 #include <interpre.hxx>
25 #include <document.hxx>
26 #include <dociter.hxx>
27 #include <matrixoperators.hxx>
28 #include <scmatrix.hxx>
29 #include <columniterator.hxx>
30 #include <unotools/collatorwrapper.hxx>
38 #include <comphelper/random.hxx>
39 #include <o3tl/float_int_conversion.hxx>
40 #include <osl/diagnose.h>
43 using namespace formula
;
45 /// Two columns of data should be sortable with GetSortArray() and QuickSort()
46 // This is an arbitrary limit.
47 static size_t MAX_COUNT_DOUBLE_FOR_SORT(const ScSheetLimits
& rSheetLimits
)
49 return rSheetLimits
.GetMaxRowCount() * 2;
52 const double ScInterpreter::fMaxGammaArgument
= 171.624376956302; // found experimental
53 const double fMachEps
= ::std::numeric_limits
<double>::epsilon();
60 virtual double GetValue(double x
) const = 0;
68 // iteration for inverse distributions
70 //template< class T > double lcl_IterateInverse( const T& rFunction, double x0, double x1, bool& rConvError )
72 /** u*w<0.0 fails for values near zero */
73 static bool lcl_HasChangeOfSign( double u
, double w
)
75 return (u
< 0.0 && w
> 0.0) || (u
> 0.0 && w
< 0.0);
78 static double lcl_IterateInverse( const ScDistFunc
& rFunction
, double fAx
, double fBx
, bool& rConvError
)
81 const double fYEps
= 1.0E-307;
82 const double fXEps
= ::std::numeric_limits
<double>::epsilon();
84 OSL_ENSURE(fAx
<fBx
, "IterateInverse: wrong interval");
86 // find enclosing interval
90 double fAy
= rFunction
.GetValue(fAx
);
91 double fBy
= rFunction
.GetValue(fBx
);
93 unsigned short nCount
;
94 for (nCount
= 0; nCount
< 1000 && !lcl_HasChangeOfSign(fAy
,fBy
); nCount
++)
96 if (std::abs(fAy
) <= std::abs(fBy
))
99 fkAx
+= (fkAx
- fkBx
) * 2.0;
104 fAy
= rFunction
.GetValue(fkAx
.get());
109 fkBx
+= (fkBx
- fkAx
) * 2.0;
112 fBy
= rFunction
.GetValue(fkBx
.get());
122 if (!lcl_HasChangeOfSign( fAy
, fBy
))
127 // inverse quadric interpolation with additional brackets
135 double fSx
= 0.5 * (fAx
+ fBx
); // potential next point
136 bool bHasToInterpolate
= true;
138 while ( nCount
< 500 && std::abs(fRy
) > fYEps
&&
139 (fBx
-fAx
) > ::std::max( std::abs(fAx
), std::abs(fBx
)) * fXEps
)
141 if (bHasToInterpolate
)
143 if (fPy
!=fQy
&& fQy
!=fRy
&& fRy
!=fPy
)
145 fSx
= fPx
* fRy
* fQy
/ (fRy
-fPy
) / (fQy
-fPy
)
146 + fRx
* fQy
* fPy
/ (fQy
-fRy
) / (fPy
-fRy
)
147 + fQx
* fPy
* fRy
/ (fPy
-fQy
) / (fRy
-fQy
);
148 bHasToInterpolate
= (fAx
< fSx
) && (fSx
< fBx
); // inside the brackets?
151 bHasToInterpolate
= false;
153 if(!bHasToInterpolate
)
155 fSx
= 0.5 * (fAx
+ fBx
);
157 fQx
= fBx
; fQy
= fBy
;
158 bHasToInterpolate
= true;
160 // shift points for next interpolation
161 fPx
= fQx
; fQx
= fRx
; fRx
= fSx
;
162 fPy
= fQy
; fQy
= fRy
; fRy
= rFunction
.GetValue(fSx
);
164 if (lcl_HasChangeOfSign( fAy
, fRy
))
166 fBx
= fRx
; fBy
= fRy
;
170 fAx
= fRx
; fAy
= fRy
;
172 // if last iteration brought too small advance, then do bisection next
174 bHasToInterpolate
= bHasToInterpolate
&& (std::abs(fRy
) * 2.0 <= std::abs(fQy
));
182 void ScInterpreter::ScNoName()
184 PushError(FormulaError::NoName
);
187 void ScInterpreter::ScBadName()
189 short nParamCount
= GetByte();
190 while (nParamCount
-- > 0)
194 PushError( FormulaError::NoName
);
197 double ScInterpreter::phi(double x
)
199 return 0.39894228040143268 * exp(-(x
* x
) / 2.0);
202 double ScInterpreter::integralPhi(double x
)
203 { // Using gauss(x)+0.5 has severe cancellation errors for x<-4
204 return 0.5 * std::erfc(-x
* M_SQRT1_2
);
207 double ScInterpreter::taylor(const double* pPolynom
, sal_uInt16 nMax
, double x
)
209 KahanSum nVal
= pPolynom
[nMax
];
210 for (short i
= nMax
-1; i
>= 0; i
--)
212 nVal
= (nVal
* x
) + pPolynom
[i
];
217 double ScInterpreter::gauss(double x
)
220 double xAbs
= std::abs(x
);
221 sal_uInt16 xShort
= static_cast<sal_uInt16
>(::rtl::math::approxFloor(xAbs
));
225 static const double t0
[] =
226 { 0.39894228040143268, -0.06649038006690545, 0.00997355701003582,
227 -0.00118732821548045, 0.00011543468761616, -0.00000944465625950,
228 0.00000066596935163, -0.00000004122667415, 0.00000000227352982,
229 0.00000000011301172, 0.00000000000511243, -0.00000000000021218 };
230 nVal
= taylor(t0
, 11, (xAbs
* xAbs
)) * xAbs
;
232 else if (xShort
<= 2)
234 static const double t2
[] =
235 { 0.47724986805182079, 0.05399096651318805, -0.05399096651318805,
236 0.02699548325659403, -0.00449924720943234, -0.00224962360471617,
237 0.00134977416282970, -0.00011783742691370, -0.00011515930357476,
238 0.00003704737285544, 0.00000282690796889, -0.00000354513195524,
239 0.00000037669563126, 0.00000019202407921, -0.00000005226908590,
240 -0.00000000491799345, 0.00000000366377919, -0.00000000015981997,
241 -0.00000000017381238, 0.00000000002624031, 0.00000000000560919,
242 -0.00000000000172127, -0.00000000000008634, 0.00000000000007894 };
243 nVal
= taylor(t2
, 23, (xAbs
- 2.0));
245 else if (xShort
<= 4)
247 static const double t4
[] =
248 { 0.49996832875816688, 0.00013383022576489, -0.00026766045152977,
249 0.00033457556441221, -0.00028996548915725, 0.00018178605666397,
250 -0.00008252863922168, 0.00002551802519049, -0.00000391665839292,
251 -0.00000074018205222, 0.00000064422023359, -0.00000017370155340,
252 0.00000000909595465, 0.00000000944943118, -0.00000000329957075,
253 0.00000000029492075, 0.00000000011874477, -0.00000000004420396,
254 0.00000000000361422, 0.00000000000143638, -0.00000000000045848 };
255 nVal
= taylor(t4
, 20, (xAbs
- 4.0));
259 static const double asympt
[] = { -1.0, 1.0, -3.0, 15.0, -105.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>
270 double ScInterpreter::gaussinv(double x
)
276 if(std::abs(q
)<=.425)
289 t
*2509.0809287301226727+33430.575583588128105
291 *t
+67265.770927008700853
293 *t
+45921.953931549871457
295 *t
+13731.693765509461125
297 *t
+1971.5909503065514427
299 *t
+133.14166789178437745
301 *t
+3.387132872796366608
311 t
*5226.495278852854561+28729.085735721942674
313 *t
+39307.89580009271061
315 *t
+21213.794301586595867
317 *t
+5394.1960214247511077
319 *t
+687.1870074920579083
321 *t
+42.313330701600911252
346 t
*7.7454501427834140764e-4+0.0227238449892691845833
348 *t
+0.24178072517745061177
350 *t
+1.27045825245236838258
352 *t
+3.64784832476320460504
354 *t
+5.7694972214606914055
356 *t
+4.6303378461565452959
358 *t
+1.42343711074968357734
368 t
*1.05075007164441684324e-9+5.475938084995344946e-4
370 *t
+0.0151986665636164571966
372 *t
+0.14810397642748007459
374 *t
+0.68976733498510000455
376 *t
+1.6763848301838038494
378 *t
+2.05319162663775882187
396 t
*2.01033439929228813265e-7+2.71155556874348757815e-5
398 *t
+0.0012426609473880784386
400 *t
+0.026532189526576123093
402 *t
+0.29656057182850489123
404 *t
+1.7848265399172913358
406 *t
+5.4637849111641143699
408 *t
+6.6579046435011037772
418 t
*2.04426310338993978564e-15+1.4215117583164458887e-7
420 *t
+1.8463183175100546818e-5
422 *t
+7.868691311456132591e-4
424 *t
+0.0148753612908506148525
426 *t
+0.13692988092273580531
428 *t
+0.59983220655588793769
441 double ScInterpreter::Fakultaet(double x
)
443 x
= ::rtl::math::approxFloor(x
);
458 SetError(FormulaError::NoValue
);
462 double ScInterpreter::BinomKoeff(double n
, double k
)
464 // this method has been duplicated as BinomialCoefficient()
465 // in scaddins/source/analysis/analysishelper.cxx
468 k
= ::rtl::math::approxFloor(k
);
489 // The algorithm is based on lanczos13m53 in lanczos.hpp
490 // in math library from http://www.boost.org
491 /** you must ensure fZ>0
492 Uses a variant of the Lanczos sum with a rational function. */
493 static double lcl_getLanczosSum(double fZ
)
495 static const double fNum
[13] ={
496 23531376880.41075968857200767445163675473,
497 42919803642.64909876895789904700198885093,
498 35711959237.35566804944018545154716670596,
499 17921034426.03720969991975575445893111267,
500 6039542586.35202800506429164430729792107,
501 1439720407.311721673663223072794912393972,
502 248874557.8620541565114603864132294232163,
503 31426415.58540019438061423162831820536287,
504 2876370.628935372441225409051620849613599,
505 186056.2653952234950402949897160456992822,
506 8071.672002365816210638002902272250613822,
507 210.8242777515793458725097339207133627117,
508 2.506628274631000270164908177133837338626
510 static const double fDenom
[13] = {
532 fSumDenom
= fDenom
[12];
533 for (nI
= 11; nI
>= 0; --nI
)
538 fSumDenom
+= fDenom
[nI
];
542 // Cancel down with fZ^12; Horner scheme with reverse coefficients
546 fSumDenom
= fDenom
[0];
547 for (nI
= 1; nI
<=12; ++nI
)
552 fSumDenom
+= fDenom
[nI
];
555 return fSumNum
/fSumDenom
;
558 // The algorithm is based on tgamma in gamma.hpp
559 // in math library from http://www.boost.org
560 /** You must ensure fZ>0; fZ>171.624376956302 will overflow. */
561 static double lcl_GetGammaHelper(double fZ
)
563 double fGamma
= lcl_getLanczosSum(fZ
);
564 const double fg
= 6.024680040776729583740234375;
565 double fZgHelp
= fZ
+ fg
- 0.5;
566 // avoid intermediate overflow
567 double fHalfpower
= pow( fZgHelp
, fZ
/ 2 - 0.25);
568 fGamma
*= fHalfpower
;
569 fGamma
/= exp(fZgHelp
);
570 fGamma
*= fHalfpower
;
571 if (fZ
<= 20.0 && fZ
== ::rtl::math::approxFloor(fZ
))
572 fGamma
= ::rtl::math::round(fGamma
);
576 // The algorithm is based on tgamma in gamma.hpp
577 // in math library from http://www.boost.org
578 /** You must ensure fZ>0 */
579 static double lcl_GetLogGammaHelper(double fZ
)
581 const double fg
= 6.024680040776729583740234375;
582 double fZgHelp
= fZ
+ fg
- 0.5;
583 return log( lcl_getLanczosSum(fZ
)) + (fZ
-0.5) * log(fZgHelp
) - fZgHelp
;
586 /** You must ensure non integer arguments for fZ<1 */
587 double ScInterpreter::GetGamma(double fZ
)
589 const double fLogPi
= log(M_PI
);
590 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
592 if (fZ
> fMaxGammaArgument
)
594 SetError(FormulaError::IllegalFPOperation
);
599 return lcl_GetGammaHelper(fZ
);
601 if (fZ
>= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x
602 return lcl_GetGammaHelper(fZ
+1) / fZ
;
604 if (fZ
>= -0.5) // shift to x>=1, might overflow
606 double fLogTest
= lcl_GetLogGammaHelper(fZ
+2) - std::log1p(fZ
) - log( std::abs(fZ
));
607 if (fLogTest
>= fLogDblMax
)
609 SetError( FormulaError::IllegalFPOperation
);
612 return lcl_GetGammaHelper(fZ
+2) / (fZ
+1) / fZ
;
615 // Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) )
616 double fLogDivisor
= lcl_GetLogGammaHelper(1-fZ
) + log( std::abs( ::rtl::math::sin( M_PI
*fZ
)));
617 if (fLogDivisor
- fLogPi
>= fLogDblMax
) // underflow
621 if (fLogPi
- fLogDivisor
> fLogDblMax
) // overflow
623 SetError(FormulaError::IllegalFPOperation
);
627 return exp( fLogPi
- fLogDivisor
) * ((::rtl::math::sin( M_PI
*fZ
) < 0.0) ? -1.0 : 1.0);
630 /** You must ensure fZ>0 */
631 double ScInterpreter::GetLogGamma(double fZ
)
633 if (fZ
>= fMaxGammaArgument
)
634 return lcl_GetLogGammaHelper(fZ
);
636 return log(lcl_GetGammaHelper(fZ
));
638 return log( lcl_GetGammaHelper(fZ
+1) / fZ
);
639 return lcl_GetLogGammaHelper(fZ
+2) - std::log1p(fZ
) - log(fZ
);
642 double ScInterpreter::GetFDist(double x
, double fF1
, double fF2
)
644 double arg
= fF2
/(fF2
+fF1
*x
);
645 double alpha
= fF2
/2.0;
646 double beta
= fF1
/2.0;
647 return GetBetaDist(arg
, alpha
, beta
);
650 double ScInterpreter::GetTDist( double T
, double fDF
, int nType
)
654 case 1 : // 1-tailed T-distribution
655 return 0.5 * GetBetaDist( fDF
/ ( fDF
+ T
* T
), fDF
/ 2.0, 0.5 );
656 case 2 : // 2-tailed T-distribution
657 return GetBetaDist( fDF
/ ( fDF
+ T
* T
), fDF
/ 2.0, 0.5);
658 case 3 : // left-tailed T-distribution (probability density function)
659 return pow( 1 + ( T
* T
/ fDF
), -( fDF
+ 1 ) / 2 ) / ( sqrt( fDF
) * GetBeta( 0.5, fDF
/ 2.0 ) );
660 case 4 : // left-tailed T-distribution (cumulative distribution function)
661 double X
= fDF
/ ( T
* T
+ fDF
);
662 double R
= 0.5 * GetBetaDist( X
, 0.5 * fDF
, 0.5 );
663 return ( T
< 0 ? R
: 1 - R
);
665 SetError( FormulaError::IllegalArgument
);
669 // for LEGACY.CHIDIST, returns right tail, fDF=degrees of freedom
670 /** You must ensure fDF>0.0 */
671 double ScInterpreter::GetChiDist(double fX
, double fDF
)
674 return 1.0; // see ODFF
676 return GetUpRegIGamma( fDF
/2.0, fX
/2.0);
680 // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
682 /** You must ensure fDF>0.0 */
683 double ScInterpreter::GetChiSqDistCDF(double fX
, double fDF
)
686 return 0.0; // see ODFF
688 return GetLowRegIGamma( fDF
/2.0, fX
/2.0);
691 double ScInterpreter::GetChiSqDistPDF(double fX
, double fDF
)
693 // you must ensure fDF is positive integer
696 return 0.0; // see ODFF
697 if (fDF
*fX
> 1391000.0)
699 // intermediate invalid values, use log
700 fValue
= exp((0.5*fDF
- 1) * log(fX
*0.5) - 0.5 * fX
- log(2.0) - GetLogGamma(0.5*fDF
));
702 else // fDF is small in most cases, we can iterate
705 if (fmod(fDF
,2.0)<0.5)
713 fValue
= 1/sqrt(fX
*2*M_PI
);
716 while ( fCount
< fDF
)
718 fValue
*= (fX
/ fCount
);
721 if (fX
>=1425.0) // underflow in e^(-x/2)
722 fValue
= exp(log(fValue
)-fX
/2);
724 fValue
*= exp(-fX
/2);
729 void ScInterpreter::ScChiSqDist()
731 sal_uInt8 nParamCount
= GetByte();
732 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
735 if (nParamCount
== 3)
736 bCumulative
= GetBool();
739 double fDF
= ::rtl::math::approxFloor(GetDouble());
741 PushIllegalArgument();
744 double fX
= GetDouble();
746 PushDouble(GetChiSqDistCDF(fX
,fDF
));
748 PushDouble(GetChiSqDistPDF(fX
,fDF
));
752 void ScInterpreter::ScChiSqDist_MS()
754 sal_uInt8 nParamCount
= GetByte();
755 if ( !MustHaveParamCount( nParamCount
, 3, 3 ) )
757 bool bCumulative
= GetBool();
758 double fDF
= ::rtl::math::approxFloor( GetDouble() );
759 if ( fDF
< 1.0 || fDF
> 1E10
)
760 PushIllegalArgument();
763 double fX
= GetDouble();
765 PushIllegalArgument();
769 PushDouble( GetChiSqDistCDF( fX
, fDF
) );
771 PushDouble( GetChiSqDistPDF( fX
, fDF
) );
776 void ScInterpreter::ScGamma()
778 double x
= GetDouble();
779 if (x
<= 0.0 && x
== ::rtl::math::approxFloor(x
))
780 PushIllegalArgument();
783 double fResult
= GetGamma(x
);
784 if (nGlobalError
!= FormulaError::NONE
)
786 PushError( nGlobalError
);
793 void ScInterpreter::ScLogGamma()
795 double x
= GetDouble();
796 if (x
> 0.0) // constraint from ODFF
797 PushDouble( GetLogGamma(x
));
799 PushIllegalArgument();
802 double ScInterpreter::GetBeta(double fAlpha
, double fBeta
)
808 fA
= fAlpha
; fB
= fBeta
;
812 fA
= fBeta
; fB
= fAlpha
;
814 if (fA
+fB
< fMaxGammaArgument
) // simple case
815 return GetGamma(fA
)/GetGamma(fA
+fB
)*GetGamma(fB
);
817 // GetLogGamma is not accurate enough, back to Lanczos for all three
818 // GetGamma and arrange factors newly.
819 const double fg
= 6.024680040776729583740234375; //see GetGamma
820 double fgm
= fg
- 0.5;
821 double fLanczos
= lcl_getLanczosSum(fA
);
822 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
823 fLanczos
*= lcl_getLanczosSum(fB
);
824 double fABgm
= fA
+fB
+fgm
;
825 fLanczos
*= sqrt((fABgm
/(fA
+fgm
))/(fB
+fgm
));
826 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
827 double fTempB
= fA
/(fB
+fgm
);
828 double fResult
= exp(-fA
* std::log1p(fTempA
)
829 -fB
* std::log1p(fTempB
)-fgm
);
834 // Same as GetBeta but with logarithm
835 double ScInterpreter::GetLogBeta(double fAlpha
, double fBeta
)
841 fA
= fAlpha
; fB
= fBeta
;
845 fA
= fBeta
; fB
= fAlpha
;
847 const double fg
= 6.024680040776729583740234375; //see GetGamma
848 double fgm
= fg
- 0.5;
849 double fLanczos
= lcl_getLanczosSum(fA
);
850 fLanczos
/= lcl_getLanczosSum(fA
+fB
);
851 fLanczos
*= lcl_getLanczosSum(fB
);
852 double fLogLanczos
= log(fLanczos
);
853 double fABgm
= fA
+fB
+fgm
;
854 fLogLanczos
+= 0.5*(log(fABgm
)-log(fA
+fgm
)-log(fB
+fgm
));
855 double fTempA
= fB
/(fA
+fgm
); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm))
856 double fTempB
= fA
/(fB
+fgm
);
857 double fResult
= -fA
* std::log1p(fTempA
)
858 -fB
* std::log1p(fTempB
)-fgm
;
859 fResult
+= fLogLanczos
;
863 // beta distribution probability density function
864 double ScInterpreter::GetBetaDistPDF(double fX
, double fA
, double fB
)
867 if (fA
== 1.0) // result b*(1-x)^(b-1)
872 return -2.0*fX
+ 2.0;
873 if (fX
== 1.0 && fB
< 1.0)
875 SetError(FormulaError::IllegalArgument
);
879 return fB
+ fB
* std::expm1((fB
-1.0) * std::log1p(-fX
));
881 return fB
* pow(0.5-fX
+0.5,fB
-1.0);
883 if (fB
== 1.0) // result a*x^(a-1)
887 if (fX
== 0.0 && fA
< 1.0)
889 SetError(FormulaError::IllegalArgument
);
892 return fA
* pow(fX
,fA
-1);
896 if (fA
< 1.0 && fX
== 0.0)
898 SetError(FormulaError::IllegalArgument
);
906 if (fB
< 1.0 && fX
== 1.0)
908 SetError(FormulaError::IllegalArgument
);
915 // normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b)
916 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
917 const double fLogDblMin
= log( ::std::numeric_limits
<double>::min());
918 double fLogY
= (fX
< 0.1) ? std::log1p(-fX
) : log(0.5-fX
+0.5);
919 double fLogX
= log(fX
);
920 double fAm1LogX
= (fA
-1.0) * fLogX
;
921 double fBm1LogY
= (fB
-1.0) * fLogY
;
922 double fLogBeta
= GetLogBeta(fA
,fB
);
923 // check whether parts over- or underflow
924 if ( fAm1LogX
< fLogDblMax
&& fAm1LogX
> fLogDblMin
925 && fBm1LogY
< fLogDblMax
&& fBm1LogY
> fLogDblMin
926 && fLogBeta
< fLogDblMax
&& fLogBeta
> fLogDblMin
927 && fAm1LogX
+ fBm1LogY
< fLogDblMax
&& fAm1LogX
+ fBm1LogY
> fLogDblMin
)
928 return pow(fX
,fA
-1.0) * pow(0.5-fX
+0.5,fB
-1.0) / GetBeta(fA
,fB
);
929 else // need logarithm;
930 // might overflow as a whole, but seldom, not worth to pre-detect it
931 return exp( fAm1LogX
+ fBm1LogY
- fLogBeta
);
936 I_x(a,b) = ---------------- * result of ContFrac
939 static double lcl_GetBetaHelperContFrac(double fX
, double fA
, double fB
)
940 { // like old version
941 double a1
, b1
, a2
, b2
, fnorm
, cfnew
, cf
;
943 b2
= 1.0 - (fA
+fB
)/(fA
+1.0)*fX
;
959 const double fMaxIter
= 50000.0;
960 // loop security, normal cases converge in less than 100 iterations.
961 // FIXME: You will get so much iterations for fX near mean,
962 // I do not know a better algorithm.
963 bool bfinished
= false;
966 const double apl2m
= fA
+ 2.0*rm
;
967 const double d2m
= rm
*(fB
-rm
)*fX
/((apl2m
-1.0)*apl2m
);
968 const double d2m1
= -(fA
+rm
)*(fA
+fB
+rm
)*fX
/(apl2m
*(apl2m
+1.0));
969 a1
= (a2
+d2m
*a1
)*fnorm
;
970 b1
= (b2
+d2m
*b1
)*fnorm
;
971 a2
= a1
+ d2m1
*a2
*fnorm
;
972 b2
= b1
+ d2m1
*b2
*fnorm
;
977 bfinished
= (std::abs(cf
-cfnew
) < std::abs(cf
)*fMachEps
);
982 while (rm
< fMaxIter
&& !bfinished
);
986 // cumulative distribution function, normalized
987 double ScInterpreter::GetBetaDist(double fXin
, double fAlpha
, double fBeta
)
990 if (fXin
<= 0.0) // values are valid, see spec
992 if (fXin
>= 1.0) // values are valid, see spec
995 return pow(fXin
, fAlpha
);
997 // 1.0 - pow(1.0-fX,fBeta) is not accurate enough
998 return -std::expm1(fBeta
* std::log1p(-fXin
));
999 //FIXME: need special algorithm for fX near fP for large fA,fB
1001 // I use always continued fraction, power series are neither
1002 // faster nor more accurate.
1003 double fY
= (0.5-fXin
)+0.5;
1004 double flnY
= std::log1p(-fXin
);
1006 double flnX
= log(fXin
);
1009 bool bReflect
= fXin
> fAlpha
/(fAlpha
+fBeta
);
1019 fResult
= lcl_GetBetaHelperContFrac(fX
,fA
,fB
);
1020 fResult
= fResult
/fA
;
1021 double fP
= fA
/(fA
+fB
);
1022 double fQ
= fB
/(fA
+fB
);
1024 if (fA
> 1.0 && fB
> 1.0 && fP
< 0.97 && fQ
< 0.97) //found experimental
1025 fTemp
= GetBetaDistPDF(fX
,fA
,fB
)*fX
*fY
;
1027 fTemp
= exp(fA
*flnX
+ fB
*flnY
- GetLogBeta(fA
,fB
));
1030 fResult
= 0.5 - fResult
+ 0.5;
1031 if (fResult
> 1.0) // ensure valid range
1038 void ScInterpreter::ScBetaDist()
1040 sal_uInt8 nParamCount
= GetByte();
1041 if ( !MustHaveParamCount( nParamCount
, 3, 6 ) ) // expanded, see #i91547#
1043 double fLowerBound
, fUpperBound
;
1044 double alpha
, beta
, x
;
1046 if (nParamCount
== 6)
1047 bIsCumulative
= GetBool();
1049 bIsCumulative
= true;
1050 if (nParamCount
>= 5)
1051 fUpperBound
= GetDouble();
1054 if (nParamCount
>= 4)
1055 fLowerBound
= GetDouble();
1059 alpha
= GetDouble();
1061 double fScale
= fUpperBound
- fLowerBound
;
1062 if (fScale
<= 0.0 || alpha
<= 0.0 || beta
<= 0.0)
1064 PushIllegalArgument();
1067 if (bIsCumulative
) // cumulative distribution function
1070 if (x
< fLowerBound
)
1072 PushDouble(0.0); return; //see spec
1074 if (x
> fUpperBound
)
1076 PushDouble(1.0); return; //see spec
1079 x
= (x
-fLowerBound
)/fScale
; // convert to standard form
1080 PushDouble(GetBetaDist(x
, alpha
, beta
));
1083 else // probability density function
1085 if (x
< fLowerBound
|| x
> fUpperBound
)
1090 x
= (x
-fLowerBound
)/fScale
;
1091 PushDouble(GetBetaDistPDF(x
, alpha
, beta
)/fScale
);
1097 Microsoft version has parameters in different order
1098 Also, upper and lowerbound are optional and have default values
1099 and different constraints apply.
1100 Basically, function is identical with ScInterpreter::ScBetaDist()
1102 void ScInterpreter::ScBetaDist_MS()
1104 sal_uInt8 nParamCount
= GetByte();
1105 if ( !MustHaveParamCount( nParamCount
, 4, 6 ) )
1107 double fLowerBound
, fUpperBound
;
1108 double alpha
, beta
, x
;
1110 if (nParamCount
== 6)
1111 fUpperBound
= GetDouble();
1114 if (nParamCount
>= 5)
1115 fLowerBound
= GetDouble();
1118 bIsCumulative
= GetBool();
1120 alpha
= GetDouble();
1122 if (alpha
<= 0.0 || beta
<= 0.0 || x
< fLowerBound
|| x
> fUpperBound
)
1124 PushIllegalArgument();
1127 double fScale
= fUpperBound
- fLowerBound
;
1128 if (bIsCumulative
) // cumulative distribution function
1130 x
= (x
-fLowerBound
)/fScale
; // convert to standard form
1131 PushDouble(GetBetaDist(x
, alpha
, beta
));
1134 else // probability density function
1136 x
= (x
-fLowerBound
)/fScale
;
1137 PushDouble(GetBetaDistPDF(x
, alpha
, beta
)/fScale
);
1142 void ScInterpreter::ScPhi()
1144 PushDouble(phi(GetDouble()));
1147 void ScInterpreter::ScGauss()
1149 PushDouble(gauss(GetDouble()));
1152 void ScInterpreter::ScFisher()
1154 double fVal
= GetDouble();
1155 if (std::abs(fVal
) >= 1.0)
1156 PushIllegalArgument();
1158 PushDouble(::atanh(fVal
));
1161 void ScInterpreter::ScFisherInv()
1163 PushDouble( tanh( GetDouble()));
1166 void ScInterpreter::ScFact()
1168 double nVal
= GetDouble();
1170 PushIllegalArgument();
1172 PushDouble(Fakultaet(nVal
));
1175 void ScInterpreter::ScCombin()
1177 if ( MustHaveParamCount( GetByte(), 2 ) )
1179 double k
= ::rtl::math::approxFloor(GetDouble());
1180 double n
= ::rtl::math::approxFloor(GetDouble());
1181 if (k
< 0.0 || n
< 0.0 || k
> n
)
1182 PushIllegalArgument();
1184 PushDouble(BinomKoeff(n
, k
));
1188 void ScInterpreter::ScCombinA()
1190 if ( MustHaveParamCount( GetByte(), 2 ) )
1192 double k
= ::rtl::math::approxFloor(GetDouble());
1193 double n
= ::rtl::math::approxFloor(GetDouble());
1194 if (k
< 0.0 || n
< 0.0 || k
> n
)
1195 PushIllegalArgument();
1197 PushDouble(BinomKoeff(n
+ k
- 1, k
));
1201 void ScInterpreter::ScPermut()
1203 if ( !MustHaveParamCount( GetByte(), 2 ) )
1206 double k
= ::rtl::math::approxFloor(GetDouble());
1207 double n
= ::rtl::math::approxFloor(GetDouble());
1208 if (n
< 0.0 || k
< 0.0 || k
> n
)
1209 PushIllegalArgument();
1211 PushInt(1); // (n! / (n - 0)!) == 1
1215 for (sal_uLong i
= static_cast<sal_uLong
>(k
)-1; i
>= 1; i
--)
1216 nVal
*= n
-static_cast<double>(i
);
1221 void ScInterpreter::ScPermutationA()
1223 if ( MustHaveParamCount( GetByte(), 2 ) )
1225 double k
= ::rtl::math::approxFloor(GetDouble());
1226 double n
= ::rtl::math::approxFloor(GetDouble());
1227 if (n
< 0.0 || k
< 0.0)
1228 PushIllegalArgument();
1230 PushDouble(pow(n
,k
));
1234 double ScInterpreter::GetBinomDistPMF(double x
, double n
, double p
)
1235 // used in ScB and ScBinomDist
1236 // preconditions: 0.0 <= x <= n, 0.0 < p < 1.0; x,n integral although double
1238 double q
= (0.5 - p
) + 0.5;
1239 double fFactor
= pow(q
, n
);
1240 if (fFactor
<=::std::numeric_limits
<double>::min())
1242 fFactor
= pow(p
, n
);
1243 if (fFactor
<= ::std::numeric_limits
<double>::min())
1244 return GetBetaDistPDF(p
, x
+1.0, n
-x
+1.0)/(n
+1.0);
1247 sal_uInt32 max
= static_cast<sal_uInt32
>(n
- x
);
1248 for (sal_uInt32 i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1249 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1255 sal_uInt32 max
= static_cast<sal_uInt32
>(x
);
1256 for (sal_uInt32 i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1257 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1262 static double lcl_GetBinomDistRange(double n
, double xs
,double xe
,
1263 double fFactor
/* q^n */, double p
, double q
)
1264 //preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double
1267 // skip summands index 0 to xs-1, start sum with index xs
1268 sal_uInt32 nXs
= static_cast<sal_uInt32
>( xs
);
1269 for (i
= 1; i
<= nXs
&& fFactor
> 0.0; i
++)
1270 fFactor
*= (n
-i
+1)/i
* p
/q
;
1271 KahanSum fSum
= fFactor
; // Summand xs
1272 sal_uInt32 nXe
= static_cast<sal_uInt32
>(xe
);
1273 for (i
= nXs
+1; i
<= nXe
&& fFactor
> 0.0; i
++)
1275 fFactor
*= (n
-i
+1)/i
* p
/q
;
1278 return std::min(fSum
.get(), 1.0);
1281 void ScInterpreter::ScB()
1283 sal_uInt8 nParamCount
= GetByte();
1284 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1286 if (nParamCount
== 3) // mass function
1288 double x
= ::rtl::math::approxFloor(GetDouble());
1289 double p
= GetDouble();
1290 double n
= ::rtl::math::approxFloor(GetDouble());
1291 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1292 PushIllegalArgument();
1294 PushDouble( (x
== 0.0) ? 1.0 : 0.0 );
1296 PushDouble( (x
== n
) ? 1.0 : 0.0);
1298 PushDouble(GetBinomDistPMF(x
,n
,p
));
1301 { // nParamCount == 4
1302 double xe
= ::rtl::math::approxFloor(GetDouble());
1303 double xs
= ::rtl::math::approxFloor(GetDouble());
1304 double p
= GetDouble();
1305 double n
= ::rtl::math::approxFloor(GetDouble());
1306 double q
= (0.5 - p
) + 0.5;
1307 bool bIsValidX
= ( 0.0 <= xs
&& xs
<= xe
&& xe
<= n
);
1308 if ( bIsValidX
&& 0.0 < p
&& p
< 1.0)
1310 if (xs
== xe
) // mass function
1311 PushDouble(GetBinomDistPMF(xs
,n
,p
));
1314 double fFactor
= pow(q
, n
);
1315 if (fFactor
> ::std::numeric_limits
<double>::min())
1316 PushDouble(lcl_GetBinomDistRange(n
,xs
,xe
,fFactor
,p
,q
));
1319 fFactor
= pow(p
, n
);
1320 if (fFactor
> ::std::numeric_limits
<double>::min())
1322 // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)}
1323 // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)}
1324 PushDouble(lcl_GetBinomDistRange(n
,n
-xe
,n
-xs
,fFactor
,q
,p
));
1327 PushDouble(GetBetaDist(q
,n
-xe
,xe
+1.0)-GetBetaDist(q
,n
-xs
+1,xs
) );
1333 if ( bIsValidX
) // not(0<p<1)
1336 PushDouble( (xs
== 0.0) ? 1.0 : 0.0 );
1337 else if ( p
== 1.0 )
1338 PushDouble( (xe
== n
) ? 1.0 : 0.0 );
1340 PushIllegalArgument();
1343 PushIllegalArgument();
1348 void ScInterpreter::ScBinomDist()
1350 if ( !MustHaveParamCount( GetByte(), 4 ) )
1353 bool bIsCum
= GetBool(); // false=mass function; true=cumulative
1354 double p
= GetDouble();
1355 double n
= ::rtl::math::approxFloor(GetDouble());
1356 double x
= ::rtl::math::approxFloor(GetDouble());
1357 double q
= (0.5 - p
) + 0.5; // get one bit more for p near 1.0
1358 if (n
< 0.0 || x
< 0.0 || x
> n
|| p
< 0.0 || p
> 1.0)
1360 PushIllegalArgument();
1365 PushDouble( (x
==0.0 || bIsCum
) ? 1.0 : 0.0 );
1370 PushDouble( (x
==n
) ? 1.0 : 0.0);
1374 PushDouble( GetBinomDistPMF(x
,n
,p
));
1381 double fFactor
= pow(q
, n
);
1383 PushDouble(fFactor
);
1384 else if (fFactor
<= ::std::numeric_limits
<double>::min())
1386 fFactor
= pow(p
, n
);
1387 if (fFactor
<= ::std::numeric_limits
<double>::min())
1388 PushDouble(GetBetaDist(q
,n
-x
,x
+1.0));
1391 if (fFactor
> fMachEps
)
1393 double fSum
= 1.0 - fFactor
;
1394 sal_uInt32 max
= static_cast<sal_uInt32
> (n
- x
) - 1;
1395 for (sal_uInt32 i
= 0; i
< max
&& fFactor
> 0.0; i
++)
1397 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1400 PushDouble( (fSum
< 0.0) ? 0.0 : fSum
);
1403 PushDouble(lcl_GetBinomDistRange(n
,n
-x
,n
,fFactor
,q
,p
));
1407 PushDouble( lcl_GetBinomDistRange(n
,0.0,x
,fFactor
,p
,q
)) ;
1412 void ScInterpreter::ScCritBinom()
1414 if ( !MustHaveParamCount( GetByte(), 3 ) )
1417 double alpha
= GetDouble();
1418 double p
= GetDouble();
1419 double n
= ::rtl::math::approxFloor(GetDouble());
1420 if (n
< 0.0 || alpha
< 0.0 || alpha
> 1.0 || p
< 0.0 || p
> 1.0)
1421 PushIllegalArgument();
1422 else if ( alpha
== 0.0 )
1424 else if ( alpha
== 1.0 )
1425 PushDouble( p
== 0 ? 0.0 : n
);
1429 double q
= (0.5 - p
) + 0.5; // get one bit more for p near 1.0
1430 if ( q
> p
) // work from the side where the cumulative curve is
1432 // work from 0 upwards
1434 if (fFactor
> ::std::numeric_limits
<double>::min())
1436 KahanSum fSum
= fFactor
;
1437 sal_uInt32 max
= static_cast<sal_uInt32
> (n
), i
;
1438 for (i
= 0; i
< max
&& fSum
< alpha
; i
++)
1440 fFactor
*= (n
-i
)/(i
+1)*p
/q
;
1447 // accumulate BinomDist until accumulated BinomDist reaches alpha
1448 KahanSum fSum
= 0.0;
1449 sal_uInt32 max
= static_cast<sal_uInt32
> (n
), i
;
1450 for (i
= 0; i
< max
&& fSum
< alpha
; i
++)
1452 const double x
= GetBetaDistPDF( p
, ( i
+ 1 ), ( n
- i
+ 1 ) )/( n
+ 1 );
1453 if ( nGlobalError
== FormulaError::NONE
)
1461 assert(i
> 0 && "coverity 2023.12.2");
1462 PushDouble( i
- 1 );
1467 // work from n backwards
1468 fFactor
= pow(p
, n
);
1469 if (fFactor
> ::std::numeric_limits
<double>::min())
1471 KahanSum fSum
= 1.0 - fFactor
;
1472 sal_uInt32 max
= static_cast<sal_uInt32
> (n
), i
;
1473 for (i
= 0; i
< max
&& fSum
>= alpha
; i
++)
1475 fFactor
*= (n
-i
)/(i
+1)*q
/p
;
1482 // accumulate BinomDist until accumulated BinomDist reaches alpha
1483 KahanSum fSum
= 0.0;
1484 sal_uInt32 max
= static_cast<sal_uInt32
> (n
), i
;
1486 for (i
= 0; i
< max
&& fSum
< alpha
; i
++)
1488 const double x
= GetBetaDistPDF( q
, ( i
+ 1 ), ( n
- i
+ 1 ) )/( n
+ 1 );
1489 if ( nGlobalError
== FormulaError::NONE
)
1497 PushDouble( n
- i
+ 1 );
1503 void ScInterpreter::ScNegBinomDist()
1505 if ( !MustHaveParamCount( GetByte(), 3 ) )
1508 double p
= GetDouble(); // probability
1509 double s
= ::rtl::math::approxFloor(GetDouble()); // No of successes
1510 double f
= ::rtl::math::approxFloor(GetDouble()); // No of failures
1511 if ((f
+ s
) <= 1.0 || p
< 0.0 || p
> 1.0)
1512 PushIllegalArgument();
1516 double fFactor
= pow(p
,s
);
1517 for (double i
= 0.0; i
< f
; i
++)
1518 fFactor
*= (i
+s
)/(i
+1.0)*q
;
1519 PushDouble(fFactor
);
1523 void ScInterpreter::ScNegBinomDist_MS()
1525 if ( !MustHaveParamCount( GetByte(), 4 ) )
1528 bool bCumulative
= GetBool();
1529 double p
= GetDouble(); // probability
1530 double s
= ::rtl::math::approxFloor(GetDouble()); // No of successes
1531 double f
= ::rtl::math::approxFloor(GetDouble()); // No of failures
1532 if ( s
< 1.0 || f
< 0.0 || p
< 0.0 || p
> 1.0 )
1533 PushIllegalArgument();
1538 PushDouble( 1.0 - GetBetaDist( q
, f
+ 1, s
) );
1541 double fFactor
= pow( p
, s
);
1542 for ( double i
= 0.0; i
< f
; i
++ )
1543 fFactor
*= ( i
+ s
) / ( i
+ 1.0 ) * q
;
1544 PushDouble( fFactor
);
1549 void ScInterpreter::ScNormDist( int nMinParamCount
)
1551 sal_uInt8 nParamCount
= GetByte();
1552 if ( !MustHaveParamCount( nParamCount
, nMinParamCount
, 4 ) )
1554 bool bCumulative
= nParamCount
!= 4 || GetBool();
1555 double sigma
= GetDouble(); // standard deviation
1556 double mue
= GetDouble(); // mean
1557 double x
= GetDouble(); // x
1560 PushIllegalArgument();
1564 PushDouble(integralPhi((x
-mue
)/sigma
));
1566 PushDouble(phi((x
-mue
)/sigma
)/sigma
);
1569 void ScInterpreter::ScLogNormDist( int nMinParamCount
) //expanded, see #i100119# and fdo72158
1571 sal_uInt8 nParamCount
= GetByte();
1572 if ( !MustHaveParamCount( nParamCount
, nMinParamCount
, 4 ) )
1574 bool bCumulative
= nParamCount
!= 4 || GetBool(); // cumulative
1575 double sigma
= nParamCount
>= 3 ? GetDouble() : 1.0; // standard deviation
1576 double mue
= nParamCount
>= 2 ? GetDouble() : 0.0; // mean
1577 double x
= GetDouble(); // x
1580 PushIllegalArgument();
1588 PushDouble(integralPhi((log(x
)-mue
)/sigma
));
1593 PushIllegalArgument();
1595 PushDouble(phi((log(x
)-mue
)/sigma
)/sigma
/x
);
1599 void ScInterpreter::ScStdNormDist()
1601 PushDouble(integralPhi(GetDouble()));
1604 void ScInterpreter::ScStdNormDist_MS()
1606 sal_uInt8 nParamCount
= GetByte();
1607 if ( !MustHaveParamCount( nParamCount
, 2 ) )
1609 bool bCumulative
= GetBool(); // cumulative
1610 double x
= GetDouble(); // x
1613 PushDouble( integralPhi( x
) );
1615 PushDouble( exp( - pow( x
, 2 ) / 2 ) / sqrt( 2 * M_PI
) );
1618 void ScInterpreter::ScExpDist()
1620 if ( !MustHaveParamCount( GetByte(), 3 ) )
1623 double kum
= GetDouble(); // 0 or 1
1624 double lambda
= GetDouble(); // lambda
1625 double x
= GetDouble(); // x
1627 PushIllegalArgument();
1628 else if (kum
== 0.0) // density
1631 PushDouble(lambda
* exp(-lambda
*x
));
1635 else // distribution
1638 PushDouble(1.0 - exp(-lambda
*x
));
1644 void ScInterpreter::ScTDist()
1646 if ( !MustHaveParamCount( GetByte(), 3 ) )
1648 double fFlag
= ::rtl::math::approxFloor(GetDouble());
1649 double fDF
= ::rtl::math::approxFloor(GetDouble());
1650 double T
= GetDouble();
1651 if (fDF
< 1.0 || T
< 0.0 || (fFlag
!= 1.0 && fFlag
!= 2.0) )
1653 PushIllegalArgument();
1656 PushDouble( GetTDist( T
, fDF
, static_cast<int>(fFlag
) ) );
1659 void ScInterpreter::ScTDist_T( int nTails
)
1661 if ( !MustHaveParamCount( GetByte(), 2 ) )
1663 double fDF
= ::rtl::math::approxFloor( GetDouble() );
1664 double fT
= GetDouble();
1665 if ( fDF
< 1.0 || ( nTails
== 2 && fT
< 0.0 ) )
1667 PushIllegalArgument();
1670 double fRes
= GetTDist( fT
, fDF
, nTails
);
1671 if ( nTails
== 1 && fT
< 0.0 )
1672 PushDouble( 1.0 - fRes
); // tdf#105937, right tail, negative X
1677 void ScInterpreter::ScTDist_MS()
1679 if ( !MustHaveParamCount( GetByte(), 3 ) )
1681 bool bCumulative
= GetBool();
1682 double fDF
= ::rtl::math::approxFloor( GetDouble() );
1683 double T
= GetDouble();
1686 PushIllegalArgument();
1689 PushDouble( GetTDist( T
, fDF
, ( bCumulative
? 4 : 3 ) ) );
1692 void ScInterpreter::ScFDist()
1694 if ( !MustHaveParamCount( GetByte(), 3 ) )
1696 double fF2
= ::rtl::math::approxFloor(GetDouble());
1697 double fF1
= ::rtl::math::approxFloor(GetDouble());
1698 double fF
= GetDouble();
1699 if (fF
< 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
)
1701 PushIllegalArgument();
1704 PushDouble(GetFDist(fF
, fF1
, fF2
));
1707 void ScInterpreter::ScFDist_LT()
1709 int nParamCount
= GetByte();
1710 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
1713 if ( nParamCount
== 3 )
1715 else if ( IsMissing() )
1722 double fF2
= ::rtl::math::approxFloor( GetDouble() );
1723 double fF1
= ::rtl::math::approxFloor( GetDouble() );
1724 double fF
= GetDouble();
1725 if ( fF
< 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
)
1727 PushIllegalArgument();
1732 // left tail cumulative distribution
1733 PushDouble( 1.0 - GetFDist( fF
, fF1
, fF2
) );
1737 // probability density function
1738 PushDouble( pow( fF1
/ fF2
, fF1
/ 2 ) * pow( fF
, ( fF1
/ 2 ) - 1 ) /
1739 ( pow( ( 1 + ( fF
* fF1
/ fF2
) ), ( fF1
+ fF2
) / 2 ) *
1740 GetBeta( fF1
/ 2, fF2
/ 2 ) ) );
1744 void ScInterpreter::ScChiDist( bool bODFF
)
1747 if ( !MustHaveParamCount( GetByte(), 2 ) )
1749 double fDF
= ::rtl::math::approxFloor(GetDouble());
1750 double fChi
= GetDouble();
1751 if ( fDF
< 1.0 // x<=0 returns 1, see ODFF1.2 6.18.11
1752 || ( !bODFF
&& fChi
< 0 ) ) // Excel does not accept negative fChi
1754 PushIllegalArgument();
1757 fResult
= GetChiDist( fChi
, fDF
);
1758 if (nGlobalError
!= FormulaError::NONE
)
1760 PushError( nGlobalError
);
1763 PushDouble(fResult
);
1766 void ScInterpreter::ScWeibull()
1768 if ( !MustHaveParamCount( GetByte(), 4 ) )
1771 double kum
= GetDouble(); // 0 or 1
1772 double beta
= GetDouble(); // beta
1773 double alpha
= GetDouble(); // alpha
1774 double x
= GetDouble(); // x
1775 if (alpha
<= 0.0 || beta
<= 0.0 || x
< 0.0)
1776 PushIllegalArgument();
1777 else if (kum
== 0.0) // Density
1778 PushDouble(alpha
/pow(beta
,alpha
)*pow(x
,alpha
-1.0)*
1779 exp(-pow(x
/beta
,alpha
)));
1780 else // Distribution
1781 PushDouble(1.0 - exp(-pow(x
/beta
,alpha
)));
1784 void ScInterpreter::ScPoissonDist( bool bODFF
)
1786 sal_uInt8 nParamCount
= GetByte();
1787 if ( !MustHaveParamCount( nParamCount
, ( bODFF
? 2 : 3 ), 3 ) )
1790 bool bCumulative
= nParamCount
!= 3 || GetBool(); // default cumulative
1791 double lambda
= GetDouble(); // Mean
1792 double x
= ::rtl::math::approxFloor(GetDouble()); // discrete distribution
1793 if (lambda
<= 0.0 || x
< 0.0)
1794 PushIllegalArgument();
1795 else if (!bCumulative
) // Probability mass function
1797 if (lambda
>712.0) // underflow in exp(-lambda)
1798 { // accuracy 11 Digits
1799 PushDouble( exp(x
*log(lambda
)-lambda
-GetLogGamma(x
+1.0)));
1803 double fPoissonVar
= 1.0;
1804 for ( double f
= 0.0; f
< x
; ++f
)
1805 fPoissonVar
*= lambda
/ ( f
+ 1.0 );
1806 PushDouble( fPoissonVar
* exp( -lambda
) );
1809 else // Cumulative distribution function
1811 if (lambda
> 712.0) // underflow in exp(-lambda)
1812 { // accuracy 12 Digits
1813 PushDouble(GetUpRegIGamma(x
+1.0,lambda
));
1817 if (x
>= 936.0) // result is always indistinguishable from 1
1821 double fSummand
= std::exp(-lambda
);
1822 KahanSum fSum
= fSummand
;
1823 int nEnd
= sal::static_int_cast
<int>( x
);
1824 for (int i
= 1; i
<= nEnd
; i
++)
1826 fSummand
= (fSummand
* lambda
)/static_cast<double>(i
);
1829 PushDouble(fSum
.get());
1835 /** Local function used in the calculation of the hypergeometric distribution.
1837 static void lcl_PutFactorialElements( ::std::vector
< double >& cn
, double fLower
, double fUpper
, double fBase
)
1839 for ( double i
= fLower
; i
<= fUpper
; ++i
)
1841 double fVal
= fBase
- i
;
1843 cn
.push_back( fVal
);
1847 /** Calculates a value of the hypergeometric distribution.
1851 This function has an extra argument bCumulative,
1852 which only calculates the non-cumulative distribution and
1853 which is optional in Calc and mandatory with Excel's HYPGEOM.DIST()
1856 @see tdf#102948, make Calc function ODFF1.2-compliant
1857 @see tdf#117041, implement note at bottom of ODFF1.2 par.6.18.37
1859 void ScInterpreter::ScHypGeomDist( int nMinParamCount
)
1861 sal_uInt8 nParamCount
= GetByte();
1862 if ( !MustHaveParamCount( nParamCount
, nMinParamCount
, 5 ) )
1865 bool bCumulative
= ( nParamCount
== 5 && GetBool() );
1866 double N
= ::rtl::math::approxFloor(GetDouble());
1867 double M
= ::rtl::math::approxFloor(GetDouble());
1868 double n
= ::rtl::math::approxFloor(GetDouble());
1869 double x
= ::rtl::math::approxFloor(GetDouble());
1871 if ( (x
< 0.0) || (n
< x
) || (N
< n
) || (N
< M
) || (M
< 0.0) )
1873 PushIllegalArgument();
1877 KahanSum fVal
= 0.0;
1879 for ( int i
= ( bCumulative
? 0 : x
); i
<= x
&& nGlobalError
== FormulaError::NONE
; i
++ )
1881 if ( (n
- i
<= N
- M
) && (i
<= M
) )
1882 fVal
+= GetHypGeomDist( i
, n
, M
, N
);
1885 PushDouble( fVal
.get() );
1888 /** Calculates a value of the hypergeometric distribution.
1890 The algorithm is designed to avoid unnecessary multiplications and division
1891 by expanding all factorial elements (9 of them). It is done by excluding
1892 those ranges that overlap in the numerator and the denominator. This allows
1893 for a fast calculation for large values which would otherwise cause an overflow
1894 in the intermediate values.
1898 double ScInterpreter::GetHypGeomDist( double x
, double n
, double M
, double N
)
1900 const size_t nMaxArraySize
= 500000; // arbitrary max array size
1902 std::vector
<double> cnNumer
, cnDenom
;
1904 size_t nEstContainerSize
= static_cast<size_t>( x
+ ::std::min( n
, M
) );
1905 size_t nMaxSize
= ::std::min( cnNumer
.max_size(), nMaxArraySize
);
1906 if ( nEstContainerSize
> nMaxSize
)
1911 cnNumer
.reserve( nEstContainerSize
+ 10 );
1912 cnDenom
.reserve( nEstContainerSize
+ 10 );
1914 // Trim coefficient C first
1915 double fCNumVarUpper
= N
- n
- M
+ x
- 1.0;
1916 double fCDenomVarLower
= 1.0;
1917 if ( N
- n
- M
+ x
>= M
- x
+ 1.0 )
1919 fCNumVarUpper
= M
- x
- 1.0;
1920 fCDenomVarLower
= N
- n
- 2.0*(M
- x
) + 1.0;
1923 double fCNumLower
= N
- n
- fCNumVarUpper
;
1924 double fCDenomUpper
= N
- n
- M
+ x
+ 1.0 - fCDenomVarLower
;
1926 double fDNumVarLower
= n
- M
;
1930 if ( N
- M
< n
+ 1.0 )
1934 if ( N
- n
< n
+ 1.0 )
1937 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1938 lcl_PutFactorialElements( cnDenom
, 0.0, N
- n
- 1.0, N
);
1943 OSL_ENSURE( fCNumLower
< n
+ 1.0, "ScHypGeomDist: wrong assertion" );
1944 lcl_PutFactorialElements( cnNumer
, N
- 2.0*n
, fCNumVarUpper
, N
- n
);
1945 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1948 OSL_ENSURE( fCDenomUpper
<= N
- M
, "ScHypGeomDist: wrong assertion" );
1950 if ( fCDenomUpper
< n
- x
+ 1.0 )
1952 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1956 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1958 fCDenomUpper
= n
- x
;
1959 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1969 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
1970 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
1974 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
1975 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
1978 OSL_ENSURE( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
1980 if ( fCDenomUpper
< n
- x
+ 1.0 )
1982 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
1985 lcl_PutFactorialElements( cnNumer
, N
- M
- n
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
1986 fCDenomUpper
= n
- x
;
1987 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
1991 OSL_ENSURE( fCDenomUpper
<= M
, "ScHypGeomDist: wrong assertion" );
1995 if ( N
- M
< M
+ 1.0 )
1999 if ( N
- n
< M
+ 1.0 )
2002 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
2003 lcl_PutFactorialElements( cnDenom
, 0.0, N
- M
- 1.0, N
);
2007 lcl_PutFactorialElements( cnNumer
, N
- n
- M
, fCNumVarUpper
, N
- n
);
2008 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
2011 if ( n
- x
+ 1.0 > fCDenomUpper
)
2013 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
2017 lcl_PutFactorialElements( cnNumer
, 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
2019 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
2020 fCDenomUpper
= n
- x
;
2027 OSL_ENSURE( M
>= n
- x
, "ScHypGeomDist: wrong assertion" );
2028 OSL_ENSURE( M
- x
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
2030 if ( N
- n
< N
- M
+ 1.0 )
2033 lcl_PutFactorialElements( cnNumer
, 0.0, fCNumVarUpper
, N
- n
);
2034 lcl_PutFactorialElements( cnDenom
, 0.0, M
- 1.0, N
);
2039 OSL_ENSURE( fCNumLower
<= N
- M
+ 1.0, "ScHypGeomDist: wrong assertion" );
2040 lcl_PutFactorialElements( cnNumer
, M
- n
, fCNumVarUpper
, N
- n
);
2041 lcl_PutFactorialElements( cnDenom
, 0.0, n
- 1.0, N
);
2044 if ( n
- x
+ 1.0 > fCDenomUpper
)
2046 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- n
+ x
, N
- M
+ 1.0 );
2047 else if ( M
>= fCDenomUpper
)
2049 lcl_PutFactorialElements( cnNumer
, N
- 2.0*M
+ 1.0, N
- M
- fCDenomUpper
, N
- M
+ 1.0 );
2051 fCDenomUpper
= n
- x
;
2052 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
2056 OSL_ENSURE( M
<= fCDenomUpper
, "ScHypGeomDist: wrong assertion" );
2057 lcl_PutFactorialElements( cnDenom
, fCDenomVarLower
, N
- n
- 2.0*M
+ x
,
2058 N
- n
- M
+ x
+ 1.0 );
2060 fCDenomUpper
= n
- x
;
2061 fCDenomVarLower
= N
- M
- 2.0*(n
- x
) + 1.0;
2065 OSL_ENSURE( fCDenomUpper
<= n
, "ScHypGeomDist: wrong assertion" );
2067 fDNumVarLower
= 0.0;
2070 double nDNumVarUpper
= fCDenomUpper
< x
+ 1.0 ? n
- x
- 1.0 : n
- fCDenomUpper
- 1.0;
2071 double nDDenomVarLower
= fCDenomUpper
< x
+ 1.0 ? fCDenomVarLower
: N
- n
- M
+ 1.0;
2072 lcl_PutFactorialElements( cnNumer
, fDNumVarLower
, nDNumVarUpper
, n
);
2073 lcl_PutFactorialElements( cnDenom
, nDDenomVarLower
, N
- n
- M
+ x
, N
- n
- M
+ x
+ 1.0 );
2075 ::std::sort( cnNumer
.begin(), cnNumer
.end() );
2076 ::std::sort( cnDenom
.begin(), cnDenom
.end() );
2077 auto it1
= cnNumer
.rbegin(), it1End
= cnNumer
.rend();
2078 auto it2
= cnDenom
.rbegin(), it2End
= cnDenom
.rend();
2080 double fFactor
= 1.0;
2081 for ( ; it1
!= it1End
|| it2
!= it2End
; )
2083 double fEnum
= 1.0, fDenom
= 1.0;
2084 if ( it1
!= it1End
)
2086 if ( it2
!= it2End
)
2088 fFactor
*= fEnum
/ fDenom
;
2094 void ScInterpreter::ScGammaDist( bool bODFF
)
2096 sal_uInt8 nMinParamCount
= ( bODFF
? 3 : 4 );
2097 sal_uInt8 nParamCount
= GetByte();
2098 if ( !MustHaveParamCount( nParamCount
, nMinParamCount
, 4 ) )
2101 if (nParamCount
== 4)
2102 bCumulative
= GetBool();
2105 double fBeta
= GetDouble(); // scale
2106 double fAlpha
= GetDouble(); // shape
2107 double fX
= GetDouble(); // x
2108 if ((!bODFF
&& fX
< 0) || fAlpha
<= 0.0 || fBeta
<= 0.0)
2109 PushIllegalArgument();
2112 if (bCumulative
) // distribution
2113 PushDouble( GetGammaDist( fX
, fAlpha
, fBeta
));
2115 PushDouble( GetGammaDistPDF( fX
, fAlpha
, fBeta
));
2119 void ScInterpreter::ScNormInv()
2121 if ( MustHaveParamCount( GetByte(), 3 ) )
2123 double sigma
= GetDouble();
2124 double mue
= GetDouble();
2125 double x
= GetDouble();
2126 if (sigma
<= 0.0 || x
< 0.0 || x
> 1.0)
2127 PushIllegalArgument();
2128 else if (x
== 0.0 || x
== 1.0)
2131 PushDouble(gaussinv(x
)*sigma
+ mue
);
2135 void ScInterpreter::ScSNormInv()
2137 double x
= GetDouble();
2138 if (x
< 0.0 || x
> 1.0)
2139 PushIllegalArgument();
2140 else if (x
== 0.0 || x
== 1.0)
2143 PushDouble(gaussinv(x
));
2146 void ScInterpreter::ScLogNormInv()
2148 sal_uInt8 nParamCount
= GetByte();
2149 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
2151 double fSigma
= ( nParamCount
== 3 ? GetDouble() : 1.0 ); // Stddev
2152 double fMue
= ( nParamCount
>= 2 ? GetDouble() : 0.0 ); // Mean
2153 double fP
= GetDouble(); // p
2154 if ( fSigma
<= 0.0 || fP
<= 0.0 || fP
>= 1.0 )
2155 PushIllegalArgument();
2157 PushDouble( exp( fMue
+ fSigma
* gaussinv( fP
) ) );
2161 class ScGammaDistFunction
: public ScDistFunc
2163 ScInterpreter
& rInt
;
2164 double fp
, fAlpha
, fBeta
;
2167 ScGammaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2168 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2170 virtual ~ScGammaDistFunction() {}
2172 double GetValue( double x
) const override
{ return fp
- rInt
.GetGammaDist(x
, fAlpha
, fBeta
); }
2175 void ScInterpreter::ScGammaInv()
2177 if ( !MustHaveParamCount( GetByte(), 3 ) )
2179 double fBeta
= GetDouble();
2180 double fAlpha
= GetDouble();
2181 double fP
= GetDouble();
2182 if (fAlpha
<= 0.0 || fBeta
<= 0.0 || fP
< 0.0 || fP
>= 1.0 )
2184 PushIllegalArgument();
2192 ScGammaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2193 double fStart
= fAlpha
* fBeta
;
2194 double fVal
= lcl_IterateInverse( aFunc
, fStart
*0.5, fStart
, bConvError
);
2196 SetError(FormulaError::NoConvergence
);
2201 class ScBetaDistFunction
: public ScDistFunc
2203 ScInterpreter
& rInt
;
2204 double fp
, fAlpha
, fBeta
;
2207 ScBetaDistFunction( ScInterpreter
& rI
, double fpVal
, double fAlphaVal
, double fBetaVal
) :
2208 rInt(rI
), fp(fpVal
), fAlpha(fAlphaVal
), fBeta(fBetaVal
) {}
2210 virtual ~ScBetaDistFunction() {}
2212 double GetValue( double x
) const override
{ return fp
- rInt
.GetBetaDist(x
, fAlpha
, fBeta
); }
2215 void ScInterpreter::ScBetaInv()
2217 sal_uInt8 nParamCount
= GetByte();
2218 if ( !MustHaveParamCount( nParamCount
, 3, 5 ) )
2220 double fP
, fA
, fB
, fAlpha
, fBeta
;
2221 if (nParamCount
== 5)
2225 if (nParamCount
>= 4)
2229 fBeta
= GetDouble();
2230 fAlpha
= GetDouble();
2232 if (fP
< 0.0 || fP
> 1.0 || fA
>= fB
|| fAlpha
<= 0.0 || fBeta
<= 0.0)
2234 PushIllegalArgument();
2239 ScBetaDistFunction
aFunc( *this, fP
, fAlpha
, fBeta
);
2240 // 0..1 as range for iteration so it isn't extended beyond the valid range
2241 double fVal
= lcl_IterateInverse( aFunc
, 0.0, 1.0, bConvError
);
2243 PushError( FormulaError::NoConvergence
);
2245 PushDouble(fA
+ fVal
*(fB
-fA
)); // scale to (A,B)
2248 // Note: T, F, and Chi are
2249 // monotonically decreasing,
2250 // therefore 1-Dist as function
2252 class ScTDistFunction
: public ScDistFunc
2254 ScInterpreter
& rInt
;
2259 ScTDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
, int nType
) :
2260 rInt( rI
), fp( fpVal
), fDF( fDFVal
), nT( nType
) {}
2262 virtual ~ScTDistFunction() {}
2264 double GetValue( double x
) const override
{ return fp
- rInt
.GetTDist( x
, fDF
, nT
); }
2267 void ScInterpreter::ScTInv( int nType
)
2269 if ( !MustHaveParamCount( GetByte(), 2 ) )
2271 double fDF
= ::rtl::math::approxFloor(GetDouble());
2272 double fP
= GetDouble();
2273 if (fDF
< 1.0 || fP
<= 0.0 || fP
> 1.0 )
2275 PushIllegalArgument();
2278 if ( nType
== 4 ) // left-tailed cumulative t-distribution
2281 PushIllegalArgument();
2282 else if ( fP
< 0.5 )
2283 PushDouble( -GetTInv( 1 - fP
, fDF
, nType
) );
2285 PushDouble( GetTInv( fP
, fDF
, nType
) );
2288 PushDouble( GetTInv( fP
, fDF
, nType
) );
2291 double ScInterpreter::GetTInv( double fAlpha
, double fSize
, int nType
)
2294 ScTDistFunction
aFunc( *this, fAlpha
, fSize
, nType
);
2295 double fVal
= lcl_IterateInverse( aFunc
, fSize
* 0.5, fSize
, bConvError
);
2297 SetError(FormulaError::NoConvergence
);
2301 class ScFDistFunction
: public ScDistFunc
2303 ScInterpreter
& rInt
;
2304 double fp
, fF1
, fF2
;
2307 ScFDistFunction( ScInterpreter
& rI
, double fpVal
, double fF1Val
, double fF2Val
) :
2308 rInt(rI
), fp(fpVal
), fF1(fF1Val
), fF2(fF2Val
) {}
2310 virtual ~ScFDistFunction() {}
2312 double GetValue( double x
) const override
{ return fp
- rInt
.GetFDist(x
, fF1
, fF2
); }
2315 void ScInterpreter::ScFInv()
2317 if ( !MustHaveParamCount( GetByte(), 3 ) )
2319 double fF2
= ::rtl::math::approxFloor(GetDouble());
2320 double fF1
= ::rtl::math::approxFloor(GetDouble());
2321 double fP
= GetDouble();
2322 if (fP
<= 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
|| fP
> 1.0)
2324 PushIllegalArgument();
2329 ScFDistFunction
aFunc( *this, fP
, fF1
, fF2
);
2330 double fVal
= lcl_IterateInverse( aFunc
, fF1
*0.5, fF1
, bConvError
);
2332 SetError(FormulaError::NoConvergence
);
2336 void ScInterpreter::ScFInv_LT()
2338 if ( !MustHaveParamCount( GetByte(), 3 ) )
2340 double fF2
= ::rtl::math::approxFloor(GetDouble());
2341 double fF1
= ::rtl::math::approxFloor(GetDouble());
2342 double fP
= GetDouble();
2343 if (fP
<= 0.0 || fF1
< 1.0 || fF2
< 1.0 || fF1
>= 1.0E10
|| fF2
>= 1.0E10
|| fP
> 1.0)
2345 PushIllegalArgument();
2350 ScFDistFunction
aFunc( *this, ( 1.0 - fP
), fF1
, fF2
);
2351 double fVal
= lcl_IterateInverse( aFunc
, fF1
*0.5, fF1
, bConvError
);
2353 SetError(FormulaError::NoConvergence
);
2357 class ScChiDistFunction
: public ScDistFunc
2359 ScInterpreter
& rInt
;
2363 ScChiDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2364 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2366 virtual ~ScChiDistFunction() {}
2368 double GetValue( double x
) const override
{ return fp
- rInt
.GetChiDist(x
, fDF
); }
2371 void ScInterpreter::ScChiInv()
2373 if ( !MustHaveParamCount( GetByte(), 2 ) )
2375 double fDF
= ::rtl::math::approxFloor(GetDouble());
2376 double fP
= GetDouble();
2377 if (fDF
< 1.0 || fP
<= 0.0 || fP
> 1.0 )
2379 PushIllegalArgument();
2384 ScChiDistFunction
aFunc( *this, fP
, fDF
);
2385 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2387 SetError(FormulaError::NoConvergence
);
2391 /***********************************************/
2392 class ScChiSqDistFunction
: public ScDistFunc
2394 ScInterpreter
& rInt
;
2398 ScChiSqDistFunction( ScInterpreter
& rI
, double fpVal
, double fDFVal
) :
2399 rInt(rI
), fp(fpVal
), fDF(fDFVal
) {}
2401 virtual ~ScChiSqDistFunction() {}
2403 double GetValue( double x
) const override
{ return fp
- rInt
.GetChiSqDistCDF(x
, fDF
); }
2406 void ScInterpreter::ScChiSqInv()
2408 if ( !MustHaveParamCount( GetByte(), 2 ) )
2410 double fDF
= ::rtl::math::approxFloor(GetDouble());
2411 double fP
= GetDouble();
2412 if (fDF
< 1.0 || fP
< 0.0 || fP
>= 1.0 )
2414 PushIllegalArgument();
2419 ScChiSqDistFunction
aFunc( *this, fP
, fDF
);
2420 double fVal
= lcl_IterateInverse( aFunc
, fDF
*0.5, fDF
, bConvError
);
2422 SetError(FormulaError::NoConvergence
);
2426 void ScInterpreter::ScConfidence()
2428 if ( MustHaveParamCount( GetByte(), 3 ) )
2430 double n
= ::rtl::math::approxFloor(GetDouble());
2431 double sigma
= GetDouble();
2432 double alpha
= GetDouble();
2433 if (sigma
<= 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || n
< 1.0)
2434 PushIllegalArgument();
2436 PushDouble( gaussinv(1.0-alpha
/2.0) * sigma
/sqrt(n
) );
2440 void ScInterpreter::ScConfidenceT()
2442 if ( MustHaveParamCount( GetByte(), 3 ) )
2444 double n
= ::rtl::math::approxFloor(GetDouble());
2445 double sigma
= GetDouble();
2446 double alpha
= GetDouble();
2447 if (sigma
<= 0.0 || alpha
<= 0.0 || alpha
>= 1.0 || n
< 1.0)
2448 PushIllegalArgument();
2449 else if (n
== 1.0) // for interoperability with Excel
2450 PushError(FormulaError::DivisionByZero
);
2452 PushDouble( sigma
* GetTInv( alpha
, n
- 1, 2 ) / sqrt( n
) );
2456 void ScInterpreter::ScZTest()
2458 sal_uInt8 nParamCount
= GetByte();
2459 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
2461 double sigma
= 0.0, x
;
2462 if (nParamCount
== 3)
2464 sigma
= GetDouble();
2467 PushIllegalArgument();
2473 KahanSum fSum
= 0.0;
2474 KahanSum fSumSqr
= 0.0;
2476 double rValCount
= 0.0;
2477 switch (GetStackType())
2483 fSumSqr
+= fVal
*fVal
;
2490 PopSingleRef( aAdr
);
2491 ScRefCellValue
aCell(mrDoc
, aAdr
);
2492 if (aCell
.hasNumeric())
2494 fVal
= GetCellValue(aAdr
, aCell
);
2496 fSumSqr
+= fVal
*fVal
;
2505 size_t nRefInList
= 0;
2506 while (nParam
-- > 0)
2509 FormulaError nErr
= FormulaError::NONE
;
2510 PopDoubleRef( aRange
, nParam
, nRefInList
);
2511 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
2512 if (aValIter
.GetFirst(fVal
, nErr
))
2515 fSumSqr
+= fVal
*fVal
;
2517 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(fVal
, nErr
))
2520 fSumSqr
+= fVal
*fVal
;
2529 case svExternalSingleRef
:
2530 case svExternalDoubleRef
:
2532 ScMatrixRef pMat
= GetMatrix();
2535 SCSIZE nCount
= pMat
->GetElementCount();
2536 if (pMat
->IsNumeric())
2538 for ( SCSIZE i
= 0; i
< nCount
; i
++ )
2540 fVal
= pMat
->GetDouble(i
);
2542 fSumSqr
+= fVal
* fVal
;
2548 for (SCSIZE i
= 0; i
< nCount
; i
++)
2549 if (!pMat
->IsStringOrEmpty(i
))
2551 fVal
= pMat
->GetDouble(i
);
2553 fSumSqr
+= fVal
* fVal
;
2560 default : SetError(FormulaError::IllegalParameter
); break;
2562 if (rValCount
<= 1.0)
2563 PushError( FormulaError::DivisionByZero
);
2566 double mue
= fSum
.get()/rValCount
;
2568 if (nParamCount
!= 3)
2570 sigma
= (fSumSqr
- fSum
*fSum
/rValCount
).get()/(rValCount
-1.0);
2573 PushError(FormulaError::DivisionByZero
);
2576 PushDouble(0.5 - gauss((mue
-x
)/sqrt(sigma
/rValCount
)));
2579 PushDouble(0.5 - gauss((mue
-x
)*sqrt(rValCount
)/sigma
));
2583 bool ScInterpreter::CalculateTest(bool _bTemplin
2584 ,const SCSIZE nC1
, const SCSIZE nC2
,const SCSIZE nR1
,const SCSIZE nR2
2585 ,const ScMatrixRef
& pMat1
,const ScMatrixRef
& pMat2
2586 ,double& fT
,double& fF
)
2588 double fCount1
= 0.0;
2589 double fCount2
= 0.0;
2590 KahanSum fSum1
= 0.0;
2591 KahanSum fSumSqr1
= 0.0;
2592 KahanSum fSum2
= 0.0;
2593 KahanSum fSumSqr2
= 0.0;
2596 for (i
= 0; i
< nC1
; i
++)
2597 for (j
= 0; j
< nR1
; j
++)
2599 if (!pMat1
->IsStringOrEmpty(i
,j
))
2601 fVal
= pMat1
->GetDouble(i
,j
);
2603 fSumSqr1
+= fVal
* fVal
;
2607 for (i
= 0; i
< nC2
; i
++)
2608 for (j
= 0; j
< nR2
; j
++)
2610 if (!pMat2
->IsStringOrEmpty(i
,j
))
2612 fVal
= pMat2
->GetDouble(i
,j
);
2614 fSumSqr2
+= fVal
* fVal
;
2618 if (fCount1
< 2.0 || fCount2
< 2.0)
2622 } // if (fCount1 < 2.0 || fCount2 < 2.0)
2625 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
).get() / (fCount1
-1.0) / fCount1
;
2626 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
).get() / (fCount2
-1.0) / fCount2
;
2627 if (fS1
+ fS2
== 0.0)
2632 fT
= std::abs(( fSum1
/fCount1
- fSum2
/fCount2
).get())/sqrt(fS1
+fS2
);
2633 double c
= fS1
/(fS1
+fS2
);
2634 // GetTDist is calculated via GetBetaDist and also works with non-integral
2635 // degrees of freedom. The result matches Excel
2636 fF
= 1.0/(c
*c
/(fCount1
-1.0)+(1.0-c
)*(1.0-c
)/(fCount2
-1.0));
2640 // according to Bronstein-Semendjajew
2641 double fS1
= (fSumSqr1
- fSum1
*fSum1
/fCount1
).get() / (fCount1
- 1.0); // Variance
2642 double fS2
= (fSumSqr2
- fSum2
*fSum2
/fCount2
).get() / (fCount2
- 1.0);
2643 fT
= std::abs( fSum1
.get()/fCount1
- fSum2
.get()/fCount2
) /
2644 sqrt( (fCount1
-1.0)*fS1
+ (fCount2
-1.0)*fS2
) *
2645 sqrt( fCount1
*fCount2
*(fCount1
+fCount2
-2)/(fCount1
+fCount2
) );
2646 fF
= fCount1
+ fCount2
- 2;
2650 void ScInterpreter::ScTTest()
2652 if ( !MustHaveParamCount( GetByte(), 4 ) )
2654 double fTyp
= ::rtl::math::approxFloor(GetDouble());
2655 double fTails
= ::rtl::math::approxFloor(GetDouble());
2656 if (fTails
!= 1.0 && fTails
!= 2.0)
2658 PushIllegalArgument();
2662 ScMatrixRef pMat2
= GetMatrix();
2663 ScMatrixRef pMat1
= GetMatrix();
2664 if (!pMat1
|| !pMat2
)
2666 PushIllegalParameter();
2673 pMat1
->GetDimensions(nC1
, nR1
);
2674 pMat2
->GetDimensions(nC2
, nR2
);
2677 if (nC1
!= nC2
|| nR1
!= nR2
)
2679 PushIllegalArgument();
2682 double fCount
= 0.0;
2683 KahanSum fSum1
= 0.0;
2684 KahanSum fSum2
= 0.0;
2685 KahanSum fSumSqrD
= 0.0;
2686 double fVal1
, fVal2
;
2687 for (i
= 0; i
< nC1
; i
++)
2688 for (j
= 0; j
< nR1
; j
++)
2690 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
2692 fVal1
= pMat1
->GetDouble(i
,j
);
2693 fVal2
= pMat2
->GetDouble(i
,j
);
2696 fSumSqrD
+= (fVal1
- fVal2
)*(fVal1
- fVal2
);
2705 KahanSum fSumD
= fSum1
- fSum2
;
2706 double fDivider
= ( fSumSqrD
*fCount
- fSumD
*fSumD
).get();
2707 if ( fDivider
== 0.0 )
2709 PushError(FormulaError::DivisionByZero
);
2712 fT
= std::abs(fSumD
.get()) * sqrt((fCount
-1.0) / fDivider
);
2715 else if (fTyp
== 2.0)
2717 if (!CalculateTest(false,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
))
2718 return; // error was pushed
2720 else if (fTyp
== 3.0)
2722 if (!CalculateTest(true,nC1
, nC2
,nR1
, nR2
,pMat1
,pMat2
,fT
,fF
))
2723 return; // error was pushed
2727 PushIllegalArgument();
2730 PushDouble( GetTDist( fT
, fF
, static_cast<int>(fTails
) ) );
2733 void ScInterpreter::ScFTest()
2735 if ( !MustHaveParamCount( GetByte(), 2 ) )
2737 ScMatrixRef pMat2
= GetMatrix();
2738 ScMatrixRef pMat1
= GetMatrix();
2739 if (!pMat1
|| !pMat2
)
2741 PushIllegalParameter();
2745 auto aVal1
= pMat1
->CollectKahan(sc::op::kOpSumAndSumSquare
);
2746 auto aVal2
= pMat2
->CollectKahan(sc::op::kOpSumAndSumSquare
);
2747 double fCount1
= aVal1
.mnCount
;
2748 double fCount2
= aVal2
.mnCount
;
2749 KahanSum fSum1
= aVal1
.maAccumulator
[0];
2750 KahanSum fSumSqr1
= aVal1
.maAccumulator
[1];
2751 KahanSum fSum2
= aVal2
.maAccumulator
[0];
2752 KahanSum fSumSqr2
= aVal2
.maAccumulator
[1];
2754 if (fCount1
< 2.0 || fCount2
< 2.0)
2759 double fS1
= (fSumSqr1
-fSum1
*fSum1
/fCount1
).get() / (fCount1
-1.0);
2760 double fS2
= (fSumSqr2
-fSum2
*fSum2
/fCount2
).get() / (fCount2
-1.0);
2761 if (fS1
== 0.0 || fS2
== 0.0)
2766 double fF
, fF1
, fF2
;
2779 double fFcdf
= GetFDist(fF
, fF1
, fF2
);
2780 PushDouble(2.0*std::min(fFcdf
, 1.0 - fFcdf
));
2783 void ScInterpreter::ScChiTest()
2785 if ( !MustHaveParamCount( GetByte(), 2 ) )
2787 ScMatrixRef pMat2
= GetMatrix();
2788 ScMatrixRef pMat1
= GetMatrix();
2789 if (!pMat1
|| !pMat2
)
2791 PushIllegalParameter();
2796 pMat1
->GetDimensions(nC1
, nR1
);
2797 pMat2
->GetDimensions(nC2
, nR2
);
2798 if (nR1
!= nR2
|| nC1
!= nC2
)
2800 PushIllegalArgument();
2803 KahanSum fChi
= 0.0;
2805 for (SCSIZE i
= 0; i
< nC1
; i
++)
2807 for (SCSIZE j
= 0; j
< nR1
; j
++)
2809 if (!(pMat1
->IsEmpty(i
,j
) || pMat2
->IsEmpty(i
,j
)))
2812 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
2814 double fValX
= pMat1
->GetDouble(i
,j
);
2815 double fValE
= pMat2
->GetDouble(i
,j
);
2818 PushError(FormulaError::DivisionByZero
);
2821 // These fTemp values guard against a failure when compiled
2822 // with optimization (using g++ 4.8.2 on tinderbox 71-TDF),
2823 // where ((fValX - fValE) * (fValX - fValE)) with
2824 // fValE==1e+308 should had produced Infinity but did
2825 // not, instead the result of divide() then was 1e+308.
2826 volatile double fTemp1
= (fValX
- fValE
) * (fValX
- fValE
);
2827 double fTemp2
= fTemp1
;
2828 if (std::isinf(fTemp2
))
2830 PushError(FormulaError::NoConvergence
);
2833 fChi
+= sc::divide( fTemp2
, fValE
);
2837 PushIllegalArgument();
2845 // not in ODFF1.2, but for interoperability with Excel
2846 PushIllegalArgument();
2850 if (nC1
== 1 || nR1
== 1)
2852 fDF
= static_cast<double>(nC1
*nR1
- 1);
2860 fDF
= static_cast<double>(nC1
-1)*static_cast<double>(nR1
-1);
2861 PushDouble(GetChiDist(fChi
.get(), fDF
));
2864 void ScInterpreter::ScKurt()
2868 std::vector
<double> values
;
2869 if ( !CalculateSkew(fSum
, fCount
, values
) )
2872 // ODF 1.2 constraints: # of numbers >= 4
2875 // for interoperability with Excel
2876 PushError( FormulaError::DivisionByZero
);
2881 double fMean
= fSum
.get() / fCount
;
2882 for (double v
: values
)
2883 vSum
+= (v
- fMean
) * (v
- fMean
);
2885 double fStdDev
= sqrt(vSum
.get() / (fCount
- 1.0));
2888 PushError( FormulaError::DivisionByZero
);
2892 KahanSum xpower4
= 0.0;
2893 for (double v
: values
)
2895 double dx
= (v
- fMean
) / fStdDev
;
2896 xpower4
+= (dx
* dx
) * (dx
* dx
);
2899 double k_d
= (fCount
- 2.0) * (fCount
- 3.0);
2900 double k_l
= fCount
* (fCount
+ 1.0) / ((fCount
- 1.0) * k_d
);
2901 double k_t
= 3.0 * (fCount
- 1.0) * (fCount
- 1.0) / k_d
;
2903 PushDouble(xpower4
.get() * k_l
- k_t
);
2906 void ScInterpreter::ScHarMean()
2908 short nParamCount
= GetByte();
2909 KahanSum nVal
= 0.0;
2910 double nValCount
= 0.0;
2913 size_t nRefInList
= 0;
2914 while ((nGlobalError
== FormulaError::NONE
) && (nParamCount
-- > 0))
2916 switch (GetStackType())
2920 double x
= GetDouble();
2927 SetError( FormulaError::IllegalArgument
);
2932 PopSingleRef( aAdr
);
2933 ScRefCellValue
aCell(mrDoc
, aAdr
);
2934 if (aCell
.hasNumeric())
2936 double x
= GetCellValue(aAdr
, aCell
);
2943 SetError( FormulaError::IllegalArgument
);
2950 FormulaError nErr
= FormulaError::NONE
;
2951 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2953 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
2954 if (aValIter
.GetFirst(nCellVal
, nErr
))
2958 nVal
+= 1.0/nCellVal
;
2962 SetError( FormulaError::IllegalArgument
);
2964 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(nCellVal
, nErr
))
2968 nVal
+= 1.0/nCellVal
;
2972 SetError( FormulaError::IllegalArgument
);
2979 case svExternalSingleRef
:
2980 case svExternalDoubleRef
:
2982 ScMatrixRef pMat
= GetMatrix();
2985 SCSIZE nCount
= pMat
->GetElementCount();
2986 if (pMat
->IsNumeric())
2988 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
2990 double x
= pMat
->GetDouble(nElem
);
2997 SetError( FormulaError::IllegalArgument
);
3002 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3003 if (!pMat
->IsStringOrEmpty(nElem
))
3005 double x
= pMat
->GetDouble(nElem
);
3012 SetError( FormulaError::IllegalArgument
);
3018 default : SetError(FormulaError::IllegalParameter
); break;
3021 if (nGlobalError
== FormulaError::NONE
)
3022 PushDouble( nValCount
/ nVal
.get() );
3024 PushError( nGlobalError
);
3027 void ScInterpreter::ScGeoMean()
3029 short nParamCount
= GetByte();
3030 KahanSum nVal
= 0.0;
3031 double nValCount
= 0.0;
3035 size_t nRefInList
= 0;
3036 while ((nGlobalError
== FormulaError::NONE
) && (nParamCount
-- > 0))
3038 switch (GetStackType())
3042 double x
= GetDouble();
3048 else if ( x
== 0.0 )
3050 // value of 0 means that function result will be 0
3051 while ( nParamCount
-- > 0 )
3057 SetError( FormulaError::IllegalArgument
);
3062 PopSingleRef( aAdr
);
3063 ScRefCellValue
aCell(mrDoc
, aAdr
);
3064 if (aCell
.hasNumeric())
3066 double x
= GetCellValue(aAdr
, aCell
);
3072 else if ( x
== 0.0 )
3074 // value of 0 means that function result will be 0
3075 while ( nParamCount
-- > 0 )
3081 SetError( FormulaError::IllegalArgument
);
3088 FormulaError nErr
= FormulaError::NONE
;
3089 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3091 ScValueIterator
aValIter(mrContext
, aRange
, mnSubTotalFlags
);
3092 if (aValIter
.GetFirst(nCellVal
, nErr
))
3096 nVal
+= log(nCellVal
);
3099 else if ( nCellVal
== 0.0 )
3101 // value of 0 means that function result will be 0
3102 while ( nParamCount
-- > 0 )
3108 SetError( FormulaError::IllegalArgument
);
3110 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(nCellVal
, nErr
))
3114 nVal
+= log(nCellVal
);
3117 else if ( nCellVal
== 0.0 )
3119 // value of 0 means that function result will be 0
3120 while ( nParamCount
-- > 0 )
3126 SetError( FormulaError::IllegalArgument
);
3133 case svExternalSingleRef
:
3134 case svExternalDoubleRef
:
3136 ScMatrixRef pMat
= GetMatrix();
3139 SCSIZE nCount
= pMat
->GetElementCount();
3140 if (pMat
->IsNumeric())
3142 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
3144 double x
= pMat
->GetDouble(ui
);
3150 else if ( x
== 0.0 )
3152 // value of 0 means that function result will be 0
3153 while ( nParamCount
-- > 0 )
3159 SetError( FormulaError::IllegalArgument
);
3164 for (SCSIZE ui
= 0; ui
< nCount
; ui
++)
3166 if (!pMat
->IsStringOrEmpty(ui
))
3168 double x
= pMat
->GetDouble(ui
);
3174 else if ( x
== 0.0 )
3176 // value of 0 means that function result will be 0
3177 while ( nParamCount
-- > 0 )
3183 SetError( FormulaError::IllegalArgument
);
3190 default : SetError(FormulaError::IllegalParameter
); break;
3193 if (nGlobalError
== FormulaError::NONE
)
3194 PushDouble(exp(nVal
.get() / nValCount
));
3196 PushError( nGlobalError
);
3199 void ScInterpreter::ScStandard()
3201 if ( MustHaveParamCount( GetByte(), 3 ) )
3203 double sigma
= GetDouble();
3204 double mue
= GetDouble();
3205 double x
= GetDouble();
3207 PushError( FormulaError::IllegalArgument
);
3208 else if (sigma
== 0.0)
3209 PushError( FormulaError::DivisionByZero
);
3211 PushDouble((x
-mue
)/sigma
);
3214 bool ScInterpreter::CalculateSkew(KahanSum
& fSum
, double& fCount
, std::vector
<double>& values
)
3216 short nParamCount
= GetByte();
3217 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3225 size_t nRefInList
= 0;
3226 while (nParamCount
-- > 0)
3228 switch (GetStackType())
3234 values
.push_back(fVal
);
3240 PopSingleRef( aAdr
);
3241 ScRefCellValue
aCell(mrDoc
, aAdr
);
3242 if (aCell
.hasNumeric())
3244 fVal
= GetCellValue(aAdr
, aCell
);
3246 values
.push_back(fVal
);
3254 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3255 FormulaError nErr
= FormulaError::NONE
;
3256 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
3257 if (aValIter
.GetFirst(fVal
, nErr
))
3260 values
.push_back(fVal
);
3263 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(fVal
, nErr
))
3266 values
.push_back(fVal
);
3274 case svExternalSingleRef
:
3275 case svExternalDoubleRef
:
3277 ScMatrixRef pMat
= GetMatrix();
3280 SCSIZE nCount
= pMat
->GetElementCount();
3281 if (pMat
->IsNumeric())
3283 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3285 fVal
= pMat
->GetDouble(nElem
);
3287 values
.push_back(fVal
);
3293 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
3294 if (!pMat
->IsStringOrEmpty(nElem
))
3296 fVal
= pMat
->GetDouble(nElem
);
3298 values
.push_back(fVal
);
3306 SetError(FormulaError::IllegalParameter
);
3311 if (nGlobalError
!= FormulaError::NONE
)
3313 PushError( nGlobalError
);
3315 } // if (nGlobalError != FormulaError::NONE)
3319 void ScInterpreter::CalculateSkewOrSkewp( bool bSkewp
)
3323 std::vector
<double> values
;
3324 if (!CalculateSkew( fSum
, fCount
, values
))
3326 // SKEW/SKEWP's constraints: they require at least three numbers
3329 // for interoperability with Excel
3330 PushError(FormulaError::DivisionByZero
);
3335 double fMean
= fSum
.get() / fCount
;
3336 for (double v
: values
)
3337 vSum
+= (v
- fMean
) * (v
- fMean
);
3339 double fStdDev
= sqrt( vSum
.get() / (bSkewp
? fCount
: (fCount
- 1.0)));
3342 PushIllegalArgument();
3346 KahanSum xcube
= 0.0;
3347 for (double v
: values
)
3349 double dx
= (v
- fMean
) / fStdDev
;
3350 xcube
+= dx
* dx
* dx
;
3354 PushDouble( xcube
.get() / fCount
);
3356 PushDouble( ((xcube
.get() * fCount
) / (fCount
- 1.0)) / (fCount
- 2.0) );
3359 void ScInterpreter::ScSkew()
3361 CalculateSkewOrSkewp( false );
3364 void ScInterpreter::ScSkewp()
3366 CalculateSkewOrSkewp( true );
3369 double ScInterpreter::GetMedian( vector
<double> & rArray
)
3371 size_t nSize
= rArray
.size();
3372 if (nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3374 SetError( FormulaError::NoValue
);
3379 size_t nMid
= nSize
/ 2;
3380 vector
<double>::iterator iMid
= rArray
.begin() + nMid
;
3381 ::std::nth_element( rArray
.begin(), iMid
, rArray
.end());
3383 return *iMid
; // Lower and upper median are equal.
3388 iMid
= ::std::max_element( rArray
.begin(), rArray
.begin() + nMid
);
3389 return (fUp
+ *iMid
) / 2;
3393 void ScInterpreter::ScMedian()
3395 sal_uInt8 nParamCount
= GetByte();
3396 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3398 vector
<double> aArray
;
3399 GetNumberSequenceArray( nParamCount
, aArray
, false );
3400 PushDouble( GetMedian( aArray
));
3403 double ScInterpreter::GetPercentile( vector
<double> & rArray
, double fPercentile
)
3405 size_t nSize
= rArray
.size();
3410 size_t nIndex
= static_cast<size_t>(::rtl::math::approxFloor( fPercentile
* (nSize
-1)));
3411 double fDiff
= fPercentile
* (nSize
-1) - ::rtl::math::approxFloor( fPercentile
* (nSize
-1));
3412 OSL_ENSURE(nIndex
< nSize
, "GetPercentile: wrong index(1)");
3413 vector
<double>::iterator iter
= rArray
.begin() + nIndex
;
3414 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3417 // Note: neg fDiff seen with forum-mso-en4-719754.xlsx with
3418 // fPercentile of near 1 where approxFloor gave nIndex of nSize-1
3419 // resulting in a non-zero tiny negative fDiff.
3424 OSL_ENSURE(nIndex
< nSize
-1, "GetPercentile: wrong index(2)");
3425 double fVal
= *iter
;
3426 iter
= ::std::min_element( rArray
.begin() + nIndex
+ 1, rArray
.end());
3427 return fVal
+ fDiff
* (*iter
- fVal
);
3432 double ScInterpreter::GetPercentileExclusive( vector
<double> & rArray
, double fPercentile
)
3434 size_t nSize1
= rArray
.size() + 1;
3435 if ( rArray
.empty() || nSize1
== 1 || nGlobalError
!= FormulaError::NONE
)
3437 SetError( FormulaError::NoValue
);
3440 if ( fPercentile
* nSize1
< 1.0 || fPercentile
* nSize1
> static_cast<double>( nSize1
- 1 ) )
3442 SetError( FormulaError::IllegalParameter
);
3446 size_t nIndex
= static_cast<size_t>(::rtl::math::approxFloor( fPercentile
* nSize1
- 1 ));
3447 double fDiff
= fPercentile
* nSize1
- 1 - ::rtl::math::approxFloor( fPercentile
* nSize1
- 1 );
3448 OSL_ENSURE(nIndex
< ( nSize1
- 1 ), "GetPercentile: wrong index(1)");
3449 vector
<double>::iterator iter
= rArray
.begin() + nIndex
;
3450 ::std::nth_element( rArray
.begin(), iter
, rArray
.end());
3455 OSL_ENSURE(nIndex
< nSize1
, "GetPercentile: wrong index(2)");
3456 double fVal
= *iter
;
3457 iter
= ::std::min_element( rArray
.begin() + nIndex
+ 1, rArray
.end());
3458 return fVal
+ fDiff
* (*iter
- fVal
);
3462 void ScInterpreter::ScPercentile( bool bInclusive
)
3464 if ( !MustHaveParamCount( GetByte(), 2 ) )
3466 double alpha
= GetDouble();
3467 if ( bInclusive
? ( alpha
< 0.0 || alpha
> 1.0 ) : ( alpha
<= 0.0 || alpha
>= 1.0 ) )
3469 PushIllegalArgument();
3472 vector
<double> aArray
;
3473 GetNumberSequenceArray( 1, aArray
, false );
3474 if ( aArray
.empty() || nGlobalError
!= FormulaError::NONE
)
3480 PushDouble( GetPercentile( aArray
, alpha
));
3482 PushDouble( GetPercentileExclusive( aArray
, alpha
));
3485 void ScInterpreter::ScQuartile( bool bInclusive
)
3487 if ( !MustHaveParamCount( GetByte(), 2 ) )
3489 double fFlag
= ::rtl::math::approxFloor(GetDouble());
3490 if ( bInclusive
? ( fFlag
< 0.0 || fFlag
> 4.0 ) : ( fFlag
<= 0.0 || fFlag
>= 4.0 ) )
3492 PushIllegalArgument();
3495 vector
<double> aArray
;
3496 GetNumberSequenceArray( 1, aArray
, false );
3497 if ( aArray
.empty() || nGlobalError
!= FormulaError::NONE
)
3503 PushDouble( fFlag
== 2.0 ? GetMedian( aArray
) : GetPercentile( aArray
, 0.25 * fFlag
) );
3505 PushDouble( fFlag
== 2.0 ? GetMedian( aArray
) : GetPercentileExclusive( aArray
, 0.25 * fFlag
) );
3508 void ScInterpreter::ScModalValue()
3510 sal_uInt8 nParamCount
= GetByte();
3511 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3513 vector
<double> aSortArray
;
3514 GetSortArray( nParamCount
, aSortArray
, nullptr, false, false );
3515 SCSIZE nSize
= aSortArray
.size();
3516 if (nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3520 SCSIZE nMaxIndex
= 0, nMax
= 1, nCount
= 1;
3521 double nOldVal
= aSortArray
[0];
3523 for ( i
= 1; i
< nSize
; i
++)
3525 if (aSortArray
[i
] == nOldVal
)
3529 nOldVal
= aSortArray
[i
];
3543 if (nMax
== 1 && nCount
== 1)
3546 PushDouble(nOldVal
);
3548 PushDouble(aSortArray
[nMaxIndex
]);
3552 void ScInterpreter::ScModalValue_MS( bool bSingle
)
3554 sal_uInt8 nParamCount
= GetByte();
3555 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
3557 vector
<double> aArray
;
3558 GetNumberSequenceArray( nParamCount
, aArray
, false );
3559 vector
< double > aSortArray( aArray
);
3560 QuickSort( aSortArray
, nullptr );
3561 SCSIZE nSize
= aSortArray
.size();
3562 if ( nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3566 SCSIZE nMax
= 1, nCount
= 1;
3567 double nOldVal
= aSortArray
[ 0 ];
3568 vector
< double > aResultArray( 1 );
3570 for ( i
= 1; i
< nSize
; i
++ )
3572 if ( aSortArray
[ i
] == nOldVal
)
3576 if ( nCount
>= nMax
&& nCount
> 1 )
3578 if ( nCount
> nMax
)
3581 if ( aResultArray
.size() != 1 )
3582 vector
< double >( 1 ).swap( aResultArray
);
3583 aResultArray
[ 0 ] = nOldVal
;
3586 aResultArray
.emplace_back( nOldVal
);
3588 nOldVal
= aSortArray
[ i
];
3592 if ( nCount
>= nMax
&& nCount
> 1 )
3594 if ( nCount
> nMax
)
3595 vector
< double >().swap( aResultArray
);
3596 aResultArray
.emplace_back( nOldVal
);
3598 if ( nMax
== 1 && nCount
== 1 )
3600 else if ( nMax
== 1 )
3601 PushDouble( nOldVal
); // there is only 1 result, no reordering needed
3604 // sort resultArray according to ordering of aArray
3605 vector
< vector
< double > > aOrder
;
3606 aOrder
.resize( aResultArray
.size(), vector
< double >( 2 ) );
3607 for ( i
= 0; i
< aResultArray
.size(); i
++ )
3609 for ( SCSIZE j
= 0; j
< nSize
; j
++ )
3611 if ( aArray
[ j
] == aResultArray
[ i
] )
3613 aOrder
[ i
][ 0 ] = aResultArray
[ i
];
3614 aOrder
[ i
][ 1 ] = j
;
3619 sort( aOrder
.begin(), aOrder
.end(), []( const std::vector
< double >& lhs
,
3620 const std::vector
< double >& rhs
)
3621 { return lhs
[ 1 ] < rhs
[ 1 ]; } );
3624 PushDouble( aOrder
[ 0 ][ 0 ] );
3627 // put result in correct order in aResultArray
3628 for ( i
= 0; i
< aResultArray
.size(); i
++ )
3629 aResultArray
[ i
] = aOrder
[ i
][ 0 ];
3630 ScMatrixRef pResMatrix
= GetNewMat( 1, aResultArray
.size(), true );
3631 pResMatrix
->PutDoubleVector( aResultArray
, 0, 0 );
3632 PushMatrix( pResMatrix
);
3638 void ScInterpreter::CalculateSmallLarge(bool bSmall
)
3640 if ( !MustHaveParamCount( GetByte(), 2 ) )
3643 SCSIZE nCol
= 0, nRow
= 0;
3644 const auto aArray
= GetRankNumberArray(nCol
, nRow
);
3645 const size_t nRankArraySize
= aArray
.size();
3646 if (nRankArraySize
== 0 || nGlobalError
!= FormulaError::NONE
)
3651 assert(nRankArraySize
== nCol
* nRow
);
3653 std::vector
<SCSIZE
> aRankArray
;
3654 aRankArray
.reserve(nRankArraySize
);
3655 std::transform(aArray
.begin(), aArray
.end(), std::back_inserter(aRankArray
),
3656 [bSmall
](double f
) {
3657 f
= (bSmall
? rtl::math::approxFloor(f
) : rtl::math::approxCeil(f
));
3658 // Valid ranks are >= 1.
3659 if (f
< 1.0 || !o3tl::convertsToAtMost(f
, std::numeric_limits
<SCSIZE
>::max()))
3660 return static_cast<SCSIZE
>(0);
3661 return static_cast<SCSIZE
>(f
);
3664 vector
<double> aSortArray
;
3665 GetNumberSequenceArray(1, aSortArray
, false );
3666 const SCSIZE nSize
= aSortArray
.size();
3667 if (nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3669 else if (nRankArraySize
== 1)
3671 const SCSIZE k
= aRankArray
[0];
3672 if (k
< 1 || nSize
< k
)
3674 if (!std::isfinite(aArray
[0]))
3675 PushDouble(aArray
[0]); // propagates error
3681 vector
<double>::iterator iPos
= aSortArray
.begin() + (bSmall
? k
-1 : nSize
-k
);
3682 ::std::nth_element( aSortArray
.begin(), iPos
, aSortArray
.end());
3688 std::set
<SCSIZE
> aIndices
;
3689 for (SCSIZE n
: aRankArray
)
3691 if (1 <= n
&& n
<= nSize
)
3692 aIndices
.insert(bSmall
? n
-1 : nSize
-n
);
3694 // We can spare sorting when the total number of ranks is small enough.
3695 // Find only the elements at given indices if, arbitrarily, the index size is
3696 // smaller than 1/3 of the haystack array's size; just sort it squarely, otherwise.
3697 if (aIndices
.size() < nSize
/3)
3699 auto itBegin
= aSortArray
.begin();
3700 for (SCSIZE i
: aIndices
)
3702 auto it
= aSortArray
.begin() + i
;
3703 std::nth_element(itBegin
, it
, aSortArray
.end());
3708 std::sort(aSortArray
.begin(), aSortArray
.end());
3710 std::vector
<double> aResultArray
;
3711 aResultArray
.reserve(nRankArraySize
);
3712 for (size_t i
= 0; i
< nRankArraySize
; ++i
)
3714 const SCSIZE n
= aRankArray
[i
];
3715 if (1 <= n
&& n
<= nSize
)
3716 aResultArray
.push_back( aSortArray
[bSmall
? n
-1 : nSize
-n
]);
3717 else if (!std::isfinite( aArray
[i
]))
3718 aResultArray
.push_back( aArray
[i
]); // propagate error
3720 aResultArray
.push_back( CreateDoubleError( FormulaError::IllegalArgument
));
3722 ScMatrixRef pResult
= GetNewMat(nCol
, nRow
, aResultArray
);
3723 PushMatrix(pResult
);
3727 void ScInterpreter::ScLarge()
3729 CalculateSmallLarge(false);
3732 void ScInterpreter::ScSmall()
3734 CalculateSmallLarge(true);
3737 void ScInterpreter::ScPercentrank( bool bInclusive
)
3739 sal_uInt8 nParamCount
= GetByte();
3740 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
3742 double fSignificance
= ( nParamCount
== 3 ? ::rtl::math::approxFloor( GetDouble() ) : 3.0 );
3743 if ( fSignificance
< 1.0 )
3745 PushIllegalArgument();
3748 double fNum
= GetDouble();
3749 vector
<double> aSortArray
;
3750 GetSortArray( 1, aSortArray
, nullptr, false, false );
3751 SCSIZE nSize
= aSortArray
.size();
3752 if ( nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3756 if ( fNum
< aSortArray
[ 0 ] || fNum
> aSortArray
[ nSize
- 1 ] )
3762 fRes
= 1.0; // fNum == aSortArray[ 0 ], see test above
3764 fRes
= GetPercentrank( aSortArray
, fNum
, bInclusive
);
3767 double fExp
= ::rtl::math::approxFloor( log10( fRes
) ) + 1.0 - fSignificance
;
3768 fRes
= ::rtl::math::round( fRes
* pow( 10, -fExp
) ) / pow( 10, -fExp
);
3775 double ScInterpreter::GetPercentrank( ::std::vector
<double> & rArray
, double fVal
, bool bInclusive
)
3777 SCSIZE nSize
= rArray
.size();
3779 if ( fVal
== rArray
[ 0 ] )
3784 fRes
= 1.0 / static_cast<double>( nSize
+ 1 );
3788 SCSIZE nOldCount
= 0;
3789 double fOldVal
= rArray
[ 0 ];
3791 for ( i
= 1; i
< nSize
&& rArray
[ i
] < fVal
; i
++ )
3793 if ( rArray
[ i
] != fOldVal
)
3796 fOldVal
= rArray
[ i
];
3799 if ( rArray
[ i
] != fOldVal
)
3801 if ( fVal
== rArray
[ i
] )
3804 fRes
= div( nOldCount
, nSize
- 1 );
3806 fRes
= static_cast<double>( i
+ 1 ) / static_cast<double>( nSize
+ 1 );
3810 // nOldCount is the count of smaller entries
3811 // fVal is between rArray[ nOldCount - 1 ] and rArray[ nOldCount ]
3812 // use linear interpolation to find a position between the entries
3813 if ( nOldCount
== 0 )
3815 OSL_FAIL( "should not happen" );
3820 double fFract
= ( fVal
- rArray
[ nOldCount
- 1 ] ) /
3821 ( rArray
[ nOldCount
] - rArray
[ nOldCount
- 1 ] );
3823 fRes
= div( static_cast<double>( nOldCount
- 1 ) + fFract
, nSize
- 1 );
3825 fRes
= ( static_cast<double>(nOldCount
) + fFract
) / static_cast<double>( nSize
+ 1 );
3832 void ScInterpreter::ScTrimMean()
3834 if ( !MustHaveParamCount( GetByte(), 2 ) )
3836 double alpha
= GetDouble();
3837 if (alpha
< 0.0 || alpha
>= 1.0)
3839 PushIllegalArgument();
3842 vector
<double> aSortArray
;
3843 GetSortArray( 1, aSortArray
, nullptr, false, false );
3844 SCSIZE nSize
= aSortArray
.size();
3845 if (nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
3849 sal_uLong nIndex
= static_cast<sal_uLong
>(::rtl::math::approxFloor(alpha
*static_cast<double>(nSize
)));
3850 if (nIndex
% 2 != 0)
3853 OSL_ENSURE(nIndex
< nSize
, "ScTrimMean: wrong index");
3854 KahanSum fSum
= 0.0;
3855 for (SCSIZE i
= nIndex
; i
< nSize
-nIndex
; i
++)
3856 fSum
+= aSortArray
[i
];
3857 PushDouble(fSum
.get()/static_cast<double>(nSize
-2*nIndex
));
3861 std::vector
<double> ScInterpreter::GetRankNumberArray( SCSIZE
& rCol
, SCSIZE
& rRow
)
3863 std::vector
<double> aArray
;
3864 switch (GetStackType())
3867 aArray
.push_back(PopDouble());
3874 ScRefCellValue
aCell(mrDoc
, aAdr
);
3875 if (aCell
.hasNumeric())
3877 aArray
.push_back(GetCellValue(aAdr
, aCell
));
3885 PopDoubleRef(aRange
, true);
3886 if (nGlobalError
!= FormulaError::NONE
)
3889 // give up unless the start and end are in the same sheet
3890 if (aRange
.aStart
.Tab() != aRange
.aEnd
.Tab())
3892 SetError(FormulaError::IllegalParameter
);
3896 // the range already is in order
3897 assert(aRange
.aStart
.Col() <= aRange
.aEnd
.Col());
3898 assert(aRange
.aStart
.Row() <= aRange
.aEnd
.Row());
3899 rCol
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
3900 rRow
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
3901 aArray
.reserve(rCol
* rRow
);
3903 FormulaError nErr
= FormulaError::NONE
;
3905 ScValueIterator
aValIter(mrContext
, aRange
, mnSubTotalFlags
);
3906 if (aValIter
.GetFirst(fCellVal
, nErr
))
3909 aArray
.push_back(fCellVal
);
3910 while (aValIter
.GetNext(fCellVal
, nErr
) && nErr
== FormulaError::NONE
);
3912 // Note that SMALL() and LARGE() rank parameters (2nd) have
3913 // ParamClass::Value, so in array mode this is never hit and
3914 // argument was converted to matrix instead, but for normal
3915 // evaluation any non-numeric value including empty cell will
3916 // result in error anyway, so just clear and propagate an existing
3917 // error here already.
3918 if (aArray
.size() != rCol
* rRow
)
3926 case svExternalSingleRef
:
3927 case svExternalDoubleRef
:
3929 ScMatrixRef pMat
= GetMatrix();
3933 const SCSIZE nCount
= pMat
->GetElementCount();
3934 aArray
.reserve(nCount
);
3935 // Do not propagate errors from matrix elements as global error.
3936 pMat
->SetErrorInterpreter(nullptr);
3937 if (pMat
->IsNumeric())
3939 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3940 aArray
.push_back(pMat
->GetDouble(i
));
3944 for (SCSIZE i
= 0; i
< nCount
; ++i
)
3946 if (pMat
->IsValue(i
))
3947 aArray
.push_back( pMat
->GetDouble(i
));
3949 aArray
.push_back( CreateDoubleError( FormulaError::NoValue
));
3952 pMat
->GetDimensions(rCol
, rRow
);
3957 SetError(FormulaError::IllegalParameter
);
3963 void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount
, vector
<double>& rArray
, bool bConvertTextInArray
)
3967 const bool bIgnoreErrVal
= bool(mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
);
3968 short nParam
= nParamCount
;
3969 size_t nRefInList
= 0;
3970 ReverseStack( nParamCount
);
3971 while (nParam
-- > 0)
3973 const StackVar eStackType
= GetStackType();
3977 rArray
.push_back( PopDouble());
3981 PopSingleRef( aAdr
);
3982 ScRefCellValue
aCell(mrDoc
, aAdr
);
3983 if (bIgnoreErrVal
&& aCell
.hasError())
3985 else if (aCell
.hasNumeric())
3986 rArray
.push_back(GetCellValue(aAdr
, aCell
));
3992 PopDoubleRef( aRange
, nParam
, nRefInList
);
3993 if (nGlobalError
!= FormulaError::NONE
)
3996 aRange
.PutInOrder();
3997 SCSIZE nCellCount
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
3998 nCellCount
*= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
3999 rArray
.reserve( rArray
.size() + nCellCount
);
4001 FormulaError nErr
= FormulaError::NONE
;
4003 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
4004 if (aValIter
.GetFirst( fCellVal
, nErr
))
4008 if (nErr
== FormulaError::NONE
)
4009 rArray
.push_back( fCellVal
);
4010 while (aValIter
.GetNext( fCellVal
, nErr
))
4012 if (nErr
== FormulaError::NONE
)
4013 rArray
.push_back( fCellVal
);
4018 rArray
.push_back( fCellVal
);
4020 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext( fCellVal
, nErr
))
4021 rArray
.push_back( fCellVal
);
4028 case svExternalSingleRef
:
4029 case svExternalDoubleRef
:
4031 ScMatrixRef pMat
= GetMatrix();
4035 SCSIZE nCount
= pMat
->GetElementCount();
4036 rArray
.reserve( rArray
.size() + nCount
);
4037 if (pMat
->IsNumeric())
4041 for (SCSIZE i
= 0; i
< nCount
; ++i
)
4043 const double fVal
= pMat
->GetDouble(i
);
4044 if (nGlobalError
== FormulaError::NONE
)
4045 rArray
.push_back( fVal
);
4047 nGlobalError
= FormulaError::NONE
;
4052 for (SCSIZE i
= 0; i
< nCount
; ++i
)
4053 rArray
.push_back( pMat
->GetDouble(i
));
4056 else if (bConvertTextInArray
&& eStackType
== svMatrix
)
4058 for (SCSIZE i
= 0; i
< nCount
; ++i
)
4060 if ( pMat
->IsValue( i
) )
4064 const double fVal
= pMat
->GetDouble(i
);
4065 if (nGlobalError
== FormulaError::NONE
)
4066 rArray
.push_back( fVal
);
4068 nGlobalError
= FormulaError::NONE
;
4071 rArray
.push_back( pMat
->GetDouble(i
));
4075 // tdf#88547 try to convert string to (date)value
4076 OUString aStr
= pMat
->GetString( i
).getString();
4077 if ( aStr
.getLength() > 0 )
4079 FormulaError nErr
= nGlobalError
;
4080 nGlobalError
= FormulaError::NONE
;
4081 double fVal
= ConvertStringToValue( aStr
);
4082 if ( nGlobalError
== FormulaError::NONE
)
4084 rArray
.push_back( fVal
);
4085 nGlobalError
= nErr
;
4090 rArray
.push_back( CreateDoubleError( FormulaError::NoValue
));
4091 // Propagate previous error if any, else
4092 // the current #VALUE! error, unless
4093 // ignoring error values.
4094 if (nErr
!= FormulaError::NONE
)
4095 nGlobalError
= nErr
;
4096 else if (!bIgnoreErrVal
)
4097 nGlobalError
= FormulaError::NoValue
;
4099 nGlobalError
= FormulaError::NONE
;
4109 for (SCSIZE i
= 0; i
< nCount
; ++i
)
4111 if (pMat
->IsValue(i
))
4113 const double fVal
= pMat
->GetDouble(i
);
4114 if (nGlobalError
== FormulaError::NONE
)
4115 rArray
.push_back( fVal
);
4117 nGlobalError
= FormulaError::NONE
;
4123 for (SCSIZE i
= 0; i
< nCount
; ++i
)
4125 if (pMat
->IsValue(i
))
4126 rArray
.push_back( pMat
->GetDouble(i
));
4134 SetError( FormulaError::IllegalParameter
);
4137 if (nGlobalError
!= FormulaError::NONE
)
4140 // nParam > 0 in case of error, clean stack environment and obtain earlier
4141 // error if there was one.
4142 while (nParam
-- > 0)
4146 void ScInterpreter::DecoladeRow( ScSortInfoArray
* pArray
, SCROW nRow1
, SCROW nRow2
)
4149 int nMax
= nRow2
- nRow1
;
4150 for (SCROW i
= nRow1
; (i
+ 4) <= nRow2
; i
+= 4)
4152 nRow
= comphelper::rng::uniform_int_distribution(0, nMax
- 1);
4153 pArray
->Swap(i
, nRow1
+ nRow
);
4157 std::unique_ptr
<ScSortInfoArray
> ScInterpreter::CreateFastSortInfoArray(
4158 const ScSortParam
& rSortParam
, bool bMatrix
, SCCOLROW nInd1
, SCCOLROW nInd2
)
4160 sal_uInt16 nUsedSorts
= 1;
4161 while (nUsedSorts
< rSortParam
.GetSortKeyCount() && rSortParam
.maKeyState
[nUsedSorts
].bDoSort
)
4163 std::unique_ptr
<ScSortInfoArray
> pArray(new ScSortInfoArray(nUsedSorts
, nInd1
, nInd2
));
4165 if (rSortParam
.bByRow
)
4167 for (sal_uInt16 nSort
= 0; nSort
< nUsedSorts
; nSort
++)
4171 SCCOL nCol
= static_cast<SCCOL
>(rSortParam
.maKeyState
[nSort
].nField
);
4172 std::optional
<sc::ColumnIterator
> pIter
= mrDoc
.GetColumnIterator(rSortParam
.nSourceTab
, nCol
, nInd1
, nInd2
);
4173 assert(pIter
->hasCell());
4175 for (SCROW nRow
= nInd1
; nRow
<= nInd2
; nRow
++, pIter
->next())
4177 ScSortInfo
& rInfo
= pArray
->Get(nSort
, nRow
);
4178 rInfo
.maCell
= pIter
->getCell();
4184 for (SCROW nRow
= nInd1
; nRow
<= nInd2
; nRow
++)
4186 ScSortInfo
& rInfo
= pArray
->Get(nSort
, nRow
);
4194 for (sal_uInt16 nSort
= 0; nSort
< nUsedSorts
; nSort
++)
4198 SCROW nRow
= rSortParam
.maKeyState
[nSort
].nField
;
4199 for (SCCOL nCol
= static_cast<SCCOL
>(nInd1
);
4200 nCol
<= static_cast<SCCOL
>(nInd2
); nCol
++)
4202 ScSortInfo
& rInfo
= pArray
->Get(nSort
, nCol
);
4203 rInfo
.maCell
= mrDoc
.GetRefCellValue(ScAddress(nCol
, nRow
, rSortParam
.nSourceTab
));
4209 for (SCCOL nCol
= static_cast<SCCOL
>(nInd1
);
4210 nCol
<= static_cast<SCCOL
>(nInd2
); nCol
++)
4212 ScSortInfo
& rInfo
= pArray
->Get(nSort
, nCol
);
4221 std::vector
<SCCOLROW
> ScInterpreter::GetSortOrder( const ScSortParam
& rSortParam
, const ScMatrixRef
& pMatSrc
)
4223 std::vector
<SCCOLROW
> aOrderIndices
;
4224 aSortParam
= rSortParam
;
4225 if (rSortParam
.bByRow
)
4227 const SCROW nLastRow
= rSortParam
.nRow2
;
4228 const SCROW nRow1
= (rSortParam
.bHasHeader
? rSortParam
.nRow1
+ 1 : rSortParam
.nRow1
);
4229 if (nRow1
< nLastRow
)
4231 std::unique_ptr
<ScSortInfoArray
> pArray(CreateFastSortInfoArray(
4232 aSortParam
, (pMatSrc
!= nullptr), nRow1
, nLastRow
));
4234 if (nLastRow
- nRow1
> 255)
4235 DecoladeRow(pArray
.get(), nRow1
, nLastRow
);
4237 QuickSort(pArray
.get(), pMatSrc
, nRow1
, nLastRow
);
4238 aOrderIndices
= pArray
->GetOrderIndices();
4243 const SCCOL nLastCol
= rSortParam
.nCol2
;
4244 const SCCOL nCol1
= (rSortParam
.bHasHeader
? rSortParam
.nCol1
+ 1 : rSortParam
.nCol1
);
4245 if (nCol1
< nLastCol
)
4247 std::unique_ptr
<ScSortInfoArray
> pArray(CreateFastSortInfoArray(
4248 aSortParam
, (pMatSrc
!= nullptr), nCol1
, nLastCol
));
4250 QuickSort(pArray
.get(), pMatSrc
, nCol1
, nLastCol
);
4251 aOrderIndices
= pArray
->GetOrderIndices();
4254 return aOrderIndices
;
4257 ScMatrixRef
ScInterpreter::CreateSortedMatrix( const ScSortParam
& rSortParam
, const ScMatrixRef
& pMatSrc
,
4258 const ScRange
& rSourceRange
, const std::vector
<SCCOLROW
>& rSortArray
, SCSIZE nsC
, SCSIZE nsR
)
4260 SCCOLROW nStartPos
= (!rSortParam
.bByRow
? rSortParam
.nCol1
: rSortParam
.nRow1
);
4261 size_t nCount
= rSortArray
.size();
4262 std::vector
<SCCOLROW
> aPosTable(nCount
);
4264 for (size_t i
= 0; i
< nCount
; ++i
)
4265 aPosTable
[rSortArray
[i
] - nStartPos
] = i
;
4267 ScMatrixRef pResMat
= nullptr;
4268 if (!rSortArray
.empty())
4270 pResMat
= GetNewMat(nsC
, nsR
, /*bEmpty*/true);
4273 ScCellIterator
aCellIter(mrDoc
, rSourceRange
);
4274 for (bool bHas
= aCellIter
.first(); bHas
; bHas
= aCellIter
.next())
4276 SCSIZE nThisCol
= static_cast<SCSIZE
>(aCellIter
.GetPos().Col() - rSourceRange
.aStart
.Col());
4277 SCSIZE nThisRow
= static_cast<SCSIZE
>(aCellIter
.GetPos().Row() - rSourceRange
.aStart
.Row());
4279 ScRefCellValue aCell
= aCellIter
.getRefCellValue();
4280 if (aCell
.hasNumeric())
4282 if (rSortParam
.bByRow
)
4283 pResMat
->PutDouble(GetCellValue(aCellIter
.GetPos(), aCell
), nThisCol
, aPosTable
[nThisRow
]);
4285 pResMat
->PutDouble(GetCellValue(aCellIter
.GetPos(), aCell
), aPosTable
[nThisCol
], nThisRow
);
4289 svl::SharedString aStr
;
4290 GetCellString(aStr
, aCell
);
4291 if (rSortParam
.bByRow
)
4292 pResMat
->PutString(aStr
, nThisCol
, aPosTable
[nThisRow
]);
4294 pResMat
->PutString(aStr
, aPosTable
[nThisCol
], nThisRow
);
4300 for (SCCOL ci
= rSourceRange
.aStart
.Col(); ci
<= rSourceRange
.aEnd
.Col(); ci
++)
4302 for (SCROW rj
= rSourceRange
.aStart
.Row(); rj
<= rSourceRange
.aEnd
.Row(); rj
++)
4304 if (pMatSrc
->IsEmptyCell(ci
, rj
))
4306 if (rSortParam
.bByRow
)
4307 pResMat
->PutEmpty(ci
, aPosTable
[rj
]);
4309 pResMat
->PutEmpty(aPosTable
[ci
], rj
);
4311 else if (pMatSrc
->IsStringOrEmpty(ci
, rj
))
4313 if (rSortParam
.bByRow
)
4314 pResMat
->PutString(pMatSrc
->GetString(ci
, rj
), ci
, aPosTable
[rj
]);
4316 pResMat
->PutString(pMatSrc
->GetString(ci
, rj
), aPosTable
[ci
], rj
);
4320 if (rSortParam
.bByRow
)
4321 pResMat
->PutDouble(pMatSrc
->GetDouble(ci
, rj
), ci
, aPosTable
[rj
]);
4323 pResMat
->PutDouble(pMatSrc
->GetDouble(ci
, rj
), aPosTable
[ci
], rj
);
4333 void ScInterpreter::QuickSort( ScSortInfoArray
* pArray
, const ScMatrixRef
& pMatSrc
, SCCOLROW nLo
, SCCOLROW nHi
)
4335 if ((nHi
- nLo
) == 1)
4337 if (Compare(pArray
, pMatSrc
, nLo
, nHi
) > 0)
4338 pArray
->Swap( nLo
, nHi
);
4346 while ((ni
<= nHi
) && (Compare(pArray
, pMatSrc
, ni
, nLo
)) < 0)
4348 while ((nj
>= nLo
) && (Compare(pArray
, pMatSrc
, nLo
, nj
)) < 0)
4353 pArray
->Swap( ni
, nj
);
4358 if ((nj
- nLo
) < (nHi
- ni
))
4361 QuickSort(pArray
, pMatSrc
, nLo
, nj
);
4363 QuickSort(pArray
, pMatSrc
, ni
, nHi
);
4368 QuickSort(pArray
, pMatSrc
, ni
, nHi
);
4370 QuickSort(pArray
, pMatSrc
, nLo
, nj
);
4375 short ScInterpreter::Compare( ScSortInfoArray
* pArray
, const ScMatrixRef
& pMatSrc
, SCCOLROW nIndex1
, SCCOLROW nIndex2
) const
4378 sal_uInt16 nSort
= 0;
4381 ScSortInfo
& rInfo1
= pArray
->Get( nSort
, nIndex1
);
4382 ScSortInfo
& rInfo2
= pArray
->Get( nSort
, nIndex2
);
4385 nRes
= CompareCell(nSort
, rInfo1
.maCell
, rInfo2
.maCell
);
4389 if (aSortParam
.bByRow
)
4390 nRes
= CompareMatrixCell( pMatSrc
, nSort
,
4391 static_cast<SCCOL
>(aSortParam
.maKeyState
[nSort
].nField
), rInfo1
.nOrg
,
4392 static_cast<SCCOL
>(aSortParam
.maKeyState
[nSort
].nField
), rInfo2
.nOrg
);
4394 nRes
= CompareMatrixCell( pMatSrc
, nSort
,
4395 static_cast<SCCOL
>(rInfo1
.nOrg
), aSortParam
.maKeyState
[nSort
].nField
,
4396 static_cast<SCCOL
>(rInfo2
.nOrg
), aSortParam
.maKeyState
[nSort
].nField
);
4398 } while ( nRes
== 0 && ++nSort
< pArray
->GetUsedSorts() );
4401 ScSortInfo
& rInfo1
= pArray
->Get( 0, nIndex1
);
4402 ScSortInfo
& rInfo2
= pArray
->Get( 0, nIndex2
);
4403 if( rInfo1
.nOrg
< rInfo2
.nOrg
)
4405 else if( rInfo1
.nOrg
> rInfo2
.nOrg
)
4411 short ScInterpreter::CompareCell( sal_uInt16 nSort
,
4412 ScRefCellValue
& rCell1
, ScRefCellValue
& rCell2
) const
4416 CellType eType1
= rCell1
.getType(), eType2
= rCell2
.getType();
4418 if (!rCell1
.isEmpty())
4420 if (!rCell2
.isEmpty())
4423 bool bStr1
= ( eType1
!= CELLTYPE_VALUE
);
4424 if (eType1
== CELLTYPE_FORMULA
)
4426 if (rCell1
.getFormula()->GetErrCode() != FormulaError::NONE
)
4431 else if (rCell1
.getFormula()->IsValue())
4438 bool bStr2
= ( eType2
!= CELLTYPE_VALUE
);
4439 if (eType2
== CELLTYPE_FORMULA
)
4441 if (rCell2
.getFormula()->GetErrCode() != FormulaError::NONE
)
4446 else if (rCell2
.getFormula()->IsValue())
4452 if ( bStr1
&& bStr2
) // only compare strings as strings!
4457 if (eType1
== CELLTYPE_STRING
)
4458 aStr1
= rCell1
.getSharedString()->getString();
4460 aStr1
= rCell1
.getString(&mrDoc
);
4462 if (eType2
== CELLTYPE_STRING
)
4463 aStr2
= rCell2
.getSharedString()->getString();
4465 aStr2
= rCell2
.getString(&mrDoc
);
4467 CollatorWrapper
& rSortCollator
= ScGlobal::GetCollator(aSortParam
.bCaseSens
);
4468 nRes
= static_cast<short>( rSortCollator
.compareString( aStr1
, aStr2
) );
4470 else if ( bStr1
) // String <-> Number or Error
4473 nRes
= -1; // String in front of Error
4475 nRes
= 1; // Number in front of String
4477 else if ( bStr2
) // Number or Error <-> String
4480 nRes
= 1; // String in front of Error
4482 nRes
= -1; // Number in front of String
4484 else if (bErr1
&& bErr2
)
4486 // nothing, two Errors are equal
4488 else if (bErr1
) // Error <-> Number
4490 nRes
= 1; // Number in front of Error
4492 else if (bErr2
) // Number <-> Error
4494 nRes
= -1; // Number in front of Error
4496 else // Mixed numbers
4498 double nVal1
= rCell1
.getValue();
4499 double nVal2
= rCell2
.getValue();
4502 else if (nVal1
> nVal2
)
4505 if ( !aSortParam
.maKeyState
[nSort
].bAscending
)
4513 if (!rCell2
.isEmpty())
4516 nRes
= 0; // both empty
4521 short ScInterpreter::CompareMatrixCell( const ScMatrixRef
& pMatSrc
, sal_uInt16 nSort
, SCCOL nCell1Col
, SCROW nCell1Row
,
4522 SCCOL nCell2Col
, SCROW nCell2Row
) const
4527 bool bCell1Empty
= false;
4528 bool bCell1Value
= false;
4529 if (pMatSrc
->IsEmpty(nCell1Col
, nCell1Row
))
4531 else if (pMatSrc
->IsStringOrEmpty(nCell1Col
, nCell1Row
))
4532 bCell1Value
= false;
4537 bool bCell2Empty
= false;
4538 bool bCell2Value
= false;
4539 if (pMatSrc
->IsEmpty(nCell2Col
, nCell2Row
))
4541 else if (pMatSrc
->IsStringOrEmpty(nCell2Col
, nCell2Row
))
4542 bCell2Value
= false;
4550 if ( !bCell1Value
&& !bCell2Value
) // only compare strings as strings!
4552 OUString aStr1
= pMatSrc
->GetString(nCell1Col
, nCell1Row
).getString();
4553 OUString aStr2
= pMatSrc
->GetString(nCell2Col
, nCell2Row
).getString();
4555 CollatorWrapper
& rSortCollator
= ScGlobal::GetCollator(aSortParam
.bCaseSens
);
4556 nRes
= static_cast<short>( rSortCollator
.compareString( aStr1
, aStr2
) );
4558 else if ( !bCell1Value
) // String <-> Number or Error
4560 nRes
= 1; // Number in front of String
4562 else if ( !bCell2Value
) // Number or Error <-> String
4564 nRes
= -1; // Number in front of String
4566 else // Mixed numbers
4568 double nVal1
= pMatSrc
->GetDouble(nCell1Col
, nCell1Row
);
4569 double nVal2
= pMatSrc
->GetDouble(nCell2Col
, nCell2Row
);
4572 else if (nVal1
> nVal2
)
4575 if ( !aSortParam
.maKeyState
[nSort
].bAscending
)
4586 nRes
= 0; // both empty
4591 void ScInterpreter::GetSortArray( sal_uInt8 nParamCount
, vector
<double>& rSortArray
, vector
<tools::Long
>* pIndexOrder
, bool bConvertTextInArray
, bool bAllowEmptyArray
)
4593 GetNumberSequenceArray( nParamCount
, rSortArray
, bConvertTextInArray
);
4594 if (rSortArray
.size() > MAX_COUNT_DOUBLE_FOR_SORT(mrDoc
.GetSheetLimits()))
4595 SetError( FormulaError::MatrixSize
);
4596 else if ( rSortArray
.empty() )
4598 if ( bAllowEmptyArray
)
4600 SetError( FormulaError::NoValue
);
4603 if (nGlobalError
== FormulaError::NONE
)
4604 QuickSort( rSortArray
, pIndexOrder
);
4607 static void lcl_QuickSort( tools::Long nLo
, tools::Long nHi
, vector
<double>& rSortArray
, vector
<tools::Long
>* pIndexOrder
)
4609 // If pIndexOrder is not NULL, we assume rSortArray.size() == pIndexOrder->size().
4615 if (rSortArray
[nLo
] > rSortArray
[nHi
])
4617 swap(rSortArray
[nLo
], rSortArray
[nHi
]);
4619 swap(pIndexOrder
->at(nLo
), pIndexOrder
->at(nHi
));
4624 tools::Long ni
= nLo
;
4625 tools::Long nj
= nHi
;
4628 double fLo
= rSortArray
[nLo
];
4629 while (ni
<= nHi
&& rSortArray
[ni
] < fLo
) ni
++;
4630 while (nj
>= nLo
&& fLo
< rSortArray
[nj
]) nj
--;
4635 swap(rSortArray
[ni
], rSortArray
[nj
]);
4637 swap(pIndexOrder
->at(ni
), pIndexOrder
->at(nj
));
4646 if ((nj
- nLo
) < (nHi
- ni
))
4648 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
4649 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
4653 if (ni
< nHi
) lcl_QuickSort(ni
, nHi
, rSortArray
, pIndexOrder
);
4654 if (nLo
< nj
) lcl_QuickSort(nLo
, nj
, rSortArray
, pIndexOrder
);
4658 void ScInterpreter::QuickSort( vector
<double>& rSortArray
, vector
<tools::Long
>* pIndexOrder
)
4660 tools::Long n
= static_cast<tools::Long
>(rSortArray
.size());
4664 pIndexOrder
->clear();
4665 pIndexOrder
->reserve(n
);
4666 for (tools::Long i
= 0; i
< n
; ++i
)
4667 pIndexOrder
->push_back(i
);
4673 size_t nValCount
= rSortArray
.size();
4674 for (size_t i
= 0; (i
+ 4) <= nValCount
-1; i
+= 4)
4676 size_t nInd
= comphelper::rng::uniform_size_distribution(0, nValCount
-2);
4677 ::std::swap( rSortArray
[i
], rSortArray
[nInd
]);
4679 ::std::swap( pIndexOrder
->at(i
), pIndexOrder
->at(nInd
));
4682 lcl_QuickSort(0, n
-1, rSortArray
, pIndexOrder
);
4685 void ScInterpreter::ScRank( bool bAverage
)
4687 sal_uInt8 nParamCount
= GetByte();
4688 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4691 if ( nParamCount
== 3 )
4692 bAscending
= GetBool();
4696 vector
<double> aSortArray
;
4697 GetSortArray( 1, aSortArray
, nullptr, false, false );
4698 double fVal
= GetDouble();
4699 SCSIZE nSize
= aSortArray
.size();
4700 if ( nSize
== 0 || nGlobalError
!= FormulaError::NONE
)
4704 if ( fVal
< aSortArray
[ 0 ] || fVal
> aSortArray
[ nSize
- 1 ] )
4705 PushError( FormulaError::NotAvailable
);
4708 double fLastPos
= 0;
4709 double fFirstPos
= -1.0;
4710 bool bFinished
= false;
4712 for (i
= 0; i
< nSize
&& !bFinished
; i
++)
4714 if ( aSortArray
[ i
] == fVal
)
4716 if ( fFirstPos
< 0 )
4717 fFirstPos
= i
+ 1.0;
4721 if ( aSortArray
[ i
] > fVal
)
4732 PushError( FormulaError::NotAvailable
);
4734 else if ( !bAverage
)
4737 PushDouble( fFirstPos
);
4739 PushDouble( nSize
+ 1.0 - fLastPos
);
4744 PushDouble( ( fFirstPos
+ fLastPos
) / 2.0 );
4746 PushDouble( nSize
+ 1.0 - ( fFirstPos
+ fLastPos
) / 2.0 );
4752 void ScInterpreter::ScAveDev()
4754 sal_uInt8 nParamCount
= GetByte();
4755 if ( !MustHaveParamCountMin( nParamCount
, 1 ) )
4757 sal_uInt16 SaveSP
= sp
;
4758 double nMiddle
= 0.0;
4759 KahanSum rVal
= 0.0;
4760 double rValCount
= 0.0;
4763 short nParam
= nParamCount
;
4764 size_t nRefInList
= 0;
4765 while (nParam
-- > 0)
4767 switch (GetStackType())
4770 rVal
+= GetDouble();
4775 PopSingleRef( aAdr
);
4776 ScRefCellValue
aCell(mrDoc
, aAdr
);
4777 if (aCell
.hasNumeric())
4779 rVal
+= GetCellValue(aAdr
, aCell
);
4787 FormulaError nErr
= FormulaError::NONE
;
4789 PopDoubleRef( aRange
, nParam
, nRefInList
);
4790 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
4791 if (aValIter
.GetFirst(nCellVal
, nErr
))
4796 while ((nErr
== FormulaError::NONE
) && aValIter
.GetNext(nCellVal
, nErr
))
4806 case svExternalSingleRef
:
4807 case svExternalDoubleRef
:
4809 ScMatrixRef pMat
= GetMatrix();
4812 SCSIZE nCount
= pMat
->GetElementCount();
4813 if (pMat
->IsNumeric())
4815 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
4817 rVal
+= pMat
->GetDouble(nElem
);
4823 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
4824 if (!pMat
->IsStringOrEmpty(nElem
))
4826 rVal
+= pMat
->GetDouble(nElem
);
4834 SetError(FormulaError::IllegalParameter
);
4838 if (nGlobalError
!= FormulaError::NONE
)
4840 PushError( nGlobalError
);
4843 nMiddle
= rVal
.get() / rValCount
;
4846 nParam
= nParamCount
;
4848 while (nParam
-- > 0)
4850 switch (GetStackType())
4853 rVal
+= std::abs(GetDouble() - nMiddle
);
4857 PopSingleRef( aAdr
);
4858 ScRefCellValue
aCell(mrDoc
, aAdr
);
4859 if (aCell
.hasNumeric())
4860 rVal
+= std::abs(GetCellValue(aAdr
, aCell
) - nMiddle
);
4866 FormulaError nErr
= FormulaError::NONE
;
4868 PopDoubleRef( aRange
, nParam
, nRefInList
);
4869 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
);
4870 if (aValIter
.GetFirst(nCellVal
, nErr
))
4872 rVal
+= std::abs(nCellVal
- nMiddle
);
4873 while (aValIter
.GetNext(nCellVal
, nErr
))
4874 rVal
+= std::abs(nCellVal
- nMiddle
);
4879 case svExternalSingleRef
:
4880 case svExternalDoubleRef
:
4882 ScMatrixRef pMat
= GetMatrix();
4885 SCSIZE nCount
= pMat
->GetElementCount();
4886 if (pMat
->IsNumeric())
4888 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
4890 rVal
+= std::abs(pMat
->GetDouble(nElem
) - nMiddle
);
4895 for (SCSIZE nElem
= 0; nElem
< nCount
; nElem
++)
4897 if (!pMat
->IsStringOrEmpty(nElem
))
4898 rVal
+= std::abs(pMat
->GetDouble(nElem
) - nMiddle
);
4904 default : SetError(FormulaError::IllegalParameter
); break;
4907 PushDouble(rVal
.get() / rValCount
);
4910 void ScInterpreter::ScDevSq()
4912 auto VarResult
= []( double fVal
, size_t /*nValCount*/ )
4916 GetStVarParams( false /*bTextAsZero*/, VarResult
);
4919 void ScInterpreter::ScProbability()
4921 sal_uInt8 nParamCount
= GetByte();
4922 if ( !MustHaveParamCount( nParamCount
, 3, 4 ) )
4926 if (nParamCount
== 4)
4931 std::swap( fLo
, fUp
);
4932 ScMatrixRef pMatP
= GetMatrix();
4933 ScMatrixRef pMatW
= GetMatrix();
4934 if (!pMatP
|| !pMatW
)
4935 PushIllegalParameter();
4940 pMatP
->GetDimensions(nC1
, nR1
);
4941 pMatW
->GetDimensions(nC2
, nR2
);
4942 if (nC1
!= nC2
|| nR1
!= nR2
|| nC1
== 0 || nR1
== 0 ||
4943 nC2
== 0 || nR2
== 0)
4947 KahanSum fSum
= 0.0;
4948 KahanSum fRes
= 0.0;
4951 for ( SCSIZE i
= 0; i
< nC1
&& !bStop
; i
++ )
4953 for (SCSIZE j
= 0; j
< nR1
&& !bStop
; ++j
)
4955 if (pMatP
->IsValue(i
,j
) && pMatW
->IsValue(i
,j
))
4957 fP
= pMatP
->GetDouble(i
,j
);
4958 fW
= pMatW
->GetDouble(i
,j
);
4959 if (fP
< 0.0 || fP
> 1.0)
4964 if (fW
>= fLo
&& fW
<= fUp
)
4969 SetError( FormulaError::IllegalArgument
);
4972 if (bStop
|| std::abs((fSum
-1.0).get()) > 1.0E-7)
4975 PushDouble(fRes
.get());
4980 void ScInterpreter::ScCorrel()
4982 // This is identical to ScPearson()
4986 void ScInterpreter::ScCovarianceP()
4988 CalculatePearsonCovar( false, false, false );
4991 void ScInterpreter::ScCovarianceS()
4993 CalculatePearsonCovar( false, false, true );
4996 void ScInterpreter::ScPearson()
4998 CalculatePearsonCovar( true, false, false );
5001 void ScInterpreter::CalculatePearsonCovar( bool _bPearson
, bool _bStexy
, bool _bSample
)
5003 if ( !MustHaveParamCount( GetByte(), 2 ) )
5005 ScMatrixRef pMat1
= GetMatrix();
5006 ScMatrixRef pMat2
= GetMatrix();
5007 if (!pMat1
|| !pMat2
)
5009 PushIllegalParameter();
5014 pMat1
->GetDimensions(nC1
, nR1
);
5015 pMat2
->GetDimensions(nC2
, nR2
);
5016 if (nR1
!= nR2
|| nC1
!= nC2
)
5018 PushIllegalArgument();
5022 * (sum((X-MeanX)(Y-MeanY)))/N equals (SumXY)/N-MeanX*MeanY mathematically,
5023 * but the latter produces wrong results if the absolute values are high,
5024 * for example above 10^8
5026 double fCount
= 0.0;
5027 KahanSum fSumX
= 0.0;
5028 KahanSum fSumY
= 0.0;
5030 for (SCSIZE i
= 0; i
< nC1
; i
++)
5032 for (SCSIZE j
= 0; j
< nR1
; j
++)
5034 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5036 fSumX
+= pMat1
->GetDouble(i
,j
);
5037 fSumY
+= pMat2
->GetDouble(i
,j
);
5042 if (fCount
< (_bStexy
? 3.0 : (_bSample
? 2.0 : 1.0)))
5046 KahanSum fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
5047 KahanSum fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
5048 KahanSum fSumSqrDeltaY
= 0.0; // sum of (ValY-MeanY)^2
5049 const double fMeanX
= fSumX
.get() / fCount
;
5050 const double fMeanY
= fSumY
.get() / fCount
;
5051 for (SCSIZE i
= 0; i
< nC1
; i
++)
5053 for (SCSIZE j
= 0; j
< nR1
; j
++)
5055 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5057 const double fValX
= pMat1
->GetDouble(i
,j
);
5058 const double fValY
= pMat2
->GetDouble(i
,j
);
5059 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
5062 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
5063 fSumSqrDeltaY
+= (fValY
- fMeanY
) * (fValY
- fMeanY
);
5070 // tdf#94962 - Values below the numerical limit lead to unexpected results
5071 if (fSumSqrDeltaX
< ::std::numeric_limits
<double>::min()
5072 || (!_bStexy
&& fSumSqrDeltaY
< ::std::numeric_limits
<double>::min()))
5073 PushError( FormulaError::DivisionByZero
);
5075 PushDouble( sqrt( ( fSumSqrDeltaY
- fSumDeltaXDeltaY
*
5076 fSumDeltaXDeltaY
/ fSumSqrDeltaX
).get() / (fCount
-2)));
5078 PushDouble( fSumDeltaXDeltaY
.get() / sqrt( fSumSqrDeltaX
.get() * fSumSqrDeltaY
.get() ));
5083 PushDouble( fSumDeltaXDeltaY
.get() / ( fCount
- 1 ) );
5085 PushDouble( fSumDeltaXDeltaY
.get() / fCount
);
5090 void ScInterpreter::ScRSQ()
5092 // Same as ScPearson()*ScPearson()
5094 if (nGlobalError
!= FormulaError::NONE
)
5097 switch (GetStackType())
5101 double fVal
= PopDouble();
5102 PushDouble( fVal
* fVal
);
5111 void ScInterpreter::ScSTEYX()
5113 CalculatePearsonCovar( true, true, false );
5115 void ScInterpreter::CalculateSlopeIntercept(bool bSlope
)
5117 if ( !MustHaveParamCount( GetByte(), 2 ) )
5119 ScMatrixRef pMat1
= GetMatrix();
5120 ScMatrixRef pMat2
= GetMatrix();
5121 if (!pMat1
|| !pMat2
)
5123 PushIllegalParameter();
5128 pMat1
->GetDimensions(nC1
, nR1
);
5129 pMat2
->GetDimensions(nC2
, nR2
);
5130 if (nR1
!= nR2
|| nC1
!= nC2
)
5132 PushIllegalArgument();
5135 // #i78250# numerical stability improved
5136 double fCount
= 0.0;
5137 KahanSum fSumX
= 0.0;
5138 KahanSum fSumY
= 0.0;
5140 for (SCSIZE i
= 0; i
< nC1
; i
++)
5142 for (SCSIZE j
= 0; j
< nR1
; j
++)
5144 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5146 fSumX
+= pMat1
->GetDouble(i
,j
);
5147 fSumY
+= pMat2
->GetDouble(i
,j
);
5156 KahanSum fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
5157 KahanSum fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
5158 double fMeanX
= fSumX
.get() / fCount
;
5159 double fMeanY
= fSumY
.get() / fCount
;
5160 for (SCSIZE i
= 0; i
< nC1
; i
++)
5162 for (SCSIZE j
= 0; j
< nR1
; j
++)
5164 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5166 double fValX
= pMat1
->GetDouble(i
,j
);
5167 double fValY
= pMat2
->GetDouble(i
,j
);
5168 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
5169 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
5173 if (fSumSqrDeltaX
== 0.0)
5174 PushError( FormulaError::DivisionByZero
);
5178 PushDouble( fSumDeltaXDeltaY
.get() / fSumSqrDeltaX
.get());
5180 PushDouble( fMeanY
- fSumDeltaXDeltaY
.get() / fSumSqrDeltaX
.get() * fMeanX
);
5185 void ScInterpreter::ScSlope()
5187 CalculateSlopeIntercept(true);
5190 void ScInterpreter::ScIntercept()
5192 CalculateSlopeIntercept(false);
5195 void ScInterpreter::ScForecast()
5197 if ( !MustHaveParamCount( GetByte(), 3 ) )
5199 ScMatrixRef pMat1
= GetMatrix();
5200 ScMatrixRef pMat2
= GetMatrix();
5201 if (!pMat1
|| !pMat2
)
5203 PushIllegalParameter();
5208 pMat1
->GetDimensions(nC1
, nR1
);
5209 pMat2
->GetDimensions(nC2
, nR2
);
5210 if (nR1
!= nR2
|| nC1
!= nC2
)
5212 PushIllegalArgument();
5215 double fVal
= GetDouble();
5216 // #i78250# numerical stability improved
5217 double fCount
= 0.0;
5218 KahanSum fSumX
= 0.0;
5219 KahanSum fSumY
= 0.0;
5221 for (SCSIZE i
= 0; i
< nC1
; i
++)
5223 for (SCSIZE j
= 0; j
< nR1
; j
++)
5225 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5227 fSumX
+= pMat1
->GetDouble(i
,j
);
5228 fSumY
+= pMat2
->GetDouble(i
,j
);
5237 KahanSum fSumDeltaXDeltaY
= 0.0; // sum of (ValX-MeanX)*(ValY-MeanY)
5238 KahanSum fSumSqrDeltaX
= 0.0; // sum of (ValX-MeanX)^2
5239 double fMeanX
= fSumX
.get() / fCount
;
5240 double fMeanY
= fSumY
.get() / fCount
;
5241 for (SCSIZE i
= 0; i
< nC1
; i
++)
5243 for (SCSIZE j
= 0; j
< nR1
; j
++)
5245 if (!pMat1
->IsStringOrEmpty(i
,j
) && !pMat2
->IsStringOrEmpty(i
,j
))
5247 double fValX
= pMat1
->GetDouble(i
,j
);
5248 double fValY
= pMat2
->GetDouble(i
,j
);
5249 fSumDeltaXDeltaY
+= (fValX
- fMeanX
) * (fValY
- fMeanY
);
5250 fSumSqrDeltaX
+= (fValX
- fMeanX
) * (fValX
- fMeanX
);
5254 if (fSumSqrDeltaX
== 0.0)
5255 PushError( FormulaError::DivisionByZero
);
5257 PushDouble( fMeanY
+ fSumDeltaXDeltaY
.get() / fSumSqrDeltaX
.get() * (fVal
- fMeanX
));
5261 static void lcl_roundUpNearestPow2(SCSIZE
& nNum
, SCSIZE
& nNumBits
)
5263 // Find the least power of 2 that is less than or equal to nNum.
5265 nNumBits
= std::numeric_limits
<SCSIZE
>::digits
;
5266 nPow2
<<= (nNumBits
- 1);
5278 assert(nPow2
< 1UL << (std::numeric_limits
<unsigned long>::digits
- 1));
5279 nNum
= nPow2
? (nPow2
<< 1) : 1;
5285 static SCSIZE
lcl_bitReverse(SCSIZE nIn
, SCSIZE nBound
)
5288 for (SCSIZE nMask
= 1; nMask
< nBound
; nMask
<<= 1)
5301 // Computes and stores twiddle factors for computing DFT later.
5302 struct ScTwiddleFactors
5304 ScTwiddleFactors(SCSIZE nN
, bool bInverse
) :
5315 mbInverse
= !mbInverse
;
5316 for (SCSIZE nIdx
= 0; nIdx
< mnN
; ++nIdx
)
5317 mfWImag
[nIdx
] = -mfWImag
[nIdx
];
5320 std::vector
<double> mfWReal
;
5321 std::vector
<double> mfWImag
;
5328 void ScTwiddleFactors::Compute()
5330 mfWReal
.resize(mnN
);
5331 mfWImag
.resize(mnN
);
5333 double nW
= (mbInverse
? 2 : -2)*M_PI
/static_cast<double>(mnN
);
5354 mfWImag
[1] = (mbInverse
? 1.0 : -1.0);
5360 mfWImag
[3] = (mbInverse
? -1.0 : 1.0);
5362 else if ((mnN
% 4) == 0)
5364 const SCSIZE nQSize
= mnN
>> 2;
5365 // Compute cos of the start quadrant.
5366 // This is the first quadrant if mbInverse == true, else it is the fourth quadrant.
5367 for (SCSIZE nIdx
= 0; nIdx
<= nQSize
; ++nIdx
)
5368 mfWReal
[nIdx
] = cos(nW
*static_cast<double>(nIdx
));
5372 const SCSIZE nQ1End
= nQSize
;
5374 for (SCSIZE nIdx
= 0; nIdx
<= nQ1End
; ++nIdx
)
5375 mfWImag
[nIdx
] = mfWReal
[nQ1End
-nIdx
];
5378 const SCSIZE nQ2End
= nQ1End
<< 1;
5379 for (SCSIZE nIdx
= nQ1End
+1; nIdx
<= nQ2End
; ++nIdx
)
5381 mfWReal
[nIdx
] = -mfWReal
[nQ2End
- nIdx
];
5382 mfWImag
[nIdx
] = mfWImag
[nQ2End
- nIdx
];
5386 const SCSIZE nQ3End
= nQ2End
+ nQ1End
;
5387 for (SCSIZE nIdx
= nQ2End
+1; nIdx
<= nQ3End
; ++nIdx
)
5389 mfWReal
[nIdx
] = -mfWReal
[nIdx
- nQ2End
];
5390 mfWImag
[nIdx
] = -mfWImag
[nIdx
- nQ2End
];
5394 for (SCSIZE nIdx
= nQ3End
+1; nIdx
< mnN
; ++nIdx
)
5396 mfWReal
[nIdx
] = mfWReal
[mnN
- nIdx
];
5397 mfWImag
[nIdx
] = -mfWImag
[mnN
- nIdx
];
5402 const SCSIZE nQ4End
= nQSize
;
5403 const SCSIZE nQ3End
= nQSize
<< 1;
5404 const SCSIZE nQ2End
= nQ3End
+ nQSize
;
5407 for (SCSIZE nIdx
= 0; nIdx
<= nQ4End
; ++nIdx
)
5408 mfWImag
[nIdx
] = -mfWReal
[nQ4End
- nIdx
];
5411 for (SCSIZE nIdx
= nQ4End
+1; nIdx
<= nQ3End
; ++nIdx
)
5413 mfWReal
[nIdx
] = -mfWReal
[nQ3End
- nIdx
];
5414 mfWImag
[nIdx
] = mfWImag
[nQ3End
- nIdx
];
5418 for (SCSIZE nIdx
= nQ3End
+1; nIdx
<= nQ2End
; ++nIdx
)
5420 mfWReal
[nIdx
] = -mfWReal
[nIdx
- nQ3End
];
5421 mfWImag
[nIdx
] = -mfWImag
[nIdx
- nQ3End
];
5425 for (SCSIZE nIdx
= nQ2End
+1; nIdx
< mnN
; ++nIdx
)
5427 mfWReal
[nIdx
] = mfWReal
[mnN
- nIdx
];
5428 mfWImag
[nIdx
] = -mfWImag
[mnN
- nIdx
];
5434 for (SCSIZE nIdx
= 0; nIdx
< mnN
; ++nIdx
)
5436 double fAngle
= nW
*static_cast<double>(nIdx
);
5437 mfWReal
[nIdx
] = cos(fAngle
);
5438 mfWImag
[nIdx
] = sin(fAngle
);
5445 // A radix-2 decimation in time FFT algorithm for complex valued input.
5449 // rfArray.size() would always be even and a power of 2. (asserted in prepare())
5450 // rfArray's first half contains the real parts and the later half contains the imaginary parts.
5451 ScComplexFFT2(std::vector
<double>& raArray
, bool bInverse
, bool bPolar
, double fMinMag
,
5452 ScTwiddleFactors
& rTF
, bool bSubSampleTFs
= false, bool bDisableNormalize
= false) :
5454 mfWReal(rTF
.mfWReal
),
5455 mfWImag(rTF
.mfWImag
),
5456 mnPoints(raArray
.size()/2),
5459 mbInverse(bInverse
),
5461 mbDisableNormalize(bDisableNormalize
),
5462 mbSubSampleTFs(bSubSampleTFs
)
5471 double getReal(SCSIZE nIdx
)
5473 return mrArray
[nIdx
];
5476 void setReal(double fVal
, SCSIZE nIdx
)
5478 mrArray
[nIdx
] = fVal
;
5481 double getImag(SCSIZE nIdx
)
5483 return mrArray
[mnPoints
+ nIdx
];
5486 void setImag(double fVal
, SCSIZE nIdx
)
5488 mrArray
[mnPoints
+ nIdx
] = fVal
;
5491 SCSIZE
getTFactorIndex(SCSIZE nPtIndex
, SCSIZE nTfIdxScaleBits
)
5493 return ( ( nPtIndex
<< nTfIdxScaleBits
) & ( mnPoints
- 1 ) ); // (x & (N-1)) is same as (x % N) but faster.
5496 void computeFly(SCSIZE nTopIdx
, SCSIZE nBottomIdx
, SCSIZE nWIdx1
, SCSIZE nWIdx2
)
5504 const double x1r
= getReal(nTopIdx
);
5505 const double x2r
= getReal(nBottomIdx
);
5507 const double& w1r
= mfWReal
[nWIdx1
];
5508 const double& w1i
= mfWImag
[nWIdx1
];
5510 const double& w2r
= mfWReal
[nWIdx2
];
5511 const double& w2i
= mfWImag
[nWIdx2
];
5513 const double x1i
= getImag(nTopIdx
);
5514 const double x2i
= getImag(nBottomIdx
);
5516 setReal(x1r
+ x2r
*w1r
- x2i
*w1i
, nTopIdx
);
5517 setImag(x1i
+ x2i
*w1r
+ x2r
*w1i
, nTopIdx
);
5519 setReal(x1r
+ x2r
*w2r
- x2i
*w2i
, nBottomIdx
);
5520 setImag(x1i
+ x2i
*w2r
+ x2r
*w2i
, nBottomIdx
);
5523 std::vector
<double>& mrArray
;
5524 std::vector
<double>& mfWReal
;
5525 std::vector
<double>& mfWImag
;
5531 bool mbDisableNormalize
:1;
5532 bool mbSubSampleTFs
:1;
5537 void ScComplexFFT2::prepare()
5539 SCSIZE nPoints
= mnPoints
;
5540 lcl_roundUpNearestPow2(nPoints
, mnStages
);
5541 assert(nPoints
== mnPoints
);
5543 // Reorder array by bit-reversed indices.
5544 for (SCSIZE nIdx
= 0; nIdx
< mnPoints
; ++nIdx
)
5546 SCSIZE nRevIdx
= lcl_bitReverse(nIdx
, mnPoints
);
5549 double fTmp
= getReal(nIdx
);
5550 setReal(getReal(nRevIdx
), nIdx
);
5551 setReal(fTmp
, nRevIdx
);
5553 fTmp
= getImag(nIdx
);
5554 setImag(getImag(nRevIdx
), nIdx
);
5555 setImag(fTmp
, nRevIdx
);
5560 static void lcl_normalize(std::vector
<double>& rCmplxArray
, bool bScaleOnlyReal
)
5562 const SCSIZE nPoints
= rCmplxArray
.size()/2;
5563 const double fScale
= 1.0/static_cast<double>(nPoints
);
5565 // Scale the real part
5566 for (SCSIZE nIdx
= 0; nIdx
< nPoints
; ++nIdx
)
5567 rCmplxArray
[nIdx
] *= fScale
;
5569 if (!bScaleOnlyReal
)
5571 const SCSIZE nLen
= nPoints
*2;
5572 for (SCSIZE nIdx
= nPoints
; nIdx
< nLen
; ++nIdx
)
5573 rCmplxArray
[nIdx
] *= fScale
;
5577 static void lcl_convertToPolar(std::vector
<double>& rCmplxArray
, double fMinMag
)
5579 const SCSIZE nPoints
= rCmplxArray
.size()/2;
5580 double fMag
, fPhase
, fR
, fI
;
5581 for (SCSIZE nIdx
= 0; nIdx
< nPoints
; ++nIdx
)
5583 fR
= rCmplxArray
[nIdx
];
5584 fI
= rCmplxArray
[nPoints
+nIdx
];
5585 fMag
= std::hypot(fR
, fI
);
5593 fPhase
= atan2(fI
, fR
);
5596 rCmplxArray
[nIdx
] = fMag
;
5597 rCmplxArray
[nPoints
+nIdx
] = fPhase
;
5601 void ScComplexFFT2::Compute()
5605 const SCSIZE nFliesInStage
= mnPoints
/2;
5606 for (SCSIZE nStage
= 0; nStage
< mnStages
; ++nStage
)
5608 const SCSIZE nTFIdxScaleBits
= mnStages
- nStage
- 1; // Twiddle factor index's scale factor in bits.
5609 const SCSIZE nFliesInGroup
= SCSIZE(1) << nStage
;
5610 const SCSIZE nGroups
= nFliesInStage
/nFliesInGroup
;
5611 const SCSIZE nFlyWidth
= nFliesInGroup
;
5612 for (SCSIZE nGroup
= 0, nFlyTopIdx
= 0; nGroup
< nGroups
; ++nGroup
)
5614 for (SCSIZE nFly
= 0; nFly
< nFliesInGroup
; ++nFly
, ++nFlyTopIdx
)
5616 SCSIZE nFlyBottomIdx
= nFlyTopIdx
+ nFlyWidth
;
5617 SCSIZE nWIdx1
= getTFactorIndex(nFlyTopIdx
, nTFIdxScaleBits
);
5618 SCSIZE nWIdx2
= getTFactorIndex(nFlyBottomIdx
, nTFIdxScaleBits
);
5620 computeFly(nFlyTopIdx
, nFlyBottomIdx
, nWIdx1
, nWIdx2
);
5623 nFlyTopIdx
+= nFlyWidth
;
5628 lcl_convertToPolar(mrArray
, mfMinMag
);
5630 // Normalize after converting to polar, so we have a chance to
5631 // save O(mnPoints) flops.
5632 if (mbInverse
&& !mbDisableNormalize
)
5633 lcl_normalize(mrArray
, mbPolar
);
5638 // Bluestein's algorithm or chirp z-transform algorithm that can be used to
5639 // compute DFT of a complex valued input of any length N in O(N lgN) time.
5640 class ScComplexBluesteinFFT
5644 ScComplexBluesteinFFT(std::vector
<double>& rArray
, bool bReal
, bool bInverse
,
5645 bool bPolar
, double fMinMag
, bool bDisableNormalize
= false) :
5647 mnPoints(rArray
.size()/2), // rArray should have space for imaginary parts even if real input.
5650 mbInverse(bInverse
),
5652 mbDisableNormalize(bDisableNormalize
)
5658 std::vector
<double>& mrArray
;
5659 const SCSIZE mnPoints
;
5664 bool mbDisableNormalize
:1;
5669 void ScComplexBluesteinFFT::Compute()
5671 std::vector
<double> aRealScalars(mnPoints
);
5672 std::vector
<double> aImagScalars(mnPoints
);
5673 double fW
= (mbInverse
? 2 : -2)*M_PI
/static_cast<double>(mnPoints
);
5674 for (SCSIZE nIdx
= 0; nIdx
< mnPoints
; ++nIdx
)
5676 double fAngle
= 0.5*fW
*static_cast<double>(nIdx
*nIdx
);
5677 aRealScalars
[nIdx
] = cos(fAngle
);
5678 aImagScalars
[nIdx
] = sin(fAngle
);
5681 SCSIZE nMinSize
= mnPoints
*2 - 1;
5682 SCSIZE nExtendedLength
= nMinSize
, nTmp
= 0;
5683 lcl_roundUpNearestPow2(nExtendedLength
, nTmp
);
5684 std::vector
<double> aASignal(nExtendedLength
*2); // complex valued
5685 std::vector
<double> aBSignal(nExtendedLength
*2); // complex valued
5687 double fReal
, fImag
;
5688 for (SCSIZE nIdx
= 0; nIdx
< mnPoints
; ++nIdx
)
5690 // Real part of A signal.
5691 aASignal
[nIdx
] = mrArray
[nIdx
]*aRealScalars
[nIdx
] + (mbReal
? 0.0 : -mrArray
[mnPoints
+nIdx
]*aImagScalars
[nIdx
]);
5692 // Imaginary part of A signal.
5693 aASignal
[nExtendedLength
+ nIdx
] = mrArray
[nIdx
]*aImagScalars
[nIdx
] + (mbReal
? 0.0 : mrArray
[mnPoints
+nIdx
]*aRealScalars
[nIdx
]);
5695 // Real part of B signal.
5696 aBSignal
[nIdx
] = fReal
= aRealScalars
[nIdx
];
5697 // Imaginary part of B signal.
5698 aBSignal
[nExtendedLength
+ nIdx
] = fImag
= -aImagScalars
[nIdx
]; // negative sign because B signal is the conjugation of the scalars.
5702 // B signal needs a mirror of its part in 0 < n < mnPoints at the tail end.
5703 aBSignal
[nExtendedLength
- nIdx
] = fReal
;
5704 aBSignal
[(nExtendedLength
<<1) - nIdx
] = fImag
;
5709 ScTwiddleFactors
aTF(nExtendedLength
, false /*not inverse*/);
5712 // Do complex-FFT2 of both A and B signal.
5713 ScComplexFFT2
aFFT2A(aASignal
, false /*not inverse*/, false /*no polar*/, 0.0 /* no clipping */,
5714 aTF
, false /*no subsample*/, true /* disable normalize */);
5717 ScComplexFFT2
aFFT2B(aBSignal
, false /*not inverse*/, false /*no polar*/, 0.0 /* no clipping */,
5718 aTF
, false /*no subsample*/, true /* disable normalize */);
5721 double fAR
, fAI
, fBR
, fBI
;
5722 for (SCSIZE nIdx
= 0; nIdx
< nExtendedLength
; ++nIdx
)
5724 fAR
= aASignal
[nIdx
];
5725 fAI
= aASignal
[nExtendedLength
+ nIdx
];
5726 fBR
= aBSignal
[nIdx
];
5727 fBI
= aBSignal
[nExtendedLength
+ nIdx
];
5729 // Do point-wise product inplace in A signal.
5730 aASignal
[nIdx
] = fAR
*fBR
- fAI
*fBI
;
5731 aASignal
[nExtendedLength
+ nIdx
] = fAR
*fBI
+ fAI
*fBR
;
5734 // Do complex-inverse-FFT2 of aASignal.
5736 ScComplexFFT2
aFFT2AI(aASignal
, true /*inverse*/, false /*no polar*/, 0.0 /* no clipping */, aTF
); // Need normalization here.
5740 // Point-wise multiply with scalars.
5741 for (SCSIZE nIdx
= 0; nIdx
< mnPoints
; ++nIdx
)
5743 fReal
= aASignal
[nIdx
];
5744 fImag
= aASignal
[nExtendedLength
+ nIdx
];
5745 mrArray
[nIdx
] = fReal
*aRealScalars
[nIdx
] - fImag
*aImagScalars
[nIdx
]; // no conjugation needed here.
5746 mrArray
[mnPoints
+ nIdx
] = fReal
*aImagScalars
[nIdx
] + fImag
*aRealScalars
[nIdx
];
5749 // Normalize/Polar operations
5751 lcl_convertToPolar(mrArray
, mfMinMag
);
5753 // Normalize after converting to polar, so we have a chance to
5754 // save O(mnPoints) flops.
5755 if (mbInverse
&& !mbDisableNormalize
)
5756 lcl_normalize(mrArray
, mbPolar
);
5761 // Computes DFT of an even length(N) real-valued input by using a
5762 // ScComplexFFT2 if N == 2^k for some k or else by using a ScComplexBluesteinFFT
5763 // with a complex valued input of length = N/2.
5768 ScRealFFT(std::vector
<double>& rInArray
, std::vector
<double>& rOutArray
, bool bInverse
,
5769 bool bPolar
, double fMinMag
) :
5770 mrInArray(rInArray
),
5771 mrOutArray(rOutArray
),
5773 mbInverse(bInverse
),
5780 std::vector
<double>& mrInArray
;
5781 std::vector
<double>& mrOutArray
;
5789 void ScRealFFT::Compute()
5791 // input length has to be even to do this optimization.
5792 assert(mrInArray
.size() % 2 == 0);
5793 assert(mrInArray
.size()*2 == mrOutArray
.size());
5794 // nN is the number of points in the complex-fft input
5795 // which will be half of the number of points in real array.
5796 const SCSIZE nN
= mrInArray
.size()/2;
5799 mrOutArray
[0] = mrInArray
[0];
5800 mrOutArray
[1] = 0.0;
5804 // work array should be the same length as mrInArray
5805 std::vector
<double> aWorkArray(nN
*2);
5806 for (SCSIZE nIdx
= 0; nIdx
< nN
; ++nIdx
)
5808 SCSIZE nDoubleIdx
= 2*nIdx
;
5809 // Use even elements as real part
5810 aWorkArray
[nIdx
] = mrInArray
[nDoubleIdx
];
5811 // and odd elements as imaginary part of the contrived complex sequence.
5812 aWorkArray
[nN
+nIdx
] = mrInArray
[nDoubleIdx
+1];
5815 ScTwiddleFactors
aTFs(nN
*2, mbInverse
);
5817 SCSIZE nNextPow2
= nN
, nTmp
= 0;
5818 lcl_roundUpNearestPow2(nNextPow2
, nTmp
);
5820 if (nNextPow2
== nN
)
5822 ScComplexFFT2
aFFT2(aWorkArray
, mbInverse
, false /*disable polar*/, 0.0 /* no clipping */,
5823 aTFs
, true /*subsample tf*/, true /*disable normalize*/);
5828 ScComplexBluesteinFFT
aFFT(aWorkArray
, false /*complex input*/, mbInverse
, false /*disable polar*/,
5829 0.0 /* no clipping */, true /*disable normalize*/);
5833 // Post process aWorkArray to populate mrOutArray
5835 const SCSIZE nTwoN
= 2*nN
, nThreeN
= 3*nN
;
5836 double fY1R
, fY2R
, fY1I
, fY2I
, fResR
, fResI
, fWR
, fWI
;
5837 for (SCSIZE nIdx
= 0; nIdx
< nN
; ++nIdx
)
5839 const SCSIZE nIdxRev
= nIdx
? (nN
- nIdx
) : 0;
5840 fY1R
= aWorkArray
[nIdx
];
5841 fY2R
= aWorkArray
[nIdxRev
];
5842 fY1I
= aWorkArray
[nN
+ nIdx
];
5843 fY2I
= aWorkArray
[nN
+ nIdxRev
];
5844 fWR
= aTFs
.mfWReal
[nIdx
];
5845 fWI
= aTFs
.mfWImag
[nIdx
];
5847 // mrOutArray has length = 4*nN
5848 // Real part of the final output (only half of the symmetry around Nyquist frequency)
5849 // Fills the first quarter.
5850 mrOutArray
[nIdx
] = fResR
= 0.5*(
5852 fWR
* (fY1I
+ fY2I
) +
5853 fWI
* (fY1R
- fY2R
) );
5854 // Imaginary part of the final output (only half of the symmetry around Nyquist frequency)
5855 // Fills the third quarter.
5856 mrOutArray
[nTwoN
+ nIdx
] = fResI
= 0.5*(
5858 fWI
* (fY1I
+ fY2I
) -
5859 fWR
* (fY1R
- fY2R
) );
5861 // Fill the missing 2 quarters using symmetry argument.
5864 // Fills the 2nd quarter.
5865 mrOutArray
[nN
+ nIdxRev
] = fResR
;
5866 // Fills the 4th quarter.
5867 mrOutArray
[nThreeN
+ nIdxRev
] = -fResI
;
5871 mrOutArray
[nN
] = fY1R
- fY1I
;
5872 mrOutArray
[nThreeN
] = 0.0;
5876 // Normalize/Polar operations
5878 lcl_convertToPolar(mrOutArray
, mfMinMag
);
5880 // Normalize after converting to polar, so we have a chance to
5881 // save O(mnPoints) flops.
5883 lcl_normalize(mrOutArray
, mbPolar
);
5886 using ScMatrixGenerator
= ScMatrixRef(SCSIZE
, SCSIZE
, std::vector
<double>&);
5890 // Generic FFT class that decides which FFT implementation to use.
5895 ScFFT(ScMatrixRef
& pMat
, bool bReal
, bool bInverse
, bool bPolar
, double fMinMag
) :
5899 mbInverse(bInverse
),
5903 ScMatrixRef
Compute(const std::function
<ScMatrixGenerator
>& rMatGenFunc
);
5906 ScMatrixRef
& mpInputMat
;
5915 ScMatrixRef
ScFFT::Compute(const std::function
<ScMatrixGenerator
>& rMatGenFunc
)
5917 std::vector
<double> aArray
;
5918 mpInputMat
->GetDoubleArray(aArray
);
5919 SCSIZE nPoints
= mbReal
? aArray
.size() : (aArray
.size()/2);
5922 std::vector
<double> aOutArray(2);
5923 aOutArray
[0] = aArray
[0];
5924 aOutArray
[1] = mbReal
? 0.0 : aArray
[1];
5926 lcl_convertToPolar(aOutArray
, mfMinMag
);
5927 return rMatGenFunc(2, 1, aOutArray
);
5930 if (mbReal
&& (nPoints
% 2) == 0)
5932 std::vector
<double> aOutArray(nPoints
*2);
5933 ScRealFFT
aFFT(aArray
, aOutArray
, mbInverse
, mbPolar
, mfMinMag
);
5935 return rMatGenFunc(2, nPoints
, aOutArray
);
5938 SCSIZE nNextPow2
= nPoints
, nTmp
= 0;
5939 lcl_roundUpNearestPow2(nNextPow2
, nTmp
);
5940 if (nNextPow2
== nPoints
&& !mbReal
)
5942 ScTwiddleFactors
aTF(nPoints
, mbInverse
);
5944 ScComplexFFT2
aFFT2(aArray
, mbInverse
, mbPolar
, mfMinMag
, aTF
);
5946 return rMatGenFunc(2, nPoints
, aArray
);
5950 aArray
.resize(nPoints
*2, 0.0);
5951 ScComplexBluesteinFFT
aFFT(aArray
, mbReal
, mbInverse
, mbPolar
, mfMinMag
);
5953 return rMatGenFunc(2, nPoints
, aArray
);
5956 void ScInterpreter::ScFourier()
5958 sal_uInt8 nParamCount
= GetByte();
5959 if ( !MustHaveParamCount( nParamCount
, 2, 5 ) )
5962 bool bInverse
= false;
5963 bool bPolar
= false;
5964 double fMinMag
= 0.0;
5966 if (nParamCount
== 5)
5971 fMinMag
= GetDouble();
5974 if (nParamCount
>= 4)
5982 if (nParamCount
>= 3)
5987 bInverse
= GetBool();
5990 bool bGroupedByColumn
= GetBool();
5992 ScMatrixRef pInputMat
= GetMatrix();
5995 PushIllegalParameter();
6000 pInputMat
->GetDimensions(nC
, nR
);
6002 if ((bGroupedByColumn
&& nC
> 2) || (!bGroupedByColumn
&& nR
> 2))
6004 // There can be no more than 2 columns (real, imaginary) if data grouped by columns.
6005 // and no more than 2 rows if data is grouped by rows.
6006 PushIllegalArgument();
6010 if (!pInputMat
->IsNumeric())
6016 bool bRealInput
= true;
6017 if (!bGroupedByColumn
)
6019 pInputMat
->MatTrans(*pInputMat
);
6020 bRealInput
= (nR
== 1);
6024 bRealInput
= (nC
== 1);
6027 ScFFT
aFFT(pInputMat
, bRealInput
, bInverse
, bPolar
, fMinMag
);
6028 std::function
<ScMatrixGenerator
> aFunc
= [this](SCSIZE nCol
, SCSIZE nRow
, std::vector
<double>& rVec
) -> ScMatrixRef
6030 return this->GetNewMat(nCol
, nRow
, rVec
);
6032 ScMatrixRef pOut
= aFFT
.Compute(aFunc
);
6036 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */