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