首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用位掩码的Sieve方法列出素数

使用位掩码的Sieve方法列出素数
EN

Stack Overflow用户
提问于 2013-01-09 01:43:10
回答 3查看 882关注 0票数 2

我写了下面的代码,使用Sieve的方法列出了所有质数,最多20亿。我将位掩码用于标记目的。虽然我能够正确地得到质数,但每次开始的时候都会缺少一些质数。请帮我找出程序中的bug。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>

#define MAX 2000000000

char* listPrimes(){
int block = sqrt(MAX);
char* mark = calloc((MAX/8),sizeof(char));
int i = 2;
int j;
char mask[8];
for(j=0;j<8;j++)
    mask[j] = 0;
mask[7] = 1;
mask[6] |= mask[7] << 1;
mask[5] |= mask[7] << 2;
mask[4] |= mask[7] << 3;
mask[3] |= mask[7] << 4;
mask[2] |= mask[7] << 5;
mask[1] |= mask[7] << 6;
mask[0] |= mask[7] << 7;

for(j=0;j<8;j++)
    printf("%d ",mask[j]);
mark[0] |= mask[0];
mark[0] |= mask[1];

while (i < block){

        for (j = 2; i*j <= block; j++)
                mark[(i*j) / 8] |= mask[((i*j) % 8 )];
        i++;
    }
printf("\n");
printf("The block size is\t:\t%d\n",block);


j = 2;
while(j<=block){
    if((mark[j / 8] & mask[j]) == 0 ){
        for(i = 2;i <= MAX; i++){
            if((i%j) == 0){
                mark[i / 8] |= mask[(i % 8)];
            }
        }
    }
while((mark[++j / 8] & mask[j % 8]) != 0);
}


for(j=0;j<=MAX;j++)
        if((mark[j / 8] & mask[(j % 8)]) == 0)
            printf("%d\n", ((8*(j / 8)) + (j % 8)));

return mark;
}   

int main(int argc,char* argv[]){

listPrimes();

return 0;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-09 05:53:35

正如ArunMK所说,在第二个while循环中,您将素数j本身标记为j的倍数。正如Lee Meador所说,您需要将j模8取为mask索引的模数,否则您将访问越界并调用未定义的行为。

调用未定义行为的另一点是

代码语言:javascript
复制
while((mark[++j / 8] & mask[j % 8]) != 0);

在这里您可以使用和修改j,而无需干预序列点。您可以通过编写以下代码来避免这种情况

代码语言:javascript
复制
do {
    ++j;
}while((mark[j/8] & mask[j%8]) != 0);

或者,如果您坚持使用具有空体的while循环

代码语言:javascript
复制
while(++j, (mark[j/8] & mask[j%8]) != 0);

您可以使用逗号运算符。

更多未定义的行为,通过访问未在

代码语言:javascript
复制
for(i = 2;i <= MAX; i++){

代码语言:javascript
复制
for(j=0;j<=MAX;j++)

此外,如果char是带符号的且八位宽,

代码语言:javascript
复制
mask[0] |= mask[7] << 7;

是实现定义的(并且可能引发实现定义的信号),因为

代码语言:javascript
复制
mask[0] | (mask[7] << 7)

( int 128)不能表示为char

但是为什么要将每个数字除以不超过第二个while循环中界限的平方根的所有素数呢?

代码语言:javascript
复制
    for(i = 2;i <= MAX; i++){
        if((i%j) == 0){

这使得你的算法不是Eratosthenes的筛子,而是一个试验性的划分。

为什么不在那里使用第一个while循环中的技术呢?(然后,为什么会有两个循环呢?)

代码语言:javascript
复制
while (i <= block){
    if ((mark[i/8] & mask[i%8]) == 0) {
        for (j = 2; i*j < MAX; j++) {
            mark[(i*j) / 8] |= mask[((i*j) % 8 )];
        }
    }
    i++;
}

不会溢出(对于给定的MAX值,如果可以表示为int),并更快地生成正确的数量级输出。

票数 1
EN

Stack Overflow用户

发布于 2013-01-09 01:55:01

更改中间循环以添加模:

代码语言:javascript
复制
j = 2;
while(j<=block){
    if((mark[j / 8] & mask[j % 8]) == 0 ){
        for(i = 2;i <= MAX; i++){
            if((i%j) == 0){
                mark[i / 8] |= mask[(i % 8)];
            }
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2013-01-09 03:37:40

在第二个while循环中,从2开始遍历i并执行if (i%j == 0)。当i也是素数时,这也是正确的。您需要检查(i != j)。还有上面报道的模数。因此它变成了:if ((i%j == 0) { if (i!=j) mark[i/j] |= mask[i%j]; }

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14220971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档