Python 试图定义一个Euler';s近似为pi,获取';列表和';int';
我试图使用Euler的一种方法在python中定义一个函数,该函数将近似于Python 试图定义一个Euler';s近似为pi,获取';列表和';int';,python,pi,approximation,Python,Pi,Approximation,我试图使用Euler的一种方法在python中定义一个函数,该函数将近似于pi。他的公式如下: 到目前为止,我的代码是: def pi_euler1(n): numerator = list(range(2 , n)) for i in numerator: j = 2 while i * j <= numerator[-1]: if i * j in numerator: numer
pi
。他的公式如下:
到目前为止,我的代码是:
def pi_euler1(n):
numerator = list(range(2 , n))
for i in numerator:
j = 2
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 1
for k in numerator:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
#Because all primes are odd, both numbers inbetween them are divisible by 2,
#and by extension 1 of the 2 numbers is divisible by 4
term = numerator / denominator
def pi_euler1(n):
分子=列表(范围(2,n))
对于分子中的i:
j=2
当i*j在术语=分子/分母时,你将一个列表除以一个数字,这是没有意义的。将k
除以循环中的分母,以便将分子
元素逐个用于等式的每个因子。然后您可以将它们重复相乘为术语term*=i/分母
,您在开始时将其初始化为term=1
另一个问题是第一个循环,它不会给出第一个n
素数。例如,对于n=3
,列表(范围(2,n))=[2]
。因此,唯一的素数是2 以下是代码,经过一些小的修改后可以正常工作:
import math
def pi_euler1(n):
lim = n * n + 4
numerator = list(range(3, lim, 2))
for i in numerator:
j = 3
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 2
euler_product = 1
for k in numerator[:n]:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
factor = k / denominator
euler_product *= factor
return euler_product * 4
print(pi_euler1(3))
print(pi_euler1(10000))
print(math.pi)
备注:
- 您只需要奇数素数,因此可以从奇数列表开始
j
可以从3
开始,并以2的步长递增。事实上,j
可以从i
开始,因为i
小于i*i
的所有倍数都已在前面删除
- 一般来说,从正在迭代的列表中删除元素是非常糟糕的做法。见例。在内部,Python在其迭代的列表中使用索引。巧合的是,在这种特定情况下,这不是问题,因为只有大于当前值的数字才会被删除
- 此外,从一个很长的列表中删除元素的速度非常慢,因为每次都需要移动完整的列表以填补空白。因此,最好使用两个单独的列表
- 您没有计算结果产品,也没有退货
- 正如你所注意到的,这个公式收敛得非常慢
- 如评论中所述,以前的版本将
n
解释为最高素数的限制,而实际上n
应该是素数。我修改了代码来纠正这一点。在上述版本中,有一个粗略的限制;下面的版本尝试对极限进行更严格的近似
这是一个经过修改的版本,没有从您正在迭代的列表中删除。它不是删除元素,而是标记它们。这要快得多,因此可以在合理的时间内使用较大的n
:
import math
def pi_euler_v3(n):
if n < 3:
lim = 6
else:
lim = n*n
while lim / math.log(lim) / 2 > n:
lim //= 2
print(n, lim)
numerator = list(range(3, lim, 2))
odd_primes = []
for i in numerator:
if i is not None:
odd_primes.append(i)
if len(odd_primes) >= n:
break
j = i
while i * j < lim:
numerator[(i*j-3) // 2] = None
j += 2
if len(odd_primes) != n:
print(f"Wrong limit calculation, only {len(odd_primes)} primes instead of {n}")
euler_product = 1
for k in odd_primes:
denominator = k + 1 if k % 4 == 3 else k - 1
euler_product *= k / denominator
return euler_product * 4
print(pi_euler_v2(100000))
print(math.pi)
谢谢你,我已经完成了你建议的所有工作,并将素数的范围更改为n+1,以便包括n,我还添加了第三个for循环,以迭代I/分母,如你所说。我对pi_euler(10)的输出是0.04486。。。更大的数字只会得到非常小的浮点输出,我会摆弄它,看看哪里出错了。不过,谢谢你,我现在有了它工作原理的前提,我认为将素数范围更改为n+1是不够的,因为在一般情况下,你不知道你的最大素数是什么(例如,第三个素数是5,不包括在n+1=4中)。更好的方法是:从一个空列表开始,找到下一个素数,然后继续追加,直到列表的长度n
。找到有效的素数生成算法应该很容易。如果你从分子=列表(范围(3,n,2))
开始,你将不会得到n
第一个素数的列表,这就是问题的定义。“…它计算乘积中前n个项的值…”,这是对n
的不同解释。解决方案是用一个足够大的数字乘以n,以获得数组限制。我宁愿以增量方式构建素数列表。但我不是素数算法的专家。从一个随机长度的列表开始听起来不是一个好的通用方法,事实上,以块的形式构建列表的额外优势是需要更少的内存。您只需要固定块长度的内存,以及存储n
素数的内存。上面的新版本试图计算一个好的极限。
3.28125
3.148427801913721
3.141592653589793
import math
def pi_euler_v3(n):
if n < 3:
lim = 6
else:
lim = n*n
while lim / math.log(lim) / 2 > n:
lim //= 2
print(n, lim)
numerator = list(range(3, lim, 2))
odd_primes = []
for i in numerator:
if i is not None:
odd_primes.append(i)
if len(odd_primes) >= n:
break
j = i
while i * j < lim:
numerator[(i*j-3) // 2] = None
j += 2
if len(odd_primes) != n:
print(f"Wrong limit calculation, only {len(odd_primes)} primes instead of {n}")
euler_product = 1
for k in odd_primes:
denominator = k + 1 if k % 4 == 3 else k - 1
euler_product *= k / denominator
return euler_product * 4
print(pi_euler_v2(100000))
print(math.pi)
3.141752253548891
3.141592653589793