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 .
21 #include "interpre.hxx"
22 #include "columnspanset.hxx"
24 #include "document.hxx"
25 #include "cellvalue.hxx"
26 #include "dociter.hxx"
27 #include "mtvcellfunc.hxx"
29 #include "formula/token.hxx"
31 using namespace formula
;
33 double const fHalfMachEps
= 0.5 * ::std::numeric_limits
<double>::epsilon();
35 // The idea how this group of gamma functions is calculated, is
36 // based on the Cephes library
37 // online http://www.moshier.net/#Cephes [called 2008-02]
39 /** You must ensure fA>0.0 && fX>0.0
40 valid results only if fX > fA+1.0
41 uses continued fraction with odd items */
42 double ScInterpreter::GetGammaContFraction( double fA
, double fX
)
45 double const fBigInv
= ::std::numeric_limits
<double>::epsilon();
46 double const fBig
= 1.0/fBigInv
;
48 double fNum
= 0.0; // dummy value
50 double fDenom
= fX
+ 2.0-fA
;
51 double fPk
= 0.0; // dummy value
52 double fPkm1
= fX
+ 1.0;
54 double fQk
= 1.0; // dummy value
55 double fQkm1
= fDenom
* fX
;
57 double fApprox
= fPkm1
/fQkm1
;
58 bool bFinished
= false;
59 double fR
= 0.0; // dummy value
66 fPk
= fPkm1
* fDenom
- fPkm2
* fNum
;
67 fQk
= fQkm1
* fDenom
- fQkm2
* fNum
;
71 bFinished
= (fabs( (fApprox
- fR
)/fR
) <= fHalfMachEps
);
80 // reduce a fraction does not change the value
81 fPkm2
= fPkm2
* fBigInv
;
82 fPkm1
= fPkm1
* fBigInv
;
83 fQkm2
= fQkm2
* fBigInv
;
84 fQkm1
= fQkm1
* fBigInv
;
86 } while (!bFinished
&& fCount
<10000);
87 // most iterations, if fX==fAlpha+1.0; approx sqrt(fAlpha) iterations then
90 SetError(errNoConvergence
);
95 /** You must ensure fA>0.0 && fX>0.0
96 valid results only if fX <= fA+1.0
98 double ScInterpreter::GetGammaSeries( double fA
, double fX
)
100 double fDenomfactor
= fA
;
101 double fSummand
= 1.0/fA
;
102 double fSum
= fSummand
;
106 fDenomfactor
= fDenomfactor
+ 1.0;
107 fSummand
= fSummand
* fX
/fDenomfactor
;
108 fSum
= fSum
+ fSummand
;
110 } while ( fSummand
/fSum
> fHalfMachEps
&& nCount
<=10000);
111 // large amount of iterations will be carried out for huge fAlpha, even
112 // if fX <= fAlpha+1.0
115 SetError(errNoConvergence
);
120 /** You must ensure fA>0.0 && fX>0.0) */
121 double ScInterpreter::GetLowRegIGamma( double fA
, double fX
)
123 double fLnFactor
= fA
* log(fX
) - fX
- GetLogGamma(fA
);
124 double fFactor
= exp(fLnFactor
); // Do we need more accuracy than exp(ln()) has?
125 if (fX
>fA
+1.0) // includes fX>1.0; 1-GetUpRegIGamma, continued fraction
126 return 1.0 - fFactor
* GetGammaContFraction(fA
,fX
);
127 else // fX<=1.0 || fX<=fA+1.0, series
128 return fFactor
* GetGammaSeries(fA
,fX
);
131 /** You must ensure fA>0.0 && fX>0.0) */
132 double ScInterpreter::GetUpRegIGamma( double fA
, double fX
)
135 double fLnFactor
= fA
*log(fX
)-fX
-GetLogGamma(fA
);
136 double fFactor
= exp(fLnFactor
); //Do I need more accuracy than exp(ln()) has?;
137 if (fX
>fA
+1.0) // includes fX>1.0
138 return fFactor
* GetGammaContFraction(fA
,fX
);
139 else //fX<=1 || fX<=fA+1, 1-GetLowRegIGamma, series
140 return 1.0 -fFactor
* GetGammaSeries(fA
,fX
);
143 /** Gamma distribution, probability density function.
144 fLambda is "scale" parameter
145 You must ensure fAlpha>0.0 and fLambda>0.0 */
146 double ScInterpreter::GetGammaDistPDF( double fX
, double fAlpha
, double fLambda
)
149 return 0.0; // see ODFF
151 // in this case 0^0 isn't zero
155 SetError(errDivisionByZero
); // should be #DIV/0
158 else if (fAlpha
== 1)
160 return (1.0 / fLambda
);
169 double fXr
= fX
/ fLambda
;
170 // use exp(ln()) only for large arguments because of less accuracy
173 const double fLogDblMax
= log( ::std::numeric_limits
<double>::max());
174 if (log(fXr
) * (fAlpha
-1.0) < fLogDblMax
&& fAlpha
< fMaxGammaArgument
)
176 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
180 return exp( (fAlpha
-1.0) * log(fXr
) - fXr
- log(fLambda
) - GetLogGamma(fAlpha
));
183 else // fXr near to zero
185 if (fAlpha
<fMaxGammaArgument
)
187 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ GetGamma(fAlpha
);
191 return pow( fXr
, fAlpha
-1.0) * exp(-fXr
) / fLambda
/ exp( GetLogGamma(fAlpha
));
197 /** Gamma distribution, cumulative distribution function.
198 fLambda is "scale" parameter
199 You must ensure fAlpha>0.0 and fLambda>0.0 */
200 double ScInterpreter::GetGammaDist( double fX
, double fAlpha
, double fLambda
)
205 return GetLowRegIGamma( fAlpha
, fX
/ fLambda
);
210 class NumericCellAccumulator
214 NumericCellAccumulator() : mfSum(0.0) {}
216 void operator() (size_t, double fVal
)
221 void operator() (size_t, const ScFormulaCell
* pCell
)
223 ScFormulaCell
& rCell
= const_cast<ScFormulaCell
&>(*pCell
);
225 mfSum
+= rCell
.GetValue();
228 double getSum() const { return mfSum
; }
231 class NumericCellCounter
235 NumericCellCounter() : mnCount(0) {}
237 void operator() (const sc::CellStoreType::value_type
& rNode
, size_t nOffset
, size_t nDataSize
)
241 case sc::element_type_numeric
:
242 mnCount
+= nDataSize
;
244 case sc::element_type_formula
:
246 sc::formula_block::const_iterator it
= sc::formula_block::begin(*rNode
.data
);
247 std::advance(it
, nOffset
);
248 sc::formula_block::const_iterator itEnd
= it
;
249 std::advance(itEnd
, nDataSize
);
250 for (; it
!= itEnd
; ++it
)
252 ScFormulaCell
& rCell
= const_cast<ScFormulaCell
&>(**it
);
253 if (rCell
.IsValueNoError())
263 size_t getCount() const { return mnCount
; }
266 class FuncCount
: public sc::ColumnSpanSet::ColumnAction
268 sc::ColumnBlockConstPosition maPos
;
274 FuncCount() : mpCol(0), mnCount(0), mnNumFmt(0) {}
276 virtual void startColumn(ScColumn
* pCol
)
279 mpCol
->InitBlockPosition(maPos
);
282 virtual void execute(SCROW nRow1
, SCROW nRow2
, bool bVal
)
287 NumericCellCounter aFunc
;
288 maPos
.miCellPos
= sc::ParseBlock(maPos
.miCellPos
, mpCol
->GetCellStore(), aFunc
, nRow1
, nRow2
);
289 mnCount
+= aFunc
.getCount();
290 mnNumFmt
= mpCol
->GetNumberFormat(nRow2
);
293 size_t getCount() const { return mnCount
; }
294 sal_uInt32
getNumberFormat() const { return mnNumFmt
; }
297 class FuncSum
: public sc::ColumnSpanSet::ColumnAction
299 sc::ColumnBlockConstPosition maPos
;
305 FuncSum() : mpCol(0), mfSum(0.0), mnNumFmt(0) {}
307 virtual void startColumn(ScColumn
* pCol
)
310 mpCol
->InitBlockPosition(maPos
);
313 virtual void execute(SCROW nRow1
, SCROW nRow2
, bool bVal
)
318 NumericCellAccumulator aFunc
;
319 maPos
.miCellPos
= sc::ParseFormulaNumeric(maPos
.miCellPos
, mpCol
->GetCellStore(), nRow1
, nRow2
, aFunc
);
320 mfSum
+= aFunc
.getSum();
321 mnNumFmt
= mpCol
->GetNumberFormat(nRow2
);
324 double getSum() const { return mfSum
; }
325 sal_uInt32
getNumberFormat() const { return mnNumFmt
; }
329 const ScMatrixRef
& pMat
, ScIterFunc eFunc
, bool bTextAsZero
,
330 sal_uLong
& rCount
, short& rFuncFmtType
, double& fRes
, double& fMem
, bool& bNull
)
335 rFuncFmtType
= NUMBERFORMAT_NUMBER
;
341 ScMatrix::IterateResult aRes
= pMat
->Sum(bTextAsZero
);
349 fRes
+= aRes
.mfFirst
+ aRes
.mfRest
;
350 rCount
+= aRes
.mnCount
;
354 rCount
+= pMat
->Count(bTextAsZero
);
357 rCount
+= pMat
->Count(true);
361 ScMatrix::IterateResult aRes
= pMat
->Product(bTextAsZero
);
363 rCount
+= aRes
.mnCount
;
368 ScMatrix::IterateResult aRes
= pMat
->SumSquare(bTextAsZero
);
370 rCount
+= aRes
.mnCount
;
380 double ScInterpreter::IterateParameters( ScIterFunc eFunc
, bool bTextAsZero
)
382 short nParamCount
= GetByte();
383 double fRes
= ( eFunc
== ifPRODUCT
) ? 1.0 : 0.0;
385 double fMem
= 0.0; // first numeric value.
387 sal_uLong nCount
= 0;
390 size_t nRefInList
= 0;
391 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
393 while (nParamCount
-- > 0)
395 switch (GetStackType())
399 if( eFunc
== ifCOUNT
)
401 OUString aStr
= PopString().getString();
402 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
403 if ( bTextAsZero
|| pFormatter
->IsNumberFormat(aStr
, nFIndex
, fVal
))
419 if ( eFunc
== ifPRODUCT
)
424 while (nParamCount
-- > 0)
426 SetError( errNoValue
);
444 if ( bNull
&& fVal
!= 0.0 )
452 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
453 case ifPRODUCT
: fRes
*= fVal
; break;
454 default: ; // nothing
456 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
458 case svExternalSingleRef
:
460 ScExternalRefCache::TokenRef pToken
;
461 ScExternalRefCache::CellFormat aFmt
;
462 PopExternalSingleRef(pToken
, &aFmt
);
463 if (nGlobalError
&& (eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
))
466 if ( eFunc
== ifCOUNT2
)
474 StackVar eType
= pToken
->GetType();
475 if (eFunc
== ifCOUNT2
)
477 if (eType
!= formula::svEmptyCell
)
482 else if (eType
== formula::svDouble
)
485 fVal
= pToken
->GetDouble();
488 nFuncFmtType
= aFmt
.mnType
;
489 nFuncFmtIndex
= aFmt
.mnIndex
;
495 if ( bNull
&& fVal
!= 0.0 )
503 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
504 case ifPRODUCT
: fRes
*= fVal
; break;
512 default: ; // nothing
515 else if (bTextAsZero
&& eType
== formula::svString
)
518 if ( eFunc
== ifPRODUCT
)
525 PopSingleRef( aAdr
);
526 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
529 if ( eFunc
== ifCOUNT2
)
533 if (glSubTotal
&& pDok
->RowFiltered( aAdr
.Row(), aAdr
.Tab()))
537 ScRefCellValue aCell
;
538 aCell
.assign(*pDok
, aAdr
);
539 if (!aCell
.isEmpty())
541 if( eFunc
== ifCOUNT2
)
543 CellType eCellType
= aCell
.meType
;
544 if (eCellType
!= CELLTYPE_NONE
)
549 else if (aCell
.hasNumeric())
552 fVal
= GetCellValue(aAdr
, aCell
);
558 if ( bNull
&& fVal
!= 0.0 )
566 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
567 case ifPRODUCT
: fRes
*= fVal
; break;
575 default: ; // nothing
578 else if (bTextAsZero
&& aCell
.hasString())
581 if ( eFunc
== ifPRODUCT
)
590 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
591 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
594 if ( eFunc
== ifCOUNT2
)
598 if( eFunc
== ifCOUNT2
)
600 ScCellIterator
aIter( pDok
, aRange
, glSubTotal
);
601 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
603 if (!aIter
.hasEmptyData())
612 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
614 if (aValIter
.GetFirst(fVal
, nErr
))
616 // placed the loop on the inside for performance reasons:
617 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
625 if ( bNull
&& fVal
!= 0.0 )
634 while (aValIter
.GetNext(fVal
, nErr
));
643 while (aValIter
.GetNext(fVal
, nErr
));
652 while (aValIter
.GetNext(fVal
, nErr
));
660 while (aValIter
.GetNext(fVal
, nErr
));
662 default: ; // nothing
669 case svExternalDoubleRef
:
672 PopExternalDoubleRef(pMat
);
676 IterateMatrix(pMat
, eFunc
, bTextAsZero
, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
681 ScMatrixRef pMat
= PopMatrix();
682 IterateMatrix(pMat
, eFunc
, bTextAsZero
, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
688 if ( eFunc
== ifCOUNT
)
692 else if ( eFunc
== ifCOUNT2
)
700 while (nParamCount
-- > 0)
702 SetError(errIllegalParameter
);
707 case ifSUM
: fRes
= ::rtl::math::approxAdd( fRes
, fMem
); break;
708 case ifAVERAGE
: fRes
= div(::rtl::math::approxAdd( fRes
, fMem
), nCount
); break;
710 case ifCOUNT
: fRes
= nCount
; break;
711 case ifPRODUCT
: if ( !nCount
) fRes
= 0.0; break;
712 default: ; // nothing
714 // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
715 // und Anzahl ist immer Number (#38345#)
716 if( eFunc
== ifCOUNT
|| nFuncFmtType
== NUMBERFORMAT_LOGICAL
)
717 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
722 void ScInterpreter::ScSumSQ()
724 PushDouble( IterateParameters( ifSUMSQ
) );
728 void ScInterpreter::ScSum()
730 short nParamCount
= GetByte();
735 size_t nRefInList
= 0;
736 while (nParamCount
-- > 0)
738 switch (GetStackType())
742 while (nParamCount
-- > 0)
744 SetError( errNoValue
);
750 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
752 case svExternalSingleRef
:
754 ScExternalRefCache::TokenRef pToken
;
755 ScExternalRefCache::CellFormat aFmt
;
756 PopExternalSingleRef(pToken
, &aFmt
);
761 StackVar eType
= pToken
->GetType();
762 if (eType
== formula::svDouble
)
764 fVal
= pToken
->GetDouble();
767 nFuncFmtType
= aFmt
.mnType
;
768 nFuncFmtIndex
= aFmt
.mnIndex
;
777 PopSingleRef( aAdr
);
779 if (glSubTotal
&& pDok
->RowFiltered( aAdr
.Row(), aAdr
.Tab()))
783 ScRefCellValue aCell
;
784 aCell
.assign(*pDok
, aAdr
);
785 if (!aCell
.isEmpty())
787 if (aCell
.hasNumeric())
789 fVal
= GetCellValue(aAdr
, aCell
);
799 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
801 sc::ColumnSpanSet
aSet(false);
802 aSet
.set(aRange
, true);
804 // Skip all filtered rows and subtotal formula cells.
805 pDok
->MarkSubTotalCells(aSet
, aRange
, false);
808 aSet
.executeColumnAction(*pDok
, aAction
);
809 fRes
+= aAction
.getSum();
811 // Get the number format of the last iterated cell.
812 nFuncFmtIndex
= aAction
.getNumberFormat();
813 nFuncFmtType
= pDok
->GetFormatTable()->GetType(nFuncFmtIndex
);
816 case svExternalDoubleRef
:
819 PopExternalDoubleRef(pMat
);
823 sal_uLong nCount
= 0;
826 IterateMatrix(pMat
, ifSUM
, false, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
832 ScMatrixRef pMat
= PopMatrix();
833 sal_uLong nCount
= 0;
836 IterateMatrix(pMat
, ifSUM
, false, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
846 while (nParamCount
-- > 0)
848 SetError(errIllegalParameter
);
852 if (nFuncFmtType
== NUMBERFORMAT_LOGICAL
)
853 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
859 void ScInterpreter::ScProduct()
861 PushDouble( IterateParameters( ifPRODUCT
) );
865 void ScInterpreter::ScAverage( bool bTextAsZero
)
867 PushDouble( IterateParameters( ifAVERAGE
, bTextAsZero
) );
870 void ScInterpreter::ScCount()
872 short nParamCount
= GetByte();
874 sal_uLong nCount
= 0;
877 size_t nRefInList
= 0;
881 while (nParamCount
-- > 0)
883 switch (GetRawStackType())
887 OUString aStr
= PopString().getString();
888 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
889 if (pFormatter
->IsNumberFormat(aStr
, nFIndex
, fVal
))
895 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
897 case svExternalSingleRef
:
899 ScExternalRefCache::TokenRef pToken
;
900 ScExternalRefCache::CellFormat aFmt
;
901 PopExternalSingleRef(pToken
, &aFmt
);
911 StackVar eType
= pToken
->GetType();
912 if (eType
== formula::svDouble
)
917 nFuncFmtType
= aFmt
.mnType
;
918 nFuncFmtIndex
= aFmt
.mnIndex
;
931 PopSingleRef( aAdr
);
937 if (glSubTotal
&& pDok
->RowFiltered( aAdr
.Row(), aAdr
.Tab()))
941 ScRefCellValue aCell
;
942 aCell
.assign(*pDok
, aAdr
);
943 if (!aCell
.isEmpty())
945 if (aCell
.hasNumeric())
961 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
968 sc::ColumnSpanSet
aSet(false);
969 aSet
.set(aRange
, true);
971 // Skip all filtered rows and subtotal formula cells.
972 pDok
->MarkSubTotalCells(aSet
, aRange
, false);
975 aSet
.executeColumnAction(*pDok
, aAction
);
976 nCount
+= aAction
.getCount();
978 // Get the number format of the last iterated cell.
979 nFuncFmtIndex
= aAction
.getNumberFormat();
980 nFuncFmtType
= pDok
->GetFormatTable()->GetType(nFuncFmtIndex
);
983 case svExternalDoubleRef
:
986 PopExternalDoubleRef(pMat
);
990 double fMem
= 0.0, fRes
= 0.0;
992 IterateMatrix(pMat
, ifCOUNT
, false, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
997 ScMatrixRef pMat
= PopMatrix();
998 double fMem
= 0.0, fRes
= 0.0;
1000 IterateMatrix(pMat
, ifCOUNT
, false, nCount
, nFuncFmtType
, fRes
, fMem
, bNull
);
1010 while (nParamCount
-- > 0)
1012 SetError(errIllegalParameter
);
1016 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
1022 void ScInterpreter::ScCount2()
1024 PushDouble( IterateParameters( ifCOUNT2
) );
1027 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */