计算π的历史

圆周率π可能是科学界内外最广为人知的自然常数了。早在公元5世纪时,南朝宋数学家祖冲之用割圆法将圆周率计算到小数点后7位数字。大约同一时间,印度的数学家也将圆周率计算到了小数点后5位。历史上首个π精确无穷级数公式(即莱布尼茨公式)直到约1000年后才由印度数学家发现。20世纪以来,随着计算机技术的快速发展,π的精度也在极速提高。截至2019年,π的十进制精度已高达1013位。虽然几乎所有的科学研究对π的精度要求都不会超过几百位,当前依然有许多科学家和爱好者为了打破记录、测试超级计算机的计算能力和高精度乘法算法等原因,不断地向π的更高位数发起挑战。
圆周率有许多优美的数学性质,由此产生的计算圆周率的公式和算法也有成千上万。借《并行计算》实验课的机会,我对其中比较有趣和有意义的一些算法进行了一波研究,实现了代码并进行了一些测试。

方法0:蒲丰投针与蒙特卡洛方法

在介绍蒙特卡洛方法之前,先讲一个概率学上的故事:
在1777年,法国数学家蒲丰(也有译作布丰)设计了一个投针试验,实验方式如下:
1) 取一张白纸,在上面画上许多条间距为a的平行线。
2) 取一根长度为l(l≤a) 的针,随机地向画有平行直线的纸上掷n次,观察针与直线相交的次数,记为m。
3)计算针与直线相交的概率.
蒲丰经过计算,得出这个概率是:
。由此蒲丰惊奇地发现:有利的扔出与不利的扔出两者次数的比,是一个包含π的表示式.如果针的长度等于a/2,那么有利扔出的概率为1/π.扔的次数越多,由此能求出越为精确的π的值。
一些数学家在这个问题上进行了实验,结果如下:
在概率学上,蒲丰投针实验是第一个用几何形式表达概率问题的例子,他首次使用随机实验处理确定性数学问题,为概率论的发展起到了一定的推动作用。
那么在计算机中,我们也可以借鉴蒲丰投针的思想,利用随机事件发生的频率来预估出圆周率的值。当然,由于计算机能够很方便地生成随机数,没有必要使用投针的方式,只需随机生成点就可以计算出圆周率。以下描述一种简单的算法:
首先在(0,1)中生成两个随机数x,y,令(x,y)为坐标系中的一个点,那么它将均匀地分布在(0,0),(1,1)的正方形内。然后统计其中到原点的距离小于1的点的数量。这些点分布在以原点为圆心、半径为1的四分之一个圆上,则其占点的总数的比值的期望为π/4。因此进行多次随机,然后将比值乘以4就可以得到近似的圆周率值。
算法的执行过程如图所示:
这个算法有一个明显的好处:它天生支持并行或分布式计算,因为每次投掷的试验都是独立的,可以在很多台设备上分别进行随机试验,之后统计结果即可。

方法1:面积积分

上面的方法已经可以在1秒内计算出圆周率的前8位小数,但是如果想要结果更加精确,难度很大。因为这个算法完全依靠随机次数的增加来逼近理论上的概率,而大数定律的收敛很慢。那么既然上面的算法是通过四分之一个单位圆的面积来得到π的值,我们可不可以直接计算圆的面积呢?
由这个思路引出了计算圆周率的第二个方法:利用面积积分。能够得到π的函数很多,因此这个思路得到的算法也不唯一。这里选用了反正切函数y=arctan(x),利用公式
,可以得到下图中曲线与坐标轴之间围成的面积为π/4。
在计算机中,计算图形的面积一般可以用划分+近似为梯形面积+求和的方式来计算。具体算法为:将(0,1)的区间等分为n个部分,如第一部分为(0,1/n]、第二部分为(1/n,2/n]等,然后分别计算x坐标在这个区间范围内对应的图形的面积。由于此时对应的图形很“细”,可以近似地看做一个梯形或一个矩形,则可以套用梯形或矩形的面积计算公式求得结果。最后将这些矩形的面积相加,就得出了不规则图形的面积。可以看出,这个算法的精确程度取决于一开始的划分数量,划分得越细,计算的精确度就越高。
同时这个算法也支持并行计算:在程序的开始对梯形的划分进行预分配,然后各个进程分别计算自己被分配到的梯形的面积,最后在进行求和即可。
并行程序的代码如下:
在单机4进程的并行环境下运行程序的结果如下图所示。可以看到,经过1e9次分割,误差2.49e-14,耗时0.589267秒,计算速度约为27位/秒。

方法2:幂级数

除了利用将函数积分转化为分段求和的方式来逼近圆周率之外,数学上还有不少可以用来计算π的公式,比如利用幂级数对arctan(x)进行展开可以得到:
对这个式子进行简单的循环求和,也可以逐渐逼近圆周率的值。
同时这种方法也可以实现并行计算,首先由主节点确定要计算的项数,将计算任务分配到各个节点,然后上多个节点可以分别计算式子的不同部分,然后将结果相加即可。
以下是这种方法的代码:
在单机4进程的并行环境下运行程序的结果如下图所示。可以看到,经过2e9次分割,误差4.98e-10,耗时0.877899秒,计算速度约为14位/秒。

方法3:改进的幂级数

以上两种方法本质上都是通过逼近一个极限为π的数列来计算圆周率的。上面的两个数列每一项衰减得比较慢,要精确到10-N大致需要计算2*10N项。
对于幂级数而言,当x越接近于0时,收敛越快。比如在上面的例子中,我们选取的x=1,离0有相当的距离。如果对arctan(x)在x=1/5处展开,可以得到级数:
以上级数由于含有1/5和1/239的指数运算,收敛速度很快。事实上,当n=4时,就有1/9*59