迭代数字< n,确定每个数字的素数因子分解

时间:2017-01-21 19:52:36

标签: python algorithm iteration prime-factoring

我想遍历每个数字< N,并且知道每个数字素数因子分解。我的问题是,最好的方法是什么?

我知道我可以使用试验分割方法找到给定数字的素数因子分解,并且只对每个小于N的数字重复该数,但这样做效率低,并且比从数字生成每个数字需要更长的时间。已知的素因子。我已经编写了一个实现,生成每个小于N的数字,来自所有小于N的素因子。有更快的方法吗?我试图使用这样一个事实,因为我为所有小于N的数字做这个以节省计算时间,而不是做试验分割方法。

我想要实现的目标: 我有一个算法,我想在每个小于N的数字上运行。对于这个算法,我需要每个数字的素数因子分解。我试图在最短的时间内得到每个数字的素数因子分解。我实际上并不需要存储主要的因子分解,我只需要使用素数分解来运行我的算法。 (该算法在代码中解决(curNum,curFactors))

我编写了一个python3程序,以递归方式生成每个数字,并了解其主要因素,但速度非常慢。 (当N = 10 ^ 7时,处理时间需要大约58秒。函数求解对此基准没有任何作用。)

curFactors是一个列表,其中每个偶数元素都是分解中素数的索引,每个奇数元素都是素数指数。我从列表列表中将其展平以节省计算时间。主起始索引用于确保我不会重复计算数字。目前Solve什么都不做,所以我可以对这个功能进行基准测试。

def iterateThroughNumbersKnowingFactors(curNumber, curFactors, primeStartIndex):
    #Generate next set of numbers
    #Handle multiplying by a prime already in the factorization seperately.
    for i in range(primeStartIndex+1,lenPrimes):
        newNum = curNumber * primelist[i]
        if(newNum > upperbound):
            break
        newFactors = curFactors[:]
        newFactors.append(i)
        newFactors.append(1)
        #Do something with this number and its factors
        solve(newNum, newFactors)
        #Go get more numbers
        iterateThroughNumbersKnowingFactors(newNum,newFactors,i)
    if(primeStartIndex > -1):
        newNum = curNumber * primelist[primeStartIndex]
        if(newNum > upperbound):
            return
        currentNumPrimes = len(curFactors)
        curFactors[currentNumPrimes-1] += 1
        #Do something with this number and its factors
        solve(newNum, curFactors)
        #Go get more numbers
        iterateThroughNumbersKnowingFactors(newNum,curFactors,primeStartIndex)

upperbound = 10**7

#https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n
primelist = primesfrom2to(upperbound+1)
lenPrimes = len(primelist)

t0 = time.clock()
iterateThroughNumbersKnowingFactors(1,[],-1)
print(str(time.clock() - t0) +" seconds process time")

有谁知道更好的方法吗?

3 个答案:

答案 0 :(得分:4)

如果您已经实施了Eratosthenes的Sieve并且其性能可以接受,那么您可以对其进行修改以存储素因子。

基本方法是这样的:每当你想要"交叉"一个数字或从列表中删除它作为素数的倍数,而是检查你可以将它除以素数而没有余数的次数(使用/%)。这将为您提供一个(素数,指数)对,表示素数因子分解的组成部分。将这些对存储在与原始编号关联的列表或词典中。当Sieve完成时,每个列表将描述相应数字的素数因子化。

答案 1 :(得分:1)

如果您想找点乐子,可以使用 Bach's algorithm[1,N] 时间内在区间 O(log(N)) 中生成一个随机数。重复此操作直到找到所有小于 N 的数的质因数分解理论上可能需要无限的时间,但该算法的预期运行时间将为 O(log^2(n))

这在效率方面可能有点损失,但如果您想要一个不以线性顺序迭代的有趣算法,那么这可能是您最好的选择:)

答案 2 :(得分:1)

利用埃拉托色尼筛法的一些灵感,您可以通过将质数传播到最多 N 的质因数列表来构建因数列表:

只知道存在哪些素数:

def primeFactors(N):
    result = [[] for _ in range(N+1)]  # lists of factors from 0..N
    for p in range(1,N+1,2):
        if p<2: p=2 
        if result[p]: continue         # empty list is a prime 
        for k in range(p,len(result),p):
                result[k].append(p)    # propagate it to all multiples
    return result

print(*enumerate(primeFactors(10)))
# (0, []) (1, []) (2, [2]) (3, [3]) (4, [2]) (5, [5]) (6, [2, 3]) (7, [7]) (8, [2]) (9, [3]) (10, [2, 5])

要获得因式分解中每个素数的每个实例:

def primeFactorsAll(N):
    result = [[] for _ in range(N+1)]
    for p in range(1,N+1,2):
        if p<2: p=2
        if result[p]: continue
        pn = p
        while pn < N:
            for k in range(pn,len(result),pn): # propagate to multiples of
                result[k].append(p)            # each power of p
            pn *= p
    return result

print(*enumerate(primeFactorsAll(10)))
# (0, []) (1, []) (2, [2]) (3, [3]) (4, [2, 2]) (5, [5]) (6, [2, 3]) (7, [7]) (8, [2, 2, 2]) (9, [3, 3]) (10, [2, 5])

对于大 N,这应该比除法方法运行得快得多。 对于 N= 10^7,在我的笔记本电脑上,primeFactors(N) 需要 8.1 秒,primeFactorsAll(N) 需要 9.7 秒。