前回の[アルゴリズム]素数を求める~エラトステネスの篩~の改良版を作ってみた

前回作ったものは何も考えずにwikipediaさんに言われた通りそのままにやったのでやっぱり効率が悪かった。
しかも、ある数が素数かどうか調べるためにまたリストを走査しなきゃいけなかった。これは明らかに欠陥w

ってことでboolean配列にして添字の数が素数ならtrueとするようにした
こうするのが本当なんですよねきっとw


final int MAX = 1000000 + 1;
boolean[] primes = new boolean[MAX];
primes[2] = true;
for (int i = 3; i < MAX; i += 2) {
    primes[i] = true;
}
for (int i = 3; i * i < MAX; i += 2) {
    if (primes[i]) {
        for (int j = i * 2; j < MAX; j += i) {
            primes[j] = false;
       }
   }
}

やってることは前回と同じ
効率化のために2の倍数は最初から除外するようにした

前回のソースと今回のソースでどれだけ速度が違うかテストしてみました
100万までの素数を求めるまでの時間を計測
前回のと今回のを交互に実行、それぞれ合計11回繰り返し、一番遅かったものを除外
計10回の平均をとりました
これだけ繰り返してるとメモリの確保に時間がかかって大きな誤差が生まれるので
オブジェクト生成の時間は含めないことにしました

Test.java


import java.util.Iterator;
import java.util.LinkedList;
public class Test {
 public static void main(String[] args) {
  final int N = 10;
  long sum = 0, sum2 = 0;
  long time;
  long m = 0, m2 = 0;
  final int MAX = 1000000;
  System.out.println("\t前回\t改良版");
  for (int i = 1; i <= N+1; i++) {
   System.out.print(i + "回目\t");
   System.out.print(time = eratosthenes(MAX));
   m = Math.max(m, time);
   sum += time;
   System.out.print("\t");
   System.out.println(time = eratosthenes2(MAX));
   m2 = Math.max(m2, time);
   sum2 += time;
  }
  System.out.println("-------------------------");
  System.out.println("平均\t" + (sum-m)/N + "\t" + (sum2-m2)/N);
 }
 static long eratosthenes(int max) {
  LinkedList primes = new LinkedList();
  LinkedList numbers = new LinkedList();
  long time = System.currentTimeMillis();
  for (int i = 2; i <= max; i++) {
   numbers.add(i);
  }
  int prime;
  Iterator it;
  do {
   prime = numbers.getFirst();
   primes.add(prime);
   it = numbers.iterator();
   while (it.hasNext()) {
    if (it.next() % prime == 0)
     it.remove();
   }
  } while (numbers.getLast() > prime * prime);
  it = numbers.iterator();
  while (it.hasNext()) {
   primes.add(it.next());
  }
  return System.currentTimeMillis() - time;
 }
 static long eratosthenes2(int max) {
  int _max = max + 1;
  boolean[] primes = new boolean[_max];
  long time = System.currentTimeMillis();
  primes[2] = true;
  for (int i = 3; i < _max; i += 2) {
   primes[i] = true;
  }
  for (int i = 3; i * i < _max; i += 2) {
   if (primes[i]) {
    for (int j = i * 2; j < _max; j += i) {
     primes[j] = false;
    }
   }
  }
  return System.currentTimeMillis() - time;
 }
}

出力結果

前回	改良版
1回目	6309	20
2回目	6169	10
3回目	6209	10
4回目	6329	10
5回目	6349	10
6回目	6299	20
7回目	6339	10
8回目	6279	10
9回目	6299	20
10回目	6360	10
11回目	6449	10
-------------------------
平均	6294	12

違いすぎるw
前回のが効率悪すぎただけですねすいませんw

このエントリーを含むはてなブックマークはてなブックマーク - 素数を求める~エラトステネスの篩 2~ この記事をクリップ!Livedoorクリップ - 素数を求める~エラトステネスの篩 2~ BuzzurlにブックマークBuzzurlにブックマーク FC2ブックマークへ追加 Bookmark this on Delicious Digg This