蒙特卡洛方法估算π的原理是:单位正方形[0,1]×[0,1]内接四分之一单位圆,其面积比为π/4;均匀撒点后,圆内点数占比≈π/4,故π≈4×(圆内点数/总点数);该方法依赖几何概率等价性,而非物理模拟。

为什么用随机点落在单位圆内比例来估算 π
因为单位正方形(边长为1)内接单位圆的面积比是 π/4,只要在正方形内均匀撒足够多的随机点,统计落入四分之一圆内的点数占比,再乘以4,就能逼近 π。关键不在于“模拟物理过程”,而在于利用几何概率的数学等价性——这是蒙特卡洛方法最基础也最典型的验证场景。
std::uniform_real_distribution 必须搭配 std::random_device 和 std::mt19937
直接用 rand() 或只用 std::mt19937 不设种子会导致分布偏差或重复序列,严重影响收敛速度和结果稳定性。正确做法是:
-
std::random_device rd提供真随机种子(实际中多数系统调用 OS entropy,可靠) -
std::mt19937 gen(rd())初始化 Mersenne Twister 引擎 -
std::uniform_real_distribution<double> dis(0.0, 1.0)</double>生成 [0,1) 区间浮点数——注意右开区间,避免边界点影响判断逻辑
漏掉 std::random_device 而只写 std::mt19937 gen(42),每次运行结果完全一样,根本不是“随机”估算。
判断点是否在四分之一圆内:用 x*x + y*y ,别开方
计算 sqrt(x*x + y*y) 多余且有害:一是浮点开方有精度损失和额外开销,二是当 <code>x、y 接近 1 时,x*x + y*y 可能略超 1.0(因舍入),但 sqrt 后再比较反而掩盖问题。直接比较平方和更准、更快。
立即学习“C++免费学习笔记(深入)”;
示例核心循环:
int in_circle = 0;
for (int i = 0; i < N; ++i) {
double x = dis(gen);
double y = dis(gen);
if (x*x + y*y <= 1.0) ++in_circle;
}
double pi_est = 4.0 * in_circle / N;
迭代次数少于 1e5 时结果波动剧烈,别信前几次输出
蒙特卡洛收敛速度是 O(1/sqrt(N)),意思是误差大致随 1/sqrt(N) 下降。试过 N = 1000,结果可能在 3.0~3.3 之间跳;N = 1e6 才稳定到小数点后 2 位左右;想看到 3.14159 这种精度,通常要 1e8 级别以上——这时得考虑 int 计数溢出(改用 long long),以及循环本身成为瓶颈(可考虑 OpenMP 并行化,但要注意 gen 非线程安全)。
最容易被忽略的是:没有做多次独立运行取平均。单次大 N 未必比 10 次中等 N 的均值更可靠,尤其当随机数引擎周期或种子质量一般时。


















