素数分解:不适合大数?

时间:2013-09-25 03:58:16

标签: python

我正试图找到一个数字的最大素数因子。当使用较小的数字时,代码在IDLE上正确运行,但是当我将更大的数字(如600851475143)分配给n时,似乎根本不会在屏幕上打印任何内容。为什么呢?

def isPrime(n):
    isPrime = True
    for i in range(2,n-1):
        if n % i == 0:
            isPrime =  False
        return isPrime

largest = 0
n = 600851475143
for i in range(2,n-1):
    if isPrime(i) and n % i == 0:
        largest = i
        n = n / i
        continue

print("The largest prime factor is", largest)

顺便说一下,我正在运行Python 3.3。

=============================================== ===============================

谢谢大家!

我修改了原始代码如下:

def isPrime(n):
    for i in range(2,n-1):
        if n % i == 0:
            return False
    return True

largest = 0
n = 600851475143
for i in range(2,n-1):
    if isPrime(i) and n % i == 0:
        largest = i
        if i == n:
            break
        n = n / i

print("The largest prime factor is", largest)

像nakedfanatic所说,他们的代码运行得更快,我稍微编辑了一下:

largest = 0
n = 600851475143
i = 2
while True:
    if n % i == 0:
        largest = i
        if n == i:
            # finished
            break
        n = n / i
    else:
        i += 1

print("The largest prime factor is", largest)

7 个答案:

答案 0 :(得分:2)

有几个优化领域:

  • 所有因素分解只需要达到sqrt(n)(含)

  • isPrime()转换为表格查找

    使用n初始化查找表,然后只计算一次所有素数< sqrt(n)并循环遍历它们。
    正如评论所指出的,这会占用大量内存空间。我们可以使用位标志将内存需求减少到1/8,如果我们跳过所有偶数,我们可以将它减少一半(然后必须测试n是否是单独的)。但对于LARGE n来说,这可能仍然令人生畏。

  • (如果使用当前代码)isPrime()早期返回(由@justhalf提供)

  • 查找最大因子时
  • 向后循环(从sqrt(n)到2)

  • 如果在除以因子之后商数为1时提前返回(由@justhalf提供)

  • 这篇文章(@prashant建议)包含更复杂的算法(使我的建议非常天真&gt;&lt;):

    Fastest way to list all primes below N

  • ...(欢迎编辑)

答案 1 :(得分:1)

最有可能的是,您的代码并没有以大n为终结,只是因为在循环中运行需要很长时间。

答案 2 :(得分:1)

这是因为即使n已经为1,您也会继续尝试。

此代码将帮助您查看问题:

def isPrime(n):
    for i in xrange(2,n-1):
        if n % i == 0:
            return False
    return True

largest = 0
n = 600851475143
for i in xrange(2,n-1):
    print 'Checking whether %d divides %d' % (i,n)
    if isPrime(i) and n % i == 0:
        largest = i
        n = n / i
        continue

print("The largest prime factor is", largest)

将产生:

...
Checking whether 6857 divides 6857
Checking whether 6858 divides 1
Checking whether 6859 divides 1
Checking whether 6860 divides 1
Checking whether 6861 divides 1
Checking whether 6862 divides 1
Checking whether 6863 divides 1
Checking whether 6864 divides 1
Checking whether 6865 divides 1
Checking whether 6866 divides 1
Checking whether 6867 divides 1
Checking whether 6868 divides 1
Checking whether 6869 divides 1
Checking whether 6870 divides 1
Checking whether 6871 divides 1
Checking whether 6872 divides 1
Checking whether 6873 divides 1
...

n变为1时,你应该打破循环,这样它就不会进行不必要的检查

n = n / i
if n==1:
    break
continue

无论如何,你的代码可能会有很多改进,哈哈,看看别人的建议。

答案 3 :(得分:1)

您的代码在O(n²)时间内运行,这意味着随着n的大小增加,它将很快变得非常慢。这就是为什么你的算法适用于较小的值,但挂起的值很大。

此代码在O(n)时间内完成相同的操作而根本不进行任何质数检查,并立即返回结果:

prime_factors = []
n = 600851475143
i = 2
while True:
    if n % i == 0:
        prime_factors.append(i)
        if n == i:
            # finished
            break
        n = n / i
    else:
        i += 1

print("The largest prime factor is", prime_factors[-1])

答案 4 :(得分:1)

更困难的问题可能需要不同的算法。

请检查此问题:Fastest way to list all primes below N

您的代码看起来不错,但对于大型n可能需要很长时间。利用数学可以使您更快地完成这个问题。

在该链接上,我推荐rwh_primes1用于纯python解决方案,primesfrom3to用作使用numpy的解决方案。这两个实现都相当简短,相对清晰,基本上做同样的事情。这些代码片段是用Python 2编写的,因此翻译可能如下所示:

def rwh_primes1(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 range(1,n//2) if sieve[i]]

答案 5 :(得分:0)

isPrime = True
for i in range(2,n-1):
    if n % i == 0:
        isPrime =  False
    return isPrime

由于无条件return,此循环始终退出第一次迭代。尝试:

for i in range(2,n-1):
    if n % i == 0:
        return False

return True

此外,上限n-1可以缩减为sqrt(n)+1

答案 6 :(得分:0)

代码的另一个方面可能会减慢代码的下半部分

largest = 0
n = 600851475143
for i in range(2,n-1):
    if isPrime(i) and n % i == 0:
        largest = i
        n = n / i
        continue

特别是声明

if isPrime(i) and n % i == 0: 

根据documentation,仅在第一个条件为True时评估第二个条件。在你的情况下,反转条件会更有意义,因此总是执行计算成本较低的除法,而更昂贵的isPrime()仅用于实际因子

largest = 0
n = 600851475143
for i in range(2,n-1):
    if n % i == 0 and isPrime(i):
        largest = i
        n = n / i
        if n == 1: 
            break