1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <interpre.hxx>
21 #include <columnspanset.hxx>
23 #include <document.hxx>
24 #include <cellvalue.hxx>
25 #include <dociter.hxx>
26 #include <mtvfunctions.hxx>
27 #include <scmatrix.hxx>
29 #include <arraysumfunctor.hxx>
31 #include <formula/token.hxx>
33 using namespace formula
;
35 double const fHalfMachEps
= 0.5 * ::std::numeric_limits
<double>::epsilon();
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]
41 /** You must ensure fA>0.0 && fX>0.0
42 valid results only if fX > fA+1.0
43 uses continued fraction with odd items */
44 double ScInterpreter::GetGammaContFraction( double fA
, double fX
)
47 double const fBigInv
= ::std::numeric_limits
<double>::epsilon();
48 double const fBig
= 1.0/fBigInv
;
51 double fDenom
= fX
+ 2.0-fA
;
52 double fPkm1
= fX
+ 1.0;
54 double fQkm1
= fDenom
* fX
;
56 double fApprox
= fPkm1
/fQkm1
;
57 bool bFinished
= false;
62 const double fNum
= fY
* fCount
;
64 double fPk
= fPkm1
* fDenom
- fPkm2
* fNum
;
65 const double fQk
= fQkm1
* fDenom
- fQkm2
* fNum
;
68 const double fR
= fPk
/fQk
;
69 bFinished
= (fabs( (fApprox
- fR
)/fR
) <= fHalfMachEps
);
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
;
84 } while (!bFinished
&& fCount
<10000);
85 // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
88 SetError(FormulaError::NoConvergence
);
93 /** You must ensure fA>0.0 && fX>0.0
94 valid results only if fX <= fA+1.0
96 double ScInterpreter::GetGammaSeries( double fA
, double fX
)
98 double fDenomfactor
= fA
;
99 double fSummand
= 1.0/fA
;
100 double fSum
= fSummand
;
104 fDenomfactor
= fDenomfactor
+ 1.0;
105 fSummand
= fSummand
* fX
/fDenomfactor
;
106 fSum
= fSum
+ fSummand
;
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
113 SetError(FormulaError::NoConvergence
);
118 /** You must ensure fA>0.0 && fX>0.0) */
119 double ScInterpreter::GetLowRegIGamma( double fA
, double fX
)
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
);
129 /** You must ensure fA>0.0 && fX>0.0) */
130 double ScInterpreter::GetUpRegIGamma( double fA
, double fX
)
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
);
141 /** Gamma distribution, probability density function.
142 fLambda is "scale" parameter
143 You must ensure fAlpha>0.0 and fLambda>0.0 */
144 double ScInterpreter::GetGammaDistPDF( double fX
, double fAlpha
, double fLambda
)
147 return 0.0; // see ODFF
149 // in this case 0^0 isn't zero
153 SetError(FormulaError::DivisionByZero
); // should be #DIV/0
156 else if (fAlpha
== 1)
158 return (1.0 / fLambda
);
167 double fXr
= fX
/ fLambda
;
168 // use exp(ln()) only for large arguments because of less accuracy
171 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
172 if (log(fXr
) * (fAlpha
-1.0) < fLogDblMax
&& fAlpha
< fMaxGammaArgument
)
174 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
178 return exp( (fAlpha
-1.0) * log(fXr
) - fXr
- log(fLambda
) - GetLogGamma(fAlpha
));
181 else // fXr near to zero
183 if (fAlpha
<fMaxGammaArgument
)
185 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
189 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ exp( GetLogGamma(fAlpha
));
195 /** Gamma distribution, cumulative distribution function.
196 fLambda is "scale" parameter
197 You must ensure fAlpha>0.0 and fLambda>0.0 */
198 double ScInterpreter::GetGammaDist( double fX
, double fAlpha
, double fLambda
)
203 return GetLowRegIGamma( fAlpha
, fX
/ fLambda
);
208 class NumericCellAccumulator
211 FormulaError mnError
;
214 NumericCellAccumulator() : maSum(0.0), mnError(FormulaError::NONE
) {}
216 void operator() (const sc::CellStoreType::value_type
& rNode
, size_t nOffset
, size_t nDataSize
)
220 case sc::element_type_numeric
:
225 const double *p
= &sc::numeric_block::at(*rNode
.data
, nOffset
);
226 maSum
+= sc::op::sumArray(p
, nDataSize
);
230 case sc::element_type_formula
:
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
)
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.
245 if (nErr
!= FormulaError::NONE
)
247 // Cell has error - skip all the rest
261 FormulaError
getError() const { return mnError
; }
262 const KahanSum
& getResult() const { return maSum
; }
265 class NumericCellCounter
269 NumericCellCounter() : mnCount(0) {}
271 void operator() (const sc::CellStoreType::value_type
& rNode
, size_t nOffset
, size_t nDataSize
)
275 case sc::element_type_numeric
:
276 mnCount
+= nDataSize
;
278 case sc::element_type_formula
:
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
)
286 ScFormulaCell
& rCell
= **it
;
287 if (rCell
.IsValueNoError())
297 size_t getCount() const { return mnCount
; }
300 class FuncCount
: public sc::ColumnSpanSet::ColumnAction
302 const ScInterpreterContext
& mrContext
;
303 sc::ColumnBlockConstPosition maPos
;
309 FuncCount(const ScInterpreterContext
& rContext
) : mrContext(rContext
), mpCol(nullptr), mnCount(0), mnNumFmt(0) {}
311 virtual void startColumn(ScColumn
* pCol
) override
314 mpCol
->InitBlockPosition(maPos
);
317 virtual void execute(SCROW nRow1
, SCROW nRow2
, bool bVal
) override
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
);
328 size_t getCount() const { return mnCount
; }
329 sal_uInt32
getNumberFormat() const { return mnNumFmt
; }
332 class FuncSum
: public sc::ColumnSpanSet::ColumnAction
334 const ScInterpreterContext
& mrContext
;
335 sc::ColumnBlockConstPosition maPos
;
338 FormulaError mnError
;
342 FuncSum(const ScInterpreterContext
& rContext
) : mrContext(rContext
), mpCol(nullptr), mfSum(0.0), mnError(FormulaError::NONE
), mnNumFmt(0) {}
344 virtual void startColumn(ScColumn
* pCol
) override
347 mpCol
->InitBlockPosition(maPos
);
350 virtual void execute(SCROW nRow1
, SCROW nRow2
, bool bVal
) override
355 if (mnError
!= FormulaError::NONE
)
358 NumericCellAccumulator aFunc
;
359 maPos
.miCellPos
= sc::ParseBlock(maPos
.miCellPos
, mpCol
->GetCellStore(), aFunc
, nRow1
, nRow2
);
360 mnError
= aFunc
.getError();
361 if (mnError
!= FormulaError::NONE
)
365 mfSum
+= aFunc
.getResult();
366 mnNumFmt
= mpCol
->GetNumberFormat(mrContext
, nRow2
);
369 FormulaError
getError() const { return mnError
; }
370 const KahanSum
& getSum() const { return mfSum
; }
371 sal_uInt32
getNumberFormat() const { return mnNumFmt
; }
376 static void IterateMatrix(
377 const ScMatrixRef
& pMat
, ScIterFunc eFunc
, bool bTextAsZero
, SubtotalFlags nSubTotalFlags
,
378 sal_uLong
& rCount
, SvNumFormatType
& rFuncFmtType
, KahanSum
& fRes
)
383 const bool bIgnoreErrVal
= bool(nSubTotalFlags
& SubtotalFlags::IgnoreErrVal
);
384 rFuncFmtType
= SvNumFormatType::NUMBER
;
390 ScMatrix::KahanIterateResult aRes
= pMat
->Sum(bTextAsZero
, bIgnoreErrVal
);
391 fRes
+= aRes
.maAccumulator
;
392 rCount
+= aRes
.mnCount
;
396 rCount
+= pMat
->Count(bTextAsZero
, false); // do not count error values
399 /* TODO: what is this supposed to be with bIgnoreErrVal? */
400 rCount
+= pMat
->Count(true, true); // do count error values
404 ScMatrix::DoubleIterateResult aRes
= pMat
->Product(bTextAsZero
, bIgnoreErrVal
);
405 fRes
*= aRes
.maAccumulator
;
406 rCount
+= aRes
.mnCount
;
411 ScMatrix::KahanIterateResult aRes
= pMat
->SumSquare(bTextAsZero
, bIgnoreErrVal
);
412 fRes
+= aRes
.maAccumulator
;
413 rCount
+= aRes
.mnCount
;
421 size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount
)
424 if (IsInArrayContext())
426 for (short i
=1; i
<= nParamCount
; ++i
)
428 if (GetStackType(i
) == svRefList
)
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();
439 static double lcl_IterResult( ScIterFunc eFunc
, double fRes
, sal_uLong nCount
)
444 fRes
= sc::div( fRes
, nCount
);
460 void ScInterpreter::IterateParameters( ScIterFunc eFunc
, bool bTextAsZero
)
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
;
468 sal_uLong nCount
= 0;
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)
478 switch (GetStackType())
482 if( eFunc
== ifCOUNT
)
484 OUString aStr
= PopString().getString();
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
)
512 if ( eFunc
== ifPRODUCT
)
517 while (nParamCount
-- > 0)
519 SetError( FormulaError::NoValue
);
535 case ifSUM
: fRes
+= fVal
; break;
536 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
537 case ifPRODUCT
: fRes
*= fVal
; break;
538 default: ; // nothing
540 nFuncFmtType
= SvNumFormatType::NUMBER
;
542 case svExternalSingleRef
:
544 ScExternalRefCache::TokenRef pToken
;
545 ScExternalRefCache::CellFormat aFmt
;
546 PopExternalSingleRef(pToken
, &aFmt
);
547 if ( nGlobalError
!= FormulaError::NONE
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
||
548 ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) ) )
550 nGlobalError
= FormulaError::NONE
;
551 if ( eFunc
== ifCOUNT2
&& !( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
559 StackVar eType
= pToken
->GetType();
560 if (eFunc
== ifCOUNT2
)
562 if ( eType
!= svEmptyCell
&&
563 ( ( pToken
->GetOpCode() != ocSubTotal
&&
564 pToken
->GetOpCode() != ocAggregate
) ||
565 ( mnSubTotalFlags
& SubtotalFlags::IgnoreNestedStAg
) ) )
567 if (nGlobalError
!= FormulaError::NONE
)
568 nGlobalError
= FormulaError::NONE
;
570 else if (eType
== svDouble
)
573 fVal
= pToken
->GetDouble();
576 nFuncFmtType
= aFmt
.mnType
;
577 nFuncFmtIndex
= aFmt
.mnIndex
;
582 case ifSUM
: fRes
+= fVal
; break;
583 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
584 case ifPRODUCT
: fRes
*= fVal
; break;
586 if ( nGlobalError
!= FormulaError::NONE
)
588 nGlobalError
= FormulaError::NONE
;
592 default: ; // nothing
595 else if (bTextAsZero
&& eType
== svString
)
598 if ( eFunc
== ifPRODUCT
)
605 PopSingleRef( aAdr
);
606 if (nGlobalError
== FormulaError::NoRef
)
608 PushError( FormulaError::NoRef
);
612 if ( ( ( mnSubTotalFlags
& SubtotalFlags::IgnoreFiltered
) &&
613 mrDoc
.RowFiltered( aAdr
.Row(), aAdr
.Tab() ) ) ||
614 ( ( mnSubTotalFlags
& SubtotalFlags::IgnoreHidden
) &&
615 mrDoc
.RowHidden( aAdr
.Row(), aAdr
.Tab() ) ) )
619 if ( nGlobalError
!= FormulaError::NONE
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
||
620 ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) ) )
622 nGlobalError
= FormulaError::NONE
;
623 if ( eFunc
== ifCOUNT2
&& !( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
627 ScRefCellValue
aCell(mrDoc
, aAdr
);
628 if (!aCell
.isEmpty())
630 if( eFunc
== ifCOUNT2
)
632 CellType eCellType
= aCell
.getType();
633 if ( eCellType
!= CELLTYPE_NONE
)
635 if ( nGlobalError
!= FormulaError::NONE
)
636 nGlobalError
= FormulaError::NONE
;
638 else if (aCell
.hasNumeric())
640 fVal
= GetCellValue(aAdr
, aCell
);
641 if (nGlobalError
!= FormulaError::NONE
)
643 if (eFunc
== ifCOUNT
|| (mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
))
644 nGlobalError
= FormulaError::NONE
;
652 case ifSUM
: fRes
+= fVal
; break;
653 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
654 case ifPRODUCT
: fRes
*= fVal
; break;
655 default: ; // nothing
658 else if (bTextAsZero
&& aCell
.hasString())
661 if ( eFunc
== ifPRODUCT
)
669 const ScRefListToken
* p
= dynamic_cast<const ScRefListToken
*>(pStack
[sp
-1]);
670 if (p
&& p
->IsArrayResult())
672 nRefArrayPos
= nRefInList
;
673 // The "one value to all references of an array" seems to
674 // be what Excel does if there are other types than just
675 // arrays of references.
678 // Create and init all elements with current value.
679 assert(nMatRows
> 0);
680 xResMat
= GetNewMat( 1, nMatRows
, true);
681 xResMat
->FillDouble( fRes
.get(), 0,0, 0,nMatRows
-1);
684 xResCount
= GetNewMat( 1, nMatRows
, true);
685 xResCount
->FillDouble( nCount
, 0,0, 0,nMatRows
-1);
690 // Current value and values from vector are operands
691 // for each vector position.
692 if (nCount
&& xResCount
)
694 for (SCSIZE i
=0; i
< nMatRows
; ++i
)
696 xResCount
->PutDouble( xResCount
->GetDouble(0,i
) + nCount
, 0,i
);
699 if (fRes
!= ResInitVal
)
701 for (SCSIZE i
=0; i
< nMatRows
; ++i
)
703 double fVecRes
= xResMat
->GetDouble(0,i
);
704 if (eFunc
== ifPRODUCT
)
705 fVecRes
*= fRes
.get();
707 fVecRes
+= fRes
.get();
708 xResMat
->PutDouble( fVecRes
, 0,i
);
719 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
720 if (nGlobalError
== FormulaError::NoRef
)
722 PushError( FormulaError::NoRef
);
726 if ( nGlobalError
!= FormulaError::NONE
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
||
727 ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) ) )
729 nGlobalError
= FormulaError::NONE
;
730 if ( eFunc
== ifCOUNT2
&& !( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
732 if ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
)
735 if( eFunc
== ifCOUNT2
)
737 ScCellIterator
aIter( mrDoc
, aRange
, mnSubTotalFlags
);
738 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
740 if ( !aIter
.isEmpty() )
746 if ( nGlobalError
!= FormulaError::NONE
)
747 nGlobalError
= FormulaError::NONE
;
749 else if (((eFunc
== ifSUM
&& !bCalcAsShown
) || eFunc
== ifCOUNT
)
750 && mnSubTotalFlags
== SubtotalFlags::NONE
)
752 // Use fast span set array method.
753 // ifSUM with bCalcAsShown has to use the slow bells and
754 // whistles ScValueIterator below.
755 sc::RangeColumnSpanSet
aSet( aRange
);
757 if ( eFunc
== ifSUM
)
759 FuncSum
aAction(mrContext
);
760 aSet
.executeColumnAction( mrDoc
, aAction
);
761 FormulaError nErr
= aAction
.getError();
762 if ( nErr
!= FormulaError::NONE
)
767 fRes
+= aAction
.getSum();
769 // Get the number format of the last iterated cell.
770 nFuncFmtIndex
= aAction
.getNumberFormat();
774 FuncCount
aAction(mrContext
);
775 aSet
.executeColumnAction(mrDoc
, aAction
);
776 nCount
+= aAction
.getCount();
778 // Get the number format of the last iterated cell.
779 nFuncFmtIndex
= aAction
.getNumberFormat();
782 nFuncFmtType
= mrContext
.NFGetType(nFuncFmtIndex
);
786 ScValueIterator
aValIter( mrContext
, aRange
, mnSubTotalFlags
, bTextAsZero
);
787 FormulaError nErr
= FormulaError::NONE
;
788 if (aValIter
.GetFirst(fVal
, nErr
))
790 // placed the loop on the inside for performance reasons:
791 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
796 if ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
)
800 if ( nErr
== FormulaError::NONE
)
807 while (aValIter
.GetNext(fVal
, nErr
));
817 while (aValIter
.GetNext(fVal
, nErr
));
821 if ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
)
825 if ( nErr
== FormulaError::NONE
)
832 while (aValIter
.GetNext(fVal
, nErr
));
842 while (aValIter
.GetNext(fVal
, nErr
));
848 if ( !( nErr
!= FormulaError::NONE
&& ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) ) )
855 while (aValIter
.GetNext(fVal
, nErr
));
860 if ( nErr
== FormulaError::NONE
)
863 while (aValIter
.GetNext(fVal
, nErr
));
865 default: ; // nothing
870 if (nRefArrayPos
!= std::numeric_limits
<size_t>::max())
872 // Update vector element with current value.
874 xResCount
->PutDouble( xResCount
->GetDouble(0,nRefArrayPos
) + nCount
, 0,nRefArrayPos
);
875 double fVecRes
= xResMat
->GetDouble(0,nRefArrayPos
);
876 if (eFunc
== ifPRODUCT
)
877 fVecRes
*= fRes
.get();
879 fVecRes
+= fRes
.get();
880 xResMat
->PutDouble( fVecRes
, 0,nRefArrayPos
);
884 nRefArrayPos
= std::numeric_limits
<size_t>::max();
888 case svExternalDoubleRef
:
891 PopExternalDoubleRef(pMat
);
892 if ( nGlobalError
!= FormulaError::NONE
&& !( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
895 IterateMatrix( pMat
, eFunc
, bTextAsZero
, mnSubTotalFlags
, nCount
, nFuncFmtType
, fRes
);
900 ScMatrixRef pMat
= PopMatrix();
902 IterateMatrix( pMat
, eFunc
, bTextAsZero
, mnSubTotalFlags
, nCount
, nFuncFmtType
, fRes
);
908 if ( eFunc
== ifCOUNT
|| ( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
910 nGlobalError
= FormulaError::NONE
;
912 else if ( eFunc
== ifCOUNT2
&& !( mnSubTotalFlags
& SubtotalFlags::IgnoreErrVal
) )
915 nGlobalError
= FormulaError::NONE
;
920 while (nParamCount
-- > 0)
922 SetError(FormulaError::IllegalParameter
);
926 // A boolean return type makes no sense on sums et al.
927 // Counts are always numbers.
928 if( nFuncFmtType
== SvNumFormatType::LOGICAL
|| eFunc
== ifCOUNT
|| eFunc
== ifCOUNT2
)
929 nFuncFmtType
= SvNumFormatType::NUMBER
;
933 // Include value of last non-references-array type and calculate final result.
934 for (SCSIZE i
=0; i
< nMatRows
; ++i
)
936 sal_uLong nVecCount
= (xResCount
? nCount
+ xResCount
->GetDouble(0,i
) : nCount
);
937 double fVecRes
= xResMat
->GetDouble(0,i
);
938 if (eFunc
== ifPRODUCT
)
939 fVecRes
*= fRes
.get();
941 fVecRes
+= fRes
.get();
942 fVecRes
= lcl_IterResult( eFunc
, fVecRes
, nVecCount
);
943 xResMat
->PutDouble( fVecRes
, 0,i
);
945 PushMatrix( xResMat
);
949 PushDouble( lcl_IterResult( eFunc
, fRes
.get(), nCount
));
953 void ScInterpreter::ScSumSQ()
955 IterateParameters( ifSUMSQ
);
958 void ScInterpreter::ScSum()
960 IterateParameters( ifSUM
);
963 void ScInterpreter::ScProduct()
965 IterateParameters( ifPRODUCT
);
968 void ScInterpreter::ScAverage( bool bTextAsZero
)
970 IterateParameters( ifAVERAGE
, bTextAsZero
);
973 void ScInterpreter::ScCount()
975 IterateParameters( ifCOUNT
);
978 void ScInterpreter::ScCount2()
980 IterateParameters( ifCOUNT2
);
984 * The purpose of RAWSUBTRACT() is exactly to not apply any error correction, approximation etc.
985 * But use the "raw" IEEE 754 double subtraction.
986 * So no Kahan summation
988 void ScInterpreter::ScRawSubtract()
990 short nParamCount
= GetByte();
991 if (!MustHaveParamCountMin( nParamCount
, 2))
994 // Reverse stack to process arguments from left to right.
995 ReverseStack( nParamCount
);
996 // Obtain the minuend.
997 double fRes
= GetDouble();
999 while (nGlobalError
== FormulaError::NONE
&& --nParamCount
> 0)
1001 // Simple single values without matrix support.
1002 fRes
-= GetDouble();
1004 while (nParamCount
-- > 0)
1010 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */