gpt4 book ai didi

c++ - 性能差异:std::accumulate vs std::inner_product vs Loop

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:42:27 25 4
gpt4 key购买 nike

今天,我想分享一些在尝试实现这个简单操作时让我大吃一惊的事情:

enter image description here

我发现了执行相同操作的不同方法:

  1. 通过使用 std::inner_product
  2. 实现谓词并使用 std::accumulate 函数。
  3. 使用 C 风格的循环。

我想通过使用 Quick Bench 并启用所有优化来执行一些基准测试。

首先,我比较了两个具有浮点值的 C++ 替代方案。这是通过使用 std::accumulate 使用的代码:

const auto predicate = [](const double previous, const double current) {
return previous + current * current;
};
const auto result = std::accumulate(input.cbegin(), input.cend(), 0, predicate);

通过使用 std::inner_product 功能与此代码对比:

const auto result = std::inner_product(input.cbegin(), input.cend(), input.cbegin(), 1);

在启用所有优化的情况下运行基准测试后,我得到了这个结果:

enter image description here

这两种算法似乎达到了相同的性能。我确实想更进一步尝试 C 实现:

double result = 0;
for (auto i = 0; i < input.size(); ++i) {
result += input[i] * input[i];
}

令人惊讶的是,我发现:

enter image description here

没想到会是这样的结果。我确定有问题所以我检查了 GCC 实现:

template<typename _InputIterator1, typename _InputIterator2, typename _Tp>
inline _Tp
inner_product(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _Tp __init)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>)
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>)
__glibcxx_requires_valid_range(__first1, __last1);

for (; __first1 != __last1; ++__first1, (void)++__first2)
__init = __init + (*__first1 * *__first2);
return __init;
}

我发现它和 C 实现一样。在回顾了实现之后,我发现了一些奇怪的东西,(或者至少我没想到会有那么大的影响):在所有的内部累加中,它都在做从迭代器 value_type 到初始值类型的转换。

在我的例子中,我将初始值初始化为 0 或 1,这些值被视为整数,并且在每次累加中,编译器都在进行转换。在不同的测试用例中,我的输入数组存储截断的 float ,所以结果没有改变。

将初始值更新为double类型后:

const auto result = std::accumulate(input.cbegin(), input.cend(), 0.0, predicate);

和:

const auto result = std::inner_product(input.cbegin(), input.cend(), input.cbegin(), 0.0);

我得到了预期的结果:

enter image description here

现在,我了解到将初始值保留为独立于迭代器基础类型的类型可能会使函数更加灵活并允许做更多的事情。但是,

如果我正在累积一个数组的元素,我希望得到与结果相同的类型。内积也一样。

它应该是默认行为吗?

为什么标准决定以这种方式执行?

最佳答案

If I am accumulating elements of an array, I am expecting to get the same type as a result.

你的期望是错误的(虽然不太清楚“与结果相同类型”是什么意思),正如你可以从std::accumulate中清楚地看到的那样文档:

template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );

template< class InputIt, class T, class BinaryOperation >
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );

返回类型与您用于初始值的类型完全相同。您可以在循环中产生相同的效果:

auto result = 0; // vs auto result = 0.0;
for (auto i = 0; i < input.size(); ++i) {
result += input[i] * input[i];
}

Why did the standard decide to perform it in this way?

因为这样你可以决定你使用什么类型来聚合。备注std::accumulate可用于左折叠和以下情况 T不等于 std::iterator_traits<InputIt>::value_type不少于(可能甚至更多)它们匹配时的频率。

关于c++ - 性能差异:std::accumulate vs std::inner_product vs Loop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52167695/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com