【发布时间】:2014-12-26 17:49:54
【问题描述】:
Eratosthenes 的标准筛子多次删除了大多数复合材料;事实上,唯一不会被多次标记的是那些恰好是两个素数的乘积。自然,随着筛子变大,透支也会增加。
对于奇数筛(即没有偶数),透支达到 100%,n = 3,509,227,有 1,503,868 个复合数和 1,503,868 个已划掉数字的划线。对于 n = 2^32,透支上升到 134.25%(透支 2,610,022,328 与弹出计数 1,944,203,427 = (2^32 / 2) - 203,280,221)。
Sieve of Sundaram - 在maths.org 有另一种解释 - 可能会更聪明一点,如果 - 且仅当 - 智能计算循环限制。然而,我所看到的消息来源似乎掩盖了这一点“优化”,而且似乎未优化的 Sundaram 每次都会被只有赔率的 Eratosthenes 击败。
有趣的是,两者都创建了完全相同的最终位图,即位 k 对应于数字 (2 * k + 1) 的位图。所以两种算法最终都必须设置完全相同的位,它们只是有不同的处理方式。
有人亲身体验过具有竞争力的、经过调整的 Sundaram 吗?能打败古希腊吗?
我已经精简了我的小因子筛子的代码(2^32,一个只有赔率的希腊语),并将片段大小调整为 256 KB,这对于具有 256 KB L2 的旧 Nehalem 和新版 Nehalem 来说是最佳的CPU(即使后者对更大的段更宽容)。但是现在我撞到了一堵砖墙,血筛仍然需要 8.5 秒来初始化。从硬盘加载筛子不是一个很有吸引力的选择,而且多线程很难以可移植的方式进行(因为像 boost 这样的库往往会给可移植性带来麻烦)......
Sundaram 能否将启动时间缩短几秒钟?
P.S.:透支本身不是问题,会被 L2 缓存吸收。关键是标准的埃拉托色尼似乎比必要的工作量增加了一倍以上,这表明可能有可能做的工作更少,速度更快。
【问题讨论】:
-
@Teepeemm:任何两个素数的乘积都被 Eratosthenes 划掉一次,取两个因子中的较低值。较高因子的循环从它自己的平方开始,从而避免了自身的较低倍数(它必须已经被划掉了)。
-
@Sam Harwell:小素数的阿特金有多快(最多 2^32,用于初始化小因子筛)?我听说阿特金在小质数方面不是很有竞争力。
-
@Redu:Sundaram 的筛子严格来说比 Eratosthenes 的仅赔率筛子更糟糕。标准形式的 SoS 使用乘法来计算要交叉的单元格的索引,而不是像 SoE 中的加法跨步。第二个缺陷是 SoS 未能跳过外循环中的非素数(导致多个非素数的额外冗余交叉)。如果您修复了这两个缺陷(请参阅我的回答中的分步说明),那么剩下的就是一个只有赔率的 SoE,再次证实了一个古老的俏皮话,即 SoE 对其大多数继任者都有很大的改进。 ;-)
-
感谢您的回复。我相信我已经通过为第二个循环设置动态限制来消除非素数的冗余(多个)交叉,并且第一个循环运行到只有它需要的地方。我将在今天晚些时候的回答中解释循环的限制。 SoS 通过将剩余数字乘以 2n+2 来自动处理仅赔率问题,以获得最终的素数列表。所以我希望它与从该算法中得到的速度一样快。
-
@Redu:请在 Code Review 上发布代码,然后在新评论中将其链接到此处 - 这样您就可以从 JavaScript 专家的经验中获益(我绝对不是)。 JavaScript 与(最终)编译为机器代码的通常的命令式语言完全不同,它通常需要完全不同的方法才能真正让它唱歌......不过,有理由认为 SoA 不能比 SoE 更快如果以同样的谨慎实施,因为它基本上是相同的,只是它进行了更多的交叉迭代(因此总共有更多的交叉)。
标签: primes sieve-of-eratosthenes sieve