Rework SUMPRODUCT to reduce the number of block position lookups.
Change-Id: I22b843142b76df1c51597a8138b1674286f78792
This commit is contained in:
@@ -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;
|
||||
|
@@ -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)
|
||||
pMat->GetDimensions(nC, nR);
|
||||
if (nC != nCLast || nR != nRLast)
|
||||
{
|
||||
PushNoValue();
|
||||
return;
|
||||
}
|
||||
ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixMul>(*pMat1, *pMat, this);
|
||||
if (!pResMat)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@@ -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: */
|
||||
|
||||
|
Reference in New Issue
Block a user