【问题标题】:Iterating through numbers < n, determining each number's prime factorization遍历数字 < n,确定每个数字的素数分解
【发布时间】:2017-06-06 15:09:38
【问题描述】:

我想遍历每个

我知道我可以使用试除法来找到给定数字的素因数分解,然后对每个小于 N 的数字重复该方法,但这效率低下,并且比从已知的主要因素。我在下面编写了一个实现,从所有小于 N 的素数中生成小于 N 的每个数字。有没有更快的方法来做到这一点?我试图利用这样一个事实,因为我对所有小于 N 的数字都这样做以节省计算时间,而不是使用试除法。

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

我编写了一个 python3 程序来递归地生成每个知道其素因数的数字,但它非常慢。 (当 N = 10^7 时,处理时间约为 58 秒。函数 solve 对此基准没有任何作用。)

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")

有人知道更好的方法吗?

【问题讨论】:

  • 你能更清楚地解释你到底想要完成什么吗?您想生成一个整数列表列表,其中包含该列表索引值的素数分解,直到某个限制?
  • 我很抱歉不清楚。我有一个算法,我想对每个小于 N 的数字运行。对于这个算法,我需要每个数字的素数分解。我的问题是获得小于 N 的每个数字的素数分解的最快方法是什么。我实际上不需要将素数分解存储在内存中,我只需要使用素数分解运行算法。
  • 所以,例如:primes = []; for i in range(upper_bound): primes.append(prime_factorization(i)) 本质上就是你想要做的事情?那么,您正在寻找优化的素数分解 Python 实现吗?
  • 是的!我正在尝试寻找一种更优化的方法来做到这一点。任何语言的答案都很棒,我可以将其转换为 Python。我实际上不知道比我正在做的更优化的方法。

标签: python algorithm iteration prime-factoring


【解决方案1】:

从 Eratosthenes 的筛子中汲取灵感,您可以通过将素数传播到最多为 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 秒。

【讨论】:

    【解决方案2】:

    如果你想玩得开心一点,你可以使用Bach's algorithmO(log(N))时间间隔[1,N]生成一个随机数。重复此操作,直到找到所有小于 N 的数的素数分解,理论上可能需要无限时间,但该算法的预期运行时间为 O(log^2(n))

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

    【讨论】:

      【解决方案3】:

      如果您已经实施了埃拉托色尼筛法并且其性能可以接受,那么您可以对其进行修改以存储素因子。

      基本方法是这样的:每当您将“划掉”一个数字或将其从列表中删除为素数的倍数时,请检查您可以将其除以素数多少次而没有余数(使用@987654321 @ 和 %)。这将为您提供一个(素数,指数)对,表示素数分解的该分量。将这些对存储在与原始号码关联的列表或字典中。当 Sieve 完成时,每个列表将描述相应数字的素因数分解。

      【讨论】:

      • 我的错误,感谢您指出这一点。我已经编辑了答案以更正它。我认为我描述的方法需要粗心的 N log N 实现。
      • 不需要分割;迭代筛子内部循环中的两个变量。一个加素数,另一个加一。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      相关资源
      最近更新 更多