summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-07-01 15:47:41 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-07-01 18:55:53 -0400
commit83f77ab0661df992f241e5f9ecb1aa8f8eaeafec (patch)
tree9890f84253d5ba548a234a44febc80e09deece62 /sc
parent9c1ca6dca3b553c302a635357e33591605343b99 (diff)
Rework SUMPRODUCT to reduce the number of block position lookups.
Change-Id: I22b843142b76df1c51597a8138b1674286f78792
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/scmatrix.hxx6
-rw-r--r--sc/source/core/tool/interpr5.cxx92
-rw-r--r--sc/source/core/tool/scmatrix.cxx156
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: */
+