LibreOffice Module sc (master)  1
interpr6.cxx
Go to the documentation of this file.
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 
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 
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 
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 
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 
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 
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  {
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 
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  {
298  mnCount += nDataSize;
299  break;
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 {
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;
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 
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  {
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 
1039 {
1040  IterateParameters( ifSUMSQ );
1041 }
1042 
1044 {
1045  IterateParameters( ifSUM );
1046 }
1047 
1049 {
1050  IterateParameters( ifPRODUCT );
1051 }
1052 
1053 void ScInterpreter::ScAverage( bool bTextAsZero )
1054 {
1055  IterateParameters( ifAVERAGE, bTextAsZero );
1056 }
1057 
1059 {
1060  IterateParameters( ifCOUNT );
1061 }
1062 
1064 {
1065  IterateParameters( ifCOUNT2 );
1066 }
1067 
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: */
double GetLowRegIGamma(double fA, double fX)
You must ensure fA>0.0 && fX>0.0)
Definition: interpr6.cxx:119
StackVar
ScIterFunc
Definition: interpre.hxx:103
CellStoreType::const_iterator miCellPos
SCROW Row() const
Definition: address.hxx:261
int SetError()
bool isEmpty() const
Definition: cellvalue.cxx:670
sal_uIntPtr sal_uLong
ocSubTotal
StoreT::const_iterator ParseBlock(const typename StoreT::const_iterator &itPos, const StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Generic algorithm to parse blocks of multi_type_vector either partially or fully. ...
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
void ScRawSubtract()
Definition: interpr6.cxx:1068
NONE
tuple log
void ScCount2()
Definition: interpr6.cxx:1063
SubtotalFlags
Definition: global.hxx:249
void ScSumSQ()
Definition: interpr6.cxx:1038
char sal_uInt16 & nParamCount
Definition: callform.cxx:53
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:49
void ScAverage(bool bTextAsZero=false)
Definition: interpr6.cxx:1053
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
bool hasString() const
Definition: cellvalue.cxx:617
int nCount
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:25
Walk through all cells in an area.
Definition: dociter.hxx:207
SCTAB Tab() const
Definition: address.hxx:270
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.cxx:421
Optimized ColumnSpanSet version that operates on a single ScRange.
void SetInterpreterContext(ScInterpreterContext *context)
Definition: dociter.hxx:98
void ScCount()
Definition: interpr6.cxx:1058
static double lcl_IterResult(ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount)
Definition: interpr6.cxx:487
double const fHalfMachEps
Definition: interpr6.cxx:35
DocumentType eType
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1044
int i
bool IsValueNoError()
std::string GetLowRegIGamma
double GetGammaDist(double fX, double fAlpha, double fLambda)
Gamma distribution, cumulative distribution function.
Definition: interpr6.cxx:198
size_t GetRefListArrayMaxSize(short nParamCount)
Check for array of references to determine the maximum size of a return column vector if in array con...
Definition: interpr6.cxx:469
std::string GetLogGamma
virtual const ScRefList * GetRefList() const override
Definition: token.cxx:647
bool GetErrorOrValue(FormulaError &rErr, double &rVal)
svExternalDoubleRef
SvNumFormatType
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:54
svExternalSingleRef
double GetUpRegIGamma(double fA, double fX)
You must ensure fA>0.0 && fX>0.0)
Definition: interpr6.cxx:130
bool hasNumeric() const
Definition: cellvalue.cxx:622
std::size_t mnCount
static void IterateMatrix(const ScMatrixRef &pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags, sal_uLong &rCount, SvNumFormatType &rFuncFmtType, double &fRes, double &fMem)
Definition: interpr6.cxx:406
const NodeContext & mrContext
FormulaError
bool isEmpty() const
Definition: dociter.cxx:1020
double GetGammaContFraction(double fA, double fX)
You must ensure fA>0.0 && fX>0.0 valid results only if fX > fA+1.0 uses continued fraction with odd i...
Definition: interpr6.cxx:44
void IterateParameters(ScIterFunc, bool bTextAsZero=false)
Definition: interpr6.cxx:511
CellType meType
Definition: cellvalue.hxx:105
std::string GetGammaContFraction
::formula::FormulaTokenRef TokenRef
sal_Int32 SCROW
Definition: types.hxx:17
ocAggregate
bool GetFirst(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:286
CellType
Definition: global.hxx:280
if(aStr!=aBuf) UpdateName_Impl(m_xFollowLb.get()
std::string GetGammaSeries
SvNumFormatType GetNumberFormatType(sal_uInt32 nFIndex) const
void * p
When adding all numerical matrix elements for a scalar result such as summation, the interpreter want...
Definition: scmatrix.hxx:143
double GetGammaSeries(double fA, double fX)
You must ensure fA>0.0 && fX>0.0 valid results only if fX <= fA+1.0 uses power series.
Definition: interpr6.cxx:96
void GetCurNumFmtInfo(const ScInterpreterContext &rContext, SvNumFormatType &nType, sal_uInt32 &nIndex)
Definition: dociter.cxx:271
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:310
void executeColumnAction(ScDocument &rDoc, sc::ColumnSpanSet::ColumnAction &ac) const
bool IsArrayResult() const
Definition: token.cxx:649
void ScProduct()
Definition: interpr6.cxx:1048
double GetGammaDistPDF(double fX, double fAlpha, double fLambda)
Gamma distribution, probability density function.
Definition: interpr6.cxx:144
sc::CellStoreType & GetCellStore()
Definition: column.hxx:187
aStr
double div(const double &fNumerator, const double &fDenominator)
Return fNumerator/fDenominator if fDenominator!=0 else #DIV/0! error coded into double.
Definition: math.hxx:30