我正在尝试回答以下欧拉问题(#10):
低于10的素数之和为2 + 3 + 5 + 7 = 17.
找出200万以下所有素数的总和。
我的程序运行正常,但是我发现计算它需要100秒,使用以下代码,以new Problem10().run()
为起点:
public class Problem10 extends Problem<Long> {
@Override
public void run() {
result = Iterators.finiteLongStream(new PrimeGenerator(), i -> i <= 2_000_000)
.sum();
}
@Override
public String getName() {
return "Problem 10";
}
}
public abstract class Iterators {
///
public static PrimitiveIterator.OfLong finiteLongIterator(final PrimitiveIterator.OfLong iterator, final LongPredicate predicate) {
return new PrimitiveIterator.OfLong() {
private long next;
@Override
public boolean hasNext() {
if (!iterator.hasNext()) {
return false;
}
next = iterator.nextLong();
return predicate.test(next);
}
@Override
public long nextLong() {
return next;
}
};
}
public static LongStream finiteLongStream(final PrimitiveIterator.OfLong iterator, final LongPredicate predicate) {
return Iterators.longStream(Iterators.finiteLongIterator(iterator, predicate));
}
public static LongStream longStream(final PrimitiveIterator.OfLong iterator) {
return StreamSupport.longStream(
Spliterators.spliteratorUnknownSize(iterator, 0), false
);
}
///
}
public class PrimeGenerator implements PrimitiveIterator.OfLong {
private final static LongNode HEAD_NODE = new LongNode(2);
private LongNode lastNode = HEAD_NODE;
private long current = 2;
@Override
public boolean hasNext() {
return true;
}
@Override
public long nextLong() {
if (lastNode.value == current) {
if (lastNode.next != null) {
long old = lastNode.value;
lastNode = lastNode.next;
current = lastNode.value;
return old;
}
return current++;
}
while (true) {
if (isPrime(current)) {
appendNode(current);
return current++;
}
current++;
}
}
private boolean isPrime(final long number) {
LongNode prime = HEAD_NODE;
while (prime != null && prime.value <= number) {
if (number % prime.value == 0) {
return false;
}
prime = prime.next;
}
return true;
}
private void appendNode(final long value) {
LongNode newNode = new LongNode(value);
couple(lastNode, newNode);
lastNode = newNode;
}
private void couple(final LongNode first, final LongNode second) {
first.next = second;
second.previous = first;
}
private static class LongNode {
public final long value;
public LongNode previous;
public LongNode next;
public LongNode(final long value) {
this.value = value;
}
}
}
我该如何优化?如果可能的话,首先根据我当前的代码提出建议,然后提出完全不同的算法。
编辑,我也想避免使用有限的Sieve of Eratosthenes,作为这样一个迭代器的重点。流是为了能够以无限的价格来做到这一点,我不确定自己的Eratosthenes方法是否适用于无数的数字,我认为这不是一件容易的事。
答案 0 :(得分:1)
如果你观察到只需要考虑小于数字平方根的素数因子,那么方法isPrime()中的迭代次数可以减少。
所以目前的情况是:
while (prime != null && prime.value <= number)
可以改为:
while (prime != null && prime.value <= square_root(number) )
可能还有其他可能性来优化您的代码,但这需要详细检查您的代码。
答案 1 :(得分:0)
以下是一些想法(不是代码,因为这似乎是家庭作业/项目问题):
不要使用平方根功能。而是计算最大素数的指数,你必须检查为素数[p] *素数[p],只要它大于你的试验值。例如,在你的代码中使用这样的东西(其中ps是你正在检查的第一个素数的索引,而iMax在进入循环之前是素数[ps] * primes [ps]。为了提高效率,总是使用“当你可以时,可以减少计算量。
while (i > iMax) {
ps++; iMax = primes[ps]*primes[ps];
};