【问题标题】:Efficient Mersenne prime generator in pythonpython中的高效梅森素数生成器
【发布时间】:2017-07-19 15:31:59
【问题描述】:

我编写的代码似乎效率不高。它只计算几个素数。

这是我的代码:

num=float(1)
a=1

while(num>0):    # Create variable to hold the factors and add 1 and itself (all numbers have these factors)
    factors = [1, num]

    # For each possible factor
    for i in range(2, int(num/4)+3):
        # Check that it is a factor and that the factor and its corresponding factor are not already in the list
        if float(num) % i == 0 and i not in factors and float(num/i) not in factors:
            # Add i and its corresponding factor to the list
            factors.append(i)
            factors.append(float(num/i))
    num=float(num)
    number=num
# Takes an integer, returns true or false
    number = float(number)
# Check if the only factors are 1 and itself and it is greater than 1
    if (len(factors) == 2 and number > 1):
        num2=2**num-1
        factors2=[1, num]
        for i in range(2, int(num2/4)+3):
        # Check that it is a factor and that the factor and its corresponding factor are not already in the list
            if float(num2) % i == 0 and i not in factors2 and float(num2/i) not in factors2:
            # Add i and its corresponding factor to the list
                factors2.append(i)
                factors2.append(float(num2/i))
        if(len(factors2)==2 and num2>1):
            print(num2)
        a=a+1
    num=num+2

如何使我的代码更高效,并能够更快地计算梅森素数。我想用这个程序找到任何可能的新完美数。

【问题讨论】:

    标签: python-3.x primes


    【解决方案1】:

    到目前为止显示的所有解决方案都使用了糟糕的算法,完全忽略了梅森素数的要点。梅森素数的优点是我们可以比其他奇数通过蛮力更有效地测试它们的素数。我们只需要检查一个指数的素数并使用Lucas-Lehmer primality test 来完成剩下的工作:

    def lucas_lehmer(p):
        s = 4
        m = 2 ** p - 1
        for _ in range(p - 2):
            s = ((s * s) - 2) % m
        return s == 0
    
    def is_prime(number):
        """
        the efficiency of this doesn't matter much as we're
        only using it to test the primeness of the exponents
        not the mersenne primes themselves
        """
    
        if number % 2 == 0:
            return number == 2
    
        i = 3
        while i * i <= number:
            if number % i == 0:
                return False
            i += 2
    
        return True
    
    print(3)  # to simplify code, treat first mersenne prime as a special case
    
    for i in range(3, 5000, 2):  # generate up to M20, found in 1961
        if is_prime(i) and lucas_lehmer(i):
            print(2 ** i - 1)
    

    OP 的代码在 M7 524287 之后陷入困境,@FrancescoBarban 的代码在 M8 2147483647 之后陷入困境。上面的代码在大约 15 秒内生成 M18!这是最多 M11,在大约 1/4 秒内生成:

    3
    7
    31
    127
    8191
    131071
    524287
    2147483647
    2305843009213693951
    618970019642690137449562111
    162259276829213363391578010288127
    170141183460469231731687303715884105727
    6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
    531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127
    

    这个程序在 M20 上停滞不前,但它并不是一个特别有效的实现。这绝对不是一个糟糕的算法。

    【讨论】:

    • 好主意@cdlane!我可以建议使用 >> aka "Bit Shift" 运算符以获得更好的性能吗?
    【解决方案2】:
    import math
    
    def is_it_prime(n):
    
        # n is already a factor of itself 
        factors = [n]
    
        #look for factors
        for i in range(1, int(math.sqrt(n)) + 1):
    
             #if i is a factor of n, append it to the list
             if n%i == 0: factors.append(i)
             else: pass
    
        #if the list has more than 2 factors n is not prime
        if len(factors) > 2: return False
        #otherwise n is prime
        else: return True
    
    n = 1
    while True:
    
        #a prime P is a Mersenne prime if P = 2 ^ n - 1
        test = (2 ** n) - 1
    
        #if test is prime is also a Mersenne prime
        if is_it_prime(test):
            print(test)
        else: pass
        n += 1
    

    它可能会停留在 2147483647,但你知道,下一个梅森素数是 2305843009213693951...所以如果它花费的时间比你预期的要多,请不要担心 ;)

    【讨论】:

    • 与其只是粘贴答案,为什么不解释为什么你的答案更好或更快?
    【解决方案3】:

    如果你只是想检查一个数是否是素数,那么你不需要找到它的所有因数。您已经知道 1 和 num 是因数。一旦你找到第三个因素,那么这个数字就不能是素数。您正在浪费时间寻找第四、第五等因素。

    梅森数的形式为 2^n - 1,因此总是奇数。因此,它的所有因素都是奇怪的。如果您只寻找奇数因素,则可以将循环的运行时间减半:从第 3 步开始,第 2 步到下一个可能的因素。

    因子成对出现,一个比平方根大,一个比平方根小。因此,正如@Francesco 的代码所示,您只需要查找直到平方根的因子。对于更大的梅森数,这可以为您节省大量时间。

    把这两点放在一起,你的循环应该更像:

    #look for factors
    for i in range(3, int(math.sqrt(n)) + 1, 2):
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-03
      • 2019-10-28
      • 2020-09-08
      • 1970-01-01
      • 2017-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多