1. XenForo 1.5.14 中文版——支持中文搜索!现已发布!查看详情
  2. Xenforo 爱好者讨论群:215909318 XenForo专区

能不能绕过π,来计算一个圆的面积?

本帖由 漂亮的石头2021-08-06 发布。版面名称:知乎日报

  1. 漂亮的石头

    漂亮的石头 版主 管理成员

    注册:
    2012-02-10
    帖子:
    486,020
    赞:
    46
    [​IMG] Mr.Bo,爱好科技,航天迷一枚,工科研究僧 阅读原文

    这个问题其实也等价于在计算机中如何表示

    [​IMG]

    ,对于半径为 1 的单位圆来说,它的面积就是

    [​IMG]



    那么估计单位圆的面积就转换为了估计

    [​IMG]

    ,那么先缩小本问题的目标,如何计算单位圆的面积?

    (1)最基础的方法就是使用几何概率,即蒙特卡罗方法:

    [​IMG]

    即撒点,假设向正方形中均匀撒入 n 个点,共有 m 个点落入圆中,那么落入圆中点的概率就为:

    [​IMG]

    这样很容易就得到了圆的面积为

    [​IMG]

    ,发现没有,成功绕开了

    [​IMG]

    算出了圆的面积,并且在单位圆情况下能够成功估计

    [​IMG]

    ,对于概率来说,实验次数越多越准,也就意味着撒点数量越多,圆的面积越精准,也意味着

    [​IMG]

    的精度越高。

    (2)第二种方法,就是离散,这是非常重要的思想

    首先就是微积分的思想,即将圆面积拆分成很多微小面积之和,通过对微小面积求和来逼近真实面积。很典型的例子就是将正方形划分为一个一个的小正方形格子,统计落在圆内的所有正方形小格子的比例。高赞回答举得一系列例子,其实也就是这个思想的体现。在高中其实就已经讲过,曲边梯形面积的求法,这就是微积分最核心的思想,无论理论多么高大上,理论基础都是这个:化曲为直,无限逼近。

    [​IMG]
    图源百度

    其次就是级数的思想,即将对单位圆面积的求解划分为一小块一小块面积的总和,很典型的一个级数就是:

    [​IMG]

    包括传统的割圆法等等,体现的核心思想就是两个字:逼近,无非就在于逼近的精度如何罢了。

    在完成单位圆面积的估算之后,其他所有圆的面积,无非就是单位圆面积的倍数了,这仅仅与圆的直径 / 半径比值相关,那么就简单通过直尺来得到圆的面积,绕开了

    [​IMG]



    在实际使用中,根据所需的精度对

    [​IMG]

    进行估计即可,比如 c 语言的 math 库函数里直接对

    [​IMG]

    值定义,也算典型的直接拿来用(狗头)

    #if defined(_USE_MATH_DEFINES) && !defined(_MATH_DEFINES_DEFINED) #define _MATH_DEFINES_DEFINED #define M_E 2.71828182845904523536 #define M_LOG2E 1.44269504088896340736 #define M_LOG10E 0.434294481903251827651 #define M_LN2 0.693147180559945309417 #define M_LN10 2.30258509299404568402 #define M_PI 3.14159265358979323846 #define M_PI_2 1.57079632679489661923 #define M_PI_4 0.785398163397448309616 #define M_1_PI 0.318309886183790671538 #define M_2_PI 0.636619772367581343076 #define M_2_SQRTPI 1.12837916709551257390 #define M_SQRT2 1.41421356237309504880 #define M_SQRT1_2 0.707106781186547524401 #endif /* _USE_MATH_DEFINES */

    那么蒙特卡罗方法的精度如何?写个代码便知:

    sample_points = 10.^(2:1:8); estimate_pi = zeros(length(sample_points),1); for i = 1:length(sample_points) n= sample_points(i); x = rand(n,1); rng('shuffle'); y = rand(n,1); rng('shuffle'); s = sum(x.^2+y.^2 <= 1); estimate_pi(i) = s/n*4; end err=abs(estimate_pi-pi) plot(err,'r','LineWidth',1); xlabel('取值点(10^x)'); ylabel('估计误差');

    下图展示了在

    [​IMG]

    点的情况下,估计值为 3.14123220000000,这显然与真实值差距较大,当然这是由于 MATLAB 的随机函数不是真随机导致的,但是蒙特卡罗方法是随机策略,每次运行的值都不同,因此很少在计算机中使用,常用的方法一般为数值积分方法。

    [​IMG]

    再用级数

    [​IMG]

    来试试,代码为:

    n=1000; y=0; num=0; for i=1:1:n num=num+(1/(i*i)); end pi=sqrt(6*num); disp(pi)

    结果为 3.140638056205995,依旧不太理想。

    如果采用对

    [​IMG]

    进行数值积分,代码为:

    a=0;b=1;s=0;n=1000;i=0; h=(b-a)/n; for i=0:n-1 xi=a+i*h; yi=1/(1+(xi)^2); xj=a+(i+1)*h; yj=1/(1+(xj)^2); s=s+(yi+yj)*h/2; end estimate_pi=vpa(4*s,30);

    那么可以得到

    [​IMG]

    为 3.141592486923,显然精度已经很高了.

    如果还想要更高的精度,就需要迭代速度更快,收敛速度更快的方法,感兴趣可以去查一下,在这里就不再过多赘述了。

    阅读原文
     
正在加载...