使用python查找Wilson Prime数的最有效方法是什么?

时间:2019-09-18 07:19:42

标签: python numbers primes

我已经编写了威尔逊素数的代码,并且我的代码适用于大多数数字,但是对于非常大的数字,它会给出 OverflowError:int太大而无法转换为浮点数。有什么方法可以为非常大的数字编写威尔逊素数代码。 主要问题是检查威尔逊素数威尔逊素数应满足以下条件。其中 P代表素数

然后((P-1)!+ 1)/(P * P)应该给出一个整数。 正如您所看到的,阶乘涉及此过程,因此对于非常大的数字而言,这非常困难。

我的代码:

def am_i_wilson(n):
    import math
    n1 = math.sqrt(n)
    n1 = math.ceil(n1)
    c = 0

    def fact(n):
        num = 1
        for i in range(2,n+1):
            num = num*i
        return num

    if n <= 1:
        return False

    for i in range(2, n1 + 1):
        if n%i == 0:
            c+ = 1

    if c != 0:
        return False

    x = (fact(n-1)+1)/((n**2)*1.0)

    return x.is_integer()

在我的代码中,如果数字为Wilson Prime,则返回True,否则返回False。这里的 n 是要检查其是否为Wilson素数的数字。

3 个答案:

答案 0 :(得分:1)

我认为这是最有效的方法

import math
def am_i_wilson(num):
    if num < 2 or not all(n % i for i in range(2, num)):
        return False
    return (math.factorial(num - 1) + 1) % (num ** 2) == 0

或者您也可以尝试

import math
def am_i_wilson(n):
    if n <= 2:
        return False
    fact=math.factorial(n-1)
    #this conditional checks that the number is prime or not
    #this condition is called wilson theorem in number theory
    if (fact+1)%n==0:
        x = (fact+1)%(n**2)
        if x==0:
            return True
        else:
            return False
    else:
        return False

答案 1 :(得分:0)

  

如果有人有更好的方法,请回答。

您的程序主要依赖于素数和计算阶乘的测试。您分离出阶乘逻辑,但嵌入了效率低下的素数测试-在知道数字不是素数之后,它将继续测试余数!我将两者分开,以便可以独立于Wilson Prime测试本身对它们进行测试和优化:

def factorial(n):
    number = 1

    for i in range(2, n + 1):
        number *= i

    return number

def am_i_prime(n):
    if n < 2:
        return False

    if n % 2 == 0:
        return n == 2

    for divisor in range(3, int(n ** 0.5) + 1, 2):
        if n % divisor == 0:
            return False

    return True

def am_i_wilson(n):
    return am_i_prime(n) and (factorial(n - 1) + 1) % n ** 2 == 0

给定固定目标进行测试的更有效方法是实施主要的筛子,并在计算筛子时针对遇到的每个主要分子,测试其是否为威尔逊素数。

答案 2 :(得分:0)

我最近一直在试验优质筛。我对Robert William Hanks编写的其中一个进行了快速修改(即修改),并提出了这个建议。首先输出:

$ ./wilson_primes.py 10000 [5, 13, 563]

...所以我怀疑Wikipedia上有关Wilson素数的文章是正确的;-)

import sys
def fact(n):
    num = 1
    for i in range(2, n+1):
        num *= i
    return num

def is_wilson(n):
    return (fact(n-1)+1) % n**2 == 0

def rwh_primes1(n):
    """ Returns  a list of primes < n """
    sieve = [True] * (n/2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i/2]:
            sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
    # return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
    for i in range(1,n/2):
        if sieve[i]:
            p = 2*i + 1         # convert index to normal prime
            if is_wilson(p):    #
                yield p         #

if len(sys.argv) > 1:
    N = int(float(sys.argv[1]))
else:
    N = 10000           # default: 1e4 10,000

print [p for p in rwh_primes1(N)]

首先,我只尝试了fact()函数,并惊讶地发现它可以产生巨大的结果。但是,与原始的主筛相比,它非常慢。记住上一次计算的阶乘并重新使用它可以跳过下一次阶乘的一部分,也许可以使其运行得更快。

编辑

我更改了fact()来记住它的最后结果,如下所示:

last_fact = 1
last_n = 1

def fact2(n):
    global last_fact, last_n
    num = last_fact
    for i in range(last_n+1, n+1):
        num *= i
    last_n = n
    last_fact = num
    return num

def is_wilson(n):
    return (fact2(n-1)+1) % n**2 == 0

确实加快了速度。 cProfile显示is_wilson()现在是瓶颈。我想不出一种简单的方法来加快它的速度。