diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-07-01 15:47:41 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-07-01 18:55:53 -0400 |
commit | 83f77ab0661df992f241e5f9ecb1aa8f8eaeafec (patch) | |
tree | 9890f84253d5ba548a234a44febc80e09deece62 /sc | |
parent | 9c1ca6dca3b553c302a635357e33591605343b99 (diff) |
Rework SUMPRODUCT to reduce the number of block position lookups.
Change-Id: I22b843142b76df1c51597a8138b1674286f78792
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/scmatrix.hxx | 6 | ||||
-rw-r--r-- | sc/source/core/tool/interpr5.cxx | 92 | ||||
-rw-r--r-- | sc/source/core/tool/scmatrix.cxx | 156 |
3 files changed, 223 insertions, 31 deletions
diff --git a/sc/inc/scmatrix.hxx b/sc/inc/scmatrix.hxx index d6ac2791bb99..ccb989f438f4 100644 --- a/sc/inc/scmatrix.hxx +++ b/sc/inc/scmatrix.hxx @@ -119,6 +119,8 @@ class SC_DLLPUBLIC ScMatrix ScMatrix& operator=( const ScMatrix&); public: + enum Op { Add, Sub, Mul, Div }; + /** * When adding all numerical matrix elements for a scalar result such as * summation, the interpreter wants to separate the first non-zero value @@ -352,8 +354,8 @@ public: double GetMaxValue( bool bTextAsZero ) const; double GetMinValue( bool bTextAsZero ) const; - // All other matrix functions MatMult, MInv, ... are in ScInterpreter - // to be numerically safe. + void GetDoubleArray( std::vector<double>& rArray ) const; + void MergeDoubleArray( std::vector<double>& rArray, Op eOp ) const; #if DEBUG_MATRIX void Dump() const; diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx index c6fc44a3509e..79a038d326b2 100644 --- a/sc/source/core/tool/interpr5.cxx +++ b/sc/source/core/tool/interpr5.cxx @@ -1595,6 +1595,49 @@ void ScInterpreter::ScPow() PushDouble(pow(fVal1,fVal2)); } +namespace { + +bool mergeArray( std::vector<double>& rRes, const std::vector<double>& rOther ) +{ + if (rRes.size() != rOther.size()) + return false; + + double fNan; + rtl::math::setNan(&fNan); + + std::vector<double>::iterator it = rRes.begin(), itEnd = rRes.end(); + std::vector<double>::const_iterator itOther = rOther.begin(); + for (; it != itEnd; ++it, ++itOther) + { + if (rtl::math::isNan(*it) || rtl::math::isNan(*itOther)) + { + *it = fNan; + continue; + } + + *it *= *itOther; + } + + return true; +} + +class SumValues : std::unary_function<double, void> +{ + double mfSum; +public: + SumValues() : mfSum(0.0) {} + + void operator() (double f) + { + if (!rtl::math::isNan(f)) + mfSum += f; + } + + double getValue() const { return mfSum; } +}; + +} + void ScInterpreter::ScSumProduct() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumProduct" ); @@ -1602,49 +1645,40 @@ void ScInterpreter::ScSumProduct() if ( !MustHaveParamCount( nParamCount, 1, 30 ) ) return; - ScMatrixRef pMat1 = NULL; - ScMatrixRef pMat2 = NULL; - ScMatrixRef pMat = NULL; - pMat2 = GetMatrix(); - if (!pMat2) + ScMatrixRef pMatLast; + ScMatrixRef pMat; + + pMatLast = GetMatrix(); + if (!pMatLast) { PushIllegalParameter(); return; } - SCSIZE nC, nC1; - SCSIZE nR, nR1; - pMat2->GetDimensions(nC, nR); - pMat = pMat2; - for (sal_uInt16 i = 1; i < nParamCount; i++) + + SCSIZE nC, nCLast, nR, nRLast; + pMatLast->GetDimensions(nCLast, nRLast); + std::vector<double> aResArray; + pMatLast->GetDoubleArray(aResArray); + + for (sal_uInt16 i = 1; i < nParamCount; ++i) { - pMat1 = GetMatrix(); - if (!pMat1) + pMat = GetMatrix(); + if (!pMat) { PushIllegalParameter(); return; } - pMat1->GetDimensions(nC1, nR1); - if (nC1 != nC || nR1 != nR) - { - PushNoValue(); - return; - } - ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixMul>(*pMat1, *pMat, this); - if (!pResMat) + pMat->GetDimensions(nC, nR); + if (nC != nCLast || nR != nRLast) { PushNoValue(); return; } - else - pMat = pResMat; - } - double fSum = 0.0; - SCSIZE nCount = pMat->GetElementCount(); - for (SCSIZE j = 0; j < nCount; j++) - { - if (!pMat->IsString(j)) - fSum += pMat->GetDouble(j); + + pMat->MergeDoubleArray(aResArray, ScMatrix::Mul); } + + double fSum = std::for_each(aResArray.begin(), aResArray.end(), SumValues()).getValue(); PushDouble(fSum); } diff --git a/sc/source/core/tool/scmatrix.cxx b/sc/source/core/tool/scmatrix.cxx index b0bef2ebc701..ffc33826bdb8 100644 --- a/sc/source/core/tool/scmatrix.cxx +++ b/sc/source/core/tool/scmatrix.cxx @@ -225,6 +225,8 @@ public: double GetMaxValue( bool bTextAsZero ) const; double GetMinValue( bool bTextAsZero ) const; + void GetDoubleArray( std::vector<double>& rArray ) const; + void MergeDoubleArray( std::vector<double>& rArray, ScMatrix::Op eOp ) const; #if DEBUG_MATRIX void Dump() const; @@ -1022,6 +1024,121 @@ public: } }; +class ToDoubleArray : std::unary_function<MatrixImplType::element_block_type, void> +{ + std::vector<double> maArray; + std::vector<double>::iterator miPos; + double mfNaN; +public: + ToDoubleArray(size_t nSize) : maArray(nSize, 0.0), miPos(maArray.begin()) + { + rtl::math::setNan(&mfNaN); + } + + void operator() (const MatrixImplType::element_block_node_type& node) + { + using namespace mdds::mtv; + + switch (node.type) + { + case mdds::mtm::element_numeric: + { + numeric_element_block::const_iterator it = numeric_element_block::begin(*node.data); + numeric_element_block::const_iterator itEnd = numeric_element_block::end(*node.data); + for (; it != itEnd; ++it, ++miPos) + *miPos = *it; + } + break; + case mdds::mtm::element_boolean: + { + boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data); + boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data); + for (; it != itEnd; ++it, ++miPos) + *miPos = *it ? 1.0 : 0.0; + } + break; + case mdds::mtm::element_string: + { + for (size_t i = 0; i < node.size; ++i, ++miPos) + *miPos = mfNaN; + } + break; + default: + ; + } + } + + void swap(std::vector<double>& rOther) + { + maArray.swap(rOther); + } +}; + +struct ArrayMul : public std::binary_function<double, double, double> +{ + double operator() (const double& lhs, const double& rhs) const + { + return lhs * rhs; + } +}; + +template<typename _Op> +class MergeDoubleArrayFunc : std::unary_function<MatrixImplType::element_block_type, void> +{ + std::vector<double>& mrArray; + std::vector<double>::iterator miPos; + double mfNaN; +public: + MergeDoubleArrayFunc(std::vector<double>& rArray) : mrArray(rArray), miPos(mrArray.begin()) + { + rtl::math::setNan(&mfNaN); + } + + void operator() (const MatrixImplType::element_block_node_type& node) + { + using namespace mdds::mtv; + static _Op op; + + switch (node.type) + { + case mdds::mtm::element_numeric: + { + numeric_element_block::const_iterator it = numeric_element_block::begin(*node.data); + numeric_element_block::const_iterator itEnd = numeric_element_block::end(*node.data); + for (; it != itEnd; ++it, ++miPos) + { + if (rtl::math::isNan(*miPos)) + continue; + + *miPos = op(*miPos, *it); + } + } + break; + case mdds::mtm::element_boolean: + { + boolean_element_block::const_iterator it = boolean_element_block::begin(*node.data); + boolean_element_block::const_iterator itEnd = boolean_element_block::end(*node.data); + for (; it != itEnd; ++it, ++miPos) + { + if (rtl::math::isNan(*miPos)) + continue; + + *miPos = op(*miPos, *it ? 1.0 : 0.0); + } + } + break; + case mdds::mtm::element_string: + { + for (size_t i = 0; i < node.size; ++i, ++miPos) + *miPos = mfNaN; + } + break; + default: + ; + } + } +}; + } ScMatrix::IterateResult ScMatrixImpl::Sum(bool bTextAsZero) const @@ -1067,6 +1184,34 @@ double ScMatrixImpl::GetMinValue( bool bTextAsZero ) const return aFunc.getValue(); } +void ScMatrixImpl::GetDoubleArray( std::vector<double>& rArray ) const +{ + MatrixImplType::size_pair_type aSize = maMat.size(); + ToDoubleArray aFunc(aSize.row*aSize.column); + maMat.walk(aFunc); + aFunc.swap(rArray); +} + +void ScMatrixImpl::MergeDoubleArray( std::vector<double>& rArray, ScMatrix::Op eOp ) const +{ + MatrixImplType::size_pair_type aSize = maMat.size(); + size_t nSize = aSize.row*aSize.column; + if (nSize != rArray.size()) + return; + + switch (eOp) + { + case ScMatrix::Mul: + { + MergeDoubleArrayFunc<ArrayMul> aFunc(rArray); + maMat.walk(aFunc); + } + break; + default: + ; + } +} + #if DEBUG_MATRIX void ScMatrixImpl::Dump() const { @@ -1419,6 +1564,16 @@ double ScMatrix::GetMinValue( bool bTextAsZero ) const return pImpl->GetMinValue(bTextAsZero); } +void ScMatrix::GetDoubleArray( std::vector<double>& rArray ) const +{ + pImpl->GetDoubleArray(rArray); +} + +void ScMatrix::MergeDoubleArray( std::vector<double>& rArray, Op eOp ) const +{ + pImpl->MergeDoubleArray(rArray, eOp); +} + #if DEBUG_MATRIX void ScMatrix::Dump() const { @@ -1427,3 +1582,4 @@ void ScMatrix::Dump() const #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + |