Quantcast
Channel: 円周率近似値の日に生まれて理系じゃないわけないだろ! - knifeのblog
Viewing all articles
Browse latest Browse all 5376

素数判定の枝刈りをどこまでやるのか

$
0
0

最近は、ちょっとプログラミングの話題が多いかな。

今回は、枝刈りについて考えてみようかと思う。

昨日の互いに素の記事では、画期的な方法で枝刈りをしてみました。

今日の題材は、素数とします。

素数も私のブログではよく出てくるものですが、今一度説明しましょう。

素数とは、1と自分自身しか約数を持たない数です。

例を挙げると、2、3、5、7、11、13、17、19、…と無限に存在することが証明されています。

ある自然数nが素数であるか判定するには、nより小さい自然数で割り切れなければ良いということ。

今回はサンプルが多くなるので、プログラム全体ではなく、素数判定ルーチンだけを考えます。
int check(unsigned int n)
で、判定したいnを与え、素数なら1、素数でないなら0を返すサブルーチンとします。

【サブルーチン1】

int check(unsigned int n)
{
    unsigned int i;
    for (i=2; i<n; i++) {
        if ( n%i == 0 ) return 0;
    }
    return 1;
}

まったく枝刈りをしていない状態です。

これをベースに、どの様な枝刈りを思いつくでしょうか?

終了判定のi<nはかなり無駄で、i<=sqrt(n)に相当するものでよい。


【サブルーチン2】

int check(unsigned int n)
{
    unsigned int i, j;
    j = sqrt((double)n)+1;
    for (i=2; i<j; i++) {
        if ( n%i == 0 ) return 0;
    }
    return 1;
}

かなり枝刈りされましたが、まだまだ枝刈りの余地はあります。


因みに、
for (i=3; i<=sqrt((double)n);p n+=2) { ... }
のようにしてはダメです。
何故かと言うと、終了判定で毎回sqrtを計算しなくてはならないからです。

2以外の素数は全て奇数。


【サブルーチン3】

int check(unsigned int n)
{
    unsigned int i, j;
    j = sqrt((double)n)+1;
    if ( n%2 == 0 ) return 0;
    for (i=3; i<j; i+=2) {
        if ( n%i == 0 ) return 0;
    }
    return 1;
}

大抵の人は、このくらいまで枝刈りをします。

もっと枝刈りを増やしてみる。

【サブルーチン4】

int check(unsigned int n)
{
    unsigned int i, j;
    j = sqrt((double)n)+1;
    if ( n%2 == 0 || n%3 == 0 ) return 0;
    for (i=5; i<j; i+=6) {
        if ( n%i == 0 || n%(i+2) == 0 ) return 0;
    }
    return 1;
}


【サブルーチン5】

int check(unsigned int n)
{
    unsigned int i, j;
    j = sqrt((double)n)+1;
    if ( n%2 == 0 || n%3 == 0 || n%5 == 0 ) return 0;
    for (i=7; i<j; i+=30) {
        if ( n%i == 0 || /* 7 37 67 97 ... */
             n%(i+4) == 0 || /* 11 41 71 101 ... */
             n%(i+6) == 0 || /* 13 43 73 103 ... */
             n%(i+10) == 0 || /* 17 47 77 107 ... */
             n%(i+12) == 0 || /* 19 49 79 109 ... */
             n%(i+16) == 0 || /* 23 53 83 113 ... */
             n%(i+22) == 0 || /* 29 59 89 119 ... */
             n%(i+24) == 0 ) { /* 31 61 91 121 ... */
            return 0;
        }
    }
    return 1;
}

サブルーチン3、4、5は、for分でi+=2、i+=6、i+=30と増えていき、if文の項数は1、2、8個と変化している。

表にまとめると、

 

if文の項数for文の追加数枝刈り率
1250.0000000000%
2666.6666666667%
83073.3333333333%
4821077.1428571429%
480231079.2207792208%
57603003080.8191808192%
9216051051081.9474643004%
1658880969969082.8975977583%
3649536022309287083.6411804644%
1021870080646969323084.2052776898%
3065610240020056049013084.7147848611%
1103619686400742073813481085.1278987838%
4414478745600030425026352721085.4906329598%
18540810731520001308276133167003085.8280601003%
8528772936499200061488978258849141086.1295907364%
44349619269795840003258915847719004473086.3912965716%
257227791764815872000192276035015421263907086.6219525619%
1543366750588895232000011728838135940697098327086.8412648150%
1018622055388670853120000785832155108026705587909087.0376638476%
7130354387720695971840000055794083012669896096741539087.2202319624%


こんな表が出来上がる。

いくらでも増やしていけるが、どこまで現実的かは、それぞれの判断に委ねることにする。

この表の規則性が解ると面白いかもしれません。
それこそ、この表を作らせる課題とかもいいかもしれません。
15行までならば、64ビットで計算出来ますね。
もっとやるなばら、多倍長演算を実装するとかしないとね。


ではでは


Viewing all articles
Browse latest Browse all 5376

Trending Articles