C – Eratosthenes的筛子 – BitField

C – Eratosthenes的筛子 – BitField,第1张

概述我即将实施 Sieve of Eratosthenes,并对筛阵列有一个普遍的问题. 我现在已经实施了几次筛子(在C中)并且总是使用一个uint8_t数组(从< stdint.h>中)作为筛子.这是非常低效的内存,因为每个数字使用8位来筛选,即使一位应该足够. 我怎么会用C来解决这个问题呢?我需要一个位数组.我几乎可以创建任何类型的数组(uint8_t,uint16_t,uint32_t,uint 我即将实施 Sieve of Eratosthenes,并对筛阵列有一个普遍的问题.

我现在已经实施了几次筛子(在C中)并且总是使用一个uint8_t数组(从< stdint.h>中)作为筛子.这是非常低效的内存,因为每个数字使用8位来筛选,即使一位应该足够.

我怎么会用C来解决这个问题呢?我需要一个位数组.我几乎可以创建任何类型的数组(uint8_t,uint16_t,uint32_t,uint64_t)并使用位掩码等访问单个位.

我应该选择哪种数据类型以及在没有性能损失的情况下应该使用哪些 *** 作来访问这些位?

PS:我不认为这只是BitArray实现的重复,因为它的问题是关于Eratosthenes的SIEve,因为它的主要性质需要高效(不仅在内存使用方面,而且在访问方面).我在想,可能会有不同的技巧来使筛分过程更有效…

解决方法 正如Weather Vane在他的评论中所提到的,你可以通过仅考虑其他所有数字来节省额外的空间,因为除了2之外的所有偶数都是非素数.

所以在你的位数组中,每个位代表一个奇数.

这是我几年前使用这种技术做的实现.

#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <time.h>#include <math.h>#include <stdint.h>uint8_t *num;int count = 0;file *primefile;int main(int argc,char *argv[]){  int i,j,root;  time_t t;  if (argc>1) count=atoi(argv[1]);  if (count < 100) {    fprintf(stderr,"InvalID number\n");    exit(1);  }  if ((num=calloc(count/16,1))==NulL) {    perror("calloc Failed");    exit(1);  }  if ((primefile=fopen("primes.dat","w"))==NulL) {    perror("Coundn't open primes.dat");    exit(1);  }  t=time(NulL);  printf("Start:\t%s",ctime(&t));  root=floor(sqrt(count));  // write 2 to the output file  i=2;  if (fwrite(&i,sizeof(i),1,primefile)==0) {    perror("Couldn't write to primes.dat");  }  // process larger numbers  for (i=3;i<count;i+=2) {    if ((num[i>>4] & (1<<((i>>1)&7)))!=0) continue;    if (fwrite(&i,primefile)==0) {      perror("Couldn't write to primes.dat");    }    if (i<root) {      for (j=3*i;j<count;j+=2*i) {        num[j>>4]|=(1<<((j>>1)&7));      }    }  }  t=time(NulL);  printf("End:\t%s",ctime(&t));  fclose(primefile);  return 0;}

这里,num是位数组,根据搜索的上限动态分配.因此,如果您正在寻找高达1000000000(10亿)的所有素数,它将使用64000000(6400万)字节的内存.

关键表达式如下:

对于“正常”位数​​组:

设置位i:

num[i>>3] |= (1<<(i&7);// same as num[i/8] |= (1<<((i%8));

检查位i:

(num[i>>3] & (1<<(i&7))) != 0// same as (num[i/8] & (1<<(i%8))) != 0

由于我们只跟踪其他所有数字,我们将i除以2(或等效地,右移1:

num[i>>4] |= (1<<((i>>1)&7);// same as num[(i/2)/8] |= (1<<(((i/2)%8));(num[i>>4] & (1<<((i>>1)&7))) != 0// same as (num[(i/2)/8] & (1<<((i/2)%8))) != 0

在上面的代码中,有一些微优化,其中2的幂的除法和模数被位移和按位AND掩码替换,但是大多数编译器应该为你做.

总结

以上是内存溢出为你收集整理的C – Eratosthenes的筛子 – BitField全部内容,希望文章能够帮你解决C – Eratosthenes的筛子 – BitField所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1241102.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存