LoginSignup
2
0

More than 5 years have passed since last update.

[C#]エラトステネスのふるいで素数を求める

Last updated at Posted at 2018-04-22

素数を求める

数学ガールの秘密ノート「整数で遊ぼう」を読んでたところ、
エラトステネスのふるいで200以下の素数を全て求める問題がありました。

※エラトステネスのふるいはWikipediaを参照

プログラムで書いてみよう!

手書きで表を書いて、消し込みをして、素数を求めたのではありますが、
じゃ、同じ手順となるようにプログラムを書いてみよう!と思いました。

書いてみた(修正後)

※albireoさんに頂いた指摘と、「抽出したメソッド、素数求めるのと、ディクショナリの更新をどっちもしてるのってどうなの?」との指摘から修正しました。

Form1.cs
private void button1_Click(object sender, EventArgs e)
{
    //エラトステネスのふるい
    //範囲の指定
    var from = 1;
    var to = 200;
    var range = Enumerable.Range(from, to);

    //範囲内全数のリストを作る。
    //1番目は数字、2番目は0:判定前、1:消した(素数でない)、2:○をつけた(素数)
    Dictionary<int, int> dic = new Dictionary<int, int>();
    range.ToList().ForEach(i => dic.Add(i, 0));

    //1を消す→単数
    dic[1] = 1;

    while (true)
    {
        //素数判定+消し込み
        int primeNumber = dic.Where(kvp => kvp.Value == 0).Min(kvp => kvp.Key);

        //素数と設定
        dic[primeNumber] = 2;

        //残っている数字のうち素数の倍数のみ抽出
        var targets = dic.Where(kvp => kvp.Value == 0 && kvp.Key % primeNumber == 0).Select(kvp => kvp.Key).ToList();

        //素数の倍数を消し込む
        targets.ForEach(num => dic[num] = 1);

        //素数の2乗が範囲の最後より大きい場合、そこで終了
        if (primeNumber * primeNumber > to) { break; }
    }
    //残っている数字を抽出。
    var remainNumbers = dic.Where(kvp => kvp.Value == 0).Select(v => v.Key).ToList();
    //残っている数字は全部素数!
    remainNumbers.ForEach(v => dic[v] = 2);

    //素数のみ出力
    var primeNumbers = dic.Where(kvp => kvp.Value == 2).Select(kvp => kvp.Key).OrderBy(v => v).ToList();
    Console.WriteLine(string.Join(",", primeNumbers));
}

出力結果

以下の通り。手書きで求めたものと合ってる。OK!

2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199

書いてみた(修正前)

Form1.cs
private void button1_Click(object sender, EventArgs e)
{
    //エラトステネスのふるい
    //範囲の指定
    var from = 1;
    var to = 200;
    var range = Enumerable.Range(from, to);

    //範囲内全数のリストを作る。
    //1番目は数字、2番目は0:判定前、1:消した(素数でない)、2:○をつけた(素数)
    Dictionary<int, int> dic = new Dictionary<int, int>();
    range.ToList().ForEach(i => dic.Add(i, 0));

    //1を消す→単数
    dic[1] = 1;

    while (true)
    {
        //素数判定+消し込み
        int primeNumber = SelectPrimeNumber(dic);

        //素数の2乗が範囲の最後より大きい場合、そこで終了
        if (primeNumber * primeNumber > to) { break; }
    }

    //残っている数字を抽出。
    var remainNumbers = dic.Where(v => v.Value == 0).Select(v => v.Key).ToList();
    //残っている数字は全部素数!
    remainNumbers.ForEach(v => dic[v] = 2);

    //素数のみ出力
    var primeNumbers = dic.Where(v => v.Value == 2).Select(v => v.Key).OrderBy(v => v).ToList();
    Console.WriteLine(string.Join(",", primeNumbers));
}


private int SelectPrimeNumber(Dictionary<int, int> dic)
{
    //消えてないうちの最小の値を求める
    var primeNumber = dic.Where(v => v.Value == 0).Min(v => v.Key);

    //素数と設定
    dic[primeNumber] = 2;

    //残っている数字のみ抽出
    var targets = dic.Where(v => v.Value == 0).Select(v => v.Key).ToList();

    //素数の倍数を消し込む
    targets.ForEach(key => { if (key % primeNumber == 0) { dic[key] = 1; } });

    //素数を返す
    return primeNumber;
}
2
0
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0