π的计算

说起圆周率的计算,估计很多人首先想到的是祖冲之的割圆术。确实,在当时的条件下,割圆术能将π计算到一个较高的精度,实在不易。
不过我们现在,希望使用计算机快速计算高精度的π,这时我们该如何去做呢?

算法库计算的思路

像计算机中的数学库计算,一般都是采用泰勒展开进行的,像sin,cos这类的函数,都可以用泰勒展开式很方便的逼近。计算机计算的方法,就是用简单的多项式去不断逼近一个特殊的函数,最终可以求得其任意位置任意精度的解。

同理,计算π,我们也希望有一个特殊的函数,其特殊位置能让我们能方便的计算出来,最后在某个特殊点是f(x) = π的形式,然后我们带入特定位置的x,就能求出π来。

泰勒展开的强大之处

泰勒展开在高等数学中,也是非常重要的,虽然说平时生活中接触到的不多,但这个公式在科学计算中简直有着匪夷所思的强大威力。

泰勒展开在讲如何用多项式逼近任意一个可微函数。

f(x)=f(x0)+f(x0)(xx0)+f′′(x0)2!(xx0)2++f(n)(x0)n!(xx0)n

而在原点的泰勒展开式,可以简化成麦克劳林展开式。

f(x)=f(0)+f(0)x+f′′(0)2!x2++f(n)(0)n!xn

这两个式子的右半部我们发现,都是多项式的形式,而对于计算机来说,多项式是非常好计算的,这样,在拟合函数时,计算就很简便了。

例如我们计算sin函数:

sin(x)=xx33!+x55!+(1)n1x2n1(2n1)!

这样就简便多了,我们可以看出这个拟合的过程:

π的计算_第1张图片

利用反三角函数

而计算π,很常用的特殊函数,就是反三角函数,根据定义有:

arctan(1)=π4π=4×arctan(1)

那么接下来的问题就是,arctan函数如何求,调用C函数库是可以,但那是别人写好的,而如果我们真的要求π的多少位精确值,那么就要用到高精度计算,而这,是C函数库所无法提供的。

所以我们就尝试用泰勒展开,自己编写其计算函数。

首先我们要推倒出arctan的展开式,对高数还有印象的话,这应该是一道经典例题,并不太难。

首先我们观察,对arctan求导可以发现:

arctan(x)=11+x2

那么我们知道,如果我们知道了 g(x)=11+x2 的展开式,那么就很好办了,两端积分就可以求出来了。

而我们知道这个展开式:

11+x=1x+x2+(1)nxn

这个展开式就是对 h(x)=11+x 求导,然后根据麦克劳林展开式得出的:

h(n)(x)=1×(2)×(3)××(n)(1+x)(n+1)h(n)(x)=(1)nn!

于是我们将 11+x 的展开式中的 x 换成 x2 :

11+x2=1x2+x4+(1)nx2n

再对两端进行做变上限的积分,为了凑牛顿-莱布尼茨公式:

arctan(x)=x011+x2dx=xx33+x55+(1)nx2n+12n+1

于是我们将arctan(1)带入,并给每一项乘一个4,得到:

π=113+1517+19+(1)n12n+1

python程序计算

#! /usr/bin/env python3
# -*- coding:UTF-8 -*-
def cal_pi():
    pi = 4
    fh = 1
    for i in range(1,50000):
        t = 2 * i + 1
        fh = fh * (-1)
        pi = pi + fh * 4 / t
    return pi

print(cal_pi())

简单地用python测试一下,发现效果虽然基本正确,但遗憾的是arctan的收敛速度有点太慢了,这个程序在没使用高精度库时只有非常少的有效位数(由于收敛太慢都没必要用高精度计算)。

我们看这个级数的项,有正有负,而且下面的分母是成线性增长的,那么用来逼近的话,就会花费大量时间在计算这些分母上,整个式子就会很长。

所以虽然我们的推倒是正确的,但却不怎么具有实用价值。

微小却重大的改进

不仅仅是我们遇到了困难,就连这个级数的发现者,德国数学家莱布尼兹(Gottfried Wilhelm Leibniz, 1646 - 1716 年)也没能其计算出有效精度的π来,但他在1674年发现的这个级数确实影响了一代数学家,以级数逼近π的方式取代了古老的割圆术等思路。

1699 年,英国的夏普,做了一点微小的改进,就让这个级数变得实用起来。我们考虑,换一个反正切函数的值也许会好些:

arctan(33)=π6

于是我们发现,级数变成了这样:
π6=arctan(33)=33[113×3+132×5+(1)n13n×(2n+1)]

这个级数的收敛就快很多了,由于多了一个 3n 的项,可以以每两项产生一个π小数位的速度来生成。

用python简单实现一下,效果还不错哦,注意我们使用了:

#! /usr/bin/env python3
# -*- coding:UTF-8 -*-

from decimal import *

getcontext().prec=2000

def cal_pi():
    fh = 1
    xs = 2 * Decimal(3).sqrt()
    pi = xs
    for i in range(1,5000):
        t = 2 * i + 1
        fh = fh * (-1)
        pi = pi + fh * xs / (t * (Decimal(3)**i)) # 其实这里可以不用分母高精度除法计算
        ## 因为分母增长太快了,而带来的影响非常小。 不过这个只是经验性质,并没有严格的数学证明。
    return pi

print(cal_pi())

更快,我还要更快

没错,刚刚我们介绍的,都是很原始的,而且也是从数学上很好推倒的两个公式,而如果读者追求那种能在电脑上算出几亿位的算法的话,推荐看下下面两个公式。

其一是贝利-波尔温-普劳夫公式(BBP公式)

π=k=0[116k(48k+128k+418k+518k+6)]

这个式子有一个最大的好处就是,里面几个式子除法没有高精度分母,这无疑大大增加了除法的效率,而且也比较简单。

其二则是著名的高斯-勒让德算法

它以迅速收敛著称,只需25次迭代即可产生π的4500万位正确数字,于1975年被理查德·布伦特和尤金·萨拉明独立发现。日本筑波大学于2009年8月17日宣布利用此算法计算出π小数点后2,576,980,370,000位数字。

知名的电脑性能测试程序Super PI也使用此算法。

算法描述起来很简洁:

  1. 设置初始值

    a0=1,b0=12,t0=14,p0=1

  2. 反复迭代计算直到所需精度

    an+1=an+bn2,bn+1=anbn,tn+1=tnpn(anan+1)2,pn+1=2pn

  3. 计算π的近似值

    π(an+1+bn+1)24tn+1

参考文献

  1. 一起来算圆周率
  2. 圓周率 p 的歷史
  3. 圆周率本身是个无理数,也是超越数。最近的发展都是利用计算机算的!
  4. 贝利-波尔温-普劳夫公式 - 维基百科
  5. 高斯-勒让德算法 - 维基百科

Markdowm源文件下载

本文使用markdown语法写成,公式使用Latex排版,有需要查看详情的请下载源文件。
百度云网盘

附录 圆周率年表

本附录转载自网友Hubert的博文:http://blog.sina.com.cn/s/blog_5519f6b0010006xe.html

公元前二○○○年 巴比伦人将31/8当成π值。埃及人认为π=(256/81)=3.1605
公元前一一○○年 中国人将3当成π。
公元前五五年 圣经虽没明讲,却暗示π=3。
公元前四三四年 安那克萨哥拉尝试化图为方。
公元前四三○年 安提丰和布赖森提出穷举法。
公元前三三五年 戴纳史特拉特斯(Dinostratos)利用割圆曲线(quadratrix)化图为方。
公元前三世纪 阿基米得以96边形计算出310/71<π<31/7。他也曾用螺线(spiral )化圆为方。
公元二世纪 托勒密求出π=3°8’ 30” = 377/120 = 3.14166…。
公元三世纪 王蕃求出π=142/45=3.1555…。
二六三年 刘徽求出π=157/50=3.14。
四五○年 祖冲之求出π=355/113。
五三○年 阿耶波多求出π=62,832/20,000=3.1416。
六五○年 婆罗门笈多求出π= =3.162…。
一二二○年 李奥纳多(斐渡那契)计算出π=3.141818…。
一五九三年 韦达首先以无穷乘积描述圆周率;罗马努斯计算出有15个小数字的圆周率。
一五九六年 万科伦计算出有32个小数字的圆周率。
一六一○年 万科伦计算出有35个小数字的圆周率。
一六二一年 斯涅尔改良阿基米得的算法。
一六五四年 惠更斯证明斯涅尔的算法。
一六五五年 华里斯发现一个计算圆周率的无穷乘积;布朗克(Brouncker)也将这个无穷乘积转换成连续分数。
一六六三年 日本的村松茂清发现准确到小数第七位的圆周率。
一六六五至六六年 牛顿发现微积分原理,并计算出有16个小数字的圆周率。这项结果直到一七三七年才被公开(这时他已去世了)。
一六七一年 格雷果里发现计算圆周率的反正切级数。
一六七四年 莱布尼兹发现计算圆周率的反正切级数。
一六九九年 夏普计算出有72个小数字的圆周率。
一七○六年 梅琴计算出有100个小数字的圆周率。锺斯(William Jones)以符号π代表圆周率。
一七一三年 清朝的康熙皇帝钦订《数理精蕴〉其中记载了有19个位数的圆周率。
一七一九年 德拉格尼计算出有127个小数字的圆周率。
一七二二年 日本的建部砚湖计算出有40个位数的圆周率。
一七四八年 欧拉发表《无穷小分析导论》(Introductio in analysin infinitorum),书中记载了欧拉定理(Euler’s theorem),和很多计算π和π 的级数。
一七五五年 欧拉发现一个收敛得很快的反正切级数。
一七六一年 朗伯特(Johann Heinrich Lambert)证明π是无理数。
一七七五年 欧拉研究出欧拉公式,这个公式可以证明π是超越数。
一七九四年 维加计算出有140个小数字的圆周率。李詹德(A.M. 0Legendre )证明π和π 是无理数。
一八四四年 冯史塔森尼斯基(L.K.Sdullz von Stassnitdq)和达斯(John Dase)在两个月内计算出有200个小数字的圆周率。
一八五五年 立克特(Richter)计算出有500个小数字的圆周率。
一八七三年 埃尔米特(Charles Hemite)证明e是超越数。
一八七三至七四年 尚克斯发表有707个小数位的圆周率。
一八七四年 中国的曾纪鸿计算出100位的圆周率。
一八八二年 林德曼(Ferdinand von Lindemann)证明π是超越数。
一九四五年 弗格森发现尚克斯发表的圆周率,从小数第527位开始都是错的。
一九四七年 弗格森花了一年的时间,以桌上型计算器计算出808个小数字。
一九四九年 ENIAC在七十个小时内,计算出2,037个小数字。
一九五五年 NORC在十三分钟内,计算出3,089个小数字。
一九五九年 位于巴黎的IBM704计算出16,167个小数字。
一九六一年 丹尼尔﹒尚克斯和雷恩屈利用纽约的IBM7090,花了8.72个小时计算出有100200个小数字的圆周率。
一九六六年 巴黎的IMB 7030计算出250,000个小数字。
一九六七年 巴黎的CDC 6600计算出500,000个小数字。
一九七三年 纪尧德和布依尔利用巴黎的CDC 7600,在23.3小时内计算出一百万个小数字。
一九八三年 嘉晃田村和安正金田利用HITAC M-280H,在三小时内计算出一千六百万个位数。
一九八八年 安正金田利用Hitachi S-820,在六小时内计算出201,326,000个位数。
一九八九年 楚诺维斯基兄弟计算出四亿八千万个位数,安正金田计算出五亿三千六百万位。楚氏兄弟计算出十亿位。
一九九五年 安正金田计算出60亿个位数。
一九九六年 楚氏兄弟计算出超过80亿个位数。
一九九七年 安正金田和高桥利用Hitachi SR2201,花了29个小时,计算出515亿个位数。

你可能感兴趣的:(数学趣谈)