当前位置: 首页 > news >正文

刷力扣用for求了无数次数组和?别急,numeric来救急

C++ 的<numeric>头文件主要包含用于数值计算算法处理的通用函数。虽然它的名字暗示它只处理数字,但其中的许多算法(如accumulate,inner_product)实际上是通过模板实现的,可以应用于任何支持特定运算符(如+,*)的用户自定义类型(例如矩阵、多项式或大整数类)。

在 C++17 和 C++20 中,这个库得到了显著增强,增加了并行执行支持和更多实用的数学工具。

首先就是我们的求和工具std::accumulate

  • 原型:T accumulate(Iter first, Iter last, T init);
  • 功能: 从init开始,依次将范围内的元素加到结果中。
  • 注意: 初始值init的类型决定了返回值的类型。如果处理整数但需要浮点结果,必须传入0.0而不是0
#include <iostream> #include <numeric> #include <vector> int main() { std::vector<int> nums = {1, 2, 3, 4, 5}; // 整数求和: 1+2+3+4+5 = 15 int sum_int = std::accumulate(nums.begin(), nums.end(), 0); // 浮点求和: 必须传入 0.0,否则会发生整数除法或截断 double sum_double = std::accumulate(nums.begin(), nums.end(), 0.0); // 自定义操作:计算乘积 (1*2*3*4*5 = 120) // C++17 起可以使用执行策略,但 accumulate 本身通常不带执行策略参数,需用 reduce //最后一个参数就代表归约为乘积计算,如果你想归约为加法就是std::plus<int>() int product = std::accumulate(nums.begin(), nums.end(), 1, std::multiplies<int>()); std::cout << "Sum: " << sum_int << ", Product: " << product << "\n"; return 0; }

这个库在C++17引入了并行与归约, reduce 与 transform_reduce (相关概念的解释在文末)

std::reducestd::transform_reduce的核心区别在于:是否在“归约(求和/累积)”之前,先对每个元素进行“变换(修改)”

#include <iostream> #include <numeric> #include <vector> #include <execution> // 并行执行策略 int main() { std::vector<int> large_data(1000000, 2); // 顺序执行 (类似 accumulate) auto sum_seq = std::reduce(large_data.begin(), large_data.end(), 0); // 并行执行 (利用多核 CPU) // std::execution::par 表示并行,std::execution::par_unseq 表示并行且无序 auto sum_par = std::reduce(std::execution::par, large_data.begin(), large_data.end(), 0); // Transform Reduce: 计算平方和 (2^2 + 2^2 + ...) auto sum_squares = std::transform_reduce( std::execution::par, large_data.begin(), large_data.end(), 0, // 初始值 std::plus<int>(), // 归约操作 (加) [](int x) { return x * x; } // 变换操作 (平方) ); std::cout << "Parallel Sum: " << sum_par << "\n"; return 0; }

可以看到,使用transform_reduce时,先修改每个数变成平方(lambda表达式)再执行归约

std::adjacent_difference 用于计算相邻元素的差值
  • 输出序列的第一个元素等于输入序列的第一个元素
#include <numeric> #include <vector> #include <iostream> int main() { std::vector<int> data = {1, 2, 4, 7, 11}; std::vector<int> diffs(data.size()); // 结果: {1, 2-1, 4-2, 7-4, 11-7} -> {1, 1, 2, 3, 4} std::adjacent_difference(data.begin(), data.end(), diffs.begin()); for (int n : diffs) std::cout << n << " "; std::cout << "\n"; return 0; }

std::partial_sum计算前缀和

输出序列的第 ii 个元素是输入序列前 i+1i+1 个元素的和

#include <numeric> #include <vector> #include <iostream> int main() { std::vector<int> nums = {1, 2, 3, 4}; std::vector<int> sums(nums.size()); std::partial_sum(nums.begin(), nums.end(), sums.begin()); for (int n : sums) std::cout << n << " "; // 输出: 1 3 6 10 return 0; }

除此之外,C++17引入了一些数学工具函数

  • std::gcd(a, b): 计算最大公约数 (Greatest Common Divisor)。
  • std::lcm(a, b): 计算最小公倍数 (Least Common Multiple)。
  • std::midpoint(a, b): 计算两个值的中间点,避免溢出
    • 传统写法(a + b) / 2ab很大时会溢出。

std::iota用于填充范围为连续递增的值。

作用: 将范围[first, last)填充为value, value+1, value+2...

#include <numeric> #include <vector> #include <iostream> int main() { std::vector<int> indices(5); // 填充为 0, 1, 2, 3, 4 std::iota(indices.begin(), indices.end(), 0); for (int i : indices) std::cout << i << " "; return 0; }

什么是执行策略,并行,归约?

旨在让标准库算法(如sort,reduce,for_each)能够利用多核 CPU 加速运行。

  • 执行策略 (Execution Policy):你告诉算法“可以怎么跑”(串行、并行、还是向量化)。
  • 并行 (Parallel):算法实际利用多个线程同时工作的状态。
  • 归约 (Reduction):一种将一堆数据“压缩”成一个结果的计算模式(如求和、求最大值),它是并行计算中最常见的操作。

在 C++17 之前,标准算法(如std::sort)只能是单线程顺序执行的。C++17 允许你在调用算法时传入一个执行策略对象作为第一个参数,以此指示库是否可以并行执行。

这些策略定义在<execution>头文件中,属于std::execution命名空间。

四种主要策略:

表格

策略对象名称含义适用场景注意事项
std::execution::seq顺序执行强制单线程。行为与 C++17 之前的算法完全一致。需要严格顺序依赖的操作;调试时。无额外开销,最安全。
std::execution::par并行执行允许多线程。算法可以将任务拆分到多个线程运行,但每个线程内的操作必须按顺序执行大部分可并行化的任务(如排序、查找)。数据竞争危险:如果操作涉及共享状态,需自行加锁或使用原子操作。
std::execution::par_unseq并行且无序允许多线程 + 向量化 (SIMD)。不仅可以在不同线程间并行,还可以在一个线程内通过 CPU 指令集(如 AVX)对数据进行向量化处理,且不保证元素访问顺序高性能数值计算、图像处理。限制最严:不能使用互斥锁,不能依赖元素访问顺序,不能有异常抛出(通常会导致std::terminate)。
std::execution::unseq无序执行 (C++20)仅允许向量化,不允许多线程。单线程内的 SIMD 优化。较少直接使用,通常由编译器自动优化或配合par_unseq
#include <algorithm> #include <vector> #include <execution> // 必须包含 void example() { std::vector<int> v = {5, 2, 9, 1, 5, 6}; // 1. 顺序执行 (传统方式) std::sort(v.begin(), v.end()); // 2. 并行执行 (可能使用多线程) std::sort(std::execution::par, v.begin(), v.end()); // 3. 并行 + 向量化 (最快,但限制最多) std::sort(std::execution::par_unseq, v.begin(), v.end()); }

归约是一种函数式编程概念,指将一个序列(集合)通过某种二元操作(如加法、乘法、取最大值),逐步合并成单个值的过程。

  • 常见例子:求和 (sum)、求积 (product)、求最大值 (max)、逻辑与 (all_of)。
C++ 中的归约算法:std::reduce
  • std::accumulate严格顺序执行。 (((init+v0)+v1)+v2)...(((init+v0​)+v1​)+v2​)...
  • std::reduce无序执行。它允许以任意顺序组合元素,以便并行。

重要约束:使用std::reduce时,你的操作符必须满足交换律结合律

就比如我们刚才使用accumulate或transfrom_reduce最后一个参数,那个就是你只要指定的归约

(accumulate和reduce如果不显示指定归约默认就是plus)

加法std::plus<T>a+b求和 (最常用)
乘法std::multiplies<T>a×b求积 (阶乘、概率连乘)
最大值std::maximum<T>max⁡(a,b)找最大值
最小值std::minimum<T>min⁡(a,b)找最小值
逻辑与std::logical_and<T>a∧b检查是否所有元素都满足条件
逻辑或std::logical_or<T>a∨b检查是否存在元素满足条件
按位与std::bit_and<T>a & b位运算掩码
按位或std::bit_or<T>$ a \\ b $
http://www.cnnetsun.cn/news/1509976.html

相关文章:

  • DeepSeek-OCR实战教程:批量处理脚本编写与异步解析任务队列设计
  • HTML常见标签
  • OpenCore Legacy Patcher终极指南:如何让旧Mac焕发新生,流畅运行最新macOS
  • CosyVoice语音克隆应用案例:为短视频配音、制作个性化语音问候消息
  • Node.js环境配置大全:LiuJuan20260223Zimage一键部署方案
  • 浦语灵笔2.5-7B显存优化实战:避免OOM的图片缩放与问题长度控制策略
  • Pixel Dimension Fissioner 游戏素材生成:角色、场景与道具像素画全流程
  • 抖音下载器终极指南:一键获取无水印视频的完整解决方案
  • CentOS 7下gdb升级踩坑实录:从7.6到14.2的全过程指南
  • 基于WebSocket与Protobuf协议的抖音直播间实时数据采集方案
  • HunyuanVideo-Foley应用场景:无障碍内容创作中AI语音描述+音效增强
  • Django 学习日记(补充1)| 彻底吃透:自定义 JWT 认证 + 全局登录中间件
  • window10添加用户
  • 个人创作者应该怎么选择发展平台
  • 现代物流之智慧基石:基于西门子PLC的智能饲喂系统综合设计与实现
  • DeOldify图像上色服务极限测试:处理超大规模分辨率图像的性能与技巧
  • WeMod Pro功能解锁技术解析与选型指南
  • 3个高级技巧:用ScintillaNET构建专业级文本编辑器的实战指南
  • 山西太原幼儿园春季穿衣指南:分层穿搭,孩子少生病
  • python3 写一个简单的webhook案例
  • MogFace-large人脸检测模型-large保姆级教程:含Gradio主题换肤技巧
  • 新手必看!Llama-3.2V-11B-cot保姆级教程:一键启动会思考的AI看图助手
  • Wan2.2-I2V-A14B企业级应用:私有化部署AI视频生成平台,保障数据安全合规
  • 硬件知识总结梳理-4(磁珠)
  • 【VR安全体验馆】深度测评:优质服务商与推荐厂家全景解析
  • 1.Unity面向对象-单一职责原则
  • SDXL-Turbo功能体验:实测打字编辑实时更新画面的神奇效果
  • 终极指南:如何用BBDown免费下载B站高清视频的完整教程
  • douyin-downloader:抖音视频批量下载解决方案
  • 彻底清理显卡驱动残留:Display Driver Uninstaller(DDU)终极指南