Atkin的分段筛可能吗?

时间:2012-05-03 10:43:00

标签: algorithm sieve-of-eratosthenes sieve sieve-of-atkin

我知道可以实施Eratosthenes的筛子,以便在没有上限(分段筛)的情况下连续找到质数。

我的问题是,阿特金/伯恩斯坦的筛子能否以同样的方式实施?

相关问题:C#: How to make Sieve of Atkin incremental

然而,相关问题只有一个答案,即“所有筛子都不可能”,这显然是不正确的。

2 个答案:

答案 0 :(得分:4)

Atkin / Bernstein在其original paper的第5部分中给出了分段版本。据推测,伯恩斯坦的primegen程序使用了这种方法。

答案 1 :(得分:2)

事实上,我可以实现一个无限制的Atkin(SoA)Sieve,而不是像我一样here in F#。请注意,这是一个纯函数版本,甚至不使用数组来组合二次方程和无广场滤波器的解,因此比更强制的方法要慢得多。

Berstein使用查找表进行优化以获得最佳的32位范围会使代码变得非常复杂并且不适合在此处进行显示,但是很容易调整我的F#代码以便序列从a开始设置下限并且仅在一个范围内使用,以便实现分段版本,和/或将相同的技术应用于使用数组的更必要的方法。

请注意,即使是Berstein的SoA实施也不比Eratosthenes的Sieve快得多,并且根据Kim Walisch's primesieve进行了所有可能的优化,但仅比等效优化的版本更快根据他的实施,Eratosthenes Sieve选择的数字范围

EDIT_ADD:对于那些不想涉及B​​erstein的伪代码和C代码的人,我在这个答案中添加一个伪代码方法来使用SoA在从低到高的范围内,从低到高+ 1的增量可能被约束到偶数模60,以便使用模(以及仅对2,3,5轮上的条目的潜在位填充)优化。

这是基于使用(4 * x ^ 2 + y ^),(3 * x ^ 2 + y ^ 2)和(3 * x ^ 2 -y ^ 2)的SoA样方的可能实现表示为数字序列,每个序列的x值固定为1和SQRT((HIGH - 1)/ 4),SQRT((HIGH - 1)/ 3)之间的值,并求解2 * x的二次曲线对于x =(SQRT(1 + 2 *(HIGH + 1)) - 1)/ 2,^ 2 + 2 * x - HIGH - 1 = 0,其中序列以我的F#代码表示为顶部链接。对于序列的优化使用的是,当仅筛选奇数复合材料时,对于" 4x"序列,y值只需要是奇数,并且" 3x"当x是偶数时,序列只需要使用y的奇数值,反之亦然。进一步的优化通过观察上述序列上的模数模式在非常小的x范围内重复并且在y的范围内重复仅为30来减少二次方程(=序列中的元素)的解的数量,这用于Berstein代码但尚未在我的F#代码中实现。

我也没有包括可以应用于素数"免费广场的众所周知的优化"剔除使用车轮分解和我在my implementations of a segmented SoE中使用的起始段地址的计算。

因此,为了计算" 4x"," 3x +"和" 3x - "的序列起始段地址。 (或者使用" 3x +"和" 3x - "像我在F#代码中那样组合),并根据上面计算了每个x的范围,伪-code如下:

  1. 计算范围LOW - FIRST_ELEMENT,其中FIRST_ELEMENT为x的每个给定值的最低适用值y或y = x - 1,对于" 3x - "序列

  2. 对于计算此范围内有多少元素的工作,这归结为(y1)^ 2 +(y2)^ 2 +(y3)^ 2 ...中有多少元素的问题是每个y数被2分开的地方,根据需要产生偶数或奇数的y。像在正方形序列分析中一样,我们观察到正方形之间的差异具有恒定的增量增量,因为delta(9 - 1)是8,delta(25 - 9)是16,增加8,delta(49 - 25)是24进一步增加8,等等。因此,对于n个元素,此示例的最后一个增量为8 * n。使用这个表达元素序列,我们得到它是一个(或者任何人选择作为第一个元素)加上八倍于(1 + 2 + 3 + ... + n)的序列。现在,当该和为(n + 1)* n / 2或n ^ 2/2 + n / 2时,线性序列的标准减少适用。通过求解二次方程n ^ 2/2 + n / 2 - range = 0或n =(SQRT(8 * range + 1)-1)/ 2,我们可以求解该范围内有多少n个元素。

  3. 现在,如果FIRST_ELEMENT + 4 *(n + 1)* n不等于LOW作为起始地址,则将n加1并使用FIRST_ELEMENT + 4 *(n + 2)*(n + 1)作为起始地址。如果使用进一步的优化将轮分解剔除应用于序列模式,则可以使用查找表数组来查找满足条件的已使用n的最接近值。

  4. 起始元素的模数12或60可以直接计算,也可以通过使用基于模数序列的重复性质的查找表来生成。

  5. 然后使用每个序列将复合状态切换到HIGH限制。如果将附加逻辑添加到序列中以仅在每个序列的适用元素之间跳转值,则不需要进一步使用模数条件。

  6. 以上是每个" 4x"序列后跟" 3x +"和" 3x - "序列(或将#34; 3x +"和#34; 3x - "组合成一组" 3x"序列),直到前面计算的x限制或按循环测试。

  7. 并且你有它:给定一个适当的方法将筛分范围划分成段,最好用作与CPU缓存大小相关的固定大小以获得最佳内存访问效率,一种分割SoA的方法就像伯恩斯坦使用但在表达方面稍微简单一些,但没有结合模运算和位打包。