π是一个无数人跟随的真正的神奇数字。我不是很清楚一个永远反复的无理数的迷人之处。在我看来,我乐于计较π,也就是计较π的值。因为π是一个无理数,它是无限的。这就意味着任何对π的计较都仅仅是个近似值。假如你计较100位,我可以计较101位而且更准确。迄今为止,有些人已经选拔出超等计较机来试图计较最准确的π。一些极值包罗 计较π的5亿位。你甚至能从网上找到包括 π的一百亿位的文本文件(留意啦!下载这个文件大概得花一会儿时间,而且没法用你平时利用的记事本应用措施打开。)。对付我而言,如何用几行简朴的Python来计较π才是我的乐趣地址。
你老是可以 利用 math.pi 变量的 。它被 包括在 尺度库中, 在你试图本身 计较它之前,你应该去利用它 。 事实上 , 我们将 用它来计较 精度 。作为 开始, 让我们看 一个 很是直截了当的 计较Pi的 要领 。像往常一样,我将利用Python 2.7,同样的想法和代码大概应用于差异的版本。我们将要利用的大部门算法来自 Pi WikiPedia page并加以实现。让我们看看下面的代码:
importsys importmath defmain(argv): iflen(argv) !=1: sys.exit('Usage: calc_pi.py <n>') print'\nComputing Pi v.01\n' a=1.0 b=1.0/math.sqrt(2) t=1.0/4.0 p=1.0 foriinrange(int(sys.argv[1])): at=(a+b)/2 bt=math.sqrt(a*b) tt=t-p*(a-at)**2 pt=2*p a=at;b=bt;t=tt;p=pt my_pi=(a+b)**2/(4*t) accuracy=100*(math.pi-my_pi)/my_pi print"Pi is approximately: "+str(my_pi) print"Accuracy with math.pi: "+str(accuracy) if__name__=="__main__": main(sys.argv[1:])
这是个很是简朴的剧本,你可以下载,运行,修改,和随意分享给别人。你可以或许看到雷同下面的输出功效:
你会发明,尽量 n 大于4 ,我们迫近 Pi 精度却没有多大的晋升。 我们可以猜到纵然 n的值更大,同样的工作(pi的迫近精度没有晋升)依旧会产生。幸运的是,有不止一种要领来揭开这个谜。利用 Python Decimal (十进制)库,我们可以就可以获得更高精度的值来迫近Pi。让我们来看看库函数是如何利用的。这个简化的版本,可以获得多于11位的数字 凡是环境小Python 浮点数给出的精度。下面是Python Decimal 库中的一个例子 :
看到这些数字。差池! 我们输入的仅是 3.14,为什么我们获得了一些垃圾(junk)? 这是内存垃圾(memory junk)。 在坚果壳,Python给你你想要的十进制数,再加上一点点特另外值。 只要精度小于垃圾号码开始时,它不会影响任何计较只要精度小于前面的垃圾号码(junk number)开始时。 您可以指定你想要几多位数的通过配置getcontext().prec 。我们试试。
很好。 此刻让我们 试着用这个 来 看看我们是否能 与我们以前的 代码 有更好的 迫近 。 此刻, 我凡是 是阻挡 利用“ from library import * ” , 但在这种环境下, 它会 使代码 看起来更大度 。
importsys importmath fromdecimalimport* defmain(argv): iflen(argv) !=1: sys.exit('Usage: calc_pi.py <n>') print'\nComputing Pi v.01\n' a=Decimal(1.0) b=Decimal(1.0/math.sqrt(2)) t=Decimal(1.0)/Decimal(4.0) p=Decimal(1.0) foriinrange(int(sys.argv[1])): at=Decimal((a+b)/2) bt=Decimal(math.sqrt(a*b)) tt=Decimal(t-p*(a-at)**2) pt=Decimal(2*p) a=at;b=bt;t=tt;p=pt my_pi=(a+b)**2/(4*t) accuracy=100*(Decimal(math.pi)-my_pi)/my_pi print"Pi is approximately: "+str(my_pi) print"Accuracy with math.pi: "+str(accuracy) if__name__=="__main__": main(sys.argv[1:])
输出功效:
好了。我们更精确了,但看起来好像有一些舍入。从n = 100和n = 1000,我们有沟通的精度。此刻怎么办?好吧,此刻我们来求助于公式。到今朝为止,我们计较Pi的方法是通过对几部门加在一起。我从DAN 的关于 Calculating Pi 的文章中发明一些代码。他发起我们用以下3个公式:
Bailey–Borwein–Plouffe 公式
Bellard的公式
Chudnovsky 算法
让我们从Bailey–Borwein–Plouffe 公式开始。它看起来是这个样子:
#p#分页标题#e#
在代码中我们可以这样编写它:
import sys import math from decimal import * def bbp(n): pi=Decimal(0) k=0 while k < n: pi+=(Decimal(1)/(16**k))*((Decimal(4)/(8*k+1))-(Decimal(2)/(8*k+4))-(Decimal(1)/(8*k+5))-(Decimal(1)/(8*k+6))) k+=1 return pi def main(argv): if len(argv) !=2: sys.exit('Usage: BaileyBorweinPlouffe.py <prec> <n>') getcontext().prec=(int(sys.argv[1])) my_pi=bbp(int(sys.argv[2])) accuracy=100*(Decimal(math.pi)-my_pi)/my_pi print"Pi is approximately "+str(my_pi) print"Accuracy with math.pi: "+str(accuracy) if __name__=="__main__": main(sys.argv[1:])
抛开“ 包装”的代码,BBP(N)的成果是你真正想要的。你给它越大的N和给 getcontext().prec 配置越大的值,你就会使计较越准确。让我们看看一些代码功效:
这有许大都字位。你可以看出,我们并没有比以前更精确。所以我们需要前进到下一个公式,贝拉公式,但愿能得到更好的精度。它看起来像这样:
我们将只改变我们的调动公式,其余的代码将保持稳定。点击这里下载Python实现的贝拉公式。让我们看一看bellards(n):
def bellard(n): pi=Decimal(0) k=0 while k < n: pi+=(Decimal(-1)**k/(1024**k))*( Decimal(256)/(10*k+1)+Decimal(1)/(10*k+9)-Decimal(64)/(10*k+3)-Decimal(32)/(4*k+1)-Decimal(4)/(10*k+5)-Decimal(4)/(10*k+7)-Decimal(1)/(4*k+3)) k+=1 pi=pi*1/(2**6) return pi
输出功效:
哦,不,我们获得的是同样的精度。好吧,让我们试试第三个公式, Chudnovsky 算法,它看起来是这个样子:
再一次,让我们看一下这个计较公式(假设我们有一个阶乘公式)。 点击这里可下载用 python 实现的 Chudnovsky 公式。
下面是措施和输出功效:
def chudnovsky(n): pi=Decimal(0) k=0 while k < n: pi+=(Decimal(-1)**k)*(Decimal(factorial(6*k))/((factorial(k)**3)*(factorial(3*k)))*(13591409+545140134*k)/(640320**(3*k))) k+=1 pi=pi*Decimal(10005).sqrt()/4270934400 pi=pi**(-1) return pi
所以我们有了什么结论?花哨的算法不会使呆板浮点世界到达更高尺度。我真的很等候能有一个比我们用求和公式时所能获得的更好的精度。我猜那是过度的要求。假如你真的需要用PI,就只需利用math.pi变量了。然而,作为兴趣和测试你的计较机真的能有多快,你老是可以实验第一个计较出Pi的百万位可能更多位是几。