【问题标题】:Python: estimate Pi with trig functions as efficiently as possiblePython:使用三角函数尽可能高效地估计 Pi
【发布时间】:2016-11-27 21:26:12
【问题描述】:

我有一个任务,我需要以一种计算有效的方式来近似 Pi。这是我的策略:我使用单位圆、等腰三角形的角平分线和 sin 的定义。我画了一张图:

例如,如果我想使用六边形(6 点/6 边),我只需计算 a:(0.5*sin(2*pi/2*x) 并将其乘以 (2*x)。最后,因为Pi = Circumference/Diameter,那么我的 Pi 近似值 = 多边形周长(因为Diameter = 1)。

基本上:

from math import sin, pi
def computePi(x):    #x: number of points desired
    p = x*sin(pi/x)
    print(p)

computePi(10000)
3.141592601912665

它很有效,而且我认为它的效率很高,不是吗?感谢您的宝贵时间!

编辑:为了避免循环,我使用阿基米德算法重新编写了它,只使用了毕达哥拉斯定理:

代码:

from math import sqrt

def approxPi(x):                  #x: number of times you want to recursively apply Archmidedes' algorithm
    s = 1                         #Unit circle
    a = None; b = None;   
    for i in range(x):
        a = sqrt(1 - (s/2)**2)
        b = 1 - a
        print('The approximate value of Pi using a {:5g}-sided polygon is {:1.8f}'.format(6*2**(i),(s*6*2**(i))/2))
        s = sqrt(b**2 + (s/2)**2)

【问题讨论】:

  • 那么,您使用pi 的值计算pi?嗯
  • 如果你要导入 pi,为什么不直接使用呢?
  • 实际上,这是一个很好的家庭作业问题(尽管可能在 Stack Overflow 上偏离主题,因为它是工作代码)。可以使用math.sin(math.radians(y)) 隐藏圆形度,其中y 是以度为单位的适当角度。由于这是近似 pi 的历史准确方法,因此可以例如将 360 除以 2 的幂,以便可以使用半角公式从第一原理计算出所需的正弦,而无需事先了解 pi
  • @UrielEli 实际上,我可以使用度数而不是弧度:sin(pi/x) = sin(180/x),不是吗?三角函数只是表示直角三角形中比率的函数,不是吗?
  • @JohnColeman 谢谢!使用弧度确实会引入圆度,但度数不会

标签: python python-3.x trigonometry


【解决方案1】:

更好的是

print(4 * math.atan(1))

这在计算中没有以任何明显的方式使用 pi(尽管作为@Jean-FrançoisFabre cmets,pi 可能在函数定义中使用),除了 trig 函数之外,它只有一个简单的乘法。当然也有

print(2 * math.acos(0))

print(2 * math.asin(1))

【讨论】:

  • 它可能使用 pi,但至少它使用三角函数内部定义的那个。
  • 或者只使用print(pi)。无需计算
  • @RoryDaulton print(sin and pi) 然后:-P
  • 是使用math.atan 计算的math.pi 还是使用pi 的固定值计算的math.atan?鸡和蛋的情况。但这回答正好回答了这个问题。也许这个问题不是那么好。计算 pi 应该在没有三角函数的情况下完成,例如:stackoverflow.com/questions/29190407/…
  • 我从下载的this Intel manual 副本中的第 3-210 页或该手册第 1 卷的第 7-39 页获得了该信息。也可以在this Wikipedia page 中查找 FLDPI。
【解决方案2】:

一个有趣但不是很有效的解决方案是使用欧拉的Basel Problem 解决方案:

from math import sqrt

def psum(n):
    return sum(1/k**2 for k in range(1,n+1))

def approxPi(n):
    s = psum(n)
    return sqrt(6*s)

例如,

>>> approxPi(100000)
3.141583104326456

正如我所说,效率不高。另一方面,显然没有微妙的循环。众所周知,许多其他系列要么收敛到 pi,要么收敛到可以轻松计算出 pi 的值,并且许多其他系列收敛得更快。

编辑时:@Simon 建议使用Gauss-Legendre algorithm 以及模块decimal,导致以下代码(将结果作为字符串返回):

import decimal
from decimal import Decimal as d

def approxPi(n):
    eps = 1/d(10**n)
    decimal.getcontext().prec = 3*n #probably overkill, but need room for products
    a = d(1)
    b = 1/d(2).sqrt()
    t = 1/d(4)
    p = d(1)
    dif = a-b
    if dif < 0: dif = -dif
    i = 1
    while dif >= eps:
        a1 = (a+b)/2
        b1 = a*b
        b1 = b1.sqrt()
        t1 = t - p*(a - a1)**2
        p1 = 2*p
        a,b,t,p = a1,b1,t1,p1
        dif = a1-b1
        if dif < 0: dif = -dif
    pi = (a + b)**2/(4*t)
    return str(pi)[:n+2]

例如,

>>> approxPi(1000)
'3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989'

同意this

上述过程不到一秒钟。 10,000 需要几秒钟。看看用这个在 Python 中获得 1,000,000 位数字需要多长时间会很有趣。

【讨论】:

  • 实际上,它应该在大约 13 次迭代中收敛到 10000 位。 “该算法具有二阶收敛性,这实质上意味着算法的每一步正确数字的数量都会增加一倍。”
  • 1000000 位应该是 20 次迭代。
  • @Simon 是的——但是当您处理如此高的精度时,单个迭代会变慢。取 2,000,000+ 位 decimal 对象的平方根(只是迭代的 1 部分)可能有点费时。我对decimal 类了解得不够多,无法估计需要多长时间,但如果从 1,000 到 10,000 的时间增加了一个数量级,那么至少在我使用 3 年的笔记本电脑上,1,000,000 可能是一个延伸。我会运行它,看看会发生什么。
  • 您是正确的,您的代码是正确的,并且迭代确实匹配。我看了一眼时间,推测这些操作会快得多。对不起!
  • @Simon 完成时我正在遛狗,所以我不知道确切的时间,但它需要 30 到 45 分钟才能跑完(我刚开始它就走了,没有计时码) .最后10位数字为5779458151,可以通过各种在线工具进行验证。
【解决方案3】:

这是解决您问题的代码:

from math import radians, sin


def computePi(n):
    p = n * (sin(radians((360/(2*n)))))
    print(p)
computePi(1000)

此代码背后的理论在此线程中进行了解释:https://math.stackexchange.com/questions/588141/how-is-the-value-of-pi-pi-actually-calculated

【讨论】:

  • R 非常感谢您的宝贵时间!
猜你喜欢
  • 2012-12-09
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多