求1亿内素数个数的C++程序 详细解释

来源:互联网 发布:北森生涯怎么样知乎 编辑:程序博客网 时间:2024/05/17 06:53
钱能的C++教程上,有一段求1亿内素数的个数的程序,之前理解得不透,今天才稍微往深了理解了一些。


一般的思路就不说了,效率低得很。书里介绍了一种用空间换时间的方法:即用二进制中的一位代表数字。显然需要1亿位,可以用int型中的位,也可以用位集bitset。


书中有这样一段程序:


for(int i=2;i<=10000;i++)
  if(p->test(i))
    for(int j=i*i;j<p-size();j+=i)
        p-reset(j);


单看这段程序,尝试了2到10000的所有素数的小于1亿的倍数,然后将位集中的相应位设为0,将其排除。


以前看到的时候,主要有两个疑问:
1.为什么有if(p->test(i))这个条件判断?
2.1万内所有数的倍数能否囊括掉1亿内的所有合数?


凡事就怕琢磨,一琢磨就能发现其实里面值得思考的地方还是挺多的。假设集合A:2-9999的小于1亿的所有倍数;集合B:1亿内所有的合数(不包括1亿)。看看这两个集合是否相等。
在证明之前,我先解释一下为什么考察的是2-9999的倍数,因为毕竟程序中尝试了2-10000的素数。其实,“2-9999的小于1亿的所有倍数”和“2-10000的小于1亿的所有倍数”是同一个集合。10000的小于1亿的倍数被包括在了2-9999的倍数中。


证明:对于集合A中的每一个元素,肯定属于集合B,故B>=A;
      对于集合B中的每一个元素,都有一个小于1万的因子,即B中的元素n=x*y,x小于1万。故也属于集      合A,所以A>=B;
      综上,A=B。
所以,我们原来的思路是:剔除掉1亿内的所有合数。现在,我们转换思路:剔除掉2-9999的所有小于1亿的倍数。


那么,怎么能够遍历2-9999所有的小于1亿的倍数呢?这个问题解决了,上述问题1也就解决了。最笨的方法,对于2-9999间的所有的数字,分别遍历每一个的所有倍数。例如,数字2,要遍历2*2,2*3,2*4,......,2*49999999;再例如,数字3,要遍历3*2,3*3,3*4,......,3*33333333.以此类推。可以发现,这样遍历会有重复。改进之,对于数字3,从3倍开始即可,即遍历3*3,3*4,3*5,......,3*33333333。不要嫌我啰嗦,我再举个例子,脑子慢。对于数字6,遍历6*6,6*7,6*8,......,6*16666666。再看,对于6来说,本身6=2*3是2的倍数,所以,2的倍数肯定囊括了6的倍数。也就是说,对于前面已经确定为合数的数字,不需要再去遍历他们的倍数,因为前面肯定已经遍历过了。这就是if(p-test(i))这个条件判断的作用。这样精简下来,要遍历的数明显变少。


老鸟们估计一眼就看出来了,所以看到我用这么多的篇幅说了两个这样扯淡的问题难免要喷了。但是,这毕竟是我思考了很久才想出的解,不要喷太狠。
原创粉丝点击