C++ 标准库的 <numeric> 头文件是进行数值计算的宝库。它不仅仅包含几个简单的函数,而是提供了一整套强大、高效且灵活的算法,用于处理序列数据。这些算法能够帮助我们写出更简洁、更具表现力且性能更高的代码,尤其是在现代 C++ (C++17 及以后) 中,它们中的许多都支持并行执行。
本文将全面介绍 <numeric> 头文件中的核心算法,分为三大类:
这类算法的目标是将一个序列中的所有元素通过某个二元操作(如加法、乘法)合并成一个单一的值。
std::accumulate (C++98)这是最经典、最基础的累积算法。它严格按照从左到右的顺序进行计算。
[first, last) 中所有元素的总和,从一个初始值 init 开始。std::reduce (C++17)std::reduce 是 std::accumulate 的现代化、可并行化版本。
accumulate 类似,但不保证计算顺序。std::execution::par 等执行策略进行并行计算,从而大幅提升性能。init 参数的版本,它会使用元素类型的默认构造函数(例如 int{} 即 0)作为初始值。何时选择?
- 需要保证顺序(如减法),或在 C++17 之前的代码中,使用
std::accumulate。- 追求性能,且操作允许乱序(如加法),现代 C++ 代码首选
std::reduce。
std::inner_product (C++98)std::transform_reduce (C++17)这是最强大的归约算法,完美体现了 "map-reduce" 思想。
扫描算法不会将序列归约为单个值,而是生成一个包含所有中间累积结果的新序列。
std::partial_sum (C++98)inclusive_scan 的早期版本。结果中的第 i 个元素是原序列前 i+1 个元素的和。std::inclusive_scan &std::exclusive_scan (C++17)这两个是现代化的、可并行的扫描算法。
inclusive_scan:包含当前元素的扫描,行为与 partial_sum 相同。exclusive_scan:不包含当前元素的扫描,结果中的第 i 个元素是原序列前 i 个元素的和。std::adjacent_difference (C++98)partial_sum 的逆运算,计算序列中每两个相邻元素之间的差。std::iota (C++11)std::gcd &std::lcm (C++17)<numeric> 头文件为 C++ 开发者提供了一套声明式、高效且功能强大的工具。通过使用这些算法,我们可以:
accumulate, transform_reduce)清晰地表达了代码的意图。下次当你需要对一个序列进行数值计算时,不妨先查阅一下 <numeric> 头文件,很可能已经有一个完美的算法在等着你了。