Python : 素数

Python : Primes in numbers

给定一个正数 n > 1 求 n 的质因数分解。结果将是具有以下形式的字符串:

"(p1**n1)(p2**n2)...(pk**nk)"

p(i) 递增,如果 n(i) 为 1,则 n(i) 为空。

示例:n = 86240 应该 return "(2**5)(5)(7**2)(11)"

这是我的代码,但我对 n>250000

的时间有疑问
def primeFactors(n):
    a=""
    i=2
    while i<=n:
        #part of identifying if number i is prime
        w1=5
        w2=2
        gg=0
        while w1*w1<=i:
            if i%w1==0:
                gg=1
                break
            w1+=w2
            w2=6-w2
        #checking if previous loop has been broken
         if gg:
            i+=1
            continue
        #countig how many thimes we can divide n on i
        c=0
        for j in range(1,n):
            if n%i!=0: break
            c+=1
            n=n//i
        #if we can divide n on i only once
        if c==1:
            a+="("+str(i)+")"
        elif c>1:
            a+="("+str(i)+"**"+str(c)+")"
        i+=1
    return a

有办法解决这个问题吗?

问题不在于程序所做的质因数分解,而是 Python 在非常短的时间内对非常大的数字进行分解。具体来说,我的理解是我们需要能够计算:

for n in range(10 ** 9, 10 ** 9 + 10):
    print(n, '=', primeFactors(n))

in <= 120ms 或更少,即每个数字 <= 12ms。在毫秒变成秒、秒变成分钟之前,OP 的代码不会超过 10 ** 9 + 4。我对您的代码的第一印象是您需要将主要逻辑与其余代码分开,使其易于理解,然后清理和优化代码的这两部分。我重写了你的程序:

def generate_primes(n):

    """ generate real primes """

    yield(2)

    primes = [(2, 4)]

    for m in range(3, n, 2):

        for prime, square in primes:

            if square > m:
                yield(m)
                primes.append((m, m * m))
                break

            if m % prime == 0:
                break

def primeFactors(n):
    string = ""
    i = 2

    for i in generate_primes(int(n ** 0.5) + 1):

        # counting how many times we can divide n on i
        c = 0

        while True:
            product, remainder = divmod(n, i)

            if remainder != 0:
                break

            n = product
            c += 1

        # if we can divide n on i only once
        if c == 1:
            string += f"({i})"
        elif c > 1:
            string += f"({i}**{c})"

    if n > 1:  # final prime factor greater than square root
        string += f"({n})"

    return string

我换了一个质数生成器以避免冗余计算。在上述测试中,此优化版本可以实现每个大数分解 32 毫秒。还是不够好。所以让我们试试@JamesKPolk 的建议并使用伪素数:

def generate_primes(n):

    """ generate 5-rough pseudoprimes """

    if n >= 2:
        yield(2)

    if n >= 3:
        yield(3)

    if n >= 5:
        m = 1
        x = 4

        while m < n:
            m += x
            yield(m)
            x = 6 - x

这里的权衡是我们将测试比实际需要更多的除数,但我们可以更快地生成这些除数。无论如何,在我的机器上,此更改实现了我们的目标,即 <= 12ms 每个大数因式分解。

输出

> time python3 test.py
1000000000 = (2**9)(5**9)
1000000001 = (7)(11)(13)(19)(52579)
1000000002 = (2)(3)(43)(983)(3943)
1000000003 = (23)(307)(141623)
1000000004 = (2**2)(41**2)(148721)
1000000005 = (3)(5)(66666667)
1000000006 = (2)(500000003)
1000000007 = (1000000007)
1000000008 = (2**3)(3**2)(7)(109**2)(167)
1000000009 = (1000000009)
0.106u 0.010s 0:00.11 100.0%    0+0k 0+0io 0pf+0w
>