当前位置: 首页 > 知识库问答 >
问题:

埃拉托色尼钻头阵列筛

巫马泰
2023-03-14

我试图找到素数使用厄拉多塞筛位数组,但我使用的是无符号整数数组。我需要能够产生多达2,147,483,647个素数。我的代码工作正常,可以生成大约10,000,000个,但是当我增加数组的大小以容纳更大的数字时,它失败了。有人能指导我如何用c语言(不是c语言)使用位向量吗?谢谢

这是我的代码:

#include <stdio.h>
#include <stdlib.h>

#define MAXBYTES 2000000
#define MAX 50000000
#define BITSIZE 32

void ClearBit(unsigned int [], unsigned int);
void SetBit(unsigned int [], unsigned int);
int  BitVal(unsigned int [], unsigned int);
void PrintBitStream(unsigned int [], unsigned long);
void PrintBitStreamData(unsigned int[], unsigned long);
int  Sieve(unsigned int[], unsigned int, unsigned int);

int main(int argc, char ** argv) {
    unsigned int maxsize = MAX;
    unsigned int i;
    //Set Bit Array
    unsigned int BitArray[MAXBYTES] = {0};
    SetBit(BitArray, 0);
    SetBit(BitArray, 1);
    i = 2;
    for (;i < maxsize;i++){

        if(Sieve(BitArray, i, maxsize)==0)
            break;
    }
    PrintBitStreamData(BitArray, maxsize-1);
    return EXIT_SUCCESS;
}

void PrintBitStreamData(unsigned int BitArray[], unsigned long maxsize) {
    unsigned int i;
    for (i = 0; i < maxsize; i++)
        if (!BitVal(BitArray, i))
            printf("%ld ", i);
    printf("\n");
}

void PrintBitStream(unsigned int BitArray[], unsigned long maxsize) {
    unsigned int i;
    for (i = 2; i < maxsize; i+=2)
        printf("%d", BitVal(BitArray, i));
    printf("\n");
}

void SetBit(unsigned int BitArray[], unsigned int pos) {
    BitArray[pos / BITSIZE] |= 1 << (pos % BITSIZE);
}

void ClearBit(unsigned int BitArray[], unsigned int pos) {
    BitArray[pos / BITSIZE] &= ~(1 << (pos % BITSIZE));
}

int BitVal(unsigned int BitArray[], unsigned int pos) {
    return ((BitArray[pos / BITSIZE] & (1 << (pos % BITSIZE))) != 0);
}

int Sieve(unsigned int BitArray[], unsigned int p, unsigned int maxsize) {
    unsigned int i;
    unsigned int j;
    j = 0;
    for (i = 2 * p; i < maxsize; i += p) {
        SetBit(BitArray, i);
        j++;
    }
    return j;
}

共有2个答案

羊舌昆杰
2023-03-14

使用位访问整数的示例< br >注意< code>GetBit()和< code>SetBit()。< br >使用2的幂时,优化编译器会使< code>/和< code>%更快。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ubitsize (sizeof(unsigned)*8)

unsigned GetBit(const unsigned *List, unsigned long index) {
  return !!(List[index / ubitsize] & (1u << (index % ubitsize)));
  }

void SetBit(unsigned *List, unsigned long index) {
  List[index / ubitsize] |= (1u << (index % ubitsize));
  }

void Sieve_of_Eratosthenes_via_bit_array(unsigned long MaxCandidatePrime) {
  unsigned long uByteSize = MaxCandidatePrime/ubitsize + 1;
  unsigned *List = calloc(uByteSize, sizeof *List);
  if (List == 0) return;

  unsigned long PrimeCount = 0;
  unsigned long Index = 0;
  for (Index = 2; Index <= MaxCandidatePrime; Index++) {
    // If found a prime ...
    if (GetBit(List, Index) == 0) {
      PrimeCount++;
      // let's see the progress
      if ((PrimeCount % (256LU*1024)) == 0) printf("%lu\n", Index);

      // Mark subsequent multiples as not--a-prime
      unsigned long Index2 = Index*2;
      while (Index2 <= MaxCandidatePrime) {
        SetBit(List, Index2);
        Index2 += Index;
      }
    }
  }
  printf("X %lu\n", Index);
  free(List);
}

void test(void) {
  Sieve_of_Eratosthenes_via_bit_array(200LU*1000*1000);
}

重写可以采用通常的建议,不保存偶数,将2视为特殊情况。这很有帮助,但我认为这是一个练习。我可以通过节省每30倍编码1个字节来节省大约4倍,因为每30个整数最多有8个素数。还有其他方案。

狄誉
2023-03-14

我肯定不会使用位数组,而是使用原生int (64位或32位,取决于体系结构)数组,并使用按位< code>|和< code >包装一个函数,将普通数字重新映射到正确的位置和位

还要考虑省略偶数,几乎没有一个是质数。因此,您可以将前128个数字存储在第一个64位数字中,然后将下一个128个数字存储在第二个数字中,等等。

这听起来有点复杂,但让它工作有点有趣!

欧拉项目似乎已经产生了一些非常好的解决方案。

好的一面是:要筛分,您不需要重新计算偶数转移,但您可以取消每隔三分之一位的筛分3,每隔5位的筛分5等。

如果您想快速的java解决方案作为详细参考,请进入聊天。

EDIT4:已更正工作代码,但速度较慢。备注:记住使用calloc!

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>

typedef unsigned long long number;

number lookFor = 2147483648ULL;
number max = 2147483648ULL*10ULL; // hopefully more then every 10th uneven number is prime

unsigned long * isComposite;

number bitslong = CHAR_BIT*sizeof(long);

time_t rawtime;
struct tm * timeinfo;
char buffer[80];

// is not called during sieve, only once per sieving prime 
// and needed for reading if a number is prime
inline long getParts(number pos, number *slot, unsigned int *bit){
    *slot = pos / bitslong;
    *bit = (unsigned int)(pos % bitslong);
}

int isPrime(number n){
    if(n == 1){
        return 0;
    }

    if(n < 4){
        return 1;
    }

    if((n%2) == 0){
        return 0;
    }

    number slot=0;
    unsigned int bit=0;
    number pos = (number)(n-3)/2;
    getParts(pos, &slot, &bit);
    // printf("? n=%lld  pos = %lld slot = %lld bit = %lu ret %d \n", n, pos, slot, bit, !(isComposite[slot] & (1<<bit)));
    return !(isComposite[slot] & (1UL<<bit));
}

// start sieving at offset (internal position) offset with width step 
int doSieve(number offset, number step){
    rawtime = time(0);
    time (&rawtime);
    timeinfo = localtime (&rawtime);

    strftime(buffer, 80, "%Y-%m-%d %H:%I:%S", timeinfo);
    unsigned int bit=0;
    number slot=0;
    getParts(offset, &slot, &bit);
    printf("doSieve %s  %lld %lld  %lu \n", buffer, offset, step, isComposite[slot]);

    while(slot < max/bitslong){
        slot += (step + bit)/bitslong;
        bit = (step + bit) % bitslong;
        isComposite[slot] |= (1UL << bit);
    } 
    return 1;
}

int sieve(){
    number spot;
    spot=1;
    number pos;
    pos = 0;
    while(spot < 1 + sqrt((float)max)){
        spot+=2;
        if(! isPrime(spot)){
            pos++;
            continue;
        }
        doSieve(pos, spot);
        pos++;
    }
}

void main(int argc, char *argv[]){
    if(argc > 1){
        char *tp = malloc(sizeof(char*));
        max = strtol(argv[1], &tp, 10);
    }
    printf("max %lld , sq %ld, malloc: %lld\n", max, (long)(1 + sqrt((float)max)), 1+max/bitslong);
    isComposite = calloc((2+max/bitslong), sizeof(unsigned long)) ;
    if(! isComposite){
        printf("no mem\n");
        exit(5);
    }
    sieve();
    number i;
    number found = 0;
    for(i = 1; i<max && found < lookFor; i++){
        if(isPrime(i)){
            found++;
            // printf(" %30lld %30lld \n", found, i);
            if(found % 10000 == 0 ){
                printf("%30lld %30lld \n", found, i);
            }
        }
        /*
        if(i % 1000 == 17){
            printf("%5lld %5lld \n", i, found);
        }
        */
    }
}
 类似资料:
  • 我有一个< code >无符号int的位数组< code>prime[]。我希望用这个数组实现一个厄拉多塞筛,让每一位代表一个数。也就是说,给定< code>n,保存对应于< code>n的位的数组元素将是< code>prime[n/32],并且特定位将在位置< code>n2中。 我的函数在数字为素数时返回1(如果其位==0),否则返回0: 我的< code>setBit(int n)函数只是

  • 就像这个问题一样,我也在厄拉多塞的筛子上工作。同样来自《c语言编程原理和实践》一书的第4章。我能够正确地实现它,并且它的功能完全符合练习的要求。 现在,我怎样才能在输入的中处理真正的大数字?类型应该允许我输入2^32=4,294,967,296的数字。但是我不能,我运行内存溢出。是的,我已经计算过了:存储2^32量的int,每个32位。所以32/8*2^32=16 GiB的内存。我只有4 GiB…

  • 我正在尝试让我的埃拉托斯特尼筛程序仅输出用户请求的前n个素数。Sieve本身工作得很好 - 它正确地输出了前100个素数(如下面的数组所示),但是最后一个循环中的计数器变量无法正常工作,我无法找出原因。例如,如果用户输入“5”表示 n,则只会打印前 3 个定焦值。 有人可以帮我找出我的错误吗?我的目的是让“count”成为一个非常简单的计数器,每次都会增加1,直到它达到n。

  • 我正在尝试对厄拉多塞的筛子进行并行实现。我做了一个布尔列表,对于给定的大小,用true填充。无论何时发现一个素数,该素数的所有倍数在布尔列表中都被标记为假。 我试图使这个算法并行的方法是在仍然过滤初始质数的同时启动一个新线程。例如,算法从素数 = 2 开始。在 for 循环中,当素数 * 素数时,我做另一个 for 循环,其中检查素数 (2) 和素数 * 素数 (4) 之间的每个数字。如果布尔列表

  • 我正在做一个C程序,用厄拉多塞筛寻找质数 目前我有以下代码: C 这工作正常,即它说在1和100之间有25个素数(这是正确的)。但是,例如,如果我想知道前500个素数,它会说有118个,而实际上有95个。为了解决这个问题,我必须添加更多的倍数来删除,然后添加更多。 有没有一种方法可以使它更有效,而不仅仅是让它去除以前发现的素数的更多倍数?

  • 我正在尝试编写一个程序来实现对埃拉托西的筛选。我可以从2到任何给定的结束编号,但我们正在处理的赋值要求我们输入起始值。我完全被卡住了。我试过很多不同的代码,但它总是给我奇怪的答案。 我的起点是起始值,终点是结束值。我基本上想找到这个范围的素数。谢谢!!!