伪·从零开始学算法 - 2.3 - 求圆周率

本文为圆周率日特辑~

简介

圆周率 是一个圆的周长与直径之比。即:。它是一个无限不循环小数,即无理数。

据说远古时期的人们根据经验以 3 作为圆周率的值(“径一周三”),这个值至今也能够用于一些对精度要求不高的场合(如手工做木桶)。但是,对于天体运行和面积测量等方面,3 这个值未免太粗略。人们对于它的计算绝不仅限于此。

古埃及、古巴比伦、古印度、古代中国的遗迹中都能够找到关于圆周率的较精确的值,它们都能够达到 3.1 这个值。实际上,绝大多数情况下,那时的人还是把它当作有理数来计算的。总之,那时的计算可能仍然属于观测值加以拟合。

割圆术

割圆术是第一个有纪录、严谨计算 数值的算法。

一般来说,它是通过计算圆内接正多边形和/或圆外切正多边形的周长的方式来计算圆周率。随着正多边形的边数增长,其形状越接近圆,因此可以据它的周长或面积计算圆周率。理论上来说,它可以计算任意精度的圆周率的值。

目前所知最早这么做的是约公元前 250 年的阿基米德。阿基米德的算法是在计算圆的外切正六边形及内接正六边形的边长,以此计算 的上限及下限,之后再将六边形变成十二边形,继续计算边长……,一直计算到正 96 边形为止。由此,他计算出 的值在 3.140845… 和 3.142857…) 之间。

此后的托勒密等人也使用割圆术来计算圆周率,但他们是单向迫近,不如阿基米德的双向迫近精确。

三国时期的中国,刘徽也创立了割圆术。与之前不同的是,他的理论是数学史上最严谨完备简洁的割圆术:使用极限论来论证割圆术的正确性;双向迫近。

割之弥细,所失弥少。割之又割,以至于不可割,则与圆周合体而无所失矣。

与阿基米德相似,刘徽也是从正六边形开始计算的。不同的是,刘徽以面积来计算。他自己通过分割圆为 192 边形,计算出圆周率在 3.141024 与 3.142704 之间,取其近似值

刘徽割圆术原理

在下图中可以发现,如果计原多边形(黄色部分)面积为 ,新的多边形(黄色+绿色部分)面积为 ,圆面积为 ,那么新的多边形与原多边形的面积之差(绿色部分)为 ,矩形 的面积和为 。则有:

刘徽圆周率不等式示意图

后来刘徽发明一种快捷算法,通过新的多边形与原多边形的面积之差近似成等比级数来计算,可以只用 96 边形得到和 1536 边形同等的精确度,从而得令他自己满意的 3.1416。

南北朝的祖冲之,运用刘徽的算法,继续分割到 12288 边形,求得 24576 边形的面积,得 3.14159261864 < < 3.141592706934,精确到了小数点后七位,保持了世界最准确圆周率达 900 年之久。此后他又算出来两个比较简单的近似值:约率( )和密率()。

至于割圆术的算法,简要解释如下:

割圆术

设上图中圆半径为 ,弦心距为 ;正 边形的边长为 ,面积为 。由勾股定理,得

而且我们可以得到,正 边形面积等于正 边形面积加 个等腰三角形的面积,即

随着 n 的增大, 不断趋近于

于是我们可以据此编制割圆术的算法:

割圆术 (1)

据此求在正 边形下,圆周率的下限和上限:

割圆术 (2)

割圆术在 16 ~ 17 世纪之前一直都是精确计算圆周率的解决方法。奥地利天文学家克里斯托夫·格林伯格在 1630 年用 1040 边形计算到第 38 位小数,至今这仍是利用多边形算法可以达到最准确的结果(当然,是人工的情况下,我在测试算法的时候,仅用 53.6 ms 就能计算到小数点后 100 位)。

无穷级数

16 世纪及 17 世纪时, 的计算开始改用无穷级数的计算方式。但是,公式并不是唯一的。1735 年,欧拉解决了巴塞尔问题,得到了关于 的一个非常精妙的公式(可能很多人都知道):

算法如下:

欧拉的公式推导的算法

越大,结果越精确。

此外,还有莱布尼茨公式:

尼拉卡莎级数:

等一系列级数。但是许多级数的收敛速度很慢,莱布尼茨公式要到 500000 项之后,才会精确到 的第五位小数。

印度数学家斯里尼瓦瑟·拉马努金在 1914 年发表了许多与 相关的公式,这些公式十分新颖,极为优雅而又颇具数学深度,收敛速度也非常快。

以下为一例:

第一位使用拉马努金公式计算 并取得进展的是比尔·高斯珀,他在 1985 年算得了小数点后一千七百万位。

拉马努金公式开创了现代数值近似算法的先河。此后波尔文兄弟和楚德诺夫斯基兄弟进一步发展了这类算法。后者于 1987 年提出了楚德诺夫斯基公式,如下所示:

此公式每计算一项就能得到 的约 14 位数值,因而被用于突破圆周率的数位的计算。利用该公式,有人已经计算到小数点后第一万亿位。

但是很显然,这些公式已经变得非常复杂,难以记忆(虽然没有多少人需要记这个的)。

迭代算法

二十世纪中期计算机技术的发展、革新再次引发了计算 位数的热潮,除了之前的无穷级数,利用迭代算法计算圆周率的方法也被提出。

迭代算法因为收敛速度比无穷级数快很多,在 1980 年代以后广为使用。无穷级数随着项次的增加,一般来说正确的位数也会增加几位,但迭代算法每多一次计算,正确的位数会呈几何级数增长。

有一个比较有名的算法是高斯-勒让德算法,于 1975 年被理查德·布伦特和尤金·萨拉明独立发现。日本筑波大学于 2009 年 8 月 17 日宣布利用此算法计算出 小数点后 2576980370000(2.58 万亿)位数字。知名的电脑性能测试程序 Super PI 也使用此算法。

该算法的步骤如下:

第一步:设置初始值:

第二步:反复执行以下步骤直到 之间的误差到达所需精度:

的近似值为:

流程图如下:

高斯-勒让德算法

它以迅速收敛著称,算法每执行一步正确位数就会加倍,只需 25 次迭代即可产生 的 4500 万位正确数字。不过,它的缺点是内存密集。

蒙特卡罗方法

前面介绍的是靠计算得出的方法,但这个却与概率与统计有关。

蒙特卡罗方法(Monte Carlo method)是以概率统计理论为指导的一类非常重要的数值计算方法,通过进行大量重复试验计算事件发生的频率,按照大数定律,可以求得 的近似值。

布丰投针问题就是其中一个应用的例子。当一枚长度为 的针随机地往一个画满间距为 的平行线的平面上抛掷 次, 如果针与平行直线相交了 次,那么当 充分大时就可根据以下公式算出 的近似值:

布丰投针问题

另一个例子是随机地往内切四分之一圆的正方形内抛掷大量的点,落在四分之一圆内的点的数量与抛掷点的总量的比值会近似等于

蒙特卡罗方法

我们以第二个例子为例,如果要编制算法,我们可以使用解析几何的方法,把“随机地往正方形内抛掷大量的点”转化为“定义一个点,该点的横坐标和纵坐标取 范围的随机数(两坐标不一定相同),重复若干次”,把“落在四分之一圆内”这个条件转化为“点是否在 内”。于是得下面的流程图:

蒙特卡罗方法流程图

它的缺点也很明显:随机、不精确。

结语

还有很多算法,在此我就不一一列举了。

最后我放上一张图,以展示 的计算的发展。

当数学家发现新的算法、电脑变得普及时,π 的已知小数位急剧增加。注意垂直坐标使用了对数坐标

一般而言, 值并不需要过于精确便能够满足大部分的数学运算的需求。按照约尔格·阿恩特(Jörg Arndt)及克里斯托夫·黑内尔(Christoph Haenel)的计算,39 个数位已足够运算绝大多数的宇宙学的计算需求,因为这个精确度已能够将可观测宇宙圆周的精确度准确至一个原子大小。但是大家仍然对 的计算乐此不疲,这有很多原因,但计算 的本身让我想起了一个故事:

有人问英国登山家乔治·马洛里为何想要攀登珠穆朗玛峰。他回答说:“因为山就在那儿。”

参考资料