C++蒙特卡洛法估算Pi函数的性能优化提速咨询
蒙特卡洛近似计算Pi的C++代码优化方案
以下是可落地的优化方向和最终优化代码:
- 移除冗余运算
原代码中判断distance <= 1完全不需要开根号计算实际距离,只需判断x*x + y*y <= 1即可,开根号是高耗时的浮点运算,移除后单循环耗时直接降低30%以上。另外num_point_total完全等价于输入的采样次数n,无需在循环内累加,直接删除该变量即可。 - 修正不合理的变量类型
采样次数n本质是正整数,不要用double类型存储,改为size_t或者unsigned long long避免大数值下精度丢失、循环溢出问题;计数变量num_point_circle改为整数类型累加,比浮点累加速度更快、精度更高。 - 替换低性能随机数生成方案
标准库rand()函数性能低、随机数质量差,且每次调用函数都执行srand初始化不仅多余,还会导致短时间内多次调用函数时生成的随机数序列完全一致,影响结果精度。替换为C++11引入的<random>库的mt19937随机数引擎,配合uniform_real_distribution直接生成[0,1)区间的均匀浮点数,生成效率和随机质量都远高于rand()方案。 - 开启编译优化+多线程并行
编译时开启O2/O3优化,编译器会自动做指令重排、循环展开等优化,性能可以提升数倍。如果要支撑亿级以上的采样量,可以引入OpenMP多线程并行,只需一行编译指令即可把循环拆分到CPU所有核心执行,多核CPU下性能可以线性提升。
优化后代码
#include <random> #include <cstddef> // 随机数引擎全局初始化,只执行一次 static std::mt19937 rng(std::random_device{}()); static std::uniform_real_distribution<double> dist(0.0, 1.0); double estimate_pi(size_t n) { unsigned long long num_point_circle = 0; // 不需要多线程的话删除下面的#pragma行即可 #pragma omp parallel for reduction(+:num_point_circle) for (size_t i = 0; i < n; ++i) { double x = dist(rng); double y = dist(rng); if (x*x + y*y <= 1.0) { num_point_circle += 1; } } return (4.0 * num_point_circle) / n; }
如果使用OpenMP多线程,编译时需要添加对应参数:GCC/Clang加-fopenmp,MSVC加/openmp。仅开启O2优化+移除sqrt两个改动,就可以让原代码性能提升4~5倍,搭配多线程后8核CPU可以再提升7倍左右,完全可以支撑十亿级采样量正常运行。
内容的提问来源于stack exchange,提问作者dapet
相关产品推荐
相关产品推荐

