Kaydet (Commit) 83f77ab0 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Rework SUMPRODUCT to reduce the number of block position lookups.

Change-Id: I22b843142b76df1c51597a8138b1674286f78792
üst 9c1ca6dc
......@@ -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)
{
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);
}
......
......@@ -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: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment