xref: /core/sc/source/core/tool/interpr6.cxx (revision f3fc16f4)
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 <mtvfunctions.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     const double ResInitVal = (eFunc == ifPRODUCT) ? 1.0 : 0.0;
517     double fRes = ResInitVal;
518     double fVal = 0.0;
519     double fMem = 0.0;  // first numeric value != 0.0
520     sal_uLong nCount = 0;
521     ScAddress aAdr;
522     ScRange aRange;
523     size_t nRefInList = 0;
524     size_t nRefArrayPos = std::numeric_limits<size_t>::max();
525     if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
526          ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
527         nGlobalError = FormulaError::NONE;
528     while (nParamCount-- > 0)
529     {
530         switch (GetStackType())
531         {
532             case svString:
533             {
534                 if( eFunc == ifCOUNT )
535                 {
536                     OUString aStr = PopString().getString();
537                     if ( bTextAsZero )
538                         nCount++;
539                     else
540                     {
541                         // Only check if string can be converted to number, no
542                         // error propagation.
543                         FormulaError nErr = nGlobalError;
544                         nGlobalError = FormulaError::NONE;
545                         ConvertStringToValue( aStr );
546                         if (nGlobalError == FormulaError::NONE)
547                             ++nCount;
548                         nGlobalError = nErr;
549                     }
550                 }
551                 else
552                 {
553                     Pop();
554                     switch ( eFunc )
555                     {
556                         case ifAVERAGE:
557                         case ifSUM:
558                         case ifSUMSQ:
559                         case ifPRODUCT:
560                         {
561                             if ( bTextAsZero )
562                             {
563                                 nCount++;
564                                 if ( eFunc == ifPRODUCT )
565                                     fRes = 0.0;
566                             }
567                             else
568                             {
569                                 while (nParamCount-- > 0)
570                                     Pop();
571                                 SetError( FormulaError::NoValue );
572                             }
573                         }
574                         break;
575                         default:
576                             nCount++;
577                     }
578                 }
579             }
580             break;
581             case svDouble    :
582                 fVal = GetDouble();
583                 nCount++;
584                 switch( eFunc )
585                 {
586                     case ifAVERAGE:
587                     case ifSUM:
588                         if ( fMem )
589                             fRes += fVal;
590                         else
591                             fMem = fVal;
592                         break;
593                     case ifSUMSQ:   fRes += fVal * fVal; break;
594                     case ifPRODUCT: fRes *= fVal; break;
595                     default: ; // nothing
596                 }
597                 nFuncFmtType = SvNumFormatType::NUMBER;
598                 break;
599             case svExternalSingleRef:
600             {
601                 ScExternalRefCache::TokenRef pToken;
602                 ScExternalRefCache::CellFormat aFmt;
603                 PopExternalSingleRef(pToken, &aFmt);
604                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
605                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
606                 {
607                     nGlobalError = FormulaError::NONE;
608                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
609                         ++nCount;
610                     break;
611                 }
612 
613                 if (!pToken)
614                     break;
615 
616                 StackVar eType = pToken->GetType();
617                 if (eFunc == ifCOUNT2)
618                 {
619                     if ( eType != svEmptyCell &&
620                          ( ( pToken->GetOpCode() != ocSubTotal &&
621                              pToken->GetOpCode() != ocAggregate ) ||
622                            ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) )
623                         nCount++;
624                     if (nGlobalError != FormulaError::NONE)
625                         nGlobalError = FormulaError::NONE;
626                 }
627                 else if (eType == svDouble)
628                 {
629                     nCount++;
630                     fVal = pToken->GetDouble();
631                     if (aFmt.mbIsSet)
632                     {
633                         nFuncFmtType = aFmt.mnType;
634                         nFuncFmtIndex = aFmt.mnIndex;
635                     }
636                     switch( eFunc )
637                     {
638                         case ifAVERAGE:
639                         case ifSUM:
640                             if ( fMem )
641                                 fRes += fVal;
642                             else
643                                 fMem = fVal;
644                             break;
645                         case ifSUMSQ:   fRes += fVal * fVal; break;
646                         case ifPRODUCT: fRes *= fVal; break;
647                         case ifCOUNT:
648                             if ( nGlobalError != FormulaError::NONE )
649                             {
650                                 nGlobalError = FormulaError::NONE;
651                                 nCount--;
652                             }
653                             break;
654                         default: ; // nothing
655                     }
656                 }
657                 else if (bTextAsZero && eType == svString)
658                 {
659                     nCount++;
660                     if ( eFunc == ifPRODUCT )
661                         fRes = 0.0;
662                 }
663             }
664             break;
665             case svSingleRef :
666             {
667                 PopSingleRef( aAdr );
668                 if (nGlobalError == FormulaError::NoRef)
669                 {
670                     PushError( FormulaError::NoRef);
671                     return;
672                 }
673 
674                 if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreFiltered ) &&
675                      mrDoc.RowFiltered( aAdr.Row(), aAdr.Tab() ) ) ||
676                      ( ( mnSubTotalFlags & SubtotalFlags::IgnoreHidden ) &&
677                        mrDoc.RowHidden( aAdr.Row(), aAdr.Tab() ) ) )
678                 {
679                     break;
680                 }
681                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
682                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
683                 {
684                     nGlobalError = FormulaError::NONE;
685                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
686                         ++nCount;
687                     break;
688                 }
689                 ScRefCellValue aCell(mrDoc, aAdr);
690                 if (!aCell.isEmpty())
691                 {
692                     if( eFunc == ifCOUNT2 )
693                     {
694                         CellType eCellType = aCell.meType;
695                         if ( eCellType != CELLTYPE_NONE )
696                             nCount++;
697                         if ( nGlobalError != FormulaError::NONE )
698                             nGlobalError = FormulaError::NONE;
699                     }
700                     else if (aCell.hasNumeric())
701                     {
702                         nCount++;
703                         fVal = GetCellValue(aAdr, aCell);
704                         CurFmtToFuncFmt();
705                         switch( eFunc )
706                         {
707                             case ifAVERAGE:
708                             case ifSUM:
709                                 if ( fMem )
710                                     fRes += fVal;
711                                 else
712                                     fMem = fVal;
713                                 break;
714                             case ifSUMSQ:   fRes += fVal * fVal; break;
715                             case ifPRODUCT: fRes *= fVal; break;
716                             case ifCOUNT:
717                                 if ( nGlobalError != FormulaError::NONE )
718                                 {
719                                     nGlobalError = FormulaError::NONE;
720                                     nCount--;
721                                 }
722                                 break;
723                             default: ; // nothing
724                         }
725                     }
726                     else if (bTextAsZero && aCell.hasString())
727                     {
728                         nCount++;
729                         if ( eFunc == ifPRODUCT )
730                             fRes = 0.0;
731                     }
732                 }
733             }
734             break;
735             case svRefList :
736             {
737                 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
738                 if (p && p->IsArrayResult())
739                 {
740                     nRefArrayPos = nRefInList;
741                     if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
742                     {
743                         fRes = rtl::math::approxAdd( fRes, fMem);
744                         fMem = 0.0;
745                     }
746                     // The "one value to all references of an array" seems to
747                     // be what Excel does if there are other types than just
748                     // arrays of references.
749                     if (!xResMat)
750                     {
751                         // Create and init all elements with current value.
752                         assert(nMatRows > 0);
753                         xResMat = GetNewMat( 1, nMatRows, true);
754                         xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1);
755                         if (eFunc != ifSUM)
756                         {
757                             xResCount = GetNewMat( 1, nMatRows, true);
758                             xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1);
759                         }
760                     }
761                     else
762                     {
763                         // Current value and values from vector are operands
764                         // for each vector position.
765                         if (nCount && xResCount)
766                         {
767                             for (SCSIZE i=0; i < nMatRows; ++i)
768                             {
769                                 xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i);
770                             }
771                         }
772                         if (fRes != ResInitVal)
773                         {
774                             for (SCSIZE i=0; i < nMatRows; ++i)
775                             {
776                                 double fVecRes = xResMat->GetDouble(0,i);
777                                 if (eFunc == ifPRODUCT)
778                                     fVecRes *= fRes;
779                                 else
780                                     fVecRes += fRes;
781                                 xResMat->PutDouble( fVecRes, 0,i);
782                             }
783                         }
784                     }
785                     fRes = ResInitVal;
786                     nCount = 0;
787                 }
788             }
789             [[fallthrough]];
790             case svDoubleRef :
791             {
792                 PopDoubleRef( aRange, nParamCount, nRefInList);
793                 if (nGlobalError == FormulaError::NoRef)
794                 {
795                     PushError( FormulaError::NoRef);
796                     return;
797                 }
798 
799                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
800                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
801                 {
802                     nGlobalError = FormulaError::NONE;
803                     if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
804                         ++nCount;
805                     if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT )
806                         break;
807                 }
808                 if( eFunc == ifCOUNT2 )
809                 {
810                     ScCellIterator aIter( mrDoc, aRange, mnSubTotalFlags );
811                     for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
812                     {
813                         if ( !aIter.isEmpty() )
814                         {
815                             ++nCount;
816                         }
817                     }
818 
819                     if ( nGlobalError != FormulaError::NONE )
820                         nGlobalError = FormulaError::NONE;
821                 }
822                 else if (((eFunc == ifSUM && !bCalcAsShown) || eFunc == ifCOUNT )
823                         && mnSubTotalFlags == SubtotalFlags::NONE)
824                 {
825                     // Use fast span set array method.
826                     // ifSUM with bCalcAsShown has to use the slow bells and
827                     // whistles ScValueIterator below.
828                     sc::RangeColumnSpanSet aSet( aRange );
829 
830                     if ( eFunc == ifSUM )
831                     {
832                         FuncSum aAction(mrContext);
833                         aSet.executeColumnAction( mrDoc, aAction, fMem );
834                         FormulaError nErr = aAction.getError();
835                         if ( nErr != FormulaError::NONE )
836                         {
837                             PushError( nErr );
838                             return;
839                         }
840                         fRes += aAction.getSum();
841 
842                         // Get the number format of the last iterated cell.
843                         nFuncFmtIndex = aAction.getNumberFormat();
844                     }
845                     else
846                     {
847                         FuncCount aAction(mrContext);
848                         aSet.executeColumnAction(mrDoc, aAction);
849                         nCount += aAction.getCount();
850 
851                         // Get the number format of the last iterated cell.
852                         nFuncFmtIndex = aAction.getNumberFormat();
853                     }
854 
855                     nFuncFmtType = mrContext.GetNumberFormatType( nFuncFmtIndex );
856                 }
857                 else
858                 {
859                     ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags, bTextAsZero );
860                     aValIter.SetInterpreterContext( &mrContext );
861                     FormulaError nErr = FormulaError::NONE;
862                     if (aValIter.GetFirst(fVal, nErr))
863                     {
864                         // placed the loop on the inside for performance reasons:
865                         aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
866                         switch( eFunc )
867                         {
868                             case ifAVERAGE:
869                             case ifSUM:
870                                     if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
871                                     {
872                                         do
873                                         {
874                                             if ( nErr == FormulaError::NONE )
875                                             {
876                                                 SetError(nErr);
877                                                 if ( fMem )
878                                                     fRes += fVal;
879                                                 else
880                                                     fMem = fVal;
881                                                 nCount++;
882                                             }
883                                         }
884                                         while (aValIter.GetNext(fVal, nErr));
885                                     }
886                                     else
887                                     {
888                                         do
889                                         {
890                                             SetError(nErr);
891                                             if ( fMem )
892                                                 fRes += fVal;
893                                             else
894                                                 fMem = fVal;
895                                             nCount++;
896                                         }
897                                         while (aValIter.GetNext(fVal, nErr));
898                                     }
899                                     break;
900                             case ifSUMSQ:
901                                     if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
902                                     {
903                                         do
904                                         {
905                                             if ( nErr == FormulaError::NONE )
906                                             {
907                                                 SetError(nErr);
908                                                 fRes += fVal * fVal;
909                                                 nCount++;
910                                             }
911                                         }
912                                         while (aValIter.GetNext(fVal, nErr));
913                                     }
914                                     else
915                                     {
916                                         do
917                                         {
918                                             SetError(nErr);
919                                             fRes += fVal * fVal;
920                                             nCount++;
921                                         }
922                                         while (aValIter.GetNext(fVal, nErr));
923                                     }
924                                     break;
925                             case ifPRODUCT:
926                                     do
927                                     {
928                                         if ( !( nErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
929                                         {
930                                             SetError(nErr);
931                                             fRes *= fVal;
932                                             nCount++;
933                                         }
934                                     }
935                                     while (aValIter.GetNext(fVal, nErr));
936                                     break;
937                             case ifCOUNT:
938                                     do
939                                     {
940                                         if ( nErr == FormulaError::NONE )
941                                             nCount++;
942                                     }
943                                     while (aValIter.GetNext(fVal, nErr));
944                                     break;
945                             default: ;  // nothing
946                         }
947                         SetError( nErr );
948                     }
949                 }
950                 if (nRefArrayPos != std::numeric_limits<size_t>::max())
951                 {
952                     // Update vector element with current value.
953                     if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
954                     {
955                         fRes = rtl::math::approxAdd( fRes, fMem);
956                         fMem = 0.0;
957                     }
958                     if (xResCount)
959                         xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
960                     double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
961                     if (eFunc == ifPRODUCT)
962                         fVecRes *= fRes;
963                     else
964                         fVecRes += fRes;
965                     xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
966                     // Reset.
967                     fRes = ResInitVal;
968                     nCount = 0;
969                     nRefArrayPos = std::numeric_limits<size_t>::max();
970                 }
971             }
972             break;
973             case svExternalDoubleRef:
974             {
975                 ScMatrixRef pMat;
976                 PopExternalDoubleRef(pMat);
977                 if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
978                     break;
979 
980                 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
981             }
982             break;
983             case svMatrix :
984             {
985                 ScMatrixRef pMat = PopMatrix();
986 
987                 IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes, fMem );
988             }
989             break;
990             case svError:
991             {
992                 PopError();
993                 if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
994                 {
995                     nGlobalError = FormulaError::NONE;
996                 }
997                 else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
998                 {
999                     nCount++;
1000                     nGlobalError = FormulaError::NONE;
1001                 }
1002             }
1003             break;
1004             default :
1005                 while (nParamCount-- > 0)
1006                     PopError();
1007                 SetError(FormulaError::IllegalParameter);
1008         }
1009     }
1010 
1011     // A boolean return type makes no sense on sums et al.
1012     // Counts are always numbers.
1013     if( nFuncFmtType == SvNumFormatType::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
1014         nFuncFmtType = SvNumFormatType::NUMBER;
1015 
1016     if (xResMat)
1017     {
1018         // Include value of last non-references-array type and calculate final result.
1019         for (SCSIZE i=0; i < nMatRows; ++i)
1020         {
1021             sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount);
1022             double fVecRes = xResMat->GetDouble(0,i);
1023             if (eFunc == ifPRODUCT)
1024                 fVecRes *= fRes;
1025             else
1026                 fVecRes += fRes;
1027             fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nVecCount);
1028             xResMat->PutDouble( fVecRes, 0,i);
1029         }
1030         PushMatrix( xResMat);
1031     }
1032     else
1033     {
1034         PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount));
1035     }
1036 }
1037 
1038 void ScInterpreter::ScSumSQ()
1039 {
1040     IterateParameters( ifSUMSQ );
1041 }
1042 
1043 void ScInterpreter::ScSum()
1044 {
1045     IterateParameters( ifSUM );
1046 }
1047 
1048 void ScInterpreter::ScProduct()
1049 {
1050     IterateParameters( ifPRODUCT );
1051 }
1052 
1053 void ScInterpreter::ScAverage( bool bTextAsZero )
1054 {
1055     IterateParameters( ifAVERAGE, bTextAsZero );
1056 }
1057 
1058 void ScInterpreter::ScCount()
1059 {
1060     IterateParameters( ifCOUNT );
1061 }
1062 
1063 void ScInterpreter::ScCount2()
1064 {
1065     IterateParameters( ifCOUNT2 );
1066 }
1067 
1068 void ScInterpreter::ScRawSubtract()
1069 {
1070     short nParamCount = GetByte();
1071     if (!MustHaveParamCountMin( nParamCount, 2))
1072         return;
1073 
1074     // Fish the 1st parameter from the stack and push it on top.
1075     const FormulaToken* p = pStack[ sp - nParamCount ];
1076     PushWithoutError( *p );
1077     // Obtain the minuend.
1078     double fRes = GetDouble();
1079 
1080     while (nGlobalError == FormulaError::NONE && nParamCount > 1)
1081     {
1082         // Simple single values without matrix support.
1083         fRes -= GetDouble();
1084         --nParamCount;
1085     }
1086     while (nParamCount-- > 0)
1087         PopError();
1088 
1089     PushDouble( fRes);
1090 }
1091 
1092 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1093