尝试定义与pi的Euler近似值之一,获取'list和'int'的不受支持的操作数类型

时间:2019-12-10 20:38:13

标签: python pi approximation

我正在尝试使用Euler的方法之一在Python中定义一个近似pi的函数。他的公式如下: formula

到目前为止,我的代码是:

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

我知道这是错误的,并且也不完整。我只是不太确定我前面提到的 TypeError 到底是什么意思。我对此非常了解,我想创建一个术语列表,然后找到他们的产品。我在正确的路线上吗?

更新: 我已经解决了这一问题,修复了由于msconi和Johanc而普遍存在的明显错误,现在使用了以下代码:

import math
def pi_euler1(n):
    numerator = list(range(2 , 13 + math.ceil(n*(math.log(n)+math.log(math.log(n))))))
    denominator=[]
    for i in numerator:
        j = 2
        while i * j <= numerator[-1]:
            if (i * j) in numerator:
                numerator.remove(i * j)
            j += 1
    numerator.remove(2)
        for k in numerator:
            if (k + 1) % 4 == 0:
                denominator.append(k+1)
            else:
                denominator.append(k-1)
        a=1
        for i in range(n):
            a *= numerator[i] / denominator[i]
        return 4*a

这似乎可行,当我尝试以符号学轴比例绘制pi的误差图时,我遇到了域误差,但是我需要将范围的上限更改为n + 1,因为log (0)未定义。谢谢你们

2 个答案:

答案 0 :(得分:0)

term = numerator / denominator中,您将列表除以数字,这没有意义。将k除以循环中的分母,以便将numerator 分别用于每个方程式的因数。然后,您可以将它们重复乘以术语term *= i / denominator,并在开头将其初始化为term = 1

另一个问题是第一个循环,它不会为您提供第一个n质数。例如,对于n=3list(range(2 , n)) = [2]。因此,您将获得的唯一素数是2。

答案 1 :(得分:0)

下面是进行一些小的修改以使其正常工作的代码:

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)

输出:

3.28125
3.148427801913721
3.141592653589793

备注:

  • 您只需要奇数质数,因此可以从一个奇数列表开始。
  • j可以以3开头,并以2的步长递增。实际上,j可以以i开头,因为i的所有倍数都较小比i*i早已被删除。
  • 通常,从要迭代的列表中删除元素是非常不好的做法。参见例如this post。在内部,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)

输出:

3.141752253548891
3.141592653589793