mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1456 字
4 分钟
蒙特卡罗算法:用随机撒点估算圆周率
2026-06-10 13:02:01

1. 什么是蒙特卡罗算法#

蒙特卡罗算法(Monte Carlo Algorithm)是一类基于随机采样和概率统计的算法。

它的核心思想是:

当一个问题很难直接精确求解时,可以通过大量随机实验,用统计结果去近似真实答案。

简单来说,蒙特卡罗算法的流程是:

随机生成样本 → 统计样本结果 → 用样本比例估计整体结果

它不一定每次都能得到完全精确的答案,但随着随机采样次数增加,结果通常会越来越接近真实值。


2. 随机化算法的两种类型#

在计算机科学中,随机化算法通常可以分为两类:蒙特卡罗算法拉斯维加斯算法

蒙特卡罗算法的特点是:运行时间通常是确定或有限的,但结果可能存在误差。

例如用随机点估算圆周率 π\pi,如果规定生成 10000001000000 个点,那么采样次数是固定的;但估算出的 π\pi 只是近似值。通过增加随机采样次数,可以让误差概率不断降低,使结果越来越接近真实值。

拉斯维加斯算法的特点是:运行时间带有随机性,但只要算法结束,得到的结果一定正确。

例如随机化快速排序,随机选择基准值 pivot 会影响划分效果,从而影响运行时间;但排序完成后,结果一定是正确的。

区分

蒙特卡罗算法保证时间可控,算的是精度;拉斯维加斯算法保证答案正确,赌的是时间。


3. 经典例子:估算圆周率 π#

蒙特卡罗算法最经典的入门例子,就是用随机点估算圆周率 π\pi

3.1 几何模型#

假设有一个边长为 22 的正方形,中心在原点 (0,0)(0, 0),范围为 x[1,1]x \in [-1, 1]y[1,1]y \in [-1, 1]

在这个正方形中画一个内切圆,圆心在原点,半径为 11

接下来的问题是:不直接使用圆周率公式,也不调用语言内置的 π\pi 常量,如何通过在正方形内随机撒点来估算 π\pi

3.2 数学推导#

正方形边长为 22,面积为:

S正方形=2×2=4S_{\text{正方形}} = 2 \times 2 = 4

内切圆半径为 11,面积为:

S=πr2=π×12=πS_{\text{圆}} = \pi r^2 = \pi \times 1^2 = \pi

因此,圆面积和正方形面积的比值为:

SS正方形=π4\frac{S_{\text{圆}}}{S_{\text{正方形}}} = \frac{\pi}{4}

如果在正方形中随机且均匀地生成大量点,那么点落在圆内的概率,应该近似等于圆面积占正方形面积的比例:

P(点落在圆内)π4P(\text{点落在圆内}) \approx \frac{\pi}{4}

这里的“均匀”很关键。如果随机点不是均匀分布的,样本比例就不能稳定地代表面积比例,估算结果也会失真。

假设一共随机生成 totaltotal 个点,其中有 insideinside 个点落在圆内,那么:

insidetotalπ4\frac{inside}{total} \approx \frac{\pi}{4}

两边同时乘以 44,得到蒙特卡罗估算 π\pi 的核心公式:

π4×insidetotal\pi \approx 4 \times \frac{inside}{total}

3.3 如何判断点是否在圆内#

随机生成一个点 (x,y)(x, y),圆心在原点,半径为 11。根据圆的方程,判断条件为:

x2+y21x^2 + y^2 \le 1

满足则在圆内,否则在圆外。例如:

(0.3,0.4)0.32+0.42=0.251圆内(0.3, 0.4)\text{:}0.3^2 + 0.4^2 = 0.25 \le 1 \quad \Rightarrow \quad \text{圆内}(0.9,0.9)0.92+0.92=1.62>1圆外(0.9, 0.9)\text{:}0.9^2 + 0.9^2 = 1.62 > 1 \quad \Rightarrow \quad \text{圆外}

4. 算法步骤#

根据上面的推导,代码只需要做三件事:

  1. 在正方形内均匀生成随机点;
  2. 统计有多少点落在单位圆内;
  3. 用圆内点比例估算 π\pi
π4×insiden\pi \approx 4 \times \frac{inside}{n}

5. Java 代码实现#

import java.util.Random;
public class MonteCarloPi {
public static double estimatePi(int n) {
if (n <= 0) {
throw new IllegalArgumentException("采样次数必须大于 0");
}
Random random = new Random();
long inside = 0;
for (int i = 0; i < n; i++) {
// random.nextDouble() 生成 [0, 1) 之间的小数
// 乘以 2 后变成 [0, 2),再减去 1 后变成 [-1, 1)
double x = random.nextDouble() * 2 - 1;
double y = random.nextDouble() * 2 - 1;
// 判断点是否落在单位圆内
if (x * x + y * y <= 1) {
inside++;
}
}
return 4.0 * inside / n;
}
public static void main(String[] args) {
System.out.println(estimatePi(1000));
System.out.println(estimatePi(10000));
System.out.println(estimatePi(100000));
System.out.println(estimatePi(1000000));
}
}

可能的输出:

3.108
3.1464
3.13972
3.14188

由于使用了随机数,每次运行的结果可能都不完全一样。但通常来说,采样次数越多,结果越接近真实的 π\pi


6. 复杂度分析#

假设采样次数为 nn。每次采样只需要生成两个随机数并进行一次判断,都是常数时间操作。

  • 时间复杂度O(n)O(n)nn 为采样次数。
  • 空间复杂度O(1)O(1),只使用了少量变量。

这里的 nn 不是输入数组长度,而是我们主动设置的采样次数。采样次数越大,结果越稳定,但运行时间越长;采样次数越小,运行越快,但误差可能越大。这是蒙特卡罗算法中精度与效率的权衡。


7. 为什么采样越多越准确#

蒙特卡罗算法依赖的是概率统计中的大数定律。

当采样次数较少时,随机结果波动较大。例如只生成 1010 个点,可能恰好有 77 个落在圆内:

π4×710=2.8\pi \approx 4 \times \frac{7}{10} = 2.8

误差很大。但如果生成 10000001000000 个点,落在圆内的比例会更稳定,更接近真实概率 π4\frac{\pi}{4},估算出的 π\pi 也会更接近真实值。

不过需要注意:

采样次数增加,只能让结果更稳定,并不能保证每一次都精确等于真实答案。

这也是蒙特卡罗算法和确定性算法的本质区别。


8. 总结#

蒙特卡罗算法的核心是:

用大量随机实验的统计结果,去近似真实答案。

在估算圆周率 π\pi 的例子中,我们利用了圆和正方形的面积比例 π4\frac{\pi}{4},通过随机点落入圆内的比例来估算:

π4×圆内点数总点数\pi \approx 4 \times \frac{\text{圆内点数}}{\text{总点数}}

蒙特卡罗算法思路简单、容易实现,尤其适合难以精确计算的问题,比如高维积分、复杂系统模拟和概率估计。但它的结果带有随机性,通常只能得到近似答案,且精度依赖采样次数。

口诀

随机撒点,统计比例,用概率逼近答案。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

蒙特卡罗算法:用随机撒点估算圆周率
https://dawn114514.site/posts/algorithm/montecarloalgorithm/
作者
黎明
发布于
2026-06-10 13:02:01
许可协议
MIT

部分信息可能已经过时

目录