性能差异:std::accumulate vs std::inner_product vs Loop

2023-11-24

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

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,这些值被视为整数,并且在每次累加中,编译器都会进行转换。在不同的测试用例中,我的输入数组存储截断的浮点数,因此结果没有改变。

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

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

And:

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

我得到了预期的结果:

enter image description here

现在,我明白,将初始值保留为独立于迭代器基础类型的类型可能会使函数更加灵活并允许执行更多操作。但,

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

它应该是默认行为吗?

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


如果我正在累积数组的元素,我希望得到相同类型的结果。

您的期望是错误的(尽管不太清楚“与结果相同的类型”是什么意思),正如您可以清楚地看到的std::累积文档:

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];
}

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

因为这样你就可以决定使用什么类型来聚合。笔记std::accumulate可用于左折叠和箱子T不等于std::iterator_traits<InputIt>::value_type并不比它们匹配时更少(甚至可能更多)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

性能差异:std::accumulate vs std::inner_product vs Loop 的相关文章

随机推荐

  • 有没有更 Pythonic 的方法来防止向列表中添加重复项?

    是否有更Pythonic 或简洁 的方法来防止向列表添加重复项 if item not in item list item list append item 或者这实际上是一种廉价的操作 由于 hcwsha的原始解决方案已被替换 我将其记录
  • C# unity 通过属性拦截

    有没有办法在 C unity 中使用属性拦截并将对象注册代码保留在 XML 文件 如 app config 中 如果是的话 您能给我提供代码吗 这样的注册应该是什么样子 我做了很多解决方法 但没有找到解决此问题的有效解决方案 我假设您的意思
  • Firefox 内容脚本未在某些页面加载

    Context 我目前正在开发一个浏览器扩展 它可以在 Chrome 和 Opera 上按预期工作 但在 Firefox 上遇到问题 这是一个最小版本manifest json重现问题所需 name Example version 0 0
  • 如何在 3D 空间中正确移动相机?

    我想做的事 我正在尝试弄清楚如何使相机像这样工作 鼠标移动 相机旋转 上 下键 摄像机前进 后退 向前表示相机面向的方向 左 右键 相机横向移动 Q E键 相机上下移动 由于我有很多代码 因此我将尽力解释我是如何做到的 而不需要太多代码 我
  • 如何使用 python 重试 Behave 中的失败场景

    有人可以告诉我如何使用 Python 在 Behave 中再次运行失败的测试吗 如果失败 我想自动重新运行失败的测试用例 行为库实际上有一个RerunFormatter这可以帮助您重新运行之前测试运行的失败场景 它会创建一个包含所有失败场景
  • Android NavigationView 带圆角

    我正在设计一个定制抽屉 on Android 它的顶部和底部必须有圆角 我首先自定义顶部 我发现问题是形状的背景不透明 I have source toile libre org I need to build source toile l
  • 为什么“插入”函数不使用 MySQLdb 添加行?

    我正在尝试弄清楚如何在 Python 中使用 MySQLdb 库 对于这两个库我充其量都是新手 我正在关注代码here 具体来说 cursor conn cursor cursor execute DROP TABLE IF EXISTS
  • 如何将因子转换为整数\数字而不丢失信息?

    当我将因子转换为数字或整数时 我得到的是基础级别代码 而不是数字形式的值 f lt factor sample runif 5 20 replace TRUE 1 0 0248644019011408 0 0248644019011408
  • Java方法对任意数量的整数求和

    我需要写一个java方法sumAll 它接受任意数量的整数并返回它们的总和 sumAll 1 2 3 returns 6 sumAll returns 0 sumAll 20 returns 20 我不知道该怎么做 如果您使用 Java8
  • 使用 array_multisort() 和动态数量的参数/参数/规则/数据对数组进行排序

    我正在尝试对任何数组进行排序array multisort 一切都很好 但是 根据脚本中的条件 我需要更改选项 到目前为止我所拥有的是这样的 array multisort sort1 SORT ASC sort2 SORT ASC sor
  • 如何在Python中的绘图中添加填充?

    我正在尝试在绘图的左侧和右侧添加填充 但是当我改变 xlim 和 ylim 时 图像变小 我究竟做错了什么 import matplotlib pyplot as plt plt rcParams text usetex False fro
  • 在JSF2中,如何知道复合组件是否有子组件?

    我正在编写一个复合组件 您有一个名为 的特殊标签
  • 获取 Android 蓝牙设备的重命名名称

    我的 Android 手机允许我重命名已配对的设备 方法是转至 设置 gt 无线和网络 gt 蓝牙 活动页面 然后单击已配对蓝牙设备右侧的设置按钮 但是 当我查询带有以下内容的绑定设备列表时蓝牙适配器 getBondedDevices 函数
  • 如何区分日志文件中的 log4j 会话和同一 Web 应用程序的副本?

    只有一个文件 它是在 Web 应用程序副本运行时同时写入的 如何从其他日志行中仅过滤一条会话日志消息 使用具有 NDC 或 MDC 信息的 servlet 过滤器是我见过的最好方法 两者的快速比较可以在http wiki apache or
  • IL 中的 ldsfld 和 ldstr 有什么区别?

    我读过一些关于 String Empty 与 的文章 我也自己做了测试 它们之间的区别如下 字符串 空 L 0001 ldsfld string mscorlib System String Empty L 0001 ldstr 在我与朋友
  • 如何删除python3中的b符号

    如何去除bpython3脚本中的符号 import subprocess get data subprocess check output df k awk print 6 shell True data arr get data spli
  • 如何在 JasperReports 中使用条件 TextField?

    我想要一对取决于值的文本字段 并且 y 值应根据空白空间进行调整 当值为 0 我想隐藏文本字段 IE 我想隐藏staticText和textField如果参数red等于 0 并将蓝色值向上移动 在下面的 jrxml 代码中
  • RVM 的 Rails 脚本分段错误

    我遇到分段错误 应该which ruby返回 usr local bin maletor rails generate mailer ContactMailer Users maletor rvm gems ruby 1 9 2 p0 ge
  • Elixir - https URL 的问题

    我是 Elixir 和 Erlang 的新手 在访问 https URL 时遇到一些问题 我已经尝试过 Elixir 特定的HTTP选项和 Erlang 的 inets module 因此 从 iex 控制台 Interactive Eli
  • 性能差异:std::accumulate vs std::inner_product vs Loop

    今天 我想分享一些在我尝试实现这个简单操作时令我震惊的事情 我发现执行相同操作的不同方法 通过使用std inner product 实现谓词并使用std accumulate功能 使用 C 风格的循环 我想通过使用 Quick Bench