当前位置: 首页 > 知识库问答 >
问题:

为什么我的埃拉托色尼筛运行得这么慢?

彭正谊
2023-03-14

我正在为厄拉多塞的筛子用Python写一个素数程序。虽然看起来很管用,但是很慢。我该如何加快速度呢?

primes = []
upperLimit = 1000

for x in range(2,upperLimit):
  primes.append(x)
for y in range(0,int(len(primes)**0.5)):
  remove = []
  for j in range(primes[y]**2,upperLimit,primes[y]):
    remove.append(j)
  for i in remove:
    if i in primes:
      primes.remove(i)

print(primes)

更新:由于答案的帮助,我用布尔值而不是数字重写了代码。低于100000的列表现在运行时间不到6秒。

i = 2
limit = 100000
primes = [True] * limit
primes[0] = False
while i < limit**0.5:
    if primes[i-1]:
        for x in range(i * 2, limit + 1,i):
            primes[x-1] = False
    i += 1
count = 1
total = []
for i in primes:
    if i:
        total.append(count)
    count += 1
print(total)

共有2个答案

仉宪
2023-03-14

它很慢,因为有许多操作你做得比需要的多得多。合数N的寿命看起来像这样:

    < li >向素数追加N < li >对于每个小数字I(
  • 如果我还在素数中,请将其删除。

每个数字都有很多“接触”。这也是许多需要考虑的小数字。

相反,请尝试以下操作:

  • 列出布尔值(全部为 True),每个潜在素数对应一个布尔值。
  • 而最低值我标记为 True

在这一点上,你的质数正是那些仍然标记为真的值

阳德润
2023-03-14

我认为,代码中的主要低效是您维护的素数的列表。尽管调用primes可能并不明显。删除是一个非常昂贵的操作。它需要遍历列表以尝试找到要删除的值,然后需要通过将所有元素移动到您要查找的元素之后来修改list

例如。

l = [0, 1, 2, 3, 4]
l.remove(5)  # This has to look at all the elements in l, since 6 isn't there
l.remove(0)  # This finds 1 quickly but then has to move every element to the left

对于埃拉托斯特尼筛子,一种更传统的方法是使用一个数组(Python中的列表),其中包含您正在考虑的所有数字,其中每个元素都是一个布尔值,指示该数字是否可以是素数。

模仿上面的例子:

l = [True, True, True, True, True]
l[0] = False  # Just goes straight to that element and changes its value

下面是如何编写该代码的示例:

primes = [True] * 100000

# We already know 2 is the first prime
primes[0] = False
primes[1] = False

# Fine to stop at sqrt(len(primes)) here as you're already doing    
for i in range(2, len(primes)):
    if primes[i]:
        for j in range(i**2, len(primes), i):
            primes[j] = False

print([n for n, is_prime in enumerate(primes) if is_prime])

您会发现这要快得多,因为索引到列表并以这种方式更改值非常有效。

 类似资料:
  • 我正在尝试解决spoj上的Prime Path问题,我正在尝试理解在github上找到的解决方案。解决这个问题的广义逻辑是生成所有四位数素数,并添加一个边,如果我们可以通过更改一个数字从一个素数转到下一个素值。我找到的这个解决方案使用筛子来生成所有素数。与此解决方案中的筛分功能相比,维基上的稀土筛分功能有所不同。只需要帮助了解以下代码中筛分函数的变化: 这里的筛选函数计算是什么?我无法理解为什么作

  • 我正在尝试对厄拉多塞的筛子进行并行实现。我做了一个布尔列表,对于给定的大小,用true填充。无论何时发现一个素数,该素数的所有倍数在布尔列表中都被标记为假。 我试图使这个算法并行的方法是在仍然过滤初始质数的同时启动一个新线程。例如,算法从素数 = 2 开始。在 for 循环中,当素数 * 素数时,我做另一个 for 循环,其中检查素数 (2) 和素数 * 素数 (4) 之间的每个数字。如果布尔列表

  • 就像这个问题一样,我也在厄拉多塞的筛子上工作。同样来自《c语言编程原理和实践》一书的第4章。我能够正确地实现它,并且它的功能完全符合练习的要求。 现在,我怎样才能在输入的中处理真正的大数字?类型应该允许我输入2^32=4,294,967,296的数字。但是我不能,我运行内存溢出。是的,我已经计算过了:存储2^32量的int,每个32位。所以32/8*2^32=16 GiB的内存。我只有4 GiB…

  • 我试图找到素数使用厄拉多塞筛位数组,但我使用的是无符号整数数组。我需要能够产生多达2,147,483,647个素数。我的代码工作正常,可以生成大约10,000,000个,但是当我增加数组的大小以容纳更大的数字时,它失败了。有人能指导我如何用c语言(不是c语言)使用位向量吗?谢谢 这是我的代码:

  • 我正在尝试让我的埃拉托斯特尼筛程序仅输出用户请求的前n个素数。Sieve本身工作得很好 - 它正确地输出了前100个素数(如下面的数组所示),但是最后一个循环中的计数器变量无法正常工作,我无法找出原因。例如,如果用户输入“5”表示 n,则只会打印前 3 个定焦值。 有人可以帮我找出我的错误吗?我的目的是让“count”成为一个非常简单的计数器,每次都会增加1,直到它达到n。

  • 我遇到了一个分割的埃拉托斯特尼筛子的实现,它promise比传统版本运行快很多倍。有人可以解释一下分段如何改善运行时间吗?请注意,我想在 [1,b] 中找到素数。 它的原理是:(用于查找10^9之前的素数) > 我们首先生成低于 sqrt(10^9) 的筛分素数,这是偶联倍数所必需的。然后我们开始划掉第一个素数2的倍数,直到我们达到2的倍数 为了筛选下一个段,我们重置了筛选数组,并通过segmen