由Python运算π的值深入Python中科学计算的实现
作者:goldensun 发布时间:2021-10-21 03:48:06
π是一个无数人追随的真正的神奇数字。我不是很清楚一个永远重复的无理数的迷人之处。在我看来,我乐于计算π,也就是计算π的值。因为π是一个无理数,它是无限的。这就意味着任何对π的计算都仅仅是个近似值。如果你计算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 库中的一个例子 :
wpid-python_decimal_example-2013-05-28-12-54.png
看到这些数字。不对! 我们输入的仅是 3.14,为什么我们得到了一些垃圾(junk)? 这是内存垃圾(memory junk)。 简单点说,Python给你你想要的十进制数,再加上一点点额外的值。 只要精度小于垃圾数,它不会影响任何计算。通过设置getcontext().prec 你可以的到你想要的位数 。我们试试。
看到这些数字。不对! 我们输入的仅是 3.14,为什么我们得到了一些垃圾(junk)? 这是内存垃圾(memory junk)。 简单点说,Python给你你想要的十进制数,再加上一点点额外的值。 只要精度小于垃圾数,它不会影响任何计算。通过设置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 公式开始。它看起来是这个样子:
在代码中我们可以这样编写它:
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的百万位或者更多位是几。


猜你喜欢
- 问题:例如我们要选从不同省份选取一个号码,每个省份的权重不一样,直接选随机数肯定是不行的了,就需要一个模型来解决这个问题。简化成下面的问题:
- eval()函数常被称为评估函数,它的功能是去掉参数最外侧引号,变成python可执行的语句,并执行语句的函数。1 eval函数的简介和语法
- 前言来自 Google 的 Andrew Gerrand 曾经关于 Go 中的参数命名规范进行了分享,slides 为 https://ta
- 制作自己的训练集下图是我们数据的存放格式,在data目录下有验证集与测试集分别对应iris_test, iris_train 为了向伟大的M
- 基本示例?计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用&rdquo
- 今天终于抽出时间瞟了一眼JavaScript的新标准ECMA262v5,让我欣喜的是,不像是因为过于激进而被废除的v4,这个新标准对Java
- vue安装less依赖一、安装less依赖npm install less less-loader --save二、修改webpack.ba
- 本文实例讲述了Python常见数据类型转换操作。分享给大家供大家参考,具体如下:类型转换主要针对几种存储工具:list、tuple、dict
- 封装数据库操作,并且提供事务处理。 使用DbProviderFactories的数据库操作类 Imports System.Data Imp
- 身为一名小小的程序猿,在日常开发中不可以避免的要和where in和like打交道,在大多数情况下我们传的参数不多简单做下单引号、敏感字符转
- 试了一下,xmlDoc.save()行不同,就试着用fso做了出来。整理一下,供大家discuss。由于用js操作本地xml文件之后save
- 1 查找记录条数 select count(*) from table_name(换成表名)&nbs
- 本篇文章是一篇Vue.js的教程,目标在于用一种常见的业务场景——分页/无限加载,帮助读者更好的理解Vue.js中的一些设计思想。与许多To
- 前言平时我们在接收后端返回的json对象通常是一个字符串类型的object,所以一般我们要对这个object进行类型转化后,我们才能使用ob
- 为何使用函数最大化代码的重用和最小化代码冗余流程的分解编写函数>>def语句在Python中创建一个函数是通过def关键字进行的
- 开发一个相机应用,需要申请三个权限:相机、读文件、写文件。1、在AndroidManifest.xml中添加<uses-permiss
- 本文实例讲述了JS基于开关思想实现的数组去重功能。分享给大家供大家参考,具体如下:场景: 比如给你一个数组var Arr = [ 25, 7
- 决策树之CART(分类回归树)详解,具体内容如下1、CART分类回归树简介 CART分类回归树是一种典型的二叉决策树,可以处理连续型变量
- 本文实例讲述了JavaScript实现获取select下拉框中第一个值的方法。分享给大家供大家参考,具体如下:1、说明获取select下拉框
- 今天小编利用美丽的汤来为大家演示一下如何实现京东商品信息的精准匹配~~HTML文件其实就是由一组尖括号构成的标签组织起来的,每一对尖括号形式