除了算法问题之外,您的瓶颈很可能是写入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
此外,Thomas 的回答对这个问题更加详细System.out.print
,并且还提供了连接大量字符串的适当方法。
算法问题:
如果您使用 Erastothenes 筛法,那么在搜索下一个质数时,您已经找到了所有较小的质数。所以你应该存储它们,而不是检查每个大于 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;
}
为了进一步调整这个,你也可以存储素数的平方——假设你有足够的内存......