提问人:trietng 提问时间:11/15/2022 更新时间:11/27/2022 访问量:143
为什么这个 Sieve of Sundaram 实现比这个 Sieve of Eratosthenes 实现快得多?
Why is this Sieve of Sundaram implementation much faster than this Sieve of Eratosthenes implementation?
问:
我目前正在尝试比较两种不同质数生成算法的平均运行时速度。我对埃拉托色尼的筛子有这个幼稚的实现:
std::vector<int32_t> sieve_of_eratosthenes(int32_t n) {
std::vector<int32_t> primes;
std::vector<bool> sieve(n + 1, true);
for (int32_t i = 2; i * i <= n; i++) {
if (sieve[i]) {
for (int j = i * i; j <= n; j += i) {
sieve[j] = false;
}
}
}
for (int32_t i = 2; i < n; ++i) {
if (sieve[i]) primes.push_back(i);
}
return primes;
}
以及 Sundaram 筛子的实现:
std::vector<int32_t> sieve_of_sundaram(int32_t n) {
std::vector<int32_t> primes;
int32_t k = (n - 1) / 2;
std::vector<bool> sieve(k + 1, true);
for (int32_t i = 1; i * i <= k; ++i) {
if (sieve[i]) {
for (int32_t j = i; i + j + 2 * i * j <= k; ++j) {
sieve[i + j + 2 * i * j] = false;
}
}
}
if (n > 2) primes.push_back(2);
for (int32_t i = 1; i <= k; ++i) {
if(sieve[i]) primes.push_back(2 * i + 1);
}
return primes;
}
这就是我尝试测量算法速度的方式。 是从命令行输入的参数。主程序将手动运行 2 次,第一次将打印出 的平均速度,第二次将是 的平均速度。test
sieve_of_eratosthenes
sieve_of_sundaram
std::vector<int32_t> test_input(1000, 100000);
std::vector<int32_t> result;
switch (test) {
case 1:
for (auto n : test_input) {
auto start = std::chrono::high_resolution_clock::now();
auto tmp = sieve_of_eratosthenes(n);
auto end = std::chrono::high_resolution_clock::now();
int32_t runtime = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
result.push_back(runtime);
}
break;
case 2:
for (auto n : test_input) {
auto start = std::chrono::high_resolution_clock::now();
auto tmp = sieve_of_sundaram(n);
auto end = std::chrono::high_resolution_clock::now();
int32_t runtime = std::chrono::duration_cast<std::chrono::nanoseconds>(endd - start).count();
result.push_back(runtime);
}
break;
default:
break;
}
std::cout << get_avg(result); // sum of all test results / result.size()
根据理论时间复杂度,埃拉托色尼筛子应该给出更快的结果(比 快,这是孙达拉姆筛子的时间复杂度)。然而,Sundaram 的筛子实际上要快得多(几乎是埃拉托色尼筛子的 3 倍)。O(nlog(logn))
O(nlogn)
结果(以纳秒为单位):
434379
179904
答:
2赞
oluckyman
11/25/2022
#1
您没有编写经典的 Sundaram 筛子(按几率进行筛选,确实需要 O(N log N) 操作),而是使用了一个小的修改 (),使其等同于埃拉托色尼筛子的版本,避免考虑偶数。if (sieve[i]) ...
由于您的其他代码使用经典的 Eratosthenes 筛子(按素数进行筛选)并且确实考虑了偶数,因此您所谓的 Sundaram 筛子代码确实按常数因子更快。
这在维基百科上关于Sundaram筛子的文章中进行了解释。
评论