质数分解 python

Prime factorization python

我是 python 的新手,我想我会创建一个程序来 returns 给定数字的质因数。这是我的代码:

import math
import operator
import functools

def isprime (n):
    if n == 1:
        return False
    elif n == 2:
        return True
    else:
        for x in range (2, int(math.sqrt(n))+1):
            if n % x == 0:
                return False
                break
        else:
            return True



def factors (a):
    factorlist = []
    if isprime(a) == True:
        print "The number is a prime."
    else:   
        while functools.reduce(operator.mul, factorlist, 1) != a:
            for x in range (1, a):
                if a % x == 0:
                    if isprime(x) == True:
                        factorlist.append(x)
        factorlist.sort()
        print factorlist

testnumber = int(input("Enter a number."))
factors(testnumber)

我的问题是,根据数量的不同,需要很长时间。瞬间可以解决100或1000,但2000或864就是不行!我将 运行 864 作为我的输入保留了 45 分钟,但它没有打印任何内容。我的 CPU 质量有问题吗?我是 运行 笔记本电脑上的程序。

您的问题绝对不是像 864 这样小的数字的复杂性。相反,当您这样做时:

while functools.reduce(operator.mul, factorlist, 1) != a:
    for x in range (1, a):
        ...

你所做的基本上是在每次不减少时遍历所有可能的素数。这是多余的,因为无论如何您只需要浏览一次列表。

对于 2000 这样的输入,你进入了一个无限循环,因为它永远不会减少到 2000 - 这就是为什么它只保持 运行。您可以在 whilefor 之间添加 print factorlist 以查看到底发生了什么。

如果您只删除 while 语句,您将能够更快地获得结果。

(请注意,我同意上面 Ferdinand Beyer 关于大数的评论。我只是说在您的特定情况下,864 不是一个大数,并且您的程序中存在错误。)

这是最快的一个;

n = 600851475143 
i = 2

while i * i < n:
    while n%i == 0:
        n /= i
        print (i)
    i += 1

您可以在中找到该方法的说明。 n 是数字,i 是质因数。

您的代码的问题是您在调用 functools.reduce(operator.mul, factorlist, 1) 中反复进行一些昂贵的计算,并且您反复检查 isprime(x) 是否有相同的数字(和 isprime 由于循环而本身很昂贵)。

为了避免 functools.reduce 调用,您可以简单地通过改变您在@howaboutNO 的解决方案中因式分解的数字,或者通过进行递归调用(见下文)来划分已知因子。

为了避免使用相同的值调用 isprime(x) 的开销,您可以使用 memoization,这是您工具集中的一个方便的技巧。

应用这两个,我得出以下结论:

import math

def memoize(f):
    memo = {}
    def helper(x):
        if x not in memo:
            memo[x] = f(x)
        return memo[x]
    return helper

@memoize
def isprime (n):
    if n == 1:
        return False
    elif n == 2:
        return True
    else:
        for x in range (2, int(math.sqrt(n))+1):
            if n % x == 0:
                return False
                break
        else:
            return True


def factors (a):
    if a == 1:
        return []
    elif isprime(a):
        return [a]
    else:
        for x in range (2, int(math.sqrt(a))+1):
            if a % x == 0:
                return [x] + factors(a/x)

testnumber = int(input("Enter a number."))
print factors(testnumber)

它比您的代码运行得快得多。

这是一个基于模块化筛的更快的因式分解:

# modular sieve based on (2,3,5):
sieve_size = 2 * 3 * 5
sieve = [1, 7, 11, 13, 17, 19, 23, 29]

# all primes < sieve_size
base = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

def factors(a):
    f = []

    # remove factors of primes < sieve_size
    for b in base:
        while not a % b:
            a //= b
            f.append(b)
        if a < b*b:
            break

    # remnant fully factored?
    if a < b*b:
        if a > 1:
            f.append(a)
        return f

    # remove factors of values generated by modular sieve
    #   (We do not need to test for actual primality;
    #   because candidate values are generated in ascending order,
    #   if the value is composite, all factors of it will have
    #   already been removed)
    n = sieve_size
    while True:
        for s in sieve:
            b = n + s      # 31, 37, 41, 43, ...
            while not a % b:
                a //= b
                f.append(b)
            if a < b*b:
                break
        if a < b*b:
            if a > 1:
                f.append(a)
            return f
        n += sieve_size

然后进行快速测试:

import random
for i in range(30):
    val = random.randint(1000, 1000000)
    print(val, factors(val))

几乎立即给出

344779 [73, 4723]
376343 [11, 34213]
830823 [3, 7, 39563]
927157 [7, 11, 12041]
852641 [852641]
802619 [47, 17077]
80214 [2, 3, 29, 461]
348030 [2, 3, 3, 3, 5, 1289]
533572 [2, 2, 13, 31, 331]
317206 [2, 199, 797]
806636 [2, 2, 421, 479]
539294 [2, 7, 7, 5503]
706820 [2, 2, 5, 59, 599]
501587 [97, 5171]
759410 [2, 5, 75941]
375319 [7, 53617]
668889 [3, 3, 13, 5717]
545731 [545731]
496852 [2, 2, 124213]
309332 [2, 2, 17, 4549]
629728 [2, 2, 2, 2, 2, 11, 1789]
835342 [2, 417671]
505591 [71, 7121]
172411 [172411]
410995 [5, 13, 6323]
645451 [31, 47, 443]
369849 [3, 113, 1091]
67237 [71, 947]
505186 [2, 11, 22963]
945547 [945547]

除非您将其作为编程练习,否则只需使用

primefactors(testnumber)