tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / tool / interpr3.cxx
blob8567c0a8fde0bb9396388561ed59d39275b100f7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
21 #include <stdlib.h>
23 #include <interpre.hxx>
24 #include <global.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>
32 #include <cassert>
33 #include <cmath>
34 #include <memory>
35 #include <set>
36 #include <vector>
37 #include <algorithm>
38 #include <comphelper/random.hxx>
39 #include <o3tl/float_int_conversion.hxx>
40 #include <osl/diagnose.h>
42 using ::std::vector;
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();
55 namespace {
57 class ScDistFunc
59 public:
60 virtual double GetValue(double x) const = 0;
62 protected:
63 ~ScDistFunc() {}
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 )
80 rConvError = false;
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
88 KahanSum fkAx = fAx;
89 KahanSum fkBx = fBx;
90 double fAy = rFunction.GetValue(fAx);
91 double fBy = rFunction.GetValue(fBx);
92 KahanSum fTemp;
93 unsigned short nCount;
94 for (nCount = 0; nCount < 1000 && !lcl_HasChangeOfSign(fAy,fBy); nCount++)
96 if (std::abs(fAy) <= std::abs(fBy))
98 fTemp = fkAx;
99 fkAx += (fkAx - fkBx) * 2.0;
100 if (fkAx < 0.0)
101 fkAx = 0.0;
102 fkBx = fTemp;
103 fBy = fAy;
104 fAy = rFunction.GetValue(fkAx.get());
106 else
108 fTemp = fkBx;
109 fkBx += (fkBx - fkAx) * 2.0;
110 fkAx = fTemp;
111 fAy = fBy;
112 fBy = rFunction.GetValue(fkBx.get());
116 fAx = fkAx.get();
117 fBx = fkBx.get();
118 if (fAy == 0.0)
119 return fAx;
120 if (fBy == 0.0)
121 return fBx;
122 if (!lcl_HasChangeOfSign( fAy, fBy))
124 rConvError = true;
125 return 0.0;
127 // inverse quadric interpolation with additional brackets
128 // set three points
129 double fPx = fAx;
130 double fPy = fAy;
131 double fQx = fBx;
132 double fQy = fBy;
133 double fRx = fAx;
134 double fRy = fAy;
135 double fSx = 0.5 * (fAx + fBx); // potential next point
136 bool bHasToInterpolate = true;
137 nCount = 0;
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?
150 else
151 bHasToInterpolate = false;
153 if(!bHasToInterpolate)
155 fSx = 0.5 * (fAx + fBx);
156 // reset points
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);
163 // update brackets
164 if (lcl_HasChangeOfSign( fAy, fRy))
166 fBx = fRx; fBy = fRy;
168 else
170 fAx = fRx; fAy = fRy;
172 // if last iteration brought too small advance, then do bisection next
173 // time, for safety
174 bHasToInterpolate = bHasToInterpolate && (std::abs(fRy) * 2.0 <= std::abs(fQy));
175 ++nCount;
177 return fRx;
180 // General functions
182 void ScInterpreter::ScNoName()
184 PushError(FormulaError::NoName);
187 void ScInterpreter::ScBadName()
189 short nParamCount = GetByte();
190 while (nParamCount-- > 0)
192 PopError();
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];
214 return nVal.get();
217 double ScInterpreter::gauss(double x)
220 double xAbs = std::abs(x);
221 sal_uInt16 xShort = static_cast<sal_uInt16>(::rtl::math::approxFloor(xAbs));
222 double nVal = 0.0;
223 if (xShort == 0)
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));
257 else
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;
262 if (x < 0.0)
263 return -nVal;
264 else
265 return nVal;
268 // #i26836# new gaussinv implementation by Martin Eitzenberger <m.eitzenberger@unix.net>
270 double ScInterpreter::gaussinv(double x)
272 double q,t,z;
274 q=x-0.5;
276 if(std::abs(q)<=.425)
278 t=0.180625-q*q;
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
323 *t+1.0
327 else
329 if(q>0) t=1-x;
330 else t=x;
332 t=sqrt(-log(t));
334 if(t<=5.0)
336 t+=-1.6;
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
380 *t+1.0
384 else
386 t+=-5.0;
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
430 *t+1.0
435 if(q<0.0) z=-z;
438 return z;
441 double ScInterpreter::Fakultaet(double x)
443 x = ::rtl::math::approxFloor(x);
444 if (x < 0.0)
445 return 0.0;
446 else if (x == 0.0)
447 return 1.0;
448 else if (x <= 170.0)
450 double fTemp = x;
451 while (fTemp > 2.0)
453 fTemp--;
454 x *= fTemp;
457 else
458 SetError(FormulaError::NoValue);
459 return x;
462 double ScInterpreter::BinomKoeff(double n, double k)
464 // this method has been duplicated as BinomialCoefficient()
465 // in scaddins/source/analysis/analysishelper.cxx
467 double nVal = 0.0;
468 k = ::rtl::math::approxFloor(k);
469 if (n < k)
470 nVal = 0.0;
471 else if (k == 0.0)
472 nVal = 1.0;
473 else
475 nVal = n/k;
476 n--;
477 k--;
478 while (k > 0.0)
480 nVal *= n/k;
481 k--;
482 n--;
486 return nVal;
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] = {
512 39916800,
513 120543840,
514 150917976,
515 105258076,
516 45995730,
517 13339535,
518 2637558,
519 357423,
520 32670,
521 1925,
525 // Horner scheme
526 double fSumNum;
527 double fSumDenom;
528 int nI;
529 if (fZ<=1.0)
531 fSumNum = fNum[12];
532 fSumDenom = fDenom[12];
533 for (nI = 11; nI >= 0; --nI)
535 fSumNum *= fZ;
536 fSumNum += fNum[nI];
537 fSumDenom *= fZ;
538 fSumDenom += fDenom[nI];
541 else
542 // Cancel down with fZ^12; Horner scheme with reverse coefficients
544 double fZInv = 1/fZ;
545 fSumNum = fNum[0];
546 fSumDenom = fDenom[0];
547 for (nI = 1; nI <=12; ++nI)
549 fSumNum *= fZInv;
550 fSumNum += fNum[nI];
551 fSumDenom *= fZInv;
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);
573 return 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);
595 return HUGE_VAL;
598 if (fZ >= 1.0)
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);
610 return HUGE_VAL;
612 return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ;
614 // fZ<-0.5
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
618 return 0.0;
620 if (fLogDivisor<0.0)
621 if (fLogPi - fLogDivisor > fLogDblMax) // overflow
623 SetError(FormulaError::IllegalFPOperation);
624 return HUGE_VAL;
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);
635 if (fZ >= 1.0)
636 return log(lcl_GetGammaHelper(fZ));
637 if (fZ >= 0.5)
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 )
652 switch ( 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 );
666 return HUGE_VAL;
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)
673 if (fX <= 0.0)
674 return 1.0; // see ODFF
675 else
676 return GetUpRegIGamma( fDF/2.0, fX/2.0);
679 // ready for ODF 1.2
680 // for ODF CHISQDIST; cumulative distribution function, fDF=degrees of freedom
681 // returns left tail
682 /** You must ensure fDF>0.0 */
683 double ScInterpreter::GetChiSqDistCDF(double fX, double fDF)
685 if (fX <= 0.0)
686 return 0.0; // see ODFF
687 else
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
694 double fValue;
695 if (fX <= 0.0)
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
704 double fCount;
705 if (fmod(fDF,2.0)<0.5)
707 // even
708 fValue = 0.5;
709 fCount = 2.0;
711 else
713 fValue = 1/sqrt(fX*2*M_PI);
714 fCount = 1.0;
716 while ( fCount < fDF)
718 fValue *= (fX / fCount);
719 fCount += 2.0;
721 if (fX>=1425.0) // underflow in e^(-x/2)
722 fValue = exp(log(fValue)-fX/2);
723 else
724 fValue *= exp(-fX/2);
726 return fValue;
729 void ScInterpreter::ScChiSqDist()
731 sal_uInt8 nParamCount = GetByte();
732 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
733 return;
734 bool bCumulative;
735 if (nParamCount == 3)
736 bCumulative = GetBool();
737 else
738 bCumulative = true;
739 double fDF = ::rtl::math::approxFloor(GetDouble());
740 if (fDF < 1.0)
741 PushIllegalArgument();
742 else
744 double fX = GetDouble();
745 if (bCumulative)
746 PushDouble(GetChiSqDistCDF(fX,fDF));
747 else
748 PushDouble(GetChiSqDistPDF(fX,fDF));
752 void ScInterpreter::ScChiSqDist_MS()
754 sal_uInt8 nParamCount = GetByte();
755 if ( !MustHaveParamCount( nParamCount, 3, 3 ) )
756 return;
757 bool bCumulative = GetBool();
758 double fDF = ::rtl::math::approxFloor( GetDouble() );
759 if ( fDF < 1.0 || fDF > 1E10 )
760 PushIllegalArgument();
761 else
763 double fX = GetDouble();
764 if ( fX < 0 )
765 PushIllegalArgument();
766 else
768 if ( bCumulative )
769 PushDouble( GetChiSqDistCDF( fX, fDF ) );
770 else
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();
781 else
783 double fResult = GetGamma(x);
784 if (nGlobalError != FormulaError::NONE)
786 PushError( nGlobalError);
787 return;
789 PushDouble(fResult);
793 void ScInterpreter::ScLogGamma()
795 double x = GetDouble();
796 if (x > 0.0) // constraint from ODFF
797 PushDouble( GetLogGamma(x));
798 else
799 PushIllegalArgument();
802 double ScInterpreter::GetBeta(double fAlpha, double fBeta)
804 double fA;
805 double fB;
806 if (fAlpha > fBeta)
808 fA = fAlpha; fB = fBeta;
810 else
812 fA = fBeta; fB = fAlpha;
814 if (fA+fB < fMaxGammaArgument) // simple case
815 return GetGamma(fA)/GetGamma(fA+fB)*GetGamma(fB);
816 // need logarithm
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);
830 fResult *= fLanczos;
831 return fResult;
834 // Same as GetBeta but with logarithm
835 double ScInterpreter::GetLogBeta(double fAlpha, double fBeta)
837 double fA;
838 double fB;
839 if (fAlpha > fBeta)
841 fA = fAlpha; fB = fBeta;
843 else
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;
860 return fResult;
863 // beta distribution probability density function
864 double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB)
866 // special cases
867 if (fA == 1.0) // result b*(1-x)^(b-1)
869 if (fB == 1.0)
870 return 1.0;
871 if (fB == 2.0)
872 return -2.0*fX + 2.0;
873 if (fX == 1.0 && fB < 1.0)
875 SetError(FormulaError::IllegalArgument);
876 return HUGE_VAL;
878 if (fX <= 0.01)
879 return fB + fB * std::expm1((fB-1.0) * std::log1p(-fX));
880 else
881 return fB * pow(0.5-fX+0.5,fB-1.0);
883 if (fB == 1.0) // result a*x^(a-1)
885 if (fA == 2.0)
886 return fA * fX;
887 if (fX == 0.0 && fA < 1.0)
889 SetError(FormulaError::IllegalArgument);
890 return HUGE_VAL;
892 return fA * pow(fX,fA-1);
894 if (fX <= 0.0)
896 if (fA < 1.0 && fX == 0.0)
898 SetError(FormulaError::IllegalArgument);
899 return HUGE_VAL;
901 else
902 return 0.0;
904 if (fX >= 1.0)
906 if (fB < 1.0 && fX == 1.0)
908 SetError(FormulaError::IllegalArgument);
909 return HUGE_VAL;
911 else
912 return 0.0;
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);
935 x^a * (1-x)^b
936 I_x(a,b) = ---------------- * result of ContFrac
937 a * Beta(a,b)
939 static double lcl_GetBetaHelperContFrac(double fX, double fA, double fB)
940 { // like old version
941 double a1, b1, a2, b2, fnorm, cfnew, cf;
942 a1 = 1.0; b1 = 1.0;
943 b2 = 1.0 - (fA+fB)/(fA+1.0)*fX;
944 if (b2 == 0.0)
946 a2 = 0.0;
947 fnorm = 1.0;
948 cf = 1.0;
950 else
952 a2 = 1.0;
953 fnorm = 1.0/b2;
954 cf = a2*fnorm;
956 cfnew = 1.0;
957 double rm = 1.0;
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;
973 if (b2 != 0.0)
975 fnorm = 1.0/b2;
976 cfnew = a2*fnorm;
977 bfinished = (std::abs(cf-cfnew) < std::abs(cf)*fMachEps);
979 cf = cfnew;
980 rm += 1.0;
982 while (rm < fMaxIter && !bfinished);
983 return cf;
986 // cumulative distribution function, normalized
987 double ScInterpreter::GetBetaDist(double fXin, double fAlpha, double fBeta)
989 // special cases
990 if (fXin <= 0.0) // values are valid, see spec
991 return 0.0;
992 if (fXin >= 1.0) // values are valid, see spec
993 return 1.0;
994 if (fBeta == 1.0)
995 return pow(fXin, fAlpha);
996 if (fAlpha == 1.0)
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
1000 double fResult;
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);
1005 double fX = fXin;
1006 double flnX = log(fXin);
1007 double fA = fAlpha;
1008 double fB = fBeta;
1009 bool bReflect = fXin > fAlpha/(fAlpha+fBeta);
1010 if (bReflect)
1012 fA = fBeta;
1013 fB = fAlpha;
1014 fX = fY;
1015 fY = fXin;
1016 flnX = flnY;
1017 flnY = log(fXin);
1019 fResult = lcl_GetBetaHelperContFrac(fX,fA,fB);
1020 fResult = fResult/fA;
1021 double fP = fA/(fA+fB);
1022 double fQ = fB/(fA+fB);
1023 double fTemp;
1024 if (fA > 1.0 && fB > 1.0 && fP < 0.97 && fQ < 0.97) //found experimental
1025 fTemp = GetBetaDistPDF(fX,fA,fB)*fX*fY;
1026 else
1027 fTemp = exp(fA*flnX + fB*flnY - GetLogBeta(fA,fB));
1028 fResult *= fTemp;
1029 if (bReflect)
1030 fResult = 0.5 - fResult + 0.5;
1031 if (fResult > 1.0) // ensure valid range
1032 fResult = 1.0;
1033 if (fResult < 0.0)
1034 fResult = 0.0;
1035 return fResult;
1038 void ScInterpreter::ScBetaDist()
1040 sal_uInt8 nParamCount = GetByte();
1041 if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) // expanded, see #i91547#
1042 return;
1043 double fLowerBound, fUpperBound;
1044 double alpha, beta, x;
1045 bool bIsCumulative;
1046 if (nParamCount == 6)
1047 bIsCumulative = GetBool();
1048 else
1049 bIsCumulative = true;
1050 if (nParamCount >= 5)
1051 fUpperBound = GetDouble();
1052 else
1053 fUpperBound = 1.0;
1054 if (nParamCount >= 4)
1055 fLowerBound = GetDouble();
1056 else
1057 fLowerBound = 0.0;
1058 beta = GetDouble();
1059 alpha = GetDouble();
1060 x = GetDouble();
1061 double fScale = fUpperBound - fLowerBound;
1062 if (fScale <= 0.0 || alpha <= 0.0 || beta <= 0.0)
1064 PushIllegalArgument();
1065 return;
1067 if (bIsCumulative) // cumulative distribution function
1069 // special cases
1070 if (x < fLowerBound)
1072 PushDouble(0.0); return; //see spec
1074 if (x > fUpperBound)
1076 PushDouble(1.0); return; //see spec
1078 // normal cases
1079 x = (x-fLowerBound)/fScale; // convert to standard form
1080 PushDouble(GetBetaDist(x, alpha, beta));
1081 return;
1083 else // probability density function
1085 if (x < fLowerBound || x > fUpperBound)
1087 PushDouble(0.0);
1088 return;
1090 x = (x-fLowerBound)/fScale;
1091 PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1092 return;
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 ) )
1106 return;
1107 double fLowerBound, fUpperBound;
1108 double alpha, beta, x;
1109 bool bIsCumulative;
1110 if (nParamCount == 6)
1111 fUpperBound = GetDouble();
1112 else
1113 fUpperBound = 1.0;
1114 if (nParamCount >= 5)
1115 fLowerBound = GetDouble();
1116 else
1117 fLowerBound = 0.0;
1118 bIsCumulative = GetBool();
1119 beta = GetDouble();
1120 alpha = GetDouble();
1121 x = GetDouble();
1122 if (alpha <= 0.0 || beta <= 0.0 || x < fLowerBound || x > fUpperBound)
1124 PushIllegalArgument();
1125 return;
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));
1132 return;
1134 else // probability density function
1136 x = (x-fLowerBound)/fScale;
1137 PushDouble(GetBetaDistPDF(x, alpha, beta)/fScale);
1138 return;
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();
1157 else
1158 PushDouble(::atanh(fVal));
1161 void ScInterpreter::ScFisherInv()
1163 PushDouble( tanh( GetDouble()));
1166 void ScInterpreter::ScFact()
1168 double nVal = GetDouble();
1169 if (nVal < 0.0)
1170 PushIllegalArgument();
1171 else
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();
1183 else
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();
1196 else
1197 PushDouble(BinomKoeff(n + k - 1, k));
1201 void ScInterpreter::ScPermut()
1203 if ( !MustHaveParamCount( GetByte(), 2 ) )
1204 return;
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();
1210 else if (k == 0.0)
1211 PushInt(1); // (n! / (n - 0)!) == 1
1212 else
1214 double nVal = n;
1215 for (sal_uLong i = static_cast<sal_uLong>(k)-1; i >= 1; i--)
1216 nVal *= n-static_cast<double>(i);
1217 PushDouble(nVal);
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();
1229 else
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);
1245 else
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;
1250 return fFactor;
1253 else
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;
1258 return fFactor;
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
1266 sal_uInt32 i;
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;
1276 fSum += fFactor;
1278 return std::min(fSum.get(), 1.0);
1281 void ScInterpreter::ScB()
1283 sal_uInt8 nParamCount = GetByte();
1284 if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1285 return ;
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();
1293 else if (p == 0.0)
1294 PushDouble( (x == 0.0) ? 1.0 : 0.0 );
1295 else if ( p == 1.0)
1296 PushDouble( (x == n) ? 1.0 : 0.0);
1297 else
1298 PushDouble(GetBinomDistPMF(x,n,p));
1300 else
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));
1312 else
1314 double fFactor = pow(q, n);
1315 if (fFactor > ::std::numeric_limits<double>::min())
1316 PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q));
1317 else
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));
1326 else
1327 PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) );
1331 else
1333 if ( bIsValidX ) // not(0<p<1)
1335 if ( p == 0.0 )
1336 PushDouble( (xs == 0.0) ? 1.0 : 0.0 );
1337 else if ( p == 1.0 )
1338 PushDouble( (xe == n) ? 1.0 : 0.0 );
1339 else
1340 PushIllegalArgument();
1342 else
1343 PushIllegalArgument();
1348 void ScInterpreter::ScBinomDist()
1350 if ( !MustHaveParamCount( GetByte(), 4 ) )
1351 return;
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();
1361 return;
1363 if ( p == 0.0)
1365 PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 );
1366 return;
1368 if ( p == 1.0)
1370 PushDouble( (x==n) ? 1.0 : 0.0);
1371 return;
1373 if (!bIsCum)
1374 PushDouble( GetBinomDistPMF(x,n,p));
1375 else
1377 if (x == n)
1378 PushDouble(1.0);
1379 else
1381 double fFactor = pow(q, n);
1382 if (x == 0.0)
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));
1389 else
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;
1398 fSum -= fFactor;
1400 PushDouble( (fSum < 0.0) ? 0.0 : fSum );
1402 else
1403 PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p));
1406 else
1407 PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ;
1412 void ScInterpreter::ScCritBinom()
1414 if ( !MustHaveParamCount( GetByte(), 3 ) )
1415 return;
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 )
1423 PushDouble( 0.0 );
1424 else if ( alpha == 1.0 )
1425 PushDouble( p == 0 ? 0.0 : n );
1426 else
1428 double fFactor;
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
1433 fFactor = pow(q,n);
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;
1441 fSum += fFactor;
1443 PushDouble(i);
1445 else
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 )
1454 fSum += x;
1455 else
1457 PushNoValue();
1458 return;
1461 assert(i > 0 && "coverity 2023.12.2");
1462 PushDouble( i - 1 );
1465 else
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;
1476 fSum -= fFactor;
1478 PushDouble(n-i);
1480 else
1482 // accumulate BinomDist until accumulated BinomDist reaches alpha
1483 KahanSum fSum = 0.0;
1484 sal_uInt32 max = static_cast<sal_uInt32> (n), i;
1485 alpha = 1 - alpha;
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 )
1490 fSum += x;
1491 else
1493 PushNoValue();
1494 return;
1497 PushDouble( n - i + 1 );
1503 void ScInterpreter::ScNegBinomDist()
1505 if ( !MustHaveParamCount( GetByte(), 3 ) )
1506 return;
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();
1513 else
1515 double q = 1.0 - p;
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 ) )
1526 return;
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();
1534 else
1536 double q = 1.0 - p;
1537 if ( bCumulative )
1538 PushDouble( 1.0 - GetBetaDist( q, f + 1, s ) );
1539 else
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 ) )
1553 return;
1554 bool bCumulative = nParamCount != 4 || GetBool();
1555 double sigma = GetDouble(); // standard deviation
1556 double mue = GetDouble(); // mean
1557 double x = GetDouble(); // x
1558 if (sigma <= 0.0)
1560 PushIllegalArgument();
1561 return;
1563 if (bCumulative)
1564 PushDouble(integralPhi((x-mue)/sigma));
1565 else
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 ) )
1573 return;
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
1578 if (sigma <= 0.0)
1580 PushIllegalArgument();
1581 return;
1583 if (bCumulative)
1584 { // cumulative
1585 if (x <= 0.0)
1586 PushDouble(0.0);
1587 else
1588 PushDouble(integralPhi((log(x)-mue)/sigma));
1590 else
1591 { // density
1592 if (x <= 0.0)
1593 PushIllegalArgument();
1594 else
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 ) )
1608 return;
1609 bool bCumulative = GetBool(); // cumulative
1610 double x = GetDouble(); // x
1612 if ( bCumulative )
1613 PushDouble( integralPhi( x ) );
1614 else
1615 PushDouble( exp( - pow( x, 2 ) / 2 ) / sqrt( 2 * M_PI ) );
1618 void ScInterpreter::ScExpDist()
1620 if ( !MustHaveParamCount( GetByte(), 3 ) )
1621 return;
1623 double kum = GetDouble(); // 0 or 1
1624 double lambda = GetDouble(); // lambda
1625 double x = GetDouble(); // x
1626 if (lambda <= 0.0)
1627 PushIllegalArgument();
1628 else if (kum == 0.0) // density
1630 if (x >= 0.0)
1631 PushDouble(lambda * exp(-lambda*x));
1632 else
1633 PushInt(0);
1635 else // distribution
1637 if (x > 0.0)
1638 PushDouble(1.0 - exp(-lambda*x));
1639 else
1640 PushInt(0);
1644 void ScInterpreter::ScTDist()
1646 if ( !MustHaveParamCount( GetByte(), 3 ) )
1647 return;
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();
1654 return;
1656 PushDouble( GetTDist( T, fDF, static_cast<int>(fFlag) ) );
1659 void ScInterpreter::ScTDist_T( int nTails )
1661 if ( !MustHaveParamCount( GetByte(), 2 ) )
1662 return;
1663 double fDF = ::rtl::math::approxFloor( GetDouble() );
1664 double fT = GetDouble();
1665 if ( fDF < 1.0 || ( nTails == 2 && fT < 0.0 ) )
1667 PushIllegalArgument();
1668 return;
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
1673 else
1674 PushDouble( fRes );
1677 void ScInterpreter::ScTDist_MS()
1679 if ( !MustHaveParamCount( GetByte(), 3 ) )
1680 return;
1681 bool bCumulative = GetBool();
1682 double fDF = ::rtl::math::approxFloor( GetDouble() );
1683 double T = GetDouble();
1684 if ( fDF < 1.0 )
1686 PushIllegalArgument();
1687 return;
1689 PushDouble( GetTDist( T, fDF, ( bCumulative ? 4 : 3 ) ) );
1692 void ScInterpreter::ScFDist()
1694 if ( !MustHaveParamCount( GetByte(), 3 ) )
1695 return;
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();
1702 return;
1704 PushDouble(GetFDist(fF, fF1, fF2));
1707 void ScInterpreter::ScFDist_LT()
1709 int nParamCount = GetByte();
1710 if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1711 return;
1712 bool bCum;
1713 if ( nParamCount == 3 )
1714 bCum = true;
1715 else if ( IsMissing() )
1717 bCum = true;
1718 Pop();
1720 else
1721 bCum = GetBool();
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();
1728 return;
1730 if ( bCum )
1732 // left tail cumulative distribution
1733 PushDouble( 1.0 - GetFDist( fF, fF1, fF2 ) );
1735 else
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 )
1746 double fResult;
1747 if ( !MustHaveParamCount( GetByte(), 2 ) )
1748 return;
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();
1755 return;
1757 fResult = GetChiDist( fChi, fDF);
1758 if (nGlobalError != FormulaError::NONE)
1760 PushError( nGlobalError);
1761 return;
1763 PushDouble(fResult);
1766 void ScInterpreter::ScWeibull()
1768 if ( !MustHaveParamCount( GetByte(), 4 ) )
1769 return;
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 ) )
1788 return;
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)));
1801 else
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));
1815 else
1817 if (x >= 936.0) // result is always indistinguishable from 1
1818 PushDouble (1.0);
1819 else
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);
1827 fSum += fSummand;
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;
1842 if ( fVal > 1.0 )
1843 cn.push_back( fVal );
1847 /** Calculates a value of the hypergeometric distribution.
1849 @see #i47296#
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()
1855 @see fdo#71722
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 ) )
1863 return;
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();
1874 return;
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.
1896 @see #i47296#
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 )
1908 PushNoValue();
1909 return 0;
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;
1928 if ( n >= M + 1.0 )
1930 if ( N - M < n + 1.0 )
1932 // Case 1
1934 if ( N - n < n + 1.0 )
1936 // no overlap
1937 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1938 lcl_PutFactorialElements( cnDenom, 0.0, N - n - 1.0, N );
1940 else
1942 // overlap
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 )
1951 // no overlap
1952 lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
1953 else
1955 // overlap
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;
1962 else
1964 // Case 2
1966 if ( n > M - 1.0 )
1968 // no overlap
1969 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
1970 lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
1972 else
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 )
1981 // no overlap
1982 lcl_PutFactorialElements( cnNumer, N - M - n + 1.0, N - M - n + x, N - M + 1.0 );
1983 else
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" );
1993 else
1995 if ( N - M < M + 1.0 )
1997 // Case 3
1999 if ( N - n < M + 1.0 )
2001 // No overlap
2002 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2003 lcl_PutFactorialElements( cnDenom, 0.0, N - M - 1.0, N );
2005 else
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 )
2012 // No overlap
2013 lcl_PutFactorialElements( cnNumer, 1.0, N - M - n + x, N - M + 1.0 );
2014 else
2016 // Overlap
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;
2023 else
2025 // Case 4
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 )
2032 // No overlap
2033 lcl_PutFactorialElements( cnNumer, 0.0, fCNumVarUpper, N - n );
2034 lcl_PutFactorialElements( cnDenom, 0.0, M - 1.0, N );
2036 else
2038 // Overlap
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 )
2045 // No overlap
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;
2054 else
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 )
2085 fEnum = *it1++;
2086 if ( it2 != it2End )
2087 fDenom = *it2++;
2088 fFactor *= fEnum / fDenom;
2091 return fFactor;
2094 void ScInterpreter::ScGammaDist( bool bODFF )
2096 sal_uInt8 nMinParamCount = ( bODFF ? 3 : 4 );
2097 sal_uInt8 nParamCount = GetByte();
2098 if ( !MustHaveParamCount( nParamCount, nMinParamCount, 4 ) )
2099 return;
2100 bool bCumulative;
2101 if (nParamCount == 4)
2102 bCumulative = GetBool();
2103 else
2104 bCumulative = true;
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();
2110 else
2112 if (bCumulative) // distribution
2113 PushDouble( GetGammaDist( fX, fAlpha, fBeta));
2114 else // density
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)
2129 PushNoValue();
2130 else
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)
2141 PushNoValue();
2142 else
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();
2156 else
2157 PushDouble( exp( fMue + fSigma * gaussinv( fP ) ) );
2161 class ScGammaDistFunction : public ScDistFunc
2163 ScInterpreter& rInt;
2164 double fp, fAlpha, fBeta;
2166 public:
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 ) )
2178 return;
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();
2185 return;
2187 if (fP == 0.0)
2188 PushInt(0);
2189 else
2191 bool bConvError;
2192 ScGammaDistFunction aFunc( *this, fP, fAlpha, fBeta );
2193 double fStart = fAlpha * fBeta;
2194 double fVal = lcl_IterateInverse( aFunc, fStart*0.5, fStart, bConvError );
2195 if (bConvError)
2196 SetError(FormulaError::NoConvergence);
2197 PushDouble(fVal);
2201 class ScBetaDistFunction : public ScDistFunc
2203 ScInterpreter& rInt;
2204 double fp, fAlpha, fBeta;
2206 public:
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 ) )
2219 return;
2220 double fP, fA, fB, fAlpha, fBeta;
2221 if (nParamCount == 5)
2222 fB = GetDouble();
2223 else
2224 fB = 1.0;
2225 if (nParamCount >= 4)
2226 fA = GetDouble();
2227 else
2228 fA = 0.0;
2229 fBeta = GetDouble();
2230 fAlpha = GetDouble();
2231 fP = GetDouble();
2232 if (fP < 0.0 || fP > 1.0 || fA >= fB || fAlpha <= 0.0 || fBeta <= 0.0)
2234 PushIllegalArgument();
2235 return;
2238 bool bConvError;
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 );
2242 if (bConvError)
2243 PushError( FormulaError::NoConvergence);
2244 else
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;
2255 double fp, fDF;
2256 int nT;
2258 public:
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 ) )
2270 return;
2271 double fDF = ::rtl::math::approxFloor(GetDouble());
2272 double fP = GetDouble();
2273 if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2275 PushIllegalArgument();
2276 return;
2278 if ( nType == 4 ) // left-tailed cumulative t-distribution
2280 if ( fP == 1.0 )
2281 PushIllegalArgument();
2282 else if ( fP < 0.5 )
2283 PushDouble( -GetTInv( 1 - fP, fDF, nType ) );
2284 else
2285 PushDouble( GetTInv( fP, fDF, nType ) );
2287 else
2288 PushDouble( GetTInv( fP, fDF, nType ) );
2291 double ScInterpreter::GetTInv( double fAlpha, double fSize, int nType )
2293 bool bConvError;
2294 ScTDistFunction aFunc( *this, fAlpha, fSize, nType );
2295 double fVal = lcl_IterateInverse( aFunc, fSize * 0.5, fSize, bConvError );
2296 if (bConvError)
2297 SetError(FormulaError::NoConvergence);
2298 return fVal;
2301 class ScFDistFunction : public ScDistFunc
2303 ScInterpreter& rInt;
2304 double fp, fF1, fF2;
2306 public:
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 ) )
2318 return;
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();
2325 return;
2328 bool bConvError;
2329 ScFDistFunction aFunc( *this, fP, fF1, fF2 );
2330 double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2331 if (bConvError)
2332 SetError(FormulaError::NoConvergence);
2333 PushDouble(fVal);
2336 void ScInterpreter::ScFInv_LT()
2338 if ( !MustHaveParamCount( GetByte(), 3 ) )
2339 return;
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();
2346 return;
2349 bool bConvError;
2350 ScFDistFunction aFunc( *this, ( 1.0 - fP ), fF1, fF2 );
2351 double fVal = lcl_IterateInverse( aFunc, fF1*0.5, fF1, bConvError );
2352 if (bConvError)
2353 SetError(FormulaError::NoConvergence);
2354 PushDouble(fVal);
2357 class ScChiDistFunction : public ScDistFunc
2359 ScInterpreter& rInt;
2360 double fp, fDF;
2362 public:
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 ) )
2374 return;
2375 double fDF = ::rtl::math::approxFloor(GetDouble());
2376 double fP = GetDouble();
2377 if (fDF < 1.0 || fP <= 0.0 || fP > 1.0 )
2379 PushIllegalArgument();
2380 return;
2383 bool bConvError;
2384 ScChiDistFunction aFunc( *this, fP, fDF );
2385 double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2386 if (bConvError)
2387 SetError(FormulaError::NoConvergence);
2388 PushDouble(fVal);
2391 /***********************************************/
2392 class ScChiSqDistFunction : public ScDistFunc
2394 ScInterpreter& rInt;
2395 double fp, fDF;
2397 public:
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 ) )
2409 return;
2410 double fDF = ::rtl::math::approxFloor(GetDouble());
2411 double fP = GetDouble();
2412 if (fDF < 1.0 || fP < 0.0 || fP >= 1.0 )
2414 PushIllegalArgument();
2415 return;
2418 bool bConvError;
2419 ScChiSqDistFunction aFunc( *this, fP, fDF );
2420 double fVal = lcl_IterateInverse( aFunc, fDF*0.5, fDF, bConvError );
2421 if (bConvError)
2422 SetError(FormulaError::NoConvergence);
2423 PushDouble(fVal);
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();
2435 else
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);
2451 else
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 ) )
2460 return;
2461 double sigma = 0.0, x;
2462 if (nParamCount == 3)
2464 sigma = GetDouble();
2465 if (sigma <= 0.0)
2467 PushIllegalArgument();
2468 return;
2471 x = GetDouble();
2473 KahanSum fSum = 0.0;
2474 KahanSum fSumSqr = 0.0;
2475 double fVal;
2476 double rValCount = 0.0;
2477 switch (GetStackType())
2479 case svDouble :
2481 fVal = GetDouble();
2482 fSum += fVal;
2483 fSumSqr += fVal*fVal;
2484 rValCount++;
2486 break;
2487 case svSingleRef :
2489 ScAddress aAdr;
2490 PopSingleRef( aAdr );
2491 ScRefCellValue aCell(mrDoc, aAdr);
2492 if (aCell.hasNumeric())
2494 fVal = GetCellValue(aAdr, aCell);
2495 fSum += fVal;
2496 fSumSqr += fVal*fVal;
2497 rValCount++;
2500 break;
2501 case svRefList :
2502 case svDoubleRef :
2504 short nParam = 1;
2505 size_t nRefInList = 0;
2506 while (nParam-- > 0)
2508 ScRange aRange;
2509 FormulaError nErr = FormulaError::NONE;
2510 PopDoubleRef( aRange, nParam, nRefInList);
2511 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
2512 if (aValIter.GetFirst(fVal, nErr))
2514 fSum += fVal;
2515 fSumSqr += fVal*fVal;
2516 rValCount++;
2517 while ((nErr == FormulaError::NONE) && aValIter.GetNext(fVal, nErr))
2519 fSum += fVal;
2520 fSumSqr += fVal*fVal;
2521 rValCount++;
2523 SetError(nErr);
2527 break;
2528 case svMatrix :
2529 case svExternalSingleRef:
2530 case svExternalDoubleRef:
2532 ScMatrixRef pMat = GetMatrix();
2533 if (pMat)
2535 SCSIZE nCount = pMat->GetElementCount();
2536 if (pMat->IsNumeric())
2538 for ( SCSIZE i = 0; i < nCount; i++ )
2540 fVal= pMat->GetDouble(i);
2541 fSum += fVal;
2542 fSumSqr += fVal * fVal;
2543 rValCount++;
2546 else
2548 for (SCSIZE i = 0; i < nCount; i++)
2549 if (!pMat->IsStringOrEmpty(i))
2551 fVal= pMat->GetDouble(i);
2552 fSum += fVal;
2553 fSumSqr += fVal * fVal;
2554 rValCount++;
2559 break;
2560 default : SetError(FormulaError::IllegalParameter); break;
2562 if (rValCount <= 1.0)
2563 PushError( FormulaError::DivisionByZero);
2564 else
2566 double mue = fSum.get()/rValCount;
2568 if (nParamCount != 3)
2570 sigma = (fSumSqr - fSum*fSum/rValCount).get()/(rValCount-1.0);
2571 if (sigma == 0.0)
2573 PushError(FormulaError::DivisionByZero);
2574 return;
2576 PushDouble(0.5 - gauss((mue-x)/sqrt(sigma/rValCount)));
2578 else
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;
2594 double fVal;
2595 SCSIZE i,j;
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);
2602 fSum1 += fVal;
2603 fSumSqr1 += fVal * fVal;
2604 fCount1++;
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);
2613 fSum2 += fVal;
2614 fSumSqr2 += fVal * fVal;
2615 fCount2++;
2618 if (fCount1 < 2.0 || fCount2 < 2.0)
2620 PushNoValue();
2621 return false;
2622 } // if (fCount1 < 2.0 || fCount2 < 2.0)
2623 if ( _bTemplin )
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)
2629 PushNoValue();
2630 return false;
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));
2638 else
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;
2648 return true;
2650 void ScInterpreter::ScTTest()
2652 if ( !MustHaveParamCount( GetByte(), 4 ) )
2653 return;
2654 double fTyp = ::rtl::math::approxFloor(GetDouble());
2655 double fTails = ::rtl::math::approxFloor(GetDouble());
2656 if (fTails != 1.0 && fTails != 2.0)
2658 PushIllegalArgument();
2659 return;
2662 ScMatrixRef pMat2 = GetMatrix();
2663 ScMatrixRef pMat1 = GetMatrix();
2664 if (!pMat1 || !pMat2)
2666 PushIllegalParameter();
2667 return;
2669 double fT, fF;
2670 SCSIZE nC1, nC2;
2671 SCSIZE nR1, nR2;
2672 SCSIZE i, j;
2673 pMat1->GetDimensions(nC1, nR1);
2674 pMat2->GetDimensions(nC2, nR2);
2675 if (fTyp == 1.0)
2677 if (nC1 != nC2 || nR1 != nR2)
2679 PushIllegalArgument();
2680 return;
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);
2694 fSum1 += fVal1;
2695 fSum2 += fVal2;
2696 fSumSqrD += (fVal1 - fVal2)*(fVal1 - fVal2);
2697 fCount++;
2700 if (fCount < 1.0)
2702 PushNoValue();
2703 return;
2705 KahanSum fSumD = fSum1 - fSum2;
2706 double fDivider = ( fSumSqrD*fCount - fSumD*fSumD ).get();
2707 if ( fDivider == 0.0 )
2709 PushError(FormulaError::DivisionByZero);
2710 return;
2712 fT = std::abs(fSumD.get()) * sqrt((fCount-1.0) / fDivider);
2713 fF = fCount - 1.0;
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
2725 else
2727 PushIllegalArgument();
2728 return;
2730 PushDouble( GetTDist( fT, fF, static_cast<int>(fTails) ) );
2733 void ScInterpreter::ScFTest()
2735 if ( !MustHaveParamCount( GetByte(), 2 ) )
2736 return;
2737 ScMatrixRef pMat2 = GetMatrix();
2738 ScMatrixRef pMat1 = GetMatrix();
2739 if (!pMat1 || !pMat2)
2741 PushIllegalParameter();
2742 return;
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)
2756 PushNoValue();
2757 return;
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)
2763 PushNoValue();
2764 return;
2766 double fF, fF1, fF2;
2767 if (fS1 > fS2)
2769 fF = fS1/fS2;
2770 fF1 = fCount1-1.0;
2771 fF2 = fCount2-1.0;
2773 else
2775 fF = fS2/fS1;
2776 fF1 = fCount2-1.0;
2777 fF2 = fCount1-1.0;
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 ) )
2786 return;
2787 ScMatrixRef pMat2 = GetMatrix();
2788 ScMatrixRef pMat1 = GetMatrix();
2789 if (!pMat1 || !pMat2)
2791 PushIllegalParameter();
2792 return;
2794 SCSIZE nC1, nC2;
2795 SCSIZE nR1, nR2;
2796 pMat1->GetDimensions(nC1, nR1);
2797 pMat2->GetDimensions(nC2, nR2);
2798 if (nR1 != nR2 || nC1 != nC2)
2800 PushIllegalArgument();
2801 return;
2803 KahanSum fChi = 0.0;
2804 bool bEmpty = true;
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)))
2811 bEmpty = false;
2812 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
2814 double fValX = pMat1->GetDouble(i,j);
2815 double fValE = pMat2->GetDouble(i,j);
2816 if ( fValE == 0.0 )
2818 PushError(FormulaError::DivisionByZero);
2819 return;
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);
2831 return;
2833 fChi += sc::divide( fTemp2, fValE);
2835 else
2837 PushIllegalArgument();
2838 return;
2843 if ( bEmpty )
2845 // not in ODFF1.2, but for interoperability with Excel
2846 PushIllegalArgument();
2847 return;
2849 double fDF;
2850 if (nC1 == 1 || nR1 == 1)
2852 fDF = static_cast<double>(nC1*nR1 - 1);
2853 if (fDF == 0.0)
2855 PushNoValue();
2856 return;
2859 else
2860 fDF = static_cast<double>(nC1-1)*static_cast<double>(nR1-1);
2861 PushDouble(GetChiDist(fChi.get(), fDF));
2864 void ScInterpreter::ScKurt()
2866 KahanSum fSum;
2867 double fCount;
2868 std::vector<double> values;
2869 if ( !CalculateSkew(fSum, fCount, values) )
2870 return;
2872 // ODF 1.2 constraints: # of numbers >= 4
2873 if (fCount < 4.0)
2875 // for interoperability with Excel
2876 PushError( FormulaError::DivisionByZero);
2877 return;
2880 KahanSum vSum;
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));
2886 if (fStdDev == 0.0)
2888 PushError( FormulaError::DivisionByZero);
2889 return;
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;
2911 ScAddress aAdr;
2912 ScRange aRange;
2913 size_t nRefInList = 0;
2914 while ((nGlobalError == FormulaError::NONE) && (nParamCount-- > 0))
2916 switch (GetStackType())
2918 case svDouble :
2920 double x = GetDouble();
2921 if (x > 0.0)
2923 nVal += 1.0/x;
2924 nValCount++;
2926 else
2927 SetError( FormulaError::IllegalArgument);
2928 break;
2930 case svSingleRef :
2932 PopSingleRef( aAdr );
2933 ScRefCellValue aCell(mrDoc, aAdr);
2934 if (aCell.hasNumeric())
2936 double x = GetCellValue(aAdr, aCell);
2937 if (x > 0.0)
2939 nVal += 1.0/x;
2940 nValCount++;
2942 else
2943 SetError( FormulaError::IllegalArgument);
2945 break;
2947 case svDoubleRef :
2948 case svRefList :
2950 FormulaError nErr = FormulaError::NONE;
2951 PopDoubleRef( aRange, nParamCount, nRefInList);
2952 double nCellVal;
2953 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
2954 if (aValIter.GetFirst(nCellVal, nErr))
2956 if (nCellVal > 0.0)
2958 nVal += 1.0/nCellVal;
2959 nValCount++;
2961 else
2962 SetError( FormulaError::IllegalArgument);
2963 SetError(nErr);
2964 while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
2966 if (nCellVal > 0.0)
2968 nVal += 1.0/nCellVal;
2969 nValCount++;
2971 else
2972 SetError( FormulaError::IllegalArgument);
2974 SetError(nErr);
2977 break;
2978 case svMatrix :
2979 case svExternalSingleRef:
2980 case svExternalDoubleRef:
2982 ScMatrixRef pMat = GetMatrix();
2983 if (pMat)
2985 SCSIZE nCount = pMat->GetElementCount();
2986 if (pMat->IsNumeric())
2988 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
2990 double x = pMat->GetDouble(nElem);
2991 if (x > 0.0)
2993 nVal += 1.0/x;
2994 nValCount++;
2996 else
2997 SetError( FormulaError::IllegalArgument);
3000 else
3002 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3003 if (!pMat->IsStringOrEmpty(nElem))
3005 double x = pMat->GetDouble(nElem);
3006 if (x > 0.0)
3008 nVal += 1.0/x;
3009 nValCount++;
3011 else
3012 SetError( FormulaError::IllegalArgument);
3017 break;
3018 default : SetError(FormulaError::IllegalParameter); break;
3021 if (nGlobalError == FormulaError::NONE)
3022 PushDouble( nValCount / nVal.get() );
3023 else
3024 PushError( nGlobalError);
3027 void ScInterpreter::ScGeoMean()
3029 short nParamCount = GetByte();
3030 KahanSum nVal = 0.0;
3031 double nValCount = 0.0;
3032 ScAddress aAdr;
3033 ScRange aRange;
3035 size_t nRefInList = 0;
3036 while ((nGlobalError == FormulaError::NONE) && (nParamCount-- > 0))
3038 switch (GetStackType())
3040 case svDouble :
3042 double x = GetDouble();
3043 if (x > 0.0)
3045 nVal += log(x);
3046 nValCount++;
3048 else if ( x == 0.0 )
3050 // value of 0 means that function result will be 0
3051 while ( nParamCount-- > 0 )
3052 PopError();
3053 PushDouble( 0.0 );
3054 return;
3056 else
3057 SetError( FormulaError::IllegalArgument);
3058 break;
3060 case svSingleRef :
3062 PopSingleRef( aAdr );
3063 ScRefCellValue aCell(mrDoc, aAdr);
3064 if (aCell.hasNumeric())
3066 double x = GetCellValue(aAdr, aCell);
3067 if (x > 0.0)
3069 nVal += log(x);
3070 nValCount++;
3072 else if ( x == 0.0 )
3074 // value of 0 means that function result will be 0
3075 while ( nParamCount-- > 0 )
3076 PopError();
3077 PushDouble( 0.0 );
3078 return;
3080 else
3081 SetError( FormulaError::IllegalArgument);
3083 break;
3085 case svDoubleRef :
3086 case svRefList :
3088 FormulaError nErr = FormulaError::NONE;
3089 PopDoubleRef( aRange, nParamCount, nRefInList);
3090 double nCellVal;
3091 ScValueIterator aValIter(mrContext, aRange, mnSubTotalFlags);
3092 if (aValIter.GetFirst(nCellVal, nErr))
3094 if (nCellVal > 0.0)
3096 nVal += log(nCellVal);
3097 nValCount++;
3099 else if ( nCellVal == 0.0 )
3101 // value of 0 means that function result will be 0
3102 while ( nParamCount-- > 0 )
3103 PopError();
3104 PushDouble( 0.0 );
3105 return;
3107 else
3108 SetError( FormulaError::IllegalArgument);
3109 SetError(nErr);
3110 while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
3112 if (nCellVal > 0.0)
3114 nVal += log(nCellVal);
3115 nValCount++;
3117 else if ( nCellVal == 0.0 )
3119 // value of 0 means that function result will be 0
3120 while ( nParamCount-- > 0 )
3121 PopError();
3122 PushDouble( 0.0 );
3123 return;
3125 else
3126 SetError( FormulaError::IllegalArgument);
3128 SetError(nErr);
3131 break;
3132 case svMatrix :
3133 case svExternalSingleRef:
3134 case svExternalDoubleRef:
3136 ScMatrixRef pMat = GetMatrix();
3137 if (pMat)
3139 SCSIZE nCount = pMat->GetElementCount();
3140 if (pMat->IsNumeric())
3142 for (SCSIZE ui = 0; ui < nCount; ui++)
3144 double x = pMat->GetDouble(ui);
3145 if (x > 0.0)
3147 nVal += log(x);
3148 nValCount++;
3150 else if ( x == 0.0 )
3152 // value of 0 means that function result will be 0
3153 while ( nParamCount-- > 0 )
3154 PopError();
3155 PushDouble( 0.0 );
3156 return;
3158 else
3159 SetError( FormulaError::IllegalArgument);
3162 else
3164 for (SCSIZE ui = 0; ui < nCount; ui++)
3166 if (!pMat->IsStringOrEmpty(ui))
3168 double x = pMat->GetDouble(ui);
3169 if (x > 0.0)
3171 nVal += log(x);
3172 nValCount++;
3174 else if ( x == 0.0 )
3176 // value of 0 means that function result will be 0
3177 while ( nParamCount-- > 0 )
3178 PopError();
3179 PushDouble( 0.0 );
3180 return;
3182 else
3183 SetError( FormulaError::IllegalArgument);
3189 break;
3190 default : SetError(FormulaError::IllegalParameter); break;
3193 if (nGlobalError == FormulaError::NONE)
3194 PushDouble(exp(nVal.get() / nValCount));
3195 else
3196 PushError( nGlobalError);
3199 void ScInterpreter::ScStandard()
3201 if ( MustHaveParamCount( GetByte(), 3 ) )
3203 double sigma = GetDouble();
3204 double mue = GetDouble();
3205 double x = GetDouble();
3206 if (sigma < 0.0)
3207 PushError( FormulaError::IllegalArgument);
3208 else if (sigma == 0.0)
3209 PushError( FormulaError::DivisionByZero);
3210 else
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 ) )
3218 return false;
3220 fSum = 0.0;
3221 fCount = 0.0;
3222 double fVal = 0.0;
3223 ScAddress aAdr;
3224 ScRange aRange;
3225 size_t nRefInList = 0;
3226 while (nParamCount-- > 0)
3228 switch (GetStackType())
3230 case svDouble :
3232 fVal = GetDouble();
3233 fSum += fVal;
3234 values.push_back(fVal);
3235 fCount++;
3237 break;
3238 case svSingleRef :
3240 PopSingleRef( aAdr );
3241 ScRefCellValue aCell(mrDoc, aAdr);
3242 if (aCell.hasNumeric())
3244 fVal = GetCellValue(aAdr, aCell);
3245 fSum += fVal;
3246 values.push_back(fVal);
3247 fCount++;
3250 break;
3251 case svDoubleRef :
3252 case svRefList :
3254 PopDoubleRef( aRange, nParamCount, nRefInList);
3255 FormulaError nErr = FormulaError::NONE;
3256 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
3257 if (aValIter.GetFirst(fVal, nErr))
3259 fSum += fVal;
3260 values.push_back(fVal);
3261 fCount++;
3262 SetError(nErr);
3263 while ((nErr == FormulaError::NONE) && aValIter.GetNext(fVal, nErr))
3265 fSum += fVal;
3266 values.push_back(fVal);
3267 fCount++;
3269 SetError(nErr);
3272 break;
3273 case svMatrix :
3274 case svExternalSingleRef:
3275 case svExternalDoubleRef:
3277 ScMatrixRef pMat = GetMatrix();
3278 if (pMat)
3280 SCSIZE nCount = pMat->GetElementCount();
3281 if (pMat->IsNumeric())
3283 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3285 fVal = pMat->GetDouble(nElem);
3286 fSum += fVal;
3287 values.push_back(fVal);
3288 fCount++;
3291 else
3293 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
3294 if (!pMat->IsStringOrEmpty(nElem))
3296 fVal = pMat->GetDouble(nElem);
3297 fSum += fVal;
3298 values.push_back(fVal);
3299 fCount++;
3304 break;
3305 default :
3306 SetError(FormulaError::IllegalParameter);
3307 break;
3311 if (nGlobalError != FormulaError::NONE)
3313 PushError( nGlobalError);
3314 return false;
3315 } // if (nGlobalError != FormulaError::NONE)
3316 return true;
3319 void ScInterpreter::CalculateSkewOrSkewp( bool bSkewp )
3321 KahanSum fSum;
3322 double fCount;
3323 std::vector<double> values;
3324 if (!CalculateSkew( fSum, fCount, values))
3325 return;
3326 // SKEW/SKEWP's constraints: they require at least three numbers
3327 if (fCount < 3.0)
3329 // for interoperability with Excel
3330 PushError(FormulaError::DivisionByZero);
3331 return;
3334 KahanSum vSum;
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)));
3340 if (fStdDev == 0)
3342 PushIllegalArgument();
3343 return;
3346 KahanSum xcube = 0.0;
3347 for (double v : values)
3349 double dx = (v - fMean) / fStdDev;
3350 xcube += dx * dx * dx;
3353 if (bSkewp)
3354 PushDouble( xcube.get() / fCount );
3355 else
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);
3375 return 0.0;
3378 // Upper median.
3379 size_t nMid = nSize / 2;
3380 vector<double>::iterator iMid = rArray.begin() + nMid;
3381 ::std::nth_element( rArray.begin(), iMid, rArray.end());
3382 if (nSize & 1)
3383 return *iMid; // Lower and upper median are equal.
3384 else
3386 double fUp = *iMid;
3387 // Lower median.
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 ) )
3397 return;
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();
3406 if (nSize == 1)
3407 return rArray[0];
3408 else
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());
3415 if (fDiff <= 0.0)
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.
3420 return *iter;
3422 else
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 );
3438 return 0.0;
3440 if ( fPercentile * nSize1 < 1.0 || fPercentile * nSize1 > static_cast<double>( nSize1 - 1 ) )
3442 SetError( FormulaError::IllegalParameter );
3443 return 0.0;
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());
3451 if (fDiff == 0.0)
3452 return *iter;
3453 else
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 ) )
3465 return;
3466 double alpha = GetDouble();
3467 if ( bInclusive ? ( alpha < 0.0 || alpha > 1.0 ) : ( alpha <= 0.0 || alpha >= 1.0 ) )
3469 PushIllegalArgument();
3470 return;
3472 vector<double> aArray;
3473 GetNumberSequenceArray( 1, aArray, false );
3474 if ( aArray.empty() || nGlobalError != FormulaError::NONE )
3476 PushNoValue();
3477 return;
3479 if ( bInclusive )
3480 PushDouble( GetPercentile( aArray, alpha ));
3481 else
3482 PushDouble( GetPercentileExclusive( aArray, alpha ));
3485 void ScInterpreter::ScQuartile( bool bInclusive )
3487 if ( !MustHaveParamCount( GetByte(), 2 ) )
3488 return;
3489 double fFlag = ::rtl::math::approxFloor(GetDouble());
3490 if ( bInclusive ? ( fFlag < 0.0 || fFlag > 4.0 ) : ( fFlag <= 0.0 || fFlag >= 4.0 ) )
3492 PushIllegalArgument();
3493 return;
3495 vector<double> aArray;
3496 GetNumberSequenceArray( 1, aArray, false );
3497 if ( aArray.empty() || nGlobalError != FormulaError::NONE )
3499 PushNoValue();
3500 return;
3502 if ( bInclusive )
3503 PushDouble( fFlag == 2.0 ? GetMedian( aArray ) : GetPercentile( aArray, 0.25 * fFlag ) );
3504 else
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 ) )
3512 return;
3513 vector<double> aSortArray;
3514 GetSortArray( nParamCount, aSortArray, nullptr, false, false );
3515 SCSIZE nSize = aSortArray.size();
3516 if (nSize == 0 || nGlobalError != FormulaError::NONE)
3517 PushNoValue();
3518 else
3520 SCSIZE nMaxIndex = 0, nMax = 1, nCount = 1;
3521 double nOldVal = aSortArray[0];
3522 SCSIZE i;
3523 for ( i = 1; i < nSize; i++)
3525 if (aSortArray[i] == nOldVal)
3526 nCount++;
3527 else
3529 nOldVal = aSortArray[i];
3530 if (nCount > nMax)
3532 nMax = nCount;
3533 nMaxIndex = i-1;
3535 nCount = 1;
3538 if (nCount > nMax)
3540 nMax = nCount;
3541 nMaxIndex = i-1;
3543 if (nMax == 1 && nCount == 1)
3544 PushNoValue();
3545 else if (nMax == 1)
3546 PushDouble(nOldVal);
3547 else
3548 PushDouble(aSortArray[nMaxIndex]);
3552 void ScInterpreter::ScModalValue_MS( bool bSingle )
3554 sal_uInt8 nParamCount = GetByte();
3555 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
3556 return;
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 )
3563 PushNoValue();
3564 else
3566 SCSIZE nMax = 1, nCount = 1;
3567 double nOldVal = aSortArray[ 0 ];
3568 vector< double > aResultArray( 1 );
3569 SCSIZE i;
3570 for ( i = 1; i < nSize; i++ )
3572 if ( aSortArray[ i ] == nOldVal )
3573 nCount++;
3574 else
3576 if ( nCount >= nMax && nCount > 1 )
3578 if ( nCount > nMax )
3580 nMax = nCount;
3581 if ( aResultArray.size() != 1 )
3582 vector< double >( 1 ).swap( aResultArray );
3583 aResultArray[ 0 ] = nOldVal;
3585 else
3586 aResultArray.emplace_back( nOldVal );
3588 nOldVal = aSortArray[ i ];
3589 nCount = 1;
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 )
3599 PushNoValue();
3600 else if ( nMax == 1 )
3601 PushDouble( nOldVal ); // there is only 1 result, no reordering needed
3602 else
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;
3615 break;
3619 sort( aOrder.begin(), aOrder.end(), []( const std::vector< double >& lhs,
3620 const std::vector< double >& rhs )
3621 { return lhs[ 1 ] < rhs[ 1 ]; } );
3623 if ( bSingle )
3624 PushDouble( aOrder[ 0 ][ 0 ] );
3625 else
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 ) )
3641 return;
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)
3648 PushNoValue();
3649 return;
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)
3668 PushNoValue();
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
3676 else
3677 PushNoValue();
3679 else
3681 vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 : nSize-k);
3682 ::std::nth_element( aSortArray.begin(), iPos, aSortArray.end());
3683 PushDouble( *iPos);
3686 else
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());
3704 itBegin = ++it;
3707 else
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
3719 else
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 ) )
3741 return;
3742 double fSignificance = ( nParamCount == 3 ? ::rtl::math::approxFloor( GetDouble() ) : 3.0 );
3743 if ( fSignificance < 1.0 )
3745 PushIllegalArgument();
3746 return;
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 )
3753 PushNoValue();
3754 else
3756 if ( fNum < aSortArray[ 0 ] || fNum > aSortArray[ nSize - 1 ] )
3757 PushNoValue();
3758 else
3760 double fRes;
3761 if ( nSize == 1 )
3762 fRes = 1.0; // fNum == aSortArray[ 0 ], see test above
3763 else
3764 fRes = GetPercentrank( aSortArray, fNum, bInclusive );
3765 if ( fRes != 0.0 )
3767 double fExp = ::rtl::math::approxFloor( log10( fRes ) ) + 1.0 - fSignificance;
3768 fRes = ::rtl::math::round( fRes * pow( 10, -fExp ) ) / pow( 10, -fExp );
3770 PushDouble( fRes );
3775 double ScInterpreter::GetPercentrank( ::std::vector<double> & rArray, double fVal, bool bInclusive )
3777 SCSIZE nSize = rArray.size();
3778 double fRes;
3779 if ( fVal == rArray[ 0 ] )
3781 if ( bInclusive )
3782 fRes = 0.0;
3783 else
3784 fRes = 1.0 / static_cast<double>( nSize + 1 );
3786 else
3788 SCSIZE nOldCount = 0;
3789 double fOldVal = rArray[ 0 ];
3790 SCSIZE i;
3791 for ( i = 1; i < nSize && rArray[ i ] < fVal; i++ )
3793 if ( rArray[ i ] != fOldVal )
3795 nOldCount = i;
3796 fOldVal = rArray[ i ];
3799 if ( rArray[ i ] != fOldVal )
3800 nOldCount = i;
3801 if ( fVal == rArray[ i ] )
3803 if ( bInclusive )
3804 fRes = div( nOldCount, nSize - 1 );
3805 else
3806 fRes = static_cast<double>( i + 1 ) / static_cast<double>( nSize + 1 );
3808 else
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" );
3816 fRes = 0.0;
3818 else
3820 double fFract = ( fVal - rArray[ nOldCount - 1 ] ) /
3821 ( rArray[ nOldCount ] - rArray[ nOldCount - 1 ] );
3822 if ( bInclusive )
3823 fRes = div( static_cast<double>( nOldCount - 1 ) + fFract, nSize - 1 );
3824 else
3825 fRes = ( static_cast<double>(nOldCount) + fFract ) / static_cast<double>( nSize + 1 );
3829 return fRes;
3832 void ScInterpreter::ScTrimMean()
3834 if ( !MustHaveParamCount( GetByte(), 2 ) )
3835 return;
3836 double alpha = GetDouble();
3837 if (alpha < 0.0 || alpha >= 1.0)
3839 PushIllegalArgument();
3840 return;
3842 vector<double> aSortArray;
3843 GetSortArray( 1, aSortArray, nullptr, false, false );
3844 SCSIZE nSize = aSortArray.size();
3845 if (nSize == 0 || nGlobalError != FormulaError::NONE)
3846 PushNoValue();
3847 else
3849 sal_uLong nIndex = static_cast<sal_uLong>(::rtl::math::approxFloor(alpha*static_cast<double>(nSize)));
3850 if (nIndex % 2 != 0)
3851 nIndex--;
3852 nIndex /= 2;
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())
3866 case svDouble:
3867 aArray.push_back(PopDouble());
3868 rCol = rRow = 1;
3869 break;
3870 case svSingleRef:
3872 ScAddress aAdr;
3873 PopSingleRef(aAdr);
3874 ScRefCellValue aCell(mrDoc, aAdr);
3875 if (aCell.hasNumeric())
3877 aArray.push_back(GetCellValue(aAdr, aCell));
3878 rCol = rRow = 1;
3881 break;
3882 case svDoubleRef:
3884 ScRange aRange;
3885 PopDoubleRef(aRange, true);
3886 if (nGlobalError != FormulaError::NONE)
3887 break;
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);
3893 break;
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;
3904 double fCellVal;
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)
3920 aArray.clear();
3921 SetError(nErr);
3924 break;
3925 case svMatrix:
3926 case svExternalSingleRef:
3927 case svExternalDoubleRef:
3929 ScMatrixRef pMat = GetMatrix();
3930 if (!pMat)
3931 break;
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));
3942 else
3944 for (SCSIZE i = 0; i < nCount; ++i)
3946 if (pMat->IsValue(i))
3947 aArray.push_back( pMat->GetDouble(i));
3948 else
3949 aArray.push_back( CreateDoubleError( FormulaError::NoValue));
3952 pMat->GetDimensions(rCol, rRow);
3954 break;
3955 default:
3956 PopError();
3957 SetError(FormulaError::IllegalParameter);
3958 break;
3960 return aArray;
3963 void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double>& rArray, bool bConvertTextInArray )
3965 ScAddress aAdr;
3966 ScRange aRange;
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();
3974 switch (eStackType)
3976 case svDouble :
3977 rArray.push_back( PopDouble());
3978 break;
3979 case svSingleRef :
3981 PopSingleRef( aAdr );
3982 ScRefCellValue aCell(mrDoc, aAdr);
3983 if (bIgnoreErrVal && aCell.hasError())
3984 ; // nothing
3985 else if (aCell.hasNumeric())
3986 rArray.push_back(GetCellValue(aAdr, aCell));
3988 break;
3989 case svDoubleRef :
3990 case svRefList :
3992 PopDoubleRef( aRange, nParam, nRefInList);
3993 if (nGlobalError != FormulaError::NONE)
3994 break;
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;
4002 double fCellVal;
4003 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
4004 if (aValIter.GetFirst( fCellVal, nErr))
4006 if (bIgnoreErrVal)
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);
4016 else
4018 rArray.push_back( fCellVal);
4019 SetError(nErr);
4020 while ((nErr == FormulaError::NONE) && aValIter.GetNext( fCellVal, nErr))
4021 rArray.push_back( fCellVal);
4022 SetError(nErr);
4026 break;
4027 case svMatrix :
4028 case svExternalSingleRef:
4029 case svExternalDoubleRef:
4031 ScMatrixRef pMat = GetMatrix();
4032 if (!pMat)
4033 break;
4035 SCSIZE nCount = pMat->GetElementCount();
4036 rArray.reserve( rArray.size() + nCount);
4037 if (pMat->IsNumeric())
4039 if (bIgnoreErrVal)
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);
4046 else
4047 nGlobalError = FormulaError::NONE;
4050 else
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 ) )
4062 if (bIgnoreErrVal)
4064 const double fVal = pMat->GetDouble(i);
4065 if (nGlobalError == FormulaError::NONE)
4066 rArray.push_back( fVal);
4067 else
4068 nGlobalError = FormulaError::NONE;
4070 else
4071 rArray.push_back( pMat->GetDouble(i));
4073 else
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;
4087 else
4089 if (!bIgnoreErrVal)
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;
4098 else
4099 nGlobalError = FormulaError::NONE;
4105 else
4107 if (bIgnoreErrVal)
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);
4116 else
4117 nGlobalError = FormulaError::NONE;
4121 else
4123 for (SCSIZE i = 0; i < nCount; ++i)
4125 if (pMat->IsValue(i))
4126 rArray.push_back( pMat->GetDouble(i));
4131 break;
4132 default :
4133 PopError();
4134 SetError( FormulaError::IllegalParameter);
4135 break;
4137 if (nGlobalError != FormulaError::NONE)
4138 break; // while
4140 // nParam > 0 in case of error, clean stack environment and obtain earlier
4141 // error if there was one.
4142 while (nParam-- > 0)
4143 PopError();
4146 void ScInterpreter::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
4148 SCROW nRow;
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)
4162 nUsedSorts++;
4163 std::unique_ptr<ScSortInfoArray> pArray(new ScSortInfoArray(nUsedSorts, nInd1, nInd2));
4165 if (rSortParam.bByRow)
4167 for (sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++)
4169 if (!bMatrix)
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();
4179 rInfo.nOrg = nRow;
4182 else
4184 for (SCROW nRow = nInd1; nRow <= nInd2; nRow++)
4186 ScSortInfo& rInfo = pArray->Get(nSort, nRow);
4187 rInfo.nOrg = nRow;
4192 else
4194 for (sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++)
4196 if (!bMatrix)
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));
4204 rInfo.nOrg = nCol;
4207 else
4209 for (SCCOL nCol = static_cast<SCCOL>(nInd1);
4210 nCol <= static_cast<SCCOL>(nInd2); nCol++)
4212 ScSortInfo& rInfo = pArray->Get(nSort, nCol);
4213 rInfo.nOrg = nCol;
4218 return pArray;
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();
4241 else
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);
4271 if (!pMatSrc)
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]);
4284 else
4285 pResMat->PutDouble(GetCellValue(aCellIter.GetPos(), aCell), aPosTable[nThisCol], nThisRow);
4287 else
4289 svl::SharedString aStr;
4290 GetCellString(aStr, aCell);
4291 if (rSortParam.bByRow)
4292 pResMat->PutString(aStr, nThisCol, aPosTable[nThisRow]);
4293 else
4294 pResMat->PutString(aStr, aPosTable[nThisCol], nThisRow);
4298 else
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]);
4308 else
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]);
4315 else
4316 pResMat->PutString(pMatSrc->GetString(ci, rj), aPosTable[ci], rj);
4318 else
4320 if (rSortParam.bByRow)
4321 pResMat->PutDouble(pMatSrc->GetDouble(ci, rj), ci, aPosTable[rj]);
4322 else
4323 pResMat->PutDouble(pMatSrc->GetDouble(ci, rj), aPosTable[ci], rj);
4330 return pResMat;
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 );
4340 else
4342 SCCOLROW ni = nLo;
4343 SCCOLROW nj = nHi;
4346 while ((ni <= nHi) && (Compare(pArray, pMatSrc, ni, nLo)) < 0)
4347 ni++;
4348 while ((nj >= nLo) && (Compare(pArray, pMatSrc, nLo, nj)) < 0)
4349 nj--;
4350 if (ni <= nj)
4352 if (ni != nj)
4353 pArray->Swap( ni, nj );
4354 ni++;
4355 nj--;
4357 } while (ni < nj);
4358 if ((nj - nLo) < (nHi - ni))
4360 if (nLo < nj)
4361 QuickSort(pArray, pMatSrc, nLo, nj);
4362 if (ni < nHi)
4363 QuickSort(pArray, pMatSrc, ni, nHi);
4365 else
4367 if (ni < nHi)
4368 QuickSort(pArray, pMatSrc, ni, nHi);
4369 if (nLo < nj)
4370 QuickSort(pArray, pMatSrc, nLo, nj);
4375 short ScInterpreter::Compare( ScSortInfoArray* pArray, const ScMatrixRef& pMatSrc, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const
4377 short nRes;
4378 sal_uInt16 nSort = 0;
4381 ScSortInfo& rInfo1 = pArray->Get( nSort, nIndex1 );
4382 ScSortInfo& rInfo2 = pArray->Get( nSort, nIndex2 );
4383 if (!pMatSrc)
4385 nRes = CompareCell(nSort, rInfo1.maCell, rInfo2.maCell);
4387 else
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 );
4393 else
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() );
4399 if( nRes == 0 )
4401 ScSortInfo& rInfo1 = pArray->Get( 0, nIndex1 );
4402 ScSortInfo& rInfo2 = pArray->Get( 0, nIndex2 );
4403 if( rInfo1.nOrg < rInfo2.nOrg )
4404 nRes = -1;
4405 else if( rInfo1.nOrg > rInfo2.nOrg )
4406 nRes = 1;
4408 return nRes;
4411 short ScInterpreter::CompareCell( sal_uInt16 nSort,
4412 ScRefCellValue& rCell1, ScRefCellValue& rCell2 ) const
4414 short nRes = 0;
4416 CellType eType1 = rCell1.getType(), eType2 = rCell2.getType();
4418 if (!rCell1.isEmpty())
4420 if (!rCell2.isEmpty())
4422 bool bErr1 = false;
4423 bool bStr1 = ( eType1 != CELLTYPE_VALUE );
4424 if (eType1 == CELLTYPE_FORMULA)
4426 if (rCell1.getFormula()->GetErrCode() != FormulaError::NONE)
4428 bErr1 = true;
4429 bStr1 = false;
4431 else if (rCell1.getFormula()->IsValue())
4433 bStr1 = false;
4437 bool bErr2 = false;
4438 bool bStr2 = ( eType2 != CELLTYPE_VALUE );
4439 if (eType2 == CELLTYPE_FORMULA)
4441 if (rCell2.getFormula()->GetErrCode() != FormulaError::NONE)
4443 bErr2 = true;
4444 bStr2 = false;
4446 else if (rCell2.getFormula()->IsValue())
4448 bStr2 = false;
4452 if ( bStr1 && bStr2 ) // only compare strings as strings!
4454 OUString aStr1;
4455 OUString aStr2;
4457 if (eType1 == CELLTYPE_STRING)
4458 aStr1 = rCell1.getSharedString()->getString();
4459 else
4460 aStr1 = rCell1.getString(&mrDoc);
4462 if (eType2 == CELLTYPE_STRING)
4463 aStr2 = rCell2.getSharedString()->getString();
4464 else
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
4472 if (bErr2)
4473 nRes = -1; // String in front of Error
4474 else
4475 nRes = 1; // Number in front of String
4477 else if ( bStr2 ) // Number or Error <-> String
4479 if (bErr1)
4480 nRes = 1; // String in front of Error
4481 else
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();
4500 if (nVal1 < nVal2)
4501 nRes = -1;
4502 else if (nVal1 > nVal2)
4503 nRes = 1;
4505 if ( !aSortParam.maKeyState[nSort].bAscending )
4506 nRes = -nRes;
4508 else
4509 nRes = -1;
4511 else
4513 if (!rCell2.isEmpty())
4514 nRes = 1;
4515 else
4516 nRes = 0; // both empty
4518 return nRes;
4521 short ScInterpreter::CompareMatrixCell( const ScMatrixRef& pMatSrc, sal_uInt16 nSort, SCCOL nCell1Col, SCROW nCell1Row,
4522 SCCOL nCell2Col, SCROW nCell2Row ) const
4524 short nRes = 0;
4526 // 1st value
4527 bool bCell1Empty = false;
4528 bool bCell1Value = false;
4529 if (pMatSrc->IsEmpty(nCell1Col, nCell1Row))
4530 bCell1Empty = true;
4531 else if (pMatSrc->IsStringOrEmpty(nCell1Col, nCell1Row))
4532 bCell1Value = false;
4533 else
4534 bCell1Value = true;
4536 // 2nd value
4537 bool bCell2Empty = false;
4538 bool bCell2Value = false;
4539 if (pMatSrc->IsEmpty(nCell2Col, nCell2Row))
4540 bCell2Empty = true;
4541 else if (pMatSrc->IsStringOrEmpty(nCell2Col, nCell2Row))
4542 bCell2Value = false;
4543 else
4544 bCell2Value = true;
4546 if (!bCell1Empty)
4548 if (!bCell2Empty)
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);
4570 if (nVal1 < nVal2)
4571 nRes = -1;
4572 else if (nVal1 > nVal2)
4573 nRes = 1;
4575 if ( !aSortParam.maKeyState[nSort].bAscending )
4576 nRes = -nRes;
4578 else
4579 nRes = -1;
4581 else
4583 if (!bCell2Empty)
4584 nRes = 1;
4585 else
4586 nRes = 0; // both empty
4588 return nRes;
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 )
4599 return;
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().
4611 using ::std::swap;
4613 if (nHi - nLo == 1)
4615 if (rSortArray[nLo] > rSortArray[nHi])
4617 swap(rSortArray[nLo], rSortArray[nHi]);
4618 if (pIndexOrder)
4619 swap(pIndexOrder->at(nLo), pIndexOrder->at(nHi));
4621 return;
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--;
4631 if (ni <= nj)
4633 if (ni != nj)
4635 swap(rSortArray[ni], rSortArray[nj]);
4636 if (pIndexOrder)
4637 swap(pIndexOrder->at(ni), pIndexOrder->at(nj));
4640 ++ni;
4641 --nj;
4644 while (ni < 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);
4651 else
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());
4662 if (pIndexOrder)
4664 pIndexOrder->clear();
4665 pIndexOrder->reserve(n);
4666 for (tools::Long i = 0; i < n; ++i)
4667 pIndexOrder->push_back(i);
4670 if (n < 2)
4671 return;
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]);
4678 if (pIndexOrder)
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 ) )
4689 return;
4690 bool bAscending;
4691 if ( nParamCount == 3 )
4692 bAscending = GetBool();
4693 else
4694 bAscending = false;
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 )
4701 PushNoValue();
4702 else
4704 if ( fVal < aSortArray[ 0 ] || fVal > aSortArray[ nSize - 1 ] )
4705 PushError( FormulaError::NotAvailable);
4706 else
4708 double fLastPos = 0;
4709 double fFirstPos = -1.0;
4710 bool bFinished = false;
4711 SCSIZE i;
4712 for (i = 0; i < nSize && !bFinished; i++)
4714 if ( aSortArray[ i ] == fVal )
4716 if ( fFirstPos < 0 )
4717 fFirstPos = i + 1.0;
4719 else
4721 if ( aSortArray[ i ] > fVal )
4723 fLastPos = i;
4724 bFinished = true;
4728 if ( !bFinished )
4729 fLastPos = i;
4730 if (fFirstPos <= 0)
4732 PushError( FormulaError::NotAvailable);
4734 else if ( !bAverage )
4736 if ( bAscending )
4737 PushDouble( fFirstPos );
4738 else
4739 PushDouble( nSize + 1.0 - fLastPos );
4741 else
4743 if ( bAscending )
4744 PushDouble( ( fFirstPos + fLastPos ) / 2.0 );
4745 else
4746 PushDouble( nSize + 1.0 - ( fFirstPos + fLastPos ) / 2.0 );
4752 void ScInterpreter::ScAveDev()
4754 sal_uInt8 nParamCount = GetByte();
4755 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
4756 return;
4757 sal_uInt16 SaveSP = sp;
4758 double nMiddle = 0.0;
4759 KahanSum rVal = 0.0;
4760 double rValCount = 0.0;
4761 ScAddress aAdr;
4762 ScRange aRange;
4763 short nParam = nParamCount;
4764 size_t nRefInList = 0;
4765 while (nParam-- > 0)
4767 switch (GetStackType())
4769 case svDouble :
4770 rVal += GetDouble();
4771 rValCount++;
4772 break;
4773 case svSingleRef :
4775 PopSingleRef( aAdr );
4776 ScRefCellValue aCell(mrDoc, aAdr);
4777 if (aCell.hasNumeric())
4779 rVal += GetCellValue(aAdr, aCell);
4780 rValCount++;
4783 break;
4784 case svDoubleRef :
4785 case svRefList :
4787 FormulaError nErr = FormulaError::NONE;
4788 double nCellVal;
4789 PopDoubleRef( aRange, nParam, nRefInList);
4790 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
4791 if (aValIter.GetFirst(nCellVal, nErr))
4793 rVal += nCellVal;
4794 rValCount++;
4795 SetError(nErr);
4796 while ((nErr == FormulaError::NONE) && aValIter.GetNext(nCellVal, nErr))
4798 rVal += nCellVal;
4799 rValCount++;
4801 SetError(nErr);
4804 break;
4805 case svMatrix :
4806 case svExternalSingleRef:
4807 case svExternalDoubleRef:
4809 ScMatrixRef pMat = GetMatrix();
4810 if (pMat)
4812 SCSIZE nCount = pMat->GetElementCount();
4813 if (pMat->IsNumeric())
4815 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4817 rVal += pMat->GetDouble(nElem);
4818 rValCount++;
4821 else
4823 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4824 if (!pMat->IsStringOrEmpty(nElem))
4826 rVal += pMat->GetDouble(nElem);
4827 rValCount++;
4832 break;
4833 default :
4834 SetError(FormulaError::IllegalParameter);
4835 break;
4838 if (nGlobalError != FormulaError::NONE)
4840 PushError( nGlobalError);
4841 return;
4843 nMiddle = rVal.get() / rValCount;
4844 sp = SaveSP;
4845 rVal = 0.0;
4846 nParam = nParamCount;
4847 nRefInList = 0;
4848 while (nParam-- > 0)
4850 switch (GetStackType())
4852 case svDouble :
4853 rVal += std::abs(GetDouble() - nMiddle);
4854 break;
4855 case svSingleRef :
4857 PopSingleRef( aAdr );
4858 ScRefCellValue aCell(mrDoc, aAdr);
4859 if (aCell.hasNumeric())
4860 rVal += std::abs(GetCellValue(aAdr, aCell) - nMiddle);
4862 break;
4863 case svDoubleRef :
4864 case svRefList :
4866 FormulaError nErr = FormulaError::NONE;
4867 double nCellVal;
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);
4877 break;
4878 case svMatrix :
4879 case svExternalSingleRef:
4880 case svExternalDoubleRef:
4882 ScMatrixRef pMat = GetMatrix();
4883 if (pMat)
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);
4893 else
4895 for (SCSIZE nElem = 0; nElem < nCount; nElem++)
4897 if (!pMat->IsStringOrEmpty(nElem))
4898 rVal += std::abs(pMat->GetDouble(nElem) - nMiddle);
4903 break;
4904 default : SetError(FormulaError::IllegalParameter); break;
4907 PushDouble(rVal.get() / rValCount);
4910 void ScInterpreter::ScDevSq()
4912 auto VarResult = []( double fVal, size_t /*nValCount*/ )
4914 return fVal;
4916 GetStVarParams( false /*bTextAsZero*/, VarResult);
4919 void ScInterpreter::ScProbability()
4921 sal_uInt8 nParamCount = GetByte();
4922 if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
4923 return;
4924 double fUp, fLo;
4925 fUp = GetDouble();
4926 if (nParamCount == 4)
4927 fLo = GetDouble();
4928 else
4929 fLo = fUp;
4930 if (fLo > fUp)
4931 std::swap( fLo, fUp );
4932 ScMatrixRef pMatP = GetMatrix();
4933 ScMatrixRef pMatW = GetMatrix();
4934 if (!pMatP || !pMatW)
4935 PushIllegalParameter();
4936 else
4938 SCSIZE nC1, nC2;
4939 SCSIZE nR1, nR2;
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)
4944 PushNA();
4945 else
4947 KahanSum fSum = 0.0;
4948 KahanSum fRes = 0.0;
4949 bool bStop = false;
4950 double fP, fW;
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)
4960 bStop = true;
4961 else
4963 fSum += fP;
4964 if (fW >= fLo && fW <= fUp)
4965 fRes += fP;
4968 else
4969 SetError( FormulaError::IllegalArgument);
4972 if (bStop || std::abs((fSum -1.0).get()) > 1.0E-7)
4973 PushNoValue();
4974 else
4975 PushDouble(fRes.get());
4980 void ScInterpreter::ScCorrel()
4982 // This is identical to ScPearson()
4983 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 ) )
5004 return;
5005 ScMatrixRef pMat1 = GetMatrix();
5006 ScMatrixRef pMat2 = GetMatrix();
5007 if (!pMat1 || !pMat2)
5009 PushIllegalParameter();
5010 return;
5012 SCSIZE nC1, nC2;
5013 SCSIZE nR1, nR2;
5014 pMat1->GetDimensions(nC1, nR1);
5015 pMat2->GetDimensions(nC2, nR2);
5016 if (nR1 != nR2 || nC1 != nC2)
5018 PushIllegalArgument();
5019 return;
5021 /* #i78250#
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);
5038 fCount++;
5042 if (fCount < (_bStexy ? 3.0 : (_bSample ? 2.0 : 1.0)))
5043 PushNoValue();
5044 else
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);
5060 if ( _bPearson )
5062 fSumSqrDeltaX += (fValX - fMeanX) * (fValX - fMeanX);
5063 fSumSqrDeltaY += (fValY - fMeanY) * (fValY - fMeanY);
5068 if ( _bPearson )
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);
5074 else if ( _bStexy )
5075 PushDouble( sqrt( ( fSumSqrDeltaY - fSumDeltaXDeltaY *
5076 fSumDeltaXDeltaY / fSumSqrDeltaX ).get() / (fCount-2)));
5077 else
5078 PushDouble( fSumDeltaXDeltaY.get() / sqrt( fSumSqrDeltaX.get() * fSumSqrDeltaY.get() ));
5080 else
5082 if ( _bSample )
5083 PushDouble( fSumDeltaXDeltaY.get() / ( fCount - 1 ) );
5084 else
5085 PushDouble( fSumDeltaXDeltaY.get() / fCount);
5090 void ScInterpreter::ScRSQ()
5092 // Same as ScPearson()*ScPearson()
5093 ScPearson();
5094 if (nGlobalError != FormulaError::NONE)
5095 return;
5097 switch (GetStackType())
5099 case svDouble:
5101 double fVal = PopDouble();
5102 PushDouble( fVal * fVal);
5104 break;
5105 default:
5106 PopError();
5107 PushNoValue();
5111 void ScInterpreter::ScSTEYX()
5113 CalculatePearsonCovar( true, true, false );
5115 void ScInterpreter::CalculateSlopeIntercept(bool bSlope)
5117 if ( !MustHaveParamCount( GetByte(), 2 ) )
5118 return;
5119 ScMatrixRef pMat1 = GetMatrix();
5120 ScMatrixRef pMat2 = GetMatrix();
5121 if (!pMat1 || !pMat2)
5123 PushIllegalParameter();
5124 return;
5126 SCSIZE nC1, nC2;
5127 SCSIZE nR1, nR2;
5128 pMat1->GetDimensions(nC1, nR1);
5129 pMat2->GetDimensions(nC2, nR2);
5130 if (nR1 != nR2 || nC1 != nC2)
5132 PushIllegalArgument();
5133 return;
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);
5148 fCount++;
5152 if (fCount < 1.0)
5153 PushNoValue();
5154 else
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);
5175 else
5177 if ( bSlope )
5178 PushDouble( fSumDeltaXDeltaY.get() / fSumSqrDeltaX.get());
5179 else
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 ) )
5198 return;
5199 ScMatrixRef pMat1 = GetMatrix();
5200 ScMatrixRef pMat2 = GetMatrix();
5201 if (!pMat1 || !pMat2)
5203 PushIllegalParameter();
5204 return;
5206 SCSIZE nC1, nC2;
5207 SCSIZE nR1, nR2;
5208 pMat1->GetDimensions(nC1, nR1);
5209 pMat2->GetDimensions(nC2, nR2);
5210 if (nR1 != nR2 || nC1 != nC2)
5212 PushIllegalArgument();
5213 return;
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);
5229 fCount++;
5233 if (fCount < 1.0)
5234 PushNoValue();
5235 else
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);
5256 else
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.
5264 SCSIZE nPow2(1);
5265 nNumBits = std::numeric_limits<SCSIZE>::digits;
5266 nPow2 <<= (nNumBits - 1);
5267 while (nPow2 >= 1)
5269 if (nNum & nPow2)
5270 break;
5272 --nNumBits;
5273 nPow2 >>= 1;
5276 if (nPow2 != nNum)
5278 assert(nPow2 < 1UL << (std::numeric_limits<unsigned long>::digits - 1));
5279 nNum = nPow2 ? (nPow2 << 1) : 1;
5281 else
5282 --nNumBits;
5285 static SCSIZE lcl_bitReverse(SCSIZE nIn, SCSIZE nBound)
5287 SCSIZE nOut = 0;
5288 for (SCSIZE nMask = 1; nMask < nBound; nMask <<= 1)
5290 nOut <<= 1;
5292 if (nIn & nMask)
5293 nOut |= 1;
5296 return nOut;
5299 namespace {
5301 // Computes and stores twiddle factors for computing DFT later.
5302 struct ScTwiddleFactors
5304 ScTwiddleFactors(SCSIZE nN, bool bInverse) :
5305 mfWReal(nN),
5306 mfWImag(nN),
5307 mnN(nN),
5308 mbInverse(bInverse)
5311 void Compute();
5313 void Conjugate()
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;
5322 SCSIZE mnN;
5323 bool mbInverse;
5328 void ScTwiddleFactors::Compute()
5330 mfWReal.resize(mnN);
5331 mfWImag.resize(mnN);
5333 double nW = (mbInverse ? 2 : -2)*M_PI/static_cast<double>(mnN);
5335 if (mnN == 1)
5337 mfWReal[0] = 1.0;
5338 mfWImag[0] = 0.0;
5340 else if (mnN == 2)
5342 mfWReal[0] = 1;
5343 mfWImag[0] = 0;
5345 mfWReal[1] = -1;
5346 mfWImag[1] = 0;
5348 else if (mnN == 4)
5350 mfWReal[0] = 1;
5351 mfWImag[0] = 0;
5353 mfWReal[1] = 0;
5354 mfWImag[1] = (mbInverse ? 1.0 : -1.0);
5356 mfWReal[2] = -1;
5357 mfWImag[2] = 0;
5359 mfWReal[3] = 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));
5370 if (mbInverse)
5372 const SCSIZE nQ1End = nQSize;
5373 // First quadrant
5374 for (SCSIZE nIdx = 0; nIdx <= nQ1End; ++nIdx)
5375 mfWImag[nIdx] = mfWReal[nQ1End-nIdx];
5377 // Second quadrant
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];
5385 // Third quadrant
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];
5393 // Fourth Quadrant
5394 for (SCSIZE nIdx = nQ3End+1; nIdx < mnN; ++nIdx)
5396 mfWReal[nIdx] = mfWReal[mnN - nIdx];
5397 mfWImag[nIdx] = -mfWImag[mnN - nIdx];
5400 else
5402 const SCSIZE nQ4End = nQSize;
5403 const SCSIZE nQ3End = nQSize << 1;
5404 const SCSIZE nQ2End = nQ3End + nQSize;
5406 // Fourth quadrant.
5407 for (SCSIZE nIdx = 0; nIdx <= nQ4End; ++nIdx)
5408 mfWImag[nIdx] = -mfWReal[nQ4End - nIdx];
5410 // Third quadrant.
5411 for (SCSIZE nIdx = nQ4End+1; nIdx <= nQ3End; ++nIdx)
5413 mfWReal[nIdx] = -mfWReal[nQ3End - nIdx];
5414 mfWImag[nIdx] = mfWImag[nQ3End - nIdx];
5417 // Second quadrant.
5418 for (SCSIZE nIdx = nQ3End+1; nIdx <= nQ2End; ++nIdx)
5420 mfWReal[nIdx] = -mfWReal[nIdx - nQ3End];
5421 mfWImag[nIdx] = -mfWImag[nIdx - nQ3End];
5424 // First quadrant.
5425 for (SCSIZE nIdx = nQ2End+1; nIdx < mnN; ++nIdx)
5427 mfWReal[nIdx] = mfWReal[mnN - nIdx];
5428 mfWImag[nIdx] = -mfWImag[mnN - nIdx];
5432 else
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);
5443 namespace {
5445 // A radix-2 decimation in time FFT algorithm for complex valued input.
5446 class ScComplexFFT2
5448 public:
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) :
5453 mrArray(raArray),
5454 mfWReal(rTF.mfWReal),
5455 mfWImag(rTF.mfWImag),
5456 mnPoints(raArray.size()/2),
5457 mnStages(0),
5458 mfMinMag(fMinMag),
5459 mbInverse(bInverse),
5460 mbPolar(bPolar),
5461 mbDisableNormalize(bDisableNormalize),
5462 mbSubSampleTFs(bSubSampleTFs)
5465 void Compute();
5467 private:
5469 void prepare();
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)
5498 if (mbSubSampleTFs)
5500 nWIdx1 <<= 1;
5501 nWIdx2 <<= 1;
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;
5526 SCSIZE mnPoints;
5527 SCSIZE mnStages;
5528 double mfMinMag;
5529 bool mbInverse:1;
5530 bool mbPolar:1;
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);
5547 if (nIdx < nRevIdx)
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);
5586 if (fMag < fMinMag)
5588 fMag = 0.0;
5589 fPhase = 0.0;
5591 else
5593 fPhase = atan2(fI, fR);
5596 rCmplxArray[nIdx] = fMag;
5597 rCmplxArray[nPoints+nIdx] = fPhase;
5601 void ScComplexFFT2::Compute()
5603 prepare();
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;
5627 if (mbPolar)
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);
5636 namespace {
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
5642 public:
5644 ScComplexBluesteinFFT(std::vector<double>& rArray, bool bReal, bool bInverse,
5645 bool bPolar, double fMinMag, bool bDisableNormalize = false) :
5646 mrArray(rArray),
5647 mnPoints(rArray.size()/2), // rArray should have space for imaginary parts even if real input.
5648 mfMinMag(fMinMag),
5649 mbReal(bReal),
5650 mbInverse(bInverse),
5651 mbPolar(bPolar),
5652 mbDisableNormalize(bDisableNormalize)
5655 void Compute();
5657 private:
5658 std::vector<double>& mrArray;
5659 const SCSIZE mnPoints;
5660 double mfMinMag;
5661 bool mbReal:1;
5662 bool mbInverse:1;
5663 bool mbPolar:1;
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.
5700 if (nIdx)
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*/);
5710 aTF.Compute();
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 */);
5715 aFFT2A.Compute();
5717 ScComplexFFT2 aFFT2B(aBSignal, false /*not inverse*/, false /*no polar*/, 0.0 /* no clipping */,
5718 aTF, false /*no subsample*/, true /* disable normalize */);
5719 aFFT2B.Compute();
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.
5735 aTF.Conjugate();
5736 ScComplexFFT2 aFFT2AI(aASignal, true /*inverse*/, false /*no polar*/, 0.0 /* no clipping */, aTF); // Need normalization here.
5737 aFFT2AI.Compute();
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
5750 if (mbPolar)
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);
5759 namespace {
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.
5764 class ScRealFFT
5766 public:
5768 ScRealFFT(std::vector<double>& rInArray, std::vector<double>& rOutArray, bool bInverse,
5769 bool bPolar, double fMinMag) :
5770 mrInArray(rInArray),
5771 mrOutArray(rOutArray),
5772 mfMinMag(fMinMag),
5773 mbInverse(bInverse),
5774 mbPolar(bPolar)
5777 void Compute();
5779 private:
5780 std::vector<double>& mrInArray;
5781 std::vector<double>& mrOutArray;
5782 double mfMinMag;
5783 bool mbInverse:1;
5784 bool mbPolar:1;
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;
5797 if (nN == 0)
5799 mrOutArray[0] = mrInArray[0];
5800 mrOutArray[1] = 0.0;
5801 return;
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);
5816 aTFs.Compute();
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*/);
5824 aFFT2.Compute();
5826 else
5828 ScComplexBluesteinFFT aFFT(aWorkArray, false /*complex input*/, mbInverse, false /*disable polar*/,
5829 0.0 /* no clipping */, true /*disable normalize*/);
5830 aFFT.Compute();
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*(
5851 fY1R + fY2R +
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*(
5857 fY1I - fY2I +
5858 fWI * (fY1I + fY2I) -
5859 fWR * (fY1R - fY2R) );
5861 // Fill the missing 2 quarters using symmetry argument.
5862 if (nIdx)
5864 // Fills the 2nd quarter.
5865 mrOutArray[nN + nIdxRev] = fResR;
5866 // Fills the 4th quarter.
5867 mrOutArray[nThreeN + nIdxRev] = -fResI;
5869 else
5871 mrOutArray[nN] = fY1R - fY1I;
5872 mrOutArray[nThreeN] = 0.0;
5876 // Normalize/Polar operations
5877 if (mbPolar)
5878 lcl_convertToPolar(mrOutArray, mfMinMag);
5880 // Normalize after converting to polar, so we have a chance to
5881 // save O(mnPoints) flops.
5882 if (mbInverse)
5883 lcl_normalize(mrOutArray, mbPolar);
5886 using ScMatrixGenerator = ScMatrixRef(SCSIZE, SCSIZE, std::vector<double>&);
5888 namespace {
5890 // Generic FFT class that decides which FFT implementation to use.
5891 class ScFFT
5893 public:
5895 ScFFT(ScMatrixRef& pMat, bool bReal, bool bInverse, bool bPolar, double fMinMag) :
5896 mpInputMat(pMat),
5897 mfMinMag(fMinMag),
5898 mbReal(bReal),
5899 mbInverse(bInverse),
5900 mbPolar(bPolar)
5903 ScMatrixRef Compute(const std::function<ScMatrixGenerator>& rMatGenFunc);
5905 private:
5906 ScMatrixRef& mpInputMat;
5907 double mfMinMag;
5908 bool mbReal:1;
5909 bool mbInverse:1;
5910 bool mbPolar:1;
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);
5920 if (nPoints == 1)
5922 std::vector<double> aOutArray(2);
5923 aOutArray[0] = aArray[0];
5924 aOutArray[1] = mbReal ? 0.0 : aArray[1];
5925 if (mbPolar)
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);
5934 aFFT.Compute();
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);
5943 aTF.Compute();
5944 ScComplexFFT2 aFFT2(aArray, mbInverse, mbPolar, mfMinMag, aTF);
5945 aFFT2.Compute();
5946 return rMatGenFunc(2, nPoints, aArray);
5949 if (mbReal)
5950 aArray.resize(nPoints*2, 0.0);
5951 ScComplexBluesteinFFT aFFT(aArray, mbReal, mbInverse, mbPolar, mfMinMag);
5952 aFFT.Compute();
5953 return rMatGenFunc(2, nPoints, aArray);
5956 void ScInterpreter::ScFourier()
5958 sal_uInt8 nParamCount = GetByte();
5959 if ( !MustHaveParamCount( nParamCount, 2, 5 ) )
5960 return;
5962 bool bInverse = false;
5963 bool bPolar = false;
5964 double fMinMag = 0.0;
5966 if (nParamCount == 5)
5968 if (IsMissing())
5969 Pop();
5970 else
5971 fMinMag = GetDouble();
5974 if (nParamCount >= 4)
5976 if (IsMissing())
5977 Pop();
5978 else
5979 bPolar = GetBool();
5982 if (nParamCount >= 3)
5984 if (IsMissing())
5985 Pop();
5986 else
5987 bInverse = GetBool();
5990 bool bGroupedByColumn = GetBool();
5992 ScMatrixRef pInputMat = GetMatrix();
5993 if (!pInputMat)
5995 PushIllegalParameter();
5996 return;
5999 SCSIZE nC, nR;
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();
6007 return;
6010 if (!pInputMat->IsNumeric())
6012 PushNoValue();
6013 return;
6016 bool bRealInput = true;
6017 if (!bGroupedByColumn)
6019 pInputMat->MatTrans(*pInputMat);
6020 bRealInput = (nR == 1);
6022 else
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);
6033 PushMatrix(pOut);
6036 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */