• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            (轉(zhuǎn))質(zhì)數(shù)算法大全,及C程序?qū)崿F(xiàn)優(yōu)化詳解 (二) 篩選法

            質(zhì)數(shù)的定義

            一個數(shù),如果只有1和它本身兩個因數(shù),這樣的數(shù)叫做質(zhì)數(shù),又稱素數(shù)。

            在上文 《素數(shù)算法大全,及C程序?qū)崿F(xiàn)優(yōu)化詳解 (一) 試除法》中我們已經(jīng)探討了求解素數(shù)的一類算法,并且將試除法從最初的低效版本優(yōu)化的高效的V2。那么,還有沒有其它更佳算法呢?這就是下面三藏要和大家探討的內(nèi)容

            合數(shù)過濾篩選法

            算法描述:我們知道,素數(shù)N不能被2~(N-1)間的任何數(shù)整除;反過來看,只要能被2~(N-1)間的任何數(shù)整除的N,都不是素數(shù)。所以我們可以采用一個簡單的排除法:就是對N以內(nèi)的所有數(shù),只要逐個去除值為2~(N-1)的倍數(shù)的數(shù),剩下的就是素數(shù)。

            C語言實現(xiàn)

            // 合數(shù)過濾篩選法 Ver1 
            // 參數(shù):n 求解n以內(nèi)(包括n)的素數(shù)
            // 返回值:n以內(nèi)素數(shù)個數(shù)
            int CompositeNumFilterV1(int n)
            {
             int i, j;
             // 素數(shù)數(shù)量統(tǒng)計
             int count = 0;
             // 分配素數(shù)標記空間,結(jié)合后文思考為何+1
             char* flag = (char*)malloc( n+1 );
             
             // 初始化素數(shù)標記
             for (i=2; i<=n; i++)
             {
              // 為什么*(p+i)要寫成flag[i]呢?可讀性更佳爾
              flag[i] = 1;
             }
             
             // 寫程序要注意排版和留空,方便閱讀,也可減少出錯幾率
             // 以2~(N-1)為因子過濾合數(shù)
             for (i=2; i < n; i++)
             {
              for (j=2; i*j <= n; j++)
              {
               // i*j是由i,j兩整數(shù)相乘而得,顯然不是素數(shù)
               flag[i*j] = 0;
              }
             }
             
             // 統(tǒng)計素數(shù)個數(shù)
             for (i=2; i<=n; i++)
             {
              // 其實if(flag)就其同樣作用了,但這么寫是有留言的
              // 請參閱《C語言程序設(shè)計常見錯誤剖析及解決之道》一文
              if (1 == flag[i]) count++;
             }
              
             // 因輸出費時,且和算法核心相關(guān)不大,故略
             
             // 釋放內(nèi)存,別忘了傳說中的內(nèi)存泄漏
             free(flag);
             
             return count;
            }

            在上文給出的main函數(shù)中以不同參數(shù)調(diào)用CompositeNumFilterV1函數(shù),得到執(zhí)行結(jié)果如下:

            [100000]以內(nèi)素數(shù)個數(shù):9592, 計算用時:15毫秒
            [1000000]以內(nèi)素數(shù)個數(shù):78498, 計算用時:125毫秒
            [5000000]以內(nèi)素數(shù)個數(shù):348513, 計算用時:2578毫秒
            [10000000]以內(nèi)素數(shù)個數(shù):664579, 計算用時:6281毫秒

            注:因程序是非獨占性運行的,所以時間不是完全精確的,但基本能反映實情

            顯然,比上文中的試除法要快,而且誰都可以看到上例是一個未經(jīng)優(yōu)化的粗陋版本,好多地方是三藏故意采用比較低效做法,為了與后文的優(yōu)化版比較,凸顯優(yōu)化之重要,也為了初學(xué)者記住別采用類似低效做法,下面我們開始優(yōu)化之旅

            優(yōu)化分析

            上面CompositeNumFilterV1函數(shù)存在的問題有:

            1. 在外層循環(huán),需要一直執(zhí)行到n-1嗎?不要,因為n/2~n-1間的數(shù)顯然不能整出n
            2. 在內(nèi)層循環(huán)中重復(fù)使用i*j顯然是低效的,考慮到計算機中加減運算速度比乘除快,可以考慮變乘法為加法
            3. 在循環(huán)修改flag過程中,其實有很多數(shù)會被重復(fù)計算若干次,比如6=2*3=3*2,會被重復(fù)置0,類似操作很多,所以我們得設(shè)法避免或減少flag重復(fù)置0

            據(jù)上述分析,我們可將程序優(yōu)化如下:

            // 合數(shù)過濾篩選法 Ver2 
            // 參數(shù):n 求解n以內(nèi)(包括n)的素數(shù)
            // 返回值:n以內(nèi)素數(shù)個數(shù)
            int CompositeNumFilterV2(int n)
            {
             int i, j;
             // 素數(shù)數(shù)量統(tǒng)計
             int count = 0;
             // 分配素數(shù)標記空間,明白+1原因了吧,因為浪費了一個flag[0]
             char* flag = (char*)malloc( n+1 );
             
             // 初始化素數(shù)標記,要高效點咯
             flag[2] = 1;
             // 注意是i<n不是上例中的i<=n了,理由自思
             for (i=3; i<n; i++)
             {
              flag[i++] = 1;
              // 偶數(shù)自然不是素數(shù),直接置0好了
              flag[i] = 0;
             }
             // n為奇數(shù)
             if (n%2 != 0)
             {
              flag[n] = 1;
             }
             
             // 從3開始filter,因為2的倍數(shù)早在初始化時代就干掉了
             // 到n/2止的理由還要說嗎
             for (i=3; i <= n/2; i++)
             {
              // i是合數(shù),請歇著吧,因為您的工作早有您的質(zhì)因子代勞了
              if (0 == flag[i]) continue;
              
              // 從i的2倍開始過濾,變乘法為加法 
              for (j=i+i; j <= n; j+=i)
              {
               flag[j] = 0;
              }
             }
             
             // 統(tǒng)計素數(shù)個數(shù)
             for (i=2; i<=n; i++)
             {
              if (flag[i]) count++;
             }
              
             // 因輸出費時,且和算法核心相關(guān)不大,故略
             
             // 釋放內(nèi)存,別忘了傳說中的內(nèi)存泄漏
             free(flag);
             
             return count;
            }

            再來調(diào)用CompositeNumFilterV2得到執(zhí)行結(jié)果:

            [100000]以內(nèi)素數(shù)個數(shù):9592, 計算用時:n太小,時間精度不夠
            [1000000]以內(nèi)素數(shù)個數(shù):78498, 計算用時:31毫秒
            [5000000]以內(nèi)素數(shù)個數(shù):348513, 計算用時:453毫秒
            [10000000]以內(nèi)素數(shù)個數(shù):664579, 計算用時:1062毫秒
            [100000000]以內(nèi)素數(shù)個數(shù):5761455, 計算用時:12973毫秒

            哇哇,比昨天的試除發(fā)快了好多倍,可見算法的威力,值得好好學(xué)習(xí),別說學(xué)算法沒用咯。

            上例著那個計算一億以內(nèi)的素數(shù)只要約13秒,應(yīng)該算不錯了,今天是否可以休息了呢?No,我們要追求極限!

            int CompositeNumFilterV3(int n)
            {
             int i, j;
             // 素數(shù)數(shù)量統(tǒng)計
             int count = 0;
             // 分配素數(shù)標記空間,明白+1原因了吧,因為浪費了一個flag[0]
             char* flag = (char*)malloc( n+1 );
             // 干嘛用的,請仔細研究下文
             int mpLen = 2*3*5*7*11*13;
             char magicPattern[mpLen];
             // 奇怪的代碼,why,思考無法代勞,想!
             for (i=0; i<mpLen; i++)
             {
              magicPattern[i++] = 1;
              magicPattern[i++] = 0;
              magicPattern[i++] = 0;
              magicPattern[i++] = 0;
              magicPattern[i++] = 1;
              magicPattern[i] = 0;
             }
             for (i=4; i<=mpLen; i+=5)
              magicPattern[i] = 0;
             for (i=6; i<=mpLen; i+=7)
              magicPattern[i] = 0;
             for (i=10; i<=mpLen; i+=11)
              magicPattern[i] = 0;
             for (i=12; i<=mpLen; i+=13)
              magicPattern[i] = 0;
             
             // 新的初始化方法,將2,3,5,7,11,13的倍數(shù)全干掉
             // 而且采用memcpy以mpLen長的magicPattern來批量處理
             int remainder = n%mpLen;
             char* p = flag+1;
             char* pstop = p+n-remainder;
             while (p < pstop)
             {
              memcpy(p, magicPattern, mpLen);
              p += mpLen;
             }
             if (remainder > 0)
             {
              memcpy(p, magicPattern, remainder);
             }
             flag[2] = 1;
             flag[3] = 1;
             flag[5] = 1;
             flag[7] = 1;
             flag[11] = 1;
             flag[13] = 1;
             
             // 從17開始filter,因為2,3,5,7,11,13的倍數(shù)早被kill了
             // 到n/13止的,哈哈,少了好多吧
             int stop = n/13;
             for (i=17; i <= stop; i++)
             {
              // i是合數(shù),請歇著吧,因為您的工作早有您的質(zhì)因子代勞了
              if (0 == flag[i]) continue;
              
              // 從i的17倍開始過濾
              int step = i*2;
              for (j=i*17; j <= n; j+=step)
              {
               flag[j] = 0;
              }
             }
             
             // 統(tǒng)計素數(shù)個數(shù)
             for (i=2; i<=n; i++)
             {
              if (flag[i]) count++;
             }
              
             // 因輸出費時,且和算法核心相關(guān)不大,故略
             
             // 釋放內(nèi)存,別忘了傳說中的內(nèi)存泄漏
             free(flag);
             
             return count;
            }

            再看CompositeNumFilterV3執(zhí)行結(jié)果:

            [1000000]以內(nèi)素數(shù)個數(shù):78498, 計算用時:15毫秒
            [5000000]以內(nèi)素數(shù)個數(shù):348513, 計算用時:203毫秒
            [10000000]以內(nèi)素數(shù)個數(shù):664579, 計算用時:515毫秒
            [100000000]以內(nèi)素數(shù)個數(shù):5761455, 計算用時:6421毫秒

            再次優(yōu)化后速度提升了又一倍左右,三藏不禁有點滿足了,睡覺也!

            posted on 2009-05-14 15:48 小蟲蟲 閱讀(1037) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            <2009年5月>
            262728293012
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(5)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            精品久久久久久无码国产| 国产精品久久久久影院嫩草| 久久丫精品国产亚洲av不卡| 久久精品国产亚洲5555| 久久国产免费观看精品| 久久综合香蕉国产蜜臀AV| 2021最新久久久视精品爱| 亚洲国产综合久久天堂| 香蕉久久夜色精品国产2020| 日韩欧美亚洲综合久久影院Ds | 亚洲欧洲中文日韩久久AV乱码| 91久久精品视频| 久久精品亚洲福利| 亚洲国产综合久久天堂| 亚洲精品无码久久千人斩| 乱亲女H秽乱长久久久| 国产精品一久久香蕉产线看| 久久99精品国产99久久6男男| 色综合久久最新中文字幕| 99久久婷婷国产一区二区| 日韩电影久久久被窝网| 综合网日日天干夜夜久久 | 亚洲国产成人久久笫一页| 久久人人爽人人爽人人片AV不| 午夜欧美精品久久久久久久| 久久精品9988| 久久综合亚洲鲁鲁五月天| 99久久精品午夜一区二区 | 亚洲av成人无码久久精品| 国产99精品久久| 久久影院亚洲一区| 久久99国产综合精品女同| 久久久精品无码专区不卡| 人妻少妇久久中文字幕一区二区| 日韩精品久久久久久| 久久精品国产亚洲AV影院| 一级做a爱片久久毛片| 中文国产成人精品久久不卡| 91精品国产高清久久久久久国产嫩草| 无码八A片人妻少妇久久| 99久久99久久精品国产片果冻|