アルゴリズムの問題は別として、ボトルネックはおそらくSystem.out
ストリームへの書き込みです。これは時間のかかる作業です。その部分をベンチマークループから除外する必要があると思います。これをすばやくテストするには、コメントアウトします(対応するif
ステートメントを使用)。
int iterations=100000;
long time = System.nanoTime();
for(int i = 3; i < 100000; i += 2) { //notice: always use curly brackets!!!
isPrime(i);
}
long endTime = System.nanoTime();
System.out.println("Time to go through " + iterations + " iterations: " + (endTime>time?endTime-time:endTime+time));
//notice: nanoTime might turn around, resulting in smaller (negative) endTime value
また、トーマスの答えはこの問題に関してはるかに詳細System.out.print
であり、多くの文字列を連結する適切なアプローチも提供します。
アルゴリズムの問題:
エラトステネスのふるいアプローチを使用している場合は、次の素数を検索するときに、すべての小さい素数をすでに見つけています。したがって、それらを保存する必要があります。5を超えるすべての奇数をチェックする代わりに、すでに持っているものだけをチェックする必要があります。
また、同時に、それらすべてをチェックする必要はありません。あなたの数の平方根以下であるものだけをチェックする必要があります。
//suppose we have a List<Integer> primeList (populated by previous execution loops)
// and Integer numberTested as the number under testing
for(int i=0; i<primeList.size();i++) {
if(numberTested%primeList.get(i)==0) {
//divider found, not prime
break;
}
if(primeList.get(i)>Math.sqrt(numberTested)) {
//still not found a divider -- we found a prime
primeList.add(numberTested);
break;
}
}
これの問題は何ですか?Math.sqrt
コストのかかる操作です。乗算よりもはるかにコストがかかります...したがって、数値の範囲が許せば(常にそれを念頭に置く必要があります!)、乗算を使用して比較をより迅速に行うことができます。
sqrt(a)>b === a*a>b
aとbの両方が正の整数であると仮定します。
Integer currentPrimeSquare = primeList.get(i)*primeList.get(i);
if(currentPrimeSquare>numberTested) {
//still not found a divider -- we found a prime
primeList.add(numberTested);
break;
}
これをさらに調整するために、十分なメモリがある場合は、素数の平方も保存できます。