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  KahanSum maSum;
211  FormulaError mnError;
212 
213 public:
214  NumericCellAccumulator() : maSum(0.0), mnError(FormulaError::NONE) {}
215 
216  void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
217  {
218  switch (rNode.type)
219  {
221  {
222  if (nDataSize == 0)
223  return;
224 
225  const double *p = &sc::numeric_block::at(*rNode.data, nOffset);
226  sc::ArraySumFunctor functor(p, nDataSize);
227 
228  maSum += functor();
229  break;
230  }
231 
233  {
234  sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
235  std::advance(it, nOffset);
236  sc::formula_block::const_iterator itEnd = it;
237  std::advance(itEnd, nDataSize);
238  for (; it != itEnd; ++it)
239  {
240  double fVal = 0.0;
241  FormulaError nErr = FormulaError::NONE;
242  ScFormulaCell& rCell = *(*it);
243  if (!rCell.GetErrorOrValue(nErr, fVal))
244  // The cell has neither error nor value. Perhaps string result.
245  continue;
246 
247  if (nErr != FormulaError::NONE)
248  {
249  // Cell has error - skip all the rest
250  mnError = nErr;
251  return;
252  }
253 
254  maSum += fVal;
255  }
256  }
257  break;
258  default:
259  ;
260  }
261  }
262 
263  FormulaError getError() const { return mnError; }
264  KahanSum getResult() const { return maSum; }
265 };
266 
267 class NumericCellCounter
268 {
269  size_t mnCount;
270 public:
271  NumericCellCounter() : mnCount(0) {}
272 
273  void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
274  {
275  switch (rNode.type)
276  {
278  mnCount += nDataSize;
279  break;
281  {
282  sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
283  std::advance(it, nOffset);
284  sc::formula_block::const_iterator itEnd = it;
285  std::advance(itEnd, nDataSize);
286  for (; it != itEnd; ++it)
287  {
288  ScFormulaCell& rCell = **it;
289  if (rCell.IsValueNoError())
290  ++mnCount;
291  }
292  }
293  break;
294  default:
295  ;
296  }
297  }
298 
299  size_t getCount() const { return mnCount; }
300 };
301 
302 class FuncCount : public sc::ColumnSpanSet::ColumnAction
303 {
306  ScColumn* mpCol;
307  size_t mnCount;
308  sal_uInt32 mnNumFmt;
309 
310 public:
311  FuncCount(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mnCount(0), mnNumFmt(0) {}
312 
313  virtual void startColumn(ScColumn* pCol) override
314  {
315  mpCol = pCol;
316  mpCol->InitBlockPosition(maPos);
317  }
318 
319  virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) override
320  {
321  if (!bVal)
322  return;
323 
324  NumericCellCounter aFunc;
325  maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
326  mnCount += aFunc.getCount();
327  mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
328  };
329 
330  size_t getCount() const { return mnCount; }
331  sal_uInt32 getNumberFormat() const { return mnNumFmt; }
332 };
333 
334 class FuncSum : public sc::ColumnSpanSet::ColumnAction
335 {
336  const ScInterpreterContext& mrContext;
338  ScColumn* mpCol;
339  KahanSum mfSum;
340  FormulaError mnError;
341  sal_uInt32 mnNumFmt;
342 
343 public:
344  FuncSum(const ScInterpreterContext& rContext) : mrContext(rContext), mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE), mnNumFmt(0) {}
345 
346  virtual void startColumn(ScColumn* pCol) override
347  {
348  mpCol = pCol;
349  mpCol->InitBlockPosition(maPos);
350  }
351 
352  virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) override
353  {
354  if (!bVal)
355  return;
356 
357  if (mnError != FormulaError::NONE)
358  return;
359 
360  NumericCellAccumulator aFunc;
361  maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
362  mnError = aFunc.getError();
363  if (mnError != FormulaError::NONE)
364  return;
365 
366 
367  mfSum += aFunc.getResult();
368  mnNumFmt = mpCol->GetNumberFormat(mrContext, nRow2);
369  };
370 
371  FormulaError getError() const { return mnError; }
372  KahanSum getSum() const { return mfSum; }
373  sal_uInt32 getNumberFormat() const { return mnNumFmt; }
374 };
375 
376 }
377 
378 static void IterateMatrix(
379  const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags,
380  sal_uLong& rCount, SvNumFormatType& rFuncFmtType, KahanSum& fRes )
381 {
382  if (!pMat)
383  return;
384 
385  const bool bIgnoreErrVal = bool(nSubTotalFlags & SubtotalFlags::IgnoreErrVal);
386  rFuncFmtType = SvNumFormatType::NUMBER;
387  switch (eFunc)
388  {
389  case ifAVERAGE:
390  case ifSUM:
391  {
392  ScMatrix::KahanIterateResult aRes = pMat->Sum(bTextAsZero, bIgnoreErrVal);
393  fRes += aRes.maAccumulator;
394  rCount += aRes.mnCount;
395  }
396  break;
397  case ifCOUNT:
398  rCount += pMat->Count(bTextAsZero, false); // do not count error values
399  break;
400  case ifCOUNT2:
401  /* TODO: what is this supposed to be with bIgnoreErrVal? */
402  rCount += pMat->Count(true, true); // do count error values
403  break;
404  case ifPRODUCT:
405  {
406  ScMatrix::DoubleIterateResult aRes = pMat->Product(bTextAsZero, bIgnoreErrVal);
407  fRes *= aRes.maAccumulator;
408  rCount += aRes.mnCount;
409  }
410  break;
411  case ifSUMSQ:
412  {
413  ScMatrix::KahanIterateResult aRes = pMat->SumSquare(bTextAsZero, bIgnoreErrVal);
414  fRes += aRes.maAccumulator;
415  rCount += aRes.mnCount;
416  }
417  break;
418  default:
419  ;
420  }
421 }
422 
424 {
425  size_t nSize = 0;
426  if (IsInArrayContext())
427  {
428  for (short i=1; i <= nParamCount; ++i)
429  {
430  if (GetStackType(i) == svRefList)
431  {
432  const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
433  if (p && p->IsArrayResult() && p->GetRefList()->size() > nSize)
434  nSize = p->GetRefList()->size();
435  }
436  }
437  }
438  return nSize;
439 }
440 
441 static double lcl_IterResult( ScIterFunc eFunc, double fRes, sal_uLong nCount )
442 {
443  switch( eFunc )
444  {
445  case ifAVERAGE:
446  fRes = sc::div( fRes, nCount);
447  break;
448  case ifCOUNT2:
449  case ifCOUNT:
450  fRes = nCount;
451  break;
452  case ifPRODUCT:
453  if ( !nCount )
454  fRes = 0.0;
455  break;
456  default:
457  ; // nothing
458  }
459  return fRes;
460 }
461 
462 void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
463 {
464  short nParamCount = GetByte();
465  const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
466  ScMatrixRef xResMat, xResCount;
467  const double ResInitVal = (eFunc == ifPRODUCT) ? 1.0 : 0.0;
468  KahanSum fRes = ResInitVal;
469  double fVal = 0.0;
470  sal_uLong nCount = 0;
471  ScAddress aAdr;
472  ScRange aRange;
473  size_t nRefInList = 0;
474  size_t nRefArrayPos = std::numeric_limits<size_t>::max();
475  if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
476  ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
477  nGlobalError = FormulaError::NONE;
478  while (nParamCount-- > 0)
479  {
480  switch (GetStackType())
481  {
482  case svString:
483  {
484  if( eFunc == ifCOUNT )
485  {
486  OUString aStr = PopString().getString();
487  if ( bTextAsZero )
488  nCount++;
489  else
490  {
491  // Only check if string can be converted to number, no
492  // error propagation.
493  FormulaError nErr = nGlobalError;
494  nGlobalError = FormulaError::NONE;
495  ConvertStringToValue( aStr );
496  if (nGlobalError == FormulaError::NONE)
497  ++nCount;
498  nGlobalError = nErr;
499  }
500  }
501  else
502  {
503  Pop();
504  switch ( eFunc )
505  {
506  case ifAVERAGE:
507  case ifSUM:
508  case ifSUMSQ:
509  case ifPRODUCT:
510  {
511  if ( bTextAsZero )
512  {
513  nCount++;
514  if ( eFunc == ifPRODUCT )
515  fRes = 0.0;
516  }
517  else
518  {
519  while (nParamCount-- > 0)
520  Pop();
521  SetError( FormulaError::NoValue );
522  }
523  }
524  break;
525  default:
526  nCount++;
527  }
528  }
529  }
530  break;
531  case svDouble :
532  fVal = GetDouble();
533  nCount++;
534  switch( eFunc )
535  {
536  case ifAVERAGE:
537  case ifSUM: fRes += fVal; break;
538  case ifSUMSQ: fRes += fVal * fVal; break;
539  case ifPRODUCT: fRes *= fVal; break;
540  default: ; // nothing
541  }
542  nFuncFmtType = SvNumFormatType::NUMBER;
543  break;
544  case svExternalSingleRef:
545  {
548  PopExternalSingleRef(pToken, &aFmt);
549  if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
550  ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
551  {
552  nGlobalError = FormulaError::NONE;
553  if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
554  ++nCount;
555  break;
556  }
557 
558  if (!pToken)
559  break;
560 
561  StackVar eType = pToken->GetType();
562  if (eFunc == ifCOUNT2)
563  {
564  if ( eType != svEmptyCell &&
565  ( ( pToken->GetOpCode() != ocSubTotal &&
566  pToken->GetOpCode() != ocAggregate ) ||
567  ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) )
568  nCount++;
569  if (nGlobalError != FormulaError::NONE)
570  nGlobalError = FormulaError::NONE;
571  }
572  else if (eType == svDouble)
573  {
574  nCount++;
575  fVal = pToken->GetDouble();
576  if (aFmt.mbIsSet)
577  {
578  nFuncFmtType = aFmt.mnType;
579  nFuncFmtIndex = aFmt.mnIndex;
580  }
581  switch( eFunc )
582  {
583  case ifAVERAGE:
584  case ifSUM: fRes += fVal; break;
585  case ifSUMSQ: fRes += fVal * fVal; break;
586  case ifPRODUCT: fRes *= fVal; break;
587  case ifCOUNT:
588  if ( nGlobalError != FormulaError::NONE )
589  {
590  nGlobalError = FormulaError::NONE;
591  nCount--;
592  }
593  break;
594  default: ; // nothing
595  }
596  }
597  else if (bTextAsZero && eType == svString)
598  {
599  nCount++;
600  if ( eFunc == ifPRODUCT )
601  fRes = 0.0;
602  }
603  }
604  break;
605  case svSingleRef :
606  {
607  PopSingleRef( aAdr );
608  if (nGlobalError == FormulaError::NoRef)
609  {
610  PushError( FormulaError::NoRef);
611  return;
612  }
613 
614  if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreFiltered ) &&
615  mrDoc.RowFiltered( aAdr.Row(), aAdr.Tab() ) ) ||
616  ( ( mnSubTotalFlags & SubtotalFlags::IgnoreHidden ) &&
617  mrDoc.RowHidden( aAdr.Row(), aAdr.Tab() ) ) )
618  {
619  break;
620  }
621  if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
622  ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
623  {
624  nGlobalError = FormulaError::NONE;
625  if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
626  ++nCount;
627  break;
628  }
629  ScRefCellValue aCell(mrDoc, aAdr);
630  if (!aCell.isEmpty())
631  {
632  if( eFunc == ifCOUNT2 )
633  {
634  CellType eCellType = aCell.meType;
635  if ( eCellType != CELLTYPE_NONE )
636  nCount++;
637  if ( nGlobalError != FormulaError::NONE )
638  nGlobalError = FormulaError::NONE;
639  }
640  else if (aCell.hasNumeric())
641  {
642  nCount++;
643  fVal = GetCellValue(aAdr, aCell);
644  CurFmtToFuncFmt();
645  switch( eFunc )
646  {
647  case ifAVERAGE:
648  case ifSUM: fRes += fVal; break;
649  case ifSUMSQ: fRes += fVal * fVal; break;
650  case ifPRODUCT: fRes *= fVal; break;
651  case ifCOUNT:
652  if ( nGlobalError != FormulaError::NONE )
653  {
654  nGlobalError = FormulaError::NONE;
655  nCount--;
656  }
657  break;
658  default: ; // nothing
659  }
660  }
661  else if (bTextAsZero && aCell.hasString())
662  {
663  nCount++;
664  if ( eFunc == ifPRODUCT )
665  fRes = 0.0;
666  }
667  }
668  }
669  break;
670  case svRefList :
671  {
672  const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
673  if (p && p->IsArrayResult())
674  {
675  nRefArrayPos = nRefInList;
676  // The "one value to all references of an array" seems to
677  // be what Excel does if there are other types than just
678  // arrays of references.
679  if (!xResMat)
680  {
681  // Create and init all elements with current value.
682  assert(nMatRows > 0);
683  xResMat = GetNewMat( 1, nMatRows, true);
684  xResMat->FillDouble( fRes.get(), 0,0, 0,nMatRows-1);
685  if (eFunc != ifSUM)
686  {
687  xResCount = GetNewMat( 1, nMatRows, true);
688  xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1);
689  }
690  }
691  else
692  {
693  // Current value and values from vector are operands
694  // for each vector position.
695  if (nCount && xResCount)
696  {
697  for (SCSIZE i=0; i < nMatRows; ++i)
698  {
699  xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i);
700  }
701  }
702  if (fRes != ResInitVal)
703  {
704  for (SCSIZE i=0; i < nMatRows; ++i)
705  {
706  double fVecRes = xResMat->GetDouble(0,i);
707  if (eFunc == ifPRODUCT)
708  fVecRes *= fRes.get();
709  else
710  fVecRes += fRes.get();
711  xResMat->PutDouble( fVecRes, 0,i);
712  }
713  }
714  }
715  fRes = ResInitVal;
716  nCount = 0;
717  }
718  }
719  [[fallthrough]];
720  case svDoubleRef :
721  {
722  PopDoubleRef( aRange, nParamCount, nRefInList);
723  if (nGlobalError == FormulaError::NoRef)
724  {
725  PushError( FormulaError::NoRef);
726  return;
727  }
728 
729  if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
730  ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
731  {
732  nGlobalError = FormulaError::NONE;
733  if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
734  ++nCount;
735  if ( eFunc == ifCOUNT2 || eFunc == ifCOUNT )
736  break;
737  }
738  if( eFunc == ifCOUNT2 )
739  {
740  ScCellIterator aIter( mrDoc, aRange, mnSubTotalFlags );
741  for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
742  {
743  if ( !aIter.isEmpty() )
744  {
745  ++nCount;
746  }
747  }
748 
749  if ( nGlobalError != FormulaError::NONE )
750  nGlobalError = FormulaError::NONE;
751  }
752  else if (((eFunc == ifSUM && !bCalcAsShown) || eFunc == ifCOUNT )
753  && mnSubTotalFlags == SubtotalFlags::NONE)
754  {
755  // Use fast span set array method.
756  // ifSUM with bCalcAsShown has to use the slow bells and
757  // whistles ScValueIterator below.
758  sc::RangeColumnSpanSet aSet( aRange );
759 
760  if ( eFunc == ifSUM )
761  {
762  FuncSum aAction(mrContext);
763  aSet.executeColumnAction( mrDoc, aAction );
764  FormulaError nErr = aAction.getError();
765  if ( nErr != FormulaError::NONE )
766  {
767  PushError( nErr );
768  return;
769  }
770  fRes += aAction.getSum();
771 
772  // Get the number format of the last iterated cell.
773  nFuncFmtIndex = aAction.getNumberFormat();
774  }
775  else
776  {
777  FuncCount aAction(mrContext);
778  aSet.executeColumnAction(mrDoc, aAction);
779  nCount += aAction.getCount();
780 
781  // Get the number format of the last iterated cell.
782  nFuncFmtIndex = aAction.getNumberFormat();
783  }
784 
785  nFuncFmtType = mrContext.GetNumberFormatType( nFuncFmtIndex );
786  }
787  else
788  {
789  ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags, bTextAsZero );
790  aValIter.SetInterpreterContext( &mrContext );
791  FormulaError nErr = FormulaError::NONE;
792  if (aValIter.GetFirst(fVal, nErr))
793  {
794  // placed the loop on the inside for performance reasons:
795  aValIter.GetCurNumFmtInfo( mrContext, nFuncFmtType, nFuncFmtIndex );
796  switch( eFunc )
797  {
798  case ifAVERAGE:
799  case ifSUM:
800  if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
801  {
802  do
803  {
804  if ( nErr == FormulaError::NONE )
805  {
806  SetError(nErr);
807  fRes += fVal;
808  nCount++;
809  }
810  }
811  while (aValIter.GetNext(fVal, nErr));
812  }
813  else
814  {
815  do
816  {
817  SetError(nErr);
818  fRes += fVal;
819  nCount++;
820  }
821  while (aValIter.GetNext(fVal, nErr));
822  }
823  break;
824  case ifSUMSQ:
825  if ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal )
826  {
827  do
828  {
829  if ( nErr == FormulaError::NONE )
830  {
831  SetError(nErr);
832  fRes += fVal * fVal;
833  nCount++;
834  }
835  }
836  while (aValIter.GetNext(fVal, nErr));
837  }
838  else
839  {
840  do
841  {
842  SetError(nErr);
843  fRes += fVal * fVal;
844  nCount++;
845  }
846  while (aValIter.GetNext(fVal, nErr));
847  }
848  break;
849  case ifPRODUCT:
850  do
851  {
852  if ( !( nErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
853  {
854  SetError(nErr);
855  fRes *= fVal;
856  nCount++;
857  }
858  }
859  while (aValIter.GetNext(fVal, nErr));
860  break;
861  case ifCOUNT:
862  do
863  {
864  if ( nErr == FormulaError::NONE )
865  nCount++;
866  }
867  while (aValIter.GetNext(fVal, nErr));
868  break;
869  default: ; // nothing
870  }
871  SetError( nErr );
872  }
873  }
874  if (nRefArrayPos != std::numeric_limits<size_t>::max())
875  {
876  // Update vector element with current value.
877  if (xResCount)
878  xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
879  double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
880  if (eFunc == ifPRODUCT)
881  fVecRes *= fRes.get();
882  else
883  fVecRes += fRes.get();
884  xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
885  // Reset.
886  fRes = ResInitVal;
887  nCount = 0;
888  nRefArrayPos = std::numeric_limits<size_t>::max();
889  }
890  }
891  break;
892  case svExternalDoubleRef:
893  {
894  ScMatrixRef pMat;
895  PopExternalDoubleRef(pMat);
896  if ( nGlobalError != FormulaError::NONE && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
897  break;
898 
899  IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes );
900  }
901  break;
902  case svMatrix :
903  {
904  ScMatrixRef pMat = PopMatrix();
905 
906  IterateMatrix( pMat, eFunc, bTextAsZero, mnSubTotalFlags, nCount, nFuncFmtType, fRes );
907  }
908  break;
909  case svError:
910  {
911  PopError();
912  if ( eFunc == ifCOUNT || ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
913  {
914  nGlobalError = FormulaError::NONE;
915  }
916  else if ( eFunc == ifCOUNT2 && !( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
917  {
918  nCount++;
919  nGlobalError = FormulaError::NONE;
920  }
921  }
922  break;
923  default :
924  while (nParamCount-- > 0)
925  PopError();
926  SetError(FormulaError::IllegalParameter);
927  }
928  }
929 
930  // A boolean return type makes no sense on sums et al.
931  // Counts are always numbers.
932  if( nFuncFmtType == SvNumFormatType::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
933  nFuncFmtType = SvNumFormatType::NUMBER;
934 
935  if (xResMat)
936  {
937  // Include value of last non-references-array type and calculate final result.
938  for (SCSIZE i=0; i < nMatRows; ++i)
939  {
940  sal_uLong nVecCount = (xResCount ? nCount + xResCount->GetDouble(0,i) : nCount);
941  double fVecRes = xResMat->GetDouble(0,i);
942  if (eFunc == ifPRODUCT)
943  fVecRes *= fRes.get();
944  else
945  fVecRes += fRes.get();
946  fVecRes = lcl_IterResult( eFunc, fVecRes, nVecCount);
947  xResMat->PutDouble( fVecRes, 0,i);
948  }
949  PushMatrix( xResMat);
950  }
951  else
952  {
953  PushDouble( lcl_IterResult( eFunc, fRes.get(), nCount));
954  }
955 }
956 
958 {
959  IterateParameters( ifSUMSQ );
960 }
961 
963 {
964  IterateParameters( ifSUM );
965 }
966 
968 {
969  IterateParameters( ifPRODUCT );
970 }
971 
972 void ScInterpreter::ScAverage( bool bTextAsZero )
973 {
974  IterateParameters( ifAVERAGE, bTextAsZero );
975 }
976 
978 {
979  IterateParameters( ifCOUNT );
980 }
981 
983 {
984  IterateParameters( ifCOUNT2 );
985 }
986 
993 {
994  short nParamCount = GetByte();
995  if (!MustHaveParamCountMin( nParamCount, 2))
996  return;
997 
998  // Reverse stack to process arguments from left to right.
999  ReverseStack( nParamCount);
1000  // Obtain the minuend.
1001  double fRes = GetDouble();
1002 
1003  while (nGlobalError == FormulaError::NONE && --nParamCount > 0)
1004  {
1005  // Simple single values without matrix support.
1006  fRes -= GetDouble();
1007  }
1008  while (nParamCount-- > 0)
1009  PopError();
1010 
1011  PushDouble( fRes);
1012 }
1013 
1014 /* 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:101
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. ...
static void IterateMatrix(const ScMatrixRef &pMat, ScIterFunc eFunc, bool bTextAsZero, SubtotalFlags nSubTotalFlags, sal_uLong &rCount, SvNumFormatType &rFuncFmtType, KahanSum &fRes)
Definition: interpr6.cxx:378
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
constexpr double get() const
Returns the final sum.
Definition: kahan.hxx:190
void ScRawSubtract()
The purpose of RAWSUBTRACT() is exactly to not apply any error correction, approximation etc...
Definition: interpr6.cxx:992
NONE
tuple log
void ScCount2()
Definition: interpr6.cxx:982
SubtotalFlags
Definition: global.hxx:249
void ScSumSQ()
Definition: interpr6.cxx:957
char sal_uInt16 & nParamCount
Definition: callform.cxx:53
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:49
This class provides LO with Kahan summation algorithm About this algorithm: https://en.wikipedia.org/wiki/Kahan_summation_algorithm For general purpose software we assume first order error is enough.
Definition: kahan.hxx:21
void ScAverage(bool bTextAsZero=false)
Definition: interpr6.cxx:972
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:977
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:423
std::string GetLogGamma
virtual const ScRefList * GetRefList() const override
Definition: token.cxx:647
void ScSum()
Definition: interpr6.cxx:962
static double lcl_IterResult(ScIterFunc eFunc, double fRes, sal_uLong nCount)
Definition: interpr6.cxx:441
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
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:462
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
std::string GetGammaSeries
SvNumFormatType GetNumberFormatType(sal_uInt32 nFIndex) const
void * p
Iterator for executing one operation with the matrix data.
Definition: scmatrix.hxx:159
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:967
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:31