Python中的整数因子分解

6

我在这个网站上看到了很多用Python进行整数因数分解的方法,但是并不真正理解它们,所以我尝试用自己的方法来实现:

def factorisation(n):
fact = []
i = 2
while i<=n:     
    if n%i==0:      
        fact.append(i)
        n//= i
    else:
        i+=1
return fact

我认为它是有效的,但我不太清楚为什么while循环从i到n...从我的课程中,我学到了我们必须从2到sqrt(n)进行判断。

我是否有什么误解?

我能否改进它?

谢谢 :)


提前停止循环是一种优化。 - Petr Vepřek
怎么办?如果我不到n,它好像就不会返回所有的值 :/ - Kosmoz
2
每次找到一个因子,N的值就会变小,因此实际上你并没有达到N的原始值。 - Kevin
如果你没有达到n,那么你需要在最后将n的剩余值加到因子中。 - interjay
@interjay 谢谢,我没有想到过!我会尝试这个 :) - Kosmoz
这个回答解决了你的问题吗?快速质因数分解模块 - undefined
5个回答

8

你可以使用Pollard's rho整数分解算法。与其他速度较慢的算法相比,它效率很高且快速。例如:

Python 3:

from math import gcd

def factorization(n):

    factors = []

    def get_factor(n):
        x_fixed = 2
        cycle_size = 2
        x = 2
        factor = 1

        while factor == 1:
            for count in range(cycle_size):
                if factor > 1: break
                x = (x * x + 1) % n
                factor = gcd(x - x_fixed, n)

            cycle_size *= 2
            x_fixed = x

        return factor

    while n > 1:
        next = get_factor(n)
        factors.append(next)
        n //= next

    return factors

对于小数字,它非常快速,在这种情况下仅花费了0.035秒。

print(factorization(823767))

~$ time python3 factorization.py
[3, 7, 39227]

real    0m0,035s
user    0m0,031s
sys     0m0,004s

如果我们使用稍大一些的数字,计算时间会增加,但仍然非常快,例如在这种情况下只需0.038秒。
print(factorization(41612032092))

~$ time python3 factorization.py
[3, 4, 37, 1681, 127, 439]

real    0m0,038s
user    0m0,034s
sys     0m0,004s

如果我们使用非常大的数字,会花费更多时间,但考虑到这是一个巨大的数字,这仍然是一个非常合理的时间。在这种情况下,只需要 28.128 秒。

print(factorization(23756965471926357236576238546))

~$ time python3 factorization.py
[3, 3, 2, 479, 11423, 582677, 413975744296733]

real    0m28,128s
user    0m28,120s
sys     0m0,008s

希望这能对你有所帮助。祝好。


2
我真的很喜欢这个,但至少对我来说 factorization(144) 返回的是 [3, 3, 8, 2] 而不是我需要的 [3, 3, 2, 2, 2, 2]。不完整的因数分解只在2上吗?还是不可预测的? - uhoh
2
看起来不错,但不能正确处理重复因子 - 即使像25这样的数字也被标记为没有适当的因子。 - Tom Swirly
无法检索到169和13*13的相同内容。 - PouJa

8
当一个整数n不能被小于sqrt(n)的任何数字整除时,那就足以说明n是质数。在这种情况下,你将不会发现除n本身外的任何其他因子。
所以你可以在sqrt(n)处停止循环,并将n的剩余值添加到质数因子列表中。

谢谢 :) 我怎样才能在循环结束时得到 n 的剩余值? - Kosmoz
@Kosmoz 简单地使用 fact.append(n) - interjay

-1

这个带有驱动程序的函数

def factors(n):
  global tmp
  answ=[]
  tmp=(n)
  addends=[4,2,4,2,4,6,2,6]
  def divn(dvr):
     
    
    global tmp
    while tmp%(dvr)==0:
      answ.append(dvr)
      tmp=tmp//dvr
       
  divn(2)
  divn(3)
  divn(5)
  d=(7)
  while (d)*(d)<=tmp:
     
    for i in range(8):
      divn(d)
      d=d+(addends[i])
  if tmp>1:
    answ.append(tmp)    
  return answ    
     
print(factors(23756965471926357236576238546))  

在4秒内找到了

[2, 3, 3, 479, 11423, 582677, 413975744296733]

它通过在测试这三个质数后跳过2、3和5的倍数来实现。在测试完这三个数之后,它只需要测试每30个数字中的8个,从7开始,按照给定的加数列表中的加数循环添加到先前测试过的数字上。这样可以减少用作测试的非质数的数量。(30是235,因此这构成了这些数的倍数的循环)。

每个尝试的数字都会尝试多次,直到剩余的数字不再能被它整除。

它使用一个函数内部的函数来进行实际的除法尝试。


1
目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community
我已经查看了说明并找到了如何将代码与描述分开的方法。与以前一样,我试图使主程序清晰明了,它是一个驱动程序,用于展示函数的工作原理,并且可以将一个需要分解的数字与之前发布的答案中花费28秒相比较,而在当前程序中只需4秒钟。我还添加了一些相关的理论知识。 - Charles kluepfel

-1
使用递归调用的示例:
def factoring(x, print_eq=True):
    factors = []
    if x == 2:
        factors += [x]
    for i in range(2,x):
        if i*i > x:
            factors += [x]
            break
        if x%i == 0:
            factors += [i]
            factors += factoring(x//i, False)
            break
    # Factorization has been completed.
    # Print the result in pretty mode
    if print_eq:
        if x in factors:
            print(f'{x} = 1 * {x} is a prime')
        else:
            eq = ''
            nf = {i : factors.count(i) for i in factors}
            fs = list(sorted(nf))
            for i, f in enumerate(fs):
                if nf[f] > 1:
                    eq += f'{f}^{nf[f]}'
                else:
                    eq += f'{f}'
                if i < len(fs) - 1:
                    eq += ' * '
            print(f'{x} = {eq}\n')
    return factors

一些例子:
对23756965471926357236576238546进行因式分解得到:
23756965471926357236576238546 = 2 * 3^2 * 479 * 11423 * 582677 * 413975744296733
[2, 3, 3, 479, 11423, 582677, 413975744296733]
对1024进行因式分解得到:
1024 = 2^10
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
对137进行因式分解得到:
137 = 1 * 137 是一个质数
[137]

-4

如果你只是想找到最小的因子(比如在素数测试中),那么你只需要去到floor(sqrt(n))层。如果你想要所有的因子,那么你应该从0到n/2进行检查。

简而言之:

素性测试:

n = int(input('Please input a number: ')
sn = int(sqrt(n))
for x in range(2,sn+1):
    if n%x == 0:
        print('Not prime. Divisible by: '+str(x))
print(str(n)+' is prime')

分解:

n = int(input('Please input a number: ')
n2 = int(n/2)
fn = []
for x in range(2,n2+1):
    if n%x == 0:
        fn.append(x) #lower member of factor pair
        fn.append(n/x) #upper member of factor pair
print('N has the following factors: '+str(fn))

希望这能帮助你理解。


1
OP正在进行质因数分解。你的代码打印出了所有数字的因子(质数或非质数),这与质因数分解是不同的。 - interjay
正如interjay所说,那不是我真正想要的:/ 但你教会了我一些东西,所以谢谢!:) - Kosmoz
1
OP的代码输出了一个质因数分解。而“factorization”并不意味着打印出一个数字的所有因子,它意味着将一个合数转化为独立数字的乘积,所以你的代码不是质因数分解。我期待着您在另外两年内回复此评论。 - interjay
1
我刚刚注意到OP本人在上面的评论中同意了我的观点,所以你声称OP的愿望不同是相当奇怪的。 - interjay
正如你引用的那样,“整数分解是将一个合数分解为较小整数的乘积。”没错,它们在技术上不一定是质数(尽管通常被默认为是质数,这也是提问者的代码所做的)。例如,24可以被分解为2和12,或者3和8,或者4和6等等。然而,你的代码列出了所有的因子,在这种情况下是2、3、4、6、8和12,而不仅仅是一组相乘得到所讨论的数字的因子。更不用说它将它们都列了两次。这既不是提问者的意图,也不是技术上的正确答案。 - undefined
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接