xref: /core/sc/source/core/tool/interpr6.cxx (revision 08e85556)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <interpre.hxx>
21 #include <columnspanset.hxx>
22 #include <column.hxx>
23 #include <document.hxx>
24 #include <cellvalue.hxx>
25 #include <dociter.hxx>
26 #include <mtvcellfunc.hxx>
27 #include <scmatrix.hxx>
28 
29 #include <arraysumfunctor.hxx>
30 
31 #include <formula/token.hxx>
32 
33 using namespace formula;
34 
35 double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon();
36 
37 // The idea how this group of gamma functions is calculated, is
38 // based on the Cephes library
39 // online http://www.moshier.net/#Cephes [called 2008-02]
40 
41 /** You must ensure fA>0.0 && fX>0.0
42     valid results only if fX > fA+1.0
43     uses continued fraction with odd items */
44 double ScInterpreter::GetGammaContFraction( double fA, double fX )
45 {
46 
47     double const fBigInv = ::std::numeric_limits<double>::epsilon();
48     double const fBig = 1.0/fBigInv;
49     double fCount = 0.0;
50     double fY = 1.0 - fA;
51     double fDenom = fX + 2.0-fA;
52     double fPkm1 = fX + 1.0;
53     double fPkm2 = 1.0;
54     double fQkm1 = fDenom * fX;
55     double fQkm2 = fX;
56     double fApprox = fPkm1/fQkm1;
57     bool bFinished = false;
58     do
59     {
60         fCount = fCount +1.0;
61         fY = fY+ 1.0;
62         const double fNum = fY * fCount;
63         fDenom = fDenom +2.0;
64         double fPk = fPkm1 * fDenom  -  fPkm2 * fNum;
65         const double fQk = fQkm1 * fDenom  -  fQkm2 * fNum;
66         if (fQk != 0.0)
67         {
68             const double fR = fPk/fQk;
69             bFinished = (fabs( (fApprox - fR)/fR ) <= fHalfMachEps);
70             fApprox = fR;
71         }
72         fPkm2 = fPkm1;
73         fPkm1 = fPk;
74         fQkm2 = fQkm1;
75         fQkm1 = fQk;
76         if (fabs(fPk) > fBig)
77         {
78             // reduce a fraction does not change the value
79             fPkm2 = fPkm2 * fBigInv;
80             fPkm1 = fPkm1 * fBigInv;
81             fQkm2 = fQkm2 * fBigInv;
82             fQkm1 = fQkm1 * fBigInv;
83         }
84     } while (!bFinished && fCount<10000);
85     // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
86     if (!bFinished)
87     {
88         SetError(FormulaError::NoConvergence);
89     }
90     return fApprox;
91 }
92 
93 /** You must ensure fA>0.0 && fX>0.0
94     valid results only if fX <= fA+1.0
95     uses power series */
96 double ScInterpreter::GetGammaSeries( double fA, double fX )
97 {
98     double fDenomfactor = fA;
99     double fSummand = 1.0/fA;
100     double fSum = fSummand;
101     int nCount=1;
102     do
103     {
104         fDenomfactor = fDenomfactor + 1.0;
105         fSummand = fSummand * fX/fDenomfactor;
106         fSum = fSum + fSummand;
107         nCount = nCount+1;
108     } while ( fSummand/fSum > fHalfMachEps && nCount<=10000);
109     // large amount of iterations will be carried out for huge fAlpha, even
110     // if fX <= fAlpha+1.0
111     if (nCount>10000)
112     {
113         SetError(FormulaError::NoConvergence);
114     }
115     return fSum;
116 }
117 
118 /** You must ensure fA>0.0 && fX>0.0) */
119 double ScInterpreter::GetLowRegIGamma( double fA, double fX )
120 {
121     double fLnFactor = fA * log(fX) - fX - GetLogGamma(fA);
122     double fFactor = exp(fLnFactor);    // Do we need more accuracy than exp(ln()) has?
123     if (fX>fA+1.0)  // includes fX>1.0; 1-GetUpRegIGamma, continued fraction
124         return 1.0 - fFactor * GetGammaContFraction(fA,fX);
125     else            // fX<=1.0 || fX<=fA+1.0, series
126         return fFactor * GetGammaSeries(fA,fX);
127 }
128 
129 /** You must ensure fA>0.0 && fX>0.0) */
130 double ScInterpreter::GetUpRegIGamma( double fA, double fX )
131 {
132 
133     double fLnFactor= fA*log(fX)-fX-GetLogGamma(fA);
134     double fFactor = exp(fLnFactor); //Do I need more accuracy than exp(ln()) has?;
135     if (fX>fA+1.0) // includes fX>1.0
136             return fFactor * GetGammaContFraction(fA,fX);
137     else //fX<=1 || fX<=fA+1, 1-GetLowRegIGamma, series
138             return 1.0 -fFactor * GetGammaSeries(fA,fX);
139 }
140 
141 /** Gamma distribution, probability density function.
142     fLambda is "scale" parameter
143     You must ensure fAlpha>0.0 and fLambda>0.0 */
144 double ScInterpreter::GetGammaDistPDF( double fX, double fAlpha, double fLambda )
145 {
146     if (fX < 0.0)
147         return 0.0;     // see ODFF
148     else if (fX == 0)
149         // in this case 0^0 isn't zero
150     {
151         if (fAlpha < 1.0)
152         {
153             SetError(FormulaError::DivisionByZero);  // should be #DIV/0
154             return HUGE_VAL;
155         }
156         else if (fAlpha == 1)
157         {
158             return (1.0 / fLambda);
159         }
160         else
161         {
162             return 0.0;
163         }
164     }
165     else
166     {
167         double fXr = fX / fLambda;
168         // use exp(ln()) only for large arguments because of less accuracy
169         if (fXr > 1.0)
170         {
171             const double fLogDblMax = log( ::std::numeric_limits<double>::max());
172             if (log(fXr) * (fAlpha-1.0) < fLogDblMax && fAlpha < fMaxGammaArgument)
173             {
174                 return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
175             }
176             else
177             {
178                 return exp( (fAlpha-1.0) * log(fXr) - fXr - log(fLambda) - GetLogGamma(fAlpha));
179             }
180         }
181         else    // fXr near to zero
182         {
183             if (fAlpha<fMaxGammaArgument)
184             {
185                 return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / GetGamma(fAlpha);
186             }
187             else
188             {
189                 return pow( fXr, fAlpha-1.0) * exp(-fXr) / fLambda / exp( GetLogGamma(fAlpha));
190             }
191         }
192     }
193 }
194 
195 /** Gamma distribution, cumulative distribution function.
196     fLambda is "scale" parameter
197     You must ensure fAlpha>0.0 and fLambda>0.0 */
198 double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
199 {
200     if (fX <= 0.0)
201         return 0.0;
202     else
203         return GetLowRegIGamma( fAlpha, fX / fLambda);
204 }
205 
206 namespace {
207 
208 class NumericCellAccumulator
209 {
210     double mfFirst;
211     double mfRest;
212     FormulaError mnError;
213 
214 public:
215     NumericCellAccumulator() : mfFirst(0.0), mfRest(0.0), mnError(FormulaError::NONE) {}
216 
217     void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
218     {
219         switch (rNode.type)
220         {
221             case sc::element_type_numeric:
222             {
223                 const double *p = &sc::numeric_block::at(*rNode.data, nOffset);
224                 size_t i = 0;
225 
226                 // Store the first non-zero value in mfFirst (for some reason).
227                 if (!mfFirst)
228                 {
229                     for (i = 0; i < nDataSize; ++i)
230                     {
231                         if (!mfFirst)
232                             mfFirst = p[i];
233                         else
234                             break;
235                     }
236                 }
237                 p += i;
238                 nDataSize -= i;
239                 if (nDataSize == 0)
240                     return;
241 
242                 sc::ArraySumFunctor functor(p, nDataSize);
243 
244                 mfRest += functor();
245                 break;
246             }
247 
248             case sc::element_type_formula:
249             {
250                 sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
251                 std::advance(it, nOffset);
252                 sc::formula_block::const_iterator itEnd = it;
253                 std::advance(itEnd, nDataSize);
254                 for (; it != itEnd; ++it)
255                 {
256                     double fVal = 0.0;
257                     FormulaError nErr = FormulaError::NONE;
258                     ScFormulaCell& rCell = *(*it);
259                     if (!rCell.GetErrorOrValue(nErr, fVal))
260                         // The cell has neither error nor value.  Perhaps string result.
261                         continue;
262 
263                     if (nErr != FormulaError::NONE)
264                     {
265                         // Cell has error - skip all the rest
266                         mnError = nErr;
267                         return;
268                     }
269 
270                     if ( !mfFirst )
271                         mfFirst = fVal;
272                     else
273                         mfRest += fVal;
274                 }
275             }
276             break;
277             default:
278                 ;
279         }
280     }
281 
282     FormulaError getError() const { return mnError; }
283     double getFirst() const { return mfFirst; }
284     double getRest() const { return mfRest; }
285 };
286 
287 class NumericCellCounter
288 {
289     size_t mnCount;
290 public:
291     NumericCellCounter() : mnCount(0) {}
292 
293     void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
294     {
295         switch (rNode.type)
296         {
297             case sc::element_type_numeric:
298                 mnCount += nDataSize;
299             break;
300             case sc::element_type_formula:
301             {
302                 sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
303                 std::advance(it, nOffset);
304                 sc::formula_block::const_iterator itEnd = it;
305                 std::advance(itEnd, nDataSize);
306                 for (; it != itEnd; ++it)
307                 {
308                     ScFormulaCell& rCell = **it;
309                     if (rCell.IsValueNoError())
310                         ++mnCount;
311                 }
312             }
313             break;
314             default:
315                 ;
316         }
317     }
318 
319     size_t getCount() const { return mnCount; }
320 };
321 
322 class FuncCount : public sc::ColumnSpanSet::ColumnAction
323 {
324     const ScInterpreterContext& mrContext;
325     sc::ColumnBlockConstPosition maPos;
326     ScColumn* mpCol;
327     size_t mnCount;
328     sal_uInt32 mnNumFmt;
329 
330 public:
331     FuncCount(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mnCount(0), mnNumFmt(0) {}
332 
333     virtual void startColumn(ScColumn* pCol) override
334     {
335         mpCol = pCol;
336         mpCol->InitBlockPosition(maPos);
337     }
338 
339     virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) override
340     {
341         if (!bVal)
342             return;
343 
344         NumericCellCounter aFunc;
345         maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
346         mnCount += aFunc.getCount();
347         mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
348     };
349 
350     size_t getCount() const { return mnCount; }
351     sal_uInt32 getNumberFormat() const { return mnNumFmt; }
352 };
353 
354 class FuncSum : public sc::ColumnSpanSet::ColumnAction
355 {
356     const ScInterpreterContext& mrContext;
357     sc::ColumnBlockConstPosition maPos;
358     ScColumn* mpCol;
359     double mfSum;
360     FormulaError mnError;
361     sal_uInt32 mnNumFmt;
362 
363 public:
364     FuncSum(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE), mnNumFmt(0) {}
365 
366     virtual void startColumn(ScColumn* pCol) override
367     {
368         mpCol = pCol;
369         mpCol->InitBlockPosition(maPos);
370     }
371 
372     virtual void execute(SCROW, SCROW, bool) override {}
373 
374     virtual void executeSum(SCROW nRow1, SCROW nRow2, bool bVal, double& fMem ) override
375     {
376         if (!bVal)
377             return;
378 
379         if (mnError != FormulaError::NONE)
380             return;
381 
382         NumericCellAccumulator aFunc;
383         maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
384         mnError = aFunc.getError();
385         if (mnError != FormulaError::NONE)
386             return;
387 
388         if ( fMem )
389             mfSum += aFunc.getFirst() + aFunc.getRest();
390         else
391         {
392             fMem = aFunc.getFirst();
393             mfSum += aFunc.getRest();
394         }
395 
396         mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
397     };
398 
399     FormulaError getError() const { return mnError; }
400     double getSum() const { return mfSum; }
401     sal_uInt32 getNumberFormat() const { return mnNumFmt; }
402 };
403 
404 }
405 
406 static void IterateMatrix(
407     const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags,
408     sal_uLong& rCount, SvNumFormatType& rFuncFmtType, double& fRes, double& fMem )
409 {
410     if (!pMat)
411         return;
412 
413     const bool bIgnoreErrVal = bool(nSubTotalFlags & SubtotalFlags::IgnoreErrVal);
414     rFuncFmtType = SvNumFormatType::NUMBER;
415     switch (eFunc)
416     {
417         case ifAVERAGE:
418         case ifSUM:
419         {
420             ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero, bIgnoreErrVal);
421             // If the first value is a NaN, it probably means it was an empty cell,
422             // and should be treated as zero.
423             if ( !std::isfinite(aRes.mfFirst) )
424             {
425                 sal_uInt32 nErr = reinterpret_cast< sal_math_Double * >(&aRes.mfFirst)->nan_parts.fraction_lo;
426                 if (nErr & 0xffff0000)
427                 {
428                     aRes.mfFirst = 0;
429                 }
430             }
431             if ( fMem )
432                 fRes += aRes.mfFirst + aRes.mfRest;
433             else
434             {
435                 fMem = aRes.mfFirst;
436                 fRes += aRes.mfRest;
437             }
438             rCount += aRes.mnCount;
439         }
440         break;
441         case ifCOUNT:
442             rCount += pMat->Count(bTextAsZero, false);  // do not count error values
443         break;
444         case ifCOUNT2:
445             /* TODO: what is this supposed to be with bIgnoreErrVal? */
446             rCount += pMat->Count(true, true);          // do count error values
447         break;
448         case ifPRODUCT:
449         {
450             ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero, bIgnoreErrVal);
451             fRes *= aRes.mfFirst;
452             fRes *= aRes.mfRest;
453             rCount += aRes.mnCount;
454         }
455         break;
456         case ifSUMSQ:
457         {
458             ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero, bIgnoreErrVal);
459             fRes += aRes.mfFirst;
460             fRes += aRes.mfRest;
461             rCount += aRes.mnCount;
462         }
463         break;
464         default:
465             ;
466     }
467 }
468 
469 size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount )
470 {
471     size_t nSize = 0;
472     if (IsInArrayContext())
473     {
474         for (short i=1; i <= nParamCount; ++i)
475         {
476             if (GetStackType(i) == svRefList)
477             {
478                 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
479                 if (p && p->IsArrayResult() && p->GetRefList()->size() > nSize)
480                     nSize = p->GetRefList()->size();
481             }
482         }
483     }
484     return nSize;
485 }
486 
487 static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
488 {
489     switch( eFunc )
490     {
491         case ifSUM:
492             fRes = ::rtl::math::approxAdd( fRes, fMem );
493         break;
494         case ifAVERAGE:
495             fRes = sc::div( ::rtl::math::approxAdd( fRes, fMem ), nCount);
496         break;
497         case ifCOUNT2:
498         case ifCOUNT:
499             fRes = nCount;
500         break;
501         case ifPRODUCT:
502             if ( !nCount )
503                 fRes = 0.0;
504         break;
505         default:
506             ; // nothing
507     }
508     return fRes;
509 }
510 
511 void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
512 {
513     short nParamCount = GetByte();
514     const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
515     ScMatrixRef xResMat, xResCount;
516     auto ResInitVal = [eFunc]()
517     {
518         return (eFunc == ifPRODUCT) ? 1.0 : 0.0;
519     };
520     double fRes = ResInitVal();
521     double fVal = 0.0;
522     double fMem = 0.0;  // first numeric value != 0.0
523     sal_uLong nCount = 0;
524     ScAddress aAdr;
525     ScRange aRange;
526     size_t nRefInList = 0;
527     size_t nRefArrayPos = std::numeric_limits<size_t>::max();
528     if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
529          ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
530         nGlobalError = FormulaError::NONE;
531     while (nParamCount-- > 0)
532     {
533         switch (GetStackType())
534         {
535             case svString:
536             {
537                 if( eFunc == ifCOUNT )
538                 {
539                     OUString aStr = PopString().getString();
540                     if ( bTextAsZero )
541                         nCount++;
542                     else
543                     {
544                         // Only check if string can be converted to number, no
545                         // error propagation.
546                         FormulaError nErr = nGlobalError;
547                         nGlobalError = FormulaError::NONE;
548                         ConvertStringToValue( aStr );
549                         if (nGlobalError == FormulaError::NONE)
550                             ++nCount;
551                         nGlobalError = nErr;
552                     }
553                 }
554                 else
555                 {
556                     Pop();
557                     switch ( eFunc )
558                     {
559                         case ifAVERAGE:
560                         case ifSUM:
561                         case ifSUMSQ:
562                         case ifPRODUCT:
563                         {
564                             if ( bTextAsZero )
565                             {
566                                 nCount++;
567                                 if ( eFunc == ifPRODUCT )
568                                     fRes = 0.0;
569                             }
570                             else
571                             {
572                                 while (nParamCount-- > 0)
573                                     Pop();
574                                 SetError( FormulaError::NoValue );
575                             }
576                         }
577                         break;
578                         default:
579                             nCount++;
580                     }
581                 }
582             }
583             break;
584             case svDouble    :
585                 fVal = GetDouble();
586                 nCount++;
587                 switch( eFunc )
588                 {
589                     case ifAVERAGE:
590                     case ifSUM:
591                         if ( fMem )
592                             fRes += fVal;
593                         else
594                             fMem = fVal;
595                         break;
596                     case ifSUMSQ:   fRes += fVal * fVal; break;
597                     case ifPRODUCT: fRes *= fVal; break;
598                     default: ; // nothing
599                 }
600                 nFuncFmtType = SvNumFormatType::NUMBER;
601                 break;
602             case svExternalSingleRef:
603             {
604                 ScExternalRefCache::TokenRef pToken;
605                 ScExternalRefCache::CellFormat aFmt;
606                 PopExternalSingleRef(pToken, &aFmt);
607                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
608                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
609                 {
610                     nGlobalError = FormulaError::NONE;
611                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
612                         ++nCount;
613                     break;
614                 }
615 
616                 if (!pToken)
617                     break;
618 
619                 StackVar eType = pToken->GetType();
620                 if (eFunc == ifCOUNT2)
621                 {
622                     if ( eType != svEmptyCell &&
623                          ( ( pToken->GetOpCode() != ocSubTotal &&
624                              pToken->GetOpCode() != ocAggregate ) ||
625                            ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) )
626                         nCount++;
627                     if (nGlobalError != FormulaError::NONE)
628                         nGlobalError = FormulaError::NONE;
629                 }
630                 else if (eType == svDouble)
631                 {
632                     nCount++;
633                     fVal = pToken->GetDouble();
634                     if (aFmt.mbIsSet)
635                     {
636                         nFuncFmtType = aFmt.mnType;
637                         nFuncFmtIndex = aFmt.mnIndex;
638                     }
639                     switch( eFunc )
640                     {
641                         case ifAVERAGE:
642                         case ifSUM:
643                             if ( fMem )
644                                 fRes += fVal;
645                             else
646                                 fMem = fVal;
647                             break;
648                         case ifSUMSQ:   fRes += fVal * fVal; break;
649                         case ifPRODUCT: fRes *= fVal; break;
650                         case ifCOUNT:
651                             if ( nGlobalError != FormulaError::NONE )
652                             {
653                                 nGlobalError = FormulaError::NONE;
654                                 nCount--;
655                             }
656                             break;
657                         default: ; // nothing
658                     }
659                 }
660                 else if (bTextAsZero && eType == svString)
661                 {
662                     nCount++;
663                     if ( eFunc == ifPRODUCT )
664                         fRes = 0.0;
665                 }
666             }
667             break;
668             case svSingleRef :
669             {
670                 PopSingleRef( aAdr );
671                 if (nGlobalError == FormulaError::NoRef)
672                 {
673                     PushError( FormulaError::NoRef);
674                     return;
675                 }
676 
677                 if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreFiltered ) &&
678                      mrDoc.RowFiltered( aAdr.Row(), aAdr.Tab() ) ) ||
679                      ( ( mnSubTotalFlags & SubtotalFlags::IgnoreHidden ) &&
680                        mrDoc.RowHidden( aAdr.Row(), aAdr.Tab() ) ) )
681                 {
682                     break;
683                 }
684                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
685                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
686                 {
687                     nGlobalError = FormulaError::NONE;
688                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
689                         ++nCount;
690                     break;
691                 }
692                 ScRefCellValue aCell(mrDoc, aAdr);
693                 if (!aCell.isEmpty())
694                 {
695                     if( eFunc == ifCOUNT2 )
696                     {
697                         CellType eCellType = aCell.meType;
698                         if ( eCellType != CELLTYPE_NONE )
699                             nCount++;
700                         if ( nGlobalError != FormulaError::NONE )
701                             nGlobalError = FormulaError::NONE;
702                     }
703                     else if (aCell.hasNumeric())
704                     {
705                         nCount++;
706                         fVal = GetCellValue(aAdr, aCell);
707                         CurFmtToFuncFmt();
708                         switch( eFunc )
709                         {
710                             case ifAVERAGE:
711                             case ifSUM:
712                                 if ( fMem )
713                                     fRes += fVal;
714                                 else
715                                     fMem = fVal;
716                                 break;
717                             case ifSUMSQ:   fRes += fVal * fVal; break;
718                             case ifPRODUCT: fRes *= fVal; break;
719                             case ifCOUNT:
720                                 if ( nGlobalError != FormulaError::NONE )
721                                 {
722                                     nGlobalError = FormulaError::NONE;
723                                     nCount--;
724                                 }
725                                 break;
726                             default: ; // nothing
727                         }
728                     }
729                     else if (bTextAsZero && aCell.hasString())
730                     {
731                         nCount++;
732                         if ( eFunc == ifPRODUCT )
733                             fRes = 0.0;
734                     }
735                 }
736             }
737             break;
738             case svRefList :
739             {
740                 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
741                 if (p && p->IsArrayResult())
742                 {
743                     nRefArrayPos = nRefInList;
744                     if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
745                     {
746                         fRes = rtl::math::approxAdd( fRes, fMem);
747                         fMem = 0.0;
748                     }
749                     // The "one value to all references of an array" seems to
750                     // be what Excel does if there are other types than just
751                     // arrays of references.
752                     if (!xResMat)
753                     {
754                         // Create and init all elements with current value.
755                         assert(nMatRows > 0);
756                         xResMat = GetNewMat( 1, nMatRows, true);
757                         xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1);
758                         if (eFunc != ifSUM)
759                         {
760                             xResCount = GetNewMat( 1, nMatRows, true);
761                             xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1);
762                         }
763                     }
764                     else
765                     {
766                         // Current value and values from vector are operands
767                         // for each vector position.
768                         if (nCount && xResCount)
769                         {
770                             for (SCSIZE i=0; i < nMatRows; ++i)
771                             {
772                                 xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i);
773                             }
774                         }
775                         if (fRes != ResInitVal())
776                         {
777                             for (SCSIZE i=0; i < nMatRows; ++i)
778                             {
779                                 double fVecRes = xResMat->GetDouble(0,i);
780                                 if (eFunc == ifPRODUCT)
781                                     fVecRes *= fRes;
782                                 else
783                                     fVecRes += fRes;
784                                 xResMat->PutDouble( fVecRes, 0,i);
785                             }
786                         }
787                     }
788                     fRes = ResInitVal();
789                     nCount = 0;
790                 }
791             }
792             [[fallthrough]];
793             case svDoubleRef :
794             {
795                 PopDoubleRef( aRange, nParamCount, nRefInList);
796                 if (nGlobalError == FormulaError::NoRef)
797                 {
798                     PushError( FormulaError::NoRef);
799                     return;
800                 }
801 
802                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
803                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
804                 {
805                     nGlobalError = FormulaError::NONE;
806                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
807                         ++nCount;
808                     if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT )
809                         break;
810                 }
811                 if( eFunc == ifCOUNT2 )
812                 {
813                     ScCellIterator aIter( mrDoc, aRange, mnSubTotalFlags );
814                     for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
815                     {
816                         if ( !aIter.isEmpty() )
817                         {
818                             ++nCount;
819                         }
820                     }
821 
822                     if ( nGlobalError != FormulaError::NONE )
823                         nGlobalError = FormulaError::NONE;
824                 }
825                 else if (((eFunc == ifSUM && !bCalcAsShown) || eFunc == ifCOUNT )
826                         && mnSubTotalFlags == SubtotalFlags::NONE)
827                 {
828                     // Use fast span set array method.
829                     // ifSUM with bCalcAsShown has to use the slow bells and
830                     // whistles ScValueIterator below.
831                     sc::RangeColumnSpanSet aSet( aRange );
832 
833                     if ( eFunc == ifSUM )
834                     {
835                         FuncSum aAction(mrContext);
836                         aSet.executeColumnAction( mrDoc, aAction, fMem );
837                         FormulaError nErr = aAction.getError();
838                         if ( nErr != FormulaError::NONE )
839                         {
840                             PushError( nErr );
841                             return;
842                         }
843                         fRes += aAction.getSum();
844 
845                         // Get the number format of the last iterated cell.
846                         nFuncFmtIndex = aAction.getNumberFormat();
847                     }
848                     else
849                     {
850                         FuncCount aAction(mrContext);
851                         aSet.executeColumnAction(mrDoc, aAction);
852                         nCount += aAction.getCount();
853 
854                         // Get the number format of the last iterated cell.
855                         nFuncFmtIndex = aAction.getNumberFormat();
856                     }
857 
858                     nFuncFmtType = mrContext.GetNumberFormatType( nFuncFmtIndex );
859                 }
860                 else
861                 {
862                     ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags, bTextAsZero );
863                     aValIter.SetInterpreterContext( &mrContext );
864                     FormulaError nErr = FormulaError::NONE;
865                     if (aValIter.GetFirst(fVal, nErr))
866                     {
867                         // placed the loop on the inside for performance reasons:
868                         aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
869                         switch( eFunc )
870                         {
871                             case ifAVERAGE:
872                             case ifSUM:
873                                     if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
874                                     {
875                                         do
876                                         {
877                                             if ( nErr == FormulaError::NONE )
878                                             {
879                                                 SetError(nErr);
880                                                 if ( fMem )
881                                                     fRes += fVal;
882                                                 else
883                                                     fMem = fVal;
884                                                 nCount++;
885                                             }
886                                         }
887                                         while (aValIter.GetNext(fVal, nErr));
888                                     }
889                                     else
890                                     {
891                                         do
892                                         {
893                                             SetError(nErr);
894                                             if ( fMem )
895                                                 fRes += fVal;
896                                             else
897                                                 fMem = fVal;
898                                             nCount++;
899                                         }
900                                         while (aValIter.GetNext(fVal, nErr));
901                                     }
902                                     break;
903                             case ifSUMSQ:
904                                     if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
905                                     {
906                                         do
907                                         {
908                                             if ( nErr == FormulaError::NONE )
909                                             {
910                                                 SetError(nErr);
911                                                 fRes += fVal * fVal;
912                                                 nCount++;
913                                             }
914                                         }
915                                         while (aValIter.GetNext(fVal, nErr));
916                                     }
917                                     else
918                                     {
919                                         do
920                                         {
921                                             SetError(nErr);
922                                             fRes += fVal * fVal;
923                                             nCount++;
924                                         }
925                                         while (aValIter.GetNext(fVal, nErr));
926                                     }
927                                     break;
928                             case ifPRODUCT:
929                                     do
930                                     {
931                                         if ( !( nErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
932                                         {
933                                             SetError(nErr);
934                                             fRes *= fVal;
935                                             nCount++;
936                                         }
937                                     }
938                                     while (aValIter.GetNext(fVal, nErr));
939                                     break;
940                             case ifCOUNT:
941                                     do
942                                     {
943                                         if ( nErr == FormulaError::NONE )
944                                             nCount++;
945                                     }
946                                     while (aValIter.GetNext(fVal, nErr));
947                                     break;
948                             default: ;  // nothing
949                         }
950                         SetError( nErr );
951                     }
952                 }
953                 if (nRefArrayPos != std::numeric_limits<size_t>::max())
954                 {
955                     // Update vector element with current value.
956                     if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
957                     {
958                         fRes = rtl::math::approxAdd( fRes, fMem);
959                         fMem = 0.0;
960                     }
961                     if (xResCount)
962                         xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
963                     double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
964                     if (eFunc == ifPRODUCT)
965                         fVecRes *= fRes;
966                     else
967                         fVecRes += fRes;
968                     xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
969                     // Reset.
970                     fRes = ResInitVal();
971                     nCount = 0;
972                     nRefArrayPos = std::numeric_limits<size_t>::max();
973                 }
974             }
975             break;
976             case svExternalDoubleRef:
977             {
978                 ScMatrixRef pMat;
979                 PopExternalDoubleRef(pMat);
980                 if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
981                     break;
982 
983                 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
984             }
985             break;
986             case svMatrix :
987             {
988                 ScMatrixRef pMat = PopMatrix();
989 
990                 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
991             }
992             break;
993             case svError:
994             {
995                 PopError();
996                 if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
997                 {
998                     nGlobalError = FormulaError::NONE;
999                 }
1000                 else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
1001                 {
1002                     nCount++;
1003                     nGlobalError = FormulaError::NONE;
1004                 }
1005             }
1006             break;
1007             default :
1008                 while (nParamCount-- > 0)
1009                     PopError();
1010                 SetError(FormulaError::IllegalParameter);
1011         }
1012     }
1013 
1014     // A boolean return type makes no sense on sums et al.
1015     // Counts are always numbers.
1016     if( nFuncFmtType == SvNumFormatType::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
1017         nFuncFmtType = SvNumFormatType::NUMBER;
1018 
1019     if (xResMat)
1020     {
1021         // Include value of last non-references-array type and calculate final result.
1022         for (SCSIZE i=0; i < nMatRows; ++i)
1023         {
1024             sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount);
1025             double fVecRes = xResMat->GetDouble(0,i);
1026             if (eFunc == ifPRODUCT)
1027                 fVecRes *= fRes;
1028             else
1029                 fVecRes += fRes;
1030             fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nVecCount);
1031             xResMat->PutDouble( fVecRes, 0,i);
1032         }
1033         PushMatrix( xResMat);
1034     }
1035     else
1036     {
1037         PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount));
1038     }
1039 }
1040 
1041 void ScInterpreter::ScSumSQ()
1042 {
1043     IterateParameters( ifSUMSQ );
1044 }
1045 
1046 void ScInterpreter::ScSum()
1047 {
1048     IterateParameters( ifSUM );
1049 }
1050 
1051 void ScInterpreter::ScProduct()
1052 {
1053     IterateParameters( ifPRODUCT );
1054 }
1055 
1056 void ScInterpreter::ScAverage( bool bTextAsZero )
1057 {
1058     IterateParameters( ifAVERAGE, bTextAsZero );
1059 }
1060 
1061 void ScInterpreter::ScCount()
1062 {
1063     IterateParameters( ifCOUNT );
1064 }
1065 
1066 void ScInterpreter::ScCount2()
1067 {
1068     IterateParameters( ifCOUNT2 );
1069 }
1070 
1071 void ScInterpreter::ScRawSubtract()
1072 {
1073     short nParamCount = GetByte();
1074     if (!MustHaveParamCountMin( nParamCount, 2))
1075         return;
1076 
1077     // Fish the 1st parameter from the stack and push it on top.
1078     const FormulaToken* p = pStack[ sp - nParamCount ];
1079     PushWithoutError( *p );
1080     // Obtain the minuend.
1081     double fRes = GetDouble();
1082 
1083     while (nGlobalError == FormulaError::NONE && nParamCount > 1)
1084     {
1085         // Simple single values without matrix support.
1086         fRes -= GetDouble();
1087         --nParamCount;
1088     }
1089     while (nParamCount-- > 0)
1090         PopError();
1091 
1092     PushDouble( fRes);
1093 }
1094 
1095 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1096