- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
最近我一直在研究使用阿特金筛 (http://en.wikipedia.org/wiki/Sieve_of_atkin) 生成其素数的 C++ 素数生成器。我的目标是能够生成任何 32 位数字。我将主要使用它来解决项目欧拉问题。大多数情况下,这只是一个夏季项目。
该程序使用位板来存储素数:即一系列的 1 和 0,例如第 11 位为 1,第 12 位为 0,第 13 位为 1,等等。为了有效使用内存,这实际上是一个字符数组,每个字符包含 8 位。我使用标志和按位运算符来设置和检索位。该算法的要点很简单:使用一些我不假装理解的方程式来定义数字是否被认为是“质数”。这将在大多数情况下得到正确答案,但一些非质数将被标记为质数。因此,在遍历列表时,将刚刚找到的素数的所有倍数设置为“非素数”。这有一个方便的优势,即素数越大,所需的处理器时间就越少。
我已经完成了 90%,还有一个问题:一些素数丢失了。
通过检查位板,我确定在第一遍中省略了这些素数,这基本上为多个方程的每个解切换了一个数字(参见维基百科条目)。我一次又一次地检查了这段代码。我什至尝试增加维基百科文章中显示的范围,这效率较低,但我认为可能会达到一些我不知何故遗漏的数字。没有任何效果。这些数字只是评估为非素数。我的大部分测试都是针对 128 以下的所有素数进行的。在此范围内,这些是被忽略的素数:
23 和 59。
我毫不怀疑,在更高的范围内,会丢失更多(只是不想计算所有这些)。我不知道为什么缺少这些,但它们确实存在。这两个质数有什么特别之处吗?我已经双重和三次检查,发现并修复错误,但我仍然可能遗漏了一些愚蠢的东西。
无论如何,这是我的代码:
#include <iostream>
#include <limits.h>
#include <math.h>
using namespace std;
const unsigned short DWORD_BITS = 8;
unsigned char flag(const unsigned char);
void printBinary(unsigned char);
class PrimeGen
{
public:
unsigned char* sieve;
unsigned sievelen;
unsigned limit;
unsigned bookmark;
PrimeGen(const unsigned);
void firstPass();
unsigned next();
bool getBit(const unsigned);
void onBit(const unsigned);
void offBit(const unsigned);
void switchBit(const unsigned);
void printBoard();
};
PrimeGen::PrimeGen(const unsigned max_num)
{
limit = max_num;
sievelen = limit / DWORD_BITS + 1;
bookmark = 0;
sieve = (unsigned char*) malloc(sievelen);
for (unsigned i = 0; i < sievelen; i++) {sieve[i] = 0;}
firstPass();
}
inline bool PrimeGen::getBit(const unsigned index)
{
return sieve[index/DWORD_BITS] & flag(index%DWORD_BITS);
}
inline void PrimeGen::onBit(const unsigned index)
{
sieve[index/DWORD_BITS] |= flag(index%DWORD_BITS);
}
inline void PrimeGen::offBit(const unsigned index)
{
sieve[index/DWORD_BITS] &= ~flag(index%DWORD_BITS);
}
inline void PrimeGen::switchBit(const unsigned index)
{
sieve[index/DWORD_BITS] ^= flag(index%DWORD_BITS);
}
void PrimeGen::firstPass()
{
unsigned nmod,n,x,y,xroof, yroof;
//n = 4x^2 + y^2
xroof = (unsigned) sqrt(((double)(limit - 1)) / 4);
for(x = 1; x <= xroof; x++){
yroof = (unsigned) sqrt((double)(limit - 4 * x * x));
for(y = 1; y <= yroof; y++){
n = (4 * x * x) + (y * y);
nmod = n % 12;
if (nmod == 1 || nmod == 5){
switchBit(n);
}
}
}
xroof = (unsigned) sqrt(((double)(limit - 1)) / 3);
for(x = 1; x <= xroof; x++){
yroof = (unsigned) sqrt((double)(limit - 3 * x * x));
for(y = 1; y <= yroof; y++){
n = (3 * x * x) + (y * y);
nmod = n % 12;
if (nmod == 7){
switchBit(n);
}
}
}
xroof = (unsigned) sqrt(((double)(limit + 1)) / 3);
for(x = 1; x <= xroof; x++){
yroof = (unsigned) sqrt((double)(3 * x * x - 1));
for(y = 1; y <= yroof; y++){
n = (3 * x * x) - (y * y);
nmod = n % 12;
if (nmod == 11){
switchBit(n);
}
}
}
}
unsigned PrimeGen::next()
{
while (bookmark <= limit)
{
bookmark++;
if (getBit(bookmark))
{
unsigned out = bookmark;
for(unsigned num = bookmark * 2; num <= limit; num += bookmark)
{
offBit(num);
}
return out;
}
}
return 0;
}
inline void PrimeGen::printBoard()
{
for(unsigned i = 0; i < sievelen; i++)
{
if (i % 4 == 0)
cout << endl;
printBinary(sieve[i]);
cout << " ";
}
}
inline unsigned char flag(const unsigned char bit_index)
{
return ((unsigned char) 128) >> bit_index;
}
inline void printBinary(unsigned char byte)
{
unsigned int i = 1 << (sizeof(byte) * 8 - 1);
while (i > 0) {
if (byte & i)
cout << "1";
else
cout << "0";
i >>= 1;
}
}
我已尽最大努力对其进行清理并使其可读。我不是专业程序员,所以请手下留情。
这是我得到的输出,当我初始化一个名为 pgen 的 PrimeGen 对象时,使用 pgen.printBoard() 打印它的初始位板(请注意在 next() 迭代之前缺少 23 和 59),然后迭代 next () 并打印所有返回的素数:
00000101 00010100 01010000 01000101
00000100 01010001 00000100 00000100
00010001 01000001 00010000 01000000
01000101 00010100 01000000 00000001
5
7
11
13
17
19
29
31
37
41
43
47
53
61
67
71
73
79
83
89
97
101
103
107
109
113
127
DONE
Process returned 0 (0x0) execution time : 0.064 s
Press any key to continue.
最佳答案
Eureka !!!
不出所料,这对我来说是一个愚蠢的错误。
3x^2 - y^2 方程有一个我忽略的小警告:x > y。考虑到这一点,我切换 23 和 59 的次数过多,导致它们失败。
感谢大家的帮助。救了我的培根。
关于C++ Sieve of Atkin 忽略了一些质数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2145939/
根据链接:http://en.wikipedia.org/wiki/Sieve_of_Sundaram,用于生成最多为 n 的素数列表的“sundaram 筛法”的运行时间为 O(n*log(n))。
我目前正在尝试比较两种不同素数生成算法的平均运行速度。我有这个简单的埃拉托色尼筛法实现: std::vector sieve_of_eratosthenes(int32_t n) { std:
我正在研究一个简单的埃拉托色尼筛法算法,代码如下: int main() { const int n = 1000000; int sqrn = floor(sqrt(n));
当我偶然发现一种称为欧拉筛的改进版的埃拉托色尼筛时,我正在阅读不同的筛分算法。根据Wikipedia在 Haskell 中有一个稍微不同版本的想法(称为 Turner's Sieve)的实现。 现在我
这是我编写的用于在上限可以大到 1000000000 的范围之间查找素数的代码。我使用了 Hashmap,除了 2 之外没有存储任何偶数,也没有存储 sero 和 1但当我使用输入 lb = 1 和
我最近编写了这段代码,但想知道是否有更快的方法来查找素数(不是筛子;我仍在尝试实现)。有什么建议吗?我正在使用 Python,而且对它还很陌生。 def isPrime(input): cur
我正在编写一种方法来查找不超过 n(埃拉托色尼筛法)的素数,是的,这是作业。我希望提高我编写的方法的性能。最近几天我一直在调整它,但无法遵循给出的伪代码并提高性能。 伪代码如下: 创建要处理的号码队列
目前我有两个功能: 一个需要生成素数的数量。 第二个取素数上限生成。 它们是这样编码的(在 C++ 中): prime_list erato_sieve(ul_it upper_limit) {
我一直在研究 Stroustrup 的书: http://www.amazon.com/Programming-Principles-Practice-Using-C/dp/0321543726我目前
我正在尝试使用筛子打印出一组特定的素数,但我似乎没有得到任何输出,但它编译正常。程序不会退出,除非我强制执行,所以我猜它卡在了某个地方...我该如何解决这个问题? #include #include
我编写了以下代码,使用 Sieve 的方法列出了 20 亿以内的所有质数。我使用位掩码来标记目的。虽然我能够正确地得到素数,但每次都会丢失一些开头的素数。请帮我找出程序中的错误。 #include
来自 Wikipedia: The complexity of the algorithm is O(n(logn)(loglogn)) bit operations. 你是如何做到这一点的? 复杂性
来自 Wikipedia: The complexity of the algorithm is O(n(logn)(loglogn)) bit operations. 你是如何做到这一点的? 复杂性
我正在尝试实现 Sieve of Eratosthene在 C++ 中。但是,经过多次尝试后,我总是会遇到运行时错误。我认为这与正在使用的迭代器的状态在某处损坏有关。我不能把我的手指放在上面。这是我的
最近我一直在研究使用阿特金筛 (http://en.wikipedia.org/wiki/Sieve_of_atkin) 生成其素数的 C++ 素数生成器。我的目标是能够生成任何 32 位数字。我将主
我正在尝试理解“Eratosthenes 筛法”。这是我的算法(下面的代码),以及我无法理解的功能列表(按顺序)。 为什么 i * i 比 i * 2 更有效?是的,我可以理解它会减少迭代次数,因此效
我用 Java 编写了以下“分段筛”程序。它需要筛选一系列数字,使用“筛选素数”(素数数组列表变量)划掉复合数,然后返回尚未划掉的素数。这是代码: public ArrayList sieveWork
我更多地来自 java/php 背景,我现在正在学习 C++。我试图用 C++ 重新创建埃拉托色尼筛法并打印出 5000 以下的所有素数。 我正在用 http://www.compileonline.
我想首先说明我是一个 python 新手,我很感激任何能向我清楚、完整地解释它的人。 我正在查看以下链接中的代码: http://rosettacode.org/wiki/Sieve_of_Erato
我正在研究 PrimeSieve 的数组列表实现,我已经编写了所有代码,但它似乎无法运行,所以我不确定是因为循环不好还是因为我设置了错误的扫描器。 这是代码。 import java.util.S
我是一名优秀的程序员,十分优秀!