- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图通过避免删除重复的素数倍数来改进基本的埃拉托色尼筛法算法,但结果比我的预期更糟
我已经实现了两个返回范围 [2..max) 内的素数的方法
public static List<int> Sieve22Max_Basic(int n) {
var primes = new List<int>();
var sieve = new BitArray(n, true); // default all number are prime
//int crossTotal = 0;
int sqrt_n = (int)Math.Sqrt(n) + 1;
for (int p = 2; p < sqrt_n; ++p) {
if (sieve[p]) {
primes.Add(p);
//var cross = new List<int>();
int inc = p == 2 ? p : 2 * p;
for (int mul = p * p; mul < n; mul += inc) {
// cross out multiple of prime p
// cross.Add(mul);
//++crossTotal;
sieve[mul] = false;
}
//if (cross.Count > 0)
// Console.WriteLine($"Prime {p}, cross out: {string.Join(' ', cross)}");
}
}
//Console.WriteLine($"crossTotal: {crossTotal:n0}");
for (int p = sqrt_n; p < n; ++p)
if (sieve[p])
primes.Add(p);
return primes;
}
运行 Sieve22Max_Basic(100)
,看到一些倍数超过一个(例如:45, 75, 63
)
Prime 2, cross out: 4 6 8 ... 96 98
Prime 3, cross out: 9 15 21 27 33 39 45 51 57 63 69 75 81 87 93 99
Prime 5, cross out: 25 35 45 55 65 75 85 95
Prime 7, cross out: 49 63 77 91
然后,我尝试通过使用存储 smallest prime divisor
的数组来改进( spd
) 每个数字。
45 = 3 x 5 // spd[45] = 3
75 = 3 x 5 x 5 // spd[75] = 3
63 = 3 x 3 x 7 // spd[63] = 3
当遍历素数 p 的倍数时,我不会划掉数字 mul
有 spd[mul] < p
因为mul
被spd[mul]
划掉了之前
public static List<int> Sieve22Max_Enh(int n) {
var sieve = new BitArray(n, true);
var spd = new int[n];
for (int i = 0; i < n; ++i) spd[i] = i;
var primes = new List<int>();
//int crossTotal = 0;
int sqrt_n = (int)Math.Sqrt(n) + 1;
for (int p = 2; p < sqrt_n; ++p) {
if (sieve[p]) {
primes.Add(p);
//var cross = new List<int>();
int inc = p == 2 ? 1 : 2;
for (long mul = p; mul * p < n; mul += inc) {
if (spd[mul] >= p) {
sieve[(int)(mul * p)] = false;
spd[mul * p] = p;
//++crossTotal;
//cross.Add((int)(mul * p));
}
}
//if (cross.Count > 0)
// Console.WriteLine($"Prime {p}, cross out: {string.Join(' ', cross)}");
}
}
//Console.WriteLine($"crossTotal: {crossTotal:n0}");
for (int p = sqrt_n; p < n; ++p)
if (sieve[p])
primes.Add(p);
return primes;
}
我在笔记本电脑(核心 i7 - 2.6 Ghz)上进行测试,n = 10 亿
Sieve22Max_Basic
Sieve22Max_Enh
仅需 6 秒需要超过 10 秒才能完成
var timer = new Stopwatch();
int n = 1_000_000_000;
timer.Restart();
Console.WriteLine("==== Sieve22Max_Basic ===");
var list = Sieve22Max_Basic(n);
Console.WriteLine($"Count: {list.Count:n0}, Last: {list[list.Count - 1]:n0}, elapsed: {timer.Elapsed}");
Console.WriteLine();
timer.Restart();
Console.WriteLine("==== Sieve22Max_Enh ===");
list = Sieve22Max_Enh(n);
Console.WriteLine($"Count: {list.Count:n0}, Last: {list[list.Count - 1]:n0}, elapsed: {timer.Elapsed}");
您可以尝试 https://onlinegdb.com/tWfMuDDK0
为什么会变慢?
最佳答案
比较原始版本和改进版本的两个循环。
原文:
int inc = p == 2 ? p : 2 * p;
for (int mul = p * p; mul < n; mul += inc) {
sieve[mul] = false;
}
改进:
int inc = p == 2 ? 1 : 2;
for (long mul = p; mul * p < n; mul += inc) {
if (spd[mul] >= p) {
sieve[(int)(mul * p)] = false;
spd[mul * p] = p;
}
}
一些观察:
BitArray
中的值, mul += inc
并检查 mul < n
.spd[mul] >= p
, mul += inc
, mul * p
(在 for 循环条件下),检查 mul * p < n
.+=
并循环条件检查 <
在两个循环中是相同的;检查spd[mul] >= p
并更改 BitArray
中的值在他们花费的时间上具有可比性;但是额外的操作 mul * p
在第二个循环中,条件是乘法——它很昂贵!spd[mul] >= p
是true
,然后我们也执行:mul * p
(再次!),转换为 int
, 更改 BitArray
中的值, mul * p
(第三次!),我假设再次转换为 int
在 spd
的索引中, 并在数组中赋值 spd
.总而言之,您的第二个改进循环的每次迭代在计算上都“更重”。这就是为什么您的改进版本速度较慢的原因。
关于c# - Eratosthenes 筛法改进后运行速度变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71152909/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 6年前关闭。 Improve this qu
我有实体: @Entity @Table(name = "CARDS") public class Card { @ManyToOne @JoinColumn(name = "PERSON_I
我正在尝试计算二维多边形的表面法线。我正在使用 OpenGL wiki 中的 Newell 方法来计算表面法线。 https://www.opengl.org/wiki/Calculating_a_S
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 7 年前。 Improve
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 9 年前。 Improve this
我这里有以下 XML: Visa, Mastercard, , , , 0, Discover, American Express siteonly, Buyer Pay
即将发生的 Google 政策变更迫使我们实现一个对话框,以通知欧盟用户有关 Cookie/设备标识符用于广告和分析的情况。我只想向欧盟用户显示此对话框。我不想使用额外的权限(例如 android.p
本文分享自华为云社区《华为大咖说 | 企业应用AI大模型的“道、法、术” ——道:认知篇》,作者:华为云PaaS服务小智。 本期核心观点 上车:AGI是未来5~10年内,每个人都无法回避的技
我有一个与酒精相关的网站,需要先验证年龄,然后才能让他们进入该网站。我使用 HttpModule 来执行此操作,该模块检查 cookie,如果未设置,我会将它们重定向到验证页面。我验证他们的年龄并存储
在欧盟,我们有一项法律,要求网页请求存储 cookie 的许可。我们大多数人都了解 cookie 并同意它们,但仍然被迫在任何地方明确接受它们。所以我计划编写这个附加组件(ff & chrome),它
以下在 C 和/或 C++ 中是否合法? void fn(); inline void fn() { /*Do something here*/ } 让我担心的是,第一个声明看起来暗示函数将被定义
我是一名优秀的程序员,十分优秀!