1. 程式人生 > >求1億內素數個數的C++程式 詳細解釋

求1億內素數個數的C++程式 詳細解釋

錢能的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))這個條件判斷的作用。這樣精簡下來,要遍歷的數明顯變少。


老鳥們估計一眼就看出來了,所以看到我用這麼多的篇幅說了兩個這樣扯淡的問題難免要噴了。但是,這畢竟是我思考了很久才想出的解,不要噴太狠。