std::accumulate() 只有复数的实部 std::vector
std::accumulate() only the real part of a complex std::vector
我曾经取对称(厄米特)矩阵的总和(矩阵在 std::vector
中),这是一个巨大的浪费,因为虚部总是加为零(我在说关于边长为 n>1000
的巨大矩阵,所以我认为它有所不同。
所以现在我只添加矩阵的上三角部分。但是我想进一步优化它并避免添加复杂的部分,因为我不需要它。
我目前使用的是:
std::real(std::accumulate(myMatrix.begin(), myMatrix.end(), std::complex<Real>(0,0)));
这会将 myMatrix
的所有元素添加到 std::complex<Real>(0,0)
,得到我需要的总和。
但这会添加我的矢量的实部和虚部,这是一种浪费!如何编写仅添加该矩阵实部的最优化版本?
更新:
虽然我接受了有效的答案,但我发现它比对矩阵的实部和虚部求和要慢。对于边长为 128 的矩阵,它会慢 5%-10%。这很令人惊讶。非常感谢任何其他更快的建议。
请询问您是否需要更多信息。
Real real_sum = std::accumulate(
myMatrix.cbegin(), myMatrix.cend(), Real{},
[](Real const acc, std::complex<Real> const& c) { return acc + std::real(c); }
);
std::accumulate
有两个重载,其中一个需要一个运算符:
template< class InputIt, class T, class BinaryOperation >
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
只需提供您自己的而不是默认 +
:
std::accumulate(myMatrix.begin(), myMatrix.end(), Real{0},
[](Real const& sum, std::complex<Real> const& next){
return sum + std::real(next);
});
或者,您可以做一些有趣的事情,比如使用 boost::transform_iterator
:
auto make_real = [](std::complex<Real> const& c) {
return std::real(c);
};
std::accumulate(
boost::make_transform_iterator(myMatrix.begin(), make_real),
boost::make_transform_iterator(myMatrix.end(), make_real),
Real{0});
或 range-v3:
accumulate(myMatrix,
Real{0},
std::plus<>{},
[](std::complex<Real> const& c) { return c.real(); }
);
如果 real
没有重载,以上两个会更好,您可以在提升示例中提供 std::real<Real>
,在第二个示例中提供 &std::complex<Real>::real
。
绝对有必要使用 std::accumulate
吗?
Real acc = 0;
for(auto c : myMatrix)
acc += real(c);
不要误会我的意思,我赞成在合适的时候使用标准算法,但在可读性方面似乎很难超越这个循环。
这是与我的 g++-4.8.4 安装附带的实现相比:
template<typename _InputIterator, typename _Tp>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__init = __init + *__first;
return __init;
}
所以你可以看到他们几乎在做同样的事情。
我曾经取对称(厄米特)矩阵的总和(矩阵在 std::vector
中),这是一个巨大的浪费,因为虚部总是加为零(我在说关于边长为 n>1000
的巨大矩阵,所以我认为它有所不同。
所以现在我只添加矩阵的上三角部分。但是我想进一步优化它并避免添加复杂的部分,因为我不需要它。
我目前使用的是:
std::real(std::accumulate(myMatrix.begin(), myMatrix.end(), std::complex<Real>(0,0)));
这会将 myMatrix
的所有元素添加到 std::complex<Real>(0,0)
,得到我需要的总和。
但这会添加我的矢量的实部和虚部,这是一种浪费!如何编写仅添加该矩阵实部的最优化版本?
更新:
虽然我接受了有效的答案,但我发现它比对矩阵的实部和虚部求和要慢。对于边长为 128 的矩阵,它会慢 5%-10%。这很令人惊讶。非常感谢任何其他更快的建议。
请询问您是否需要更多信息。
Real real_sum = std::accumulate(
myMatrix.cbegin(), myMatrix.cend(), Real{},
[](Real const acc, std::complex<Real> const& c) { return acc + std::real(c); }
);
std::accumulate
有两个重载,其中一个需要一个运算符:
template< class InputIt, class T, class BinaryOperation >
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
只需提供您自己的而不是默认 +
:
std::accumulate(myMatrix.begin(), myMatrix.end(), Real{0},
[](Real const& sum, std::complex<Real> const& next){
return sum + std::real(next);
});
或者,您可以做一些有趣的事情,比如使用 boost::transform_iterator
:
auto make_real = [](std::complex<Real> const& c) {
return std::real(c);
};
std::accumulate(
boost::make_transform_iterator(myMatrix.begin(), make_real),
boost::make_transform_iterator(myMatrix.end(), make_real),
Real{0});
或 range-v3:
accumulate(myMatrix,
Real{0},
std::plus<>{},
[](std::complex<Real> const& c) { return c.real(); }
);
如果 real
没有重载,以上两个会更好,您可以在提升示例中提供 std::real<Real>
,在第二个示例中提供 &std::complex<Real>::real
。
绝对有必要使用 std::accumulate
吗?
Real acc = 0;
for(auto c : myMatrix)
acc += real(c);
不要误会我的意思,我赞成在合适的时候使用标准算法,但在可读性方面似乎很难超越这个循环。
这是与我的 g++-4.8.4 安装附带的实现相比:
template<typename _InputIterator, typename _Tp>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__init = __init + *__first;
return __init;
}
所以你可以看到他们几乎在做同样的事情。