【问题标题】:Sieve of Eratosthenes using precalculated primes使用预先计算的素数进行埃拉托色尼筛法
【发布时间】:2013-12-24 14:45:10
【问题描述】:

我有所有可以存储在 32 位 unsigned int 中的素数,并且我想用它们来生成一些 64 位素数。即使在逻辑和编译方面进行了优化,使用试除法也太慢了。

我正在尝试修改埃拉托色尼筛法以使用预定义列表,如下所示:

  1. 在数组 A 中,从 2 到 4294967291
  2. 在数组 B 中从 2^32 到 X 增加 1
  3. 找到当前素数的第一个倍数的 C。
  4. 从 C 标记并按当前素数跳转到 X。
  5. 转到 1。

问题是步骤 3 使用模数来找到素数倍数,这样的操作是我没有使用轨迹除法的原因。

有没有更好的方法来实现第 3 步或整个算法。

谢谢。

【问题讨论】:

  • 你需要多少个素数?
  • 0xFFFFFFFFFF 的所有素数,我想计算它们。
  • 3 给我的印象是每个素数的 O(1),而 4 给我的感觉更像是每个素数的 O(X),你能详细说明为什么你认为 3 是个问题吗?
  • 0xFFFFFFFFFF 只有 40 位。这比 64 位要少得多。
  • 3 只需要固定时间。如果你的上限是 0xFFFFFFFFFF,你只需要在 seive 中小于 0xFFFFF 的素数。

标签: c++ algorithm primes sieve-of-eratosthenes


【解决方案1】:

增加 2,而不是 1。这是您应该始终使用的最小优化 - 仅适用于赔率。无需为事件而烦恼。

在 C++ 中,使用 vector<bool> 作为筛子数组。它会自动打包。

使用分段筛预先计算您的核心素数。然后继续按适合缓存的足够大的段工作,而不向核心列表添加新的素数。对于每个素数p,维护额外的long long int value:它的当前倍数(当然,从素数的平方开始)。步长值是 两倍 p 值,或 p 在奇数填充筛数组中的偏移量,其中 i -th 条目代表数字 o + 2io 是不低于范围开始的最小奇数。不用按倍数排序,核心素数使用上限单调递增。

sqrt(0xFFFFFFFFFF) = 1048576PrimePi(1048576)=82025 primes 是您的核心素数列表中所需的全部。那是花生。

当您第一次开始(或继续工作)时,long long ints 的整数运算应该可以很好地找到模数以及范围内的最小倍数。

另请参阅相关的answer with pseudocodeanother with C code

【讨论】:

  • 这个算法是否需要修改才能找到所有 64 位素数?
  • 只是更多的空间和时间。显然,更多的核心素数。 2^32 以下有 N 个素数,N = 203,280,221。那一定更难。 :)
  • 8 字节 long long 每个整数(4 字节)素数倍数,12*204 mil = 2.5 GB 内存。你有 8 个。所以,慢慢地,这应该可以逐段(~ 100K)。 :) 随时将它们写到文件中。
  • 顺便说一句,如果您筛选到 2^64,最好不要一次预先计算所有核心素数,而是随时添加它们。这将只是一个普通的分段筛子。对于内存连续性,为了存储核心素数的信息,我将使用块索引数组long long arr[10,000,000](x12,以字节为单位)左右。见HAT。无需调整块的大小,只需从一开始就预先分配索引数组,并跟踪其中有多少已满。阅读文章,你会明白我的意思。干杯。
  • 所有 质数筛分到 2^64 需要大量的机器时间:使用最好的最大轮式分解的 Eratosthenes 筛,大约是 8 X 10^18复合剔除操作;即使在每次剔除大约 2.5 个 CPU 时钟的“primesieve”速度下,也需要大约 180 个核心年才能完成。即使多处理在这里也无济于事,除非一个人可以使用超级计算机并被分配一天左右使用十万个内核。至于将所有结果存储在硬盘上,即使使用质数间隙进行压缩也意味着大约 200,000 TB! 也许一个子范围可以吗?
猜你喜欢
  • 1970-01-01
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
相关资源
最近更新 更多