se6cxpp 发表于 2021-4-2 12:00

自学-python-3 π的计算

本帖最后由 se6cxpp 于 2021-4-2 12:20 编辑

编写初衷是看到了这么一句话
“圆周率一般用希腊字母π表示。它是一个无限不循环小数,目前已经计算出小数点后几十万亿位。既然小数点后有无穷多数字,那么一定有无穷多的数字组合。你有没有想过圆周率中是否有自己的生日数字组合或者QQ号组合和手机号组合?这个数字组合在什么位置?”


就是想看看自己的生日在π小数位的多少位,于是就开始了....


一、解决π的计算
通过查找找到一个公式


泰勒级数转换:
π/4=1-1/3+1/5-1/7+1/9...
这种还是好写的直接for循环控制循环次数就行
pi=0
for i in range(5000):
    if i%2==0:
      pi=pi+1/(2*i+1)
    else:
      pi=pi-1/(2*i+1)
print(pi*4)

算出的结果很是尴尬,因为循环100以内得到的数值和π还是有差距的,主要是因为公式的精度,于是继续找

Nilakantha 级数转换:
π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - 4/(12*13*14)...
pi=0
for i in range(5):
    if i%2==0:
      pi=pi+4/((2*i+2)*(2*i+3)*(2*i+4))
    else:
      pi=pi-4/((2*i+2)*(2*i+3)*(2*i+4))
print(pi+3)

这个就好多了,但是对于追求完美的我,继续找到了另一个公式

莱布尼兹转换



pi=0
for i in range(5):
    if i%2==0:
      pi=pi+(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
    else:
      pi=pi-(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
print(pi*4)

这种算法使得极度收敛到π


三种方法对比

x=int(input("输入计算次数:"))
pi1=0
for i in range(x):
    if i%2==0:
      pi1=pi1+1/(2*i+1)
    else:
      pi1=pi1-1/(2*i+1)
print("泰勒级数转换结果",pi1*4)
pi3=0
for i in range(x):
    if i%2==0:
      pi3=pi3+4/((2*i+2)*(2*i+3)*(2*i+4))
    else:
      pi3=pi3-4/((2*i+2)*(2*i+3)*(2*i+4))
print("Nilakantha级数转换结果",pi3+3)
pi2=0
for i in range(x):
    if i%2==0:
      pi2=pi2+(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
    else:
      pi2=pi2-(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
print("莱布尼茨级数转换",pi2*4)

大家可以看看结果
同时提供一个运算精度的比较
x=int(input("输入计算次数:"))
pi1=0
for i in range(x):
    if i%2==0:
      pi1=pi1+1/(2*i+1)
    else:
      pi1=pi1-1/(2*i+1)
pi2=0
for i in range(x):
    if i%2==0:
      pi2=pi2+(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
    else:
      pi2=pi2-(1/(2*i+1))*((1/2**(2*i+1))+(1/3**(2*i+1)))
pi3=0
for i in range(x):
    if i%2==0:
      pi3=pi3+4/((2*i+2)*(2*i+3)*(2*i+4))
    else:
      pi3=pi3-4/((2*i+2)*(2*i+3)*(2*i+4))      
result1="泰勒级数转换结果"
result2="莱布尼茨级数转换结果"
result3="Nilakantha级数转换结果"
a=pi1*4
b=pi2*4
c=pi3+3
d=3.14159265358979323846264338327950288419716939937510 # 标准值(小数后50位)
print(result1.rjust(16,"*"),":","{:.50f}".format(a))
print(result2.rjust(14,"*"),":","{:.50f}".format(b))
print(result3.rjust(18,"*"),":","{:.50f}".format(c))
m1=1-(abs(a-d)/d)          # abs()返回一个数的绝对值
m2=1-(abs(b-d)/d)
m3=1-(abs(c-d)/d)
print(m1)
print(m2)
print(m3)
这个就很直观了




解决了π的运算,发现小数位并不能到很多位
即使用format规定50位,16位以后也是用0填充,很尴尬

于是找到了decimal模块

先看个小例子
根号2的计算
from decimal import*                # 十进制函数
getcontext().prec=500               # 控制小数位数
print(Decimal('2').sqrt(),"\n")   #计算根号2
print(Decimal(2).sqrt())            #计算根号2

通过这种方法
改写(用到一点定义函数)
贝拉公式计算

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
getcontext().prec=(1000)
print(bbp(50))

成功实现
加入查找行

from decimal import *
m=input("输入运算精度(默认为10):") or "10"
n=input("输入保留有效数字(默认为10):") or "10"
def pi(x):
    pi=Decimal(0)
    k=0
    while k<=x:
      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
getcontext().prec=(int(n))

print(pi(int(m)))
y=input("输入生日日期(如2月14日(默认)输入:0214):") or "0214"

while True:
    try:
      print("从结果的第",str(pi(int(m))).index(y),"位找到结果")
      break
    except:
      print("未找到")
      break


搞定



lycgood123 发表于 2021-4-2 13:10

学习了,谢谢楼主!!

叫我小王叔叔 发表于 2021-4-2 13:38

脑洞好大。棒棒哒

啊笨 发表于 2021-4-2 14:35

太溜了,我最近也准备自学这个,请给点学习建议!

谢谢大神!

guangdate 发表于 2021-4-2 14:43

脑洞好大!厉害

傲雪不傲霜 发表于 2021-4-2 15:02

不仅学到了几种π的级数求法,也学到了Python的简单编程,不错不错

lamjiarong 发表于 2021-4-2 15:30

谢谢楼主分享!!!

Loganaahhh 发表于 2021-4-2 16:20

输入默认的0214都是没找到

se6cxpp 发表于 2021-4-2 16:57

Loganaahhh 发表于 2021-4-2 16:20
输入默认的0214都是没找到

大概在四千多位,运算精度默认10有效数字输入5000。

寒冰流火 发表于 2021-4-2 18:20

很好的经验。有了Python的基本功,还得搭上其他技术技能才行。
页: [1] 2
查看完整版本: 自学-python-3 π的计算