【问题标题】:Prime factorization python素数分解python
【发布时间】:2015-02-07 13:04:28
【问题描述】:

我对 python 很陌生,我想我会创建一个程序来返回给定数字的质因数。这是我的代码:

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 质量有关系?我正在笔记本电脑上运行程序。

【问题讨论】:

  • 因式分解大数是一个难题。很难围绕它构建流行的密码算法。所以不要指望你的幼稚程序能有效地解决这个问题。
  • 您可能希望将“if isprime(a) == True”替换为“if isprime(a)” - Python 在每次迭代时调用 functools 库中的 reduce 函数循环,这可能需要很长时间,因此您可能想用更快的东西替换它 - 还要通过在代码中放置打印语句来检查是否存在无限循环 - 将 while 循环中的 for 循环更改为列表理解,那应该让代码更快、更易读,祝你好运

标签: python primes prime-factoring


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

    您的代码的问题是您在调用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)
    

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

    【讨论】:

      【解决方案3】:

      这是一个最快的;

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

      你可以在here找到这个方法的解释。 n 是数字,i 是质因数。

      【讨论】:

        【解决方案4】:

        这是基于模块化筛子的更快分解:

        # 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]
        

        【讨论】:

          【解决方案5】:

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

          primefactors(testnumber)
          

          【讨论】:

            猜你喜欢
            • 2013-10-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-05-14
            • 2012-05-20
            相关资源
            最近更新 更多