【发布时间】:2014-03-26 13:44:13
【问题描述】:
我正在尝试回答以下欧拉问题 (#10):
10 以下的素数之和为 2 + 3 + 5 + 7 = 17。
求两百万以下的所有质数之和。
我的程序运行正常,但是我发现计算它需要 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,作为这种迭代器的重点。流是为了能够以无限的价格做到这一点,我不确定埃拉托色尼筛法是否适用于无限的数字,我认为这不是微不足道的。
【问题讨论】:
-
这看起来像是 Code Review(另一个 Stack Q&A 论坛)的问题。
-
仅供参考,编写一个好的 Eratoshenes 筛选算法是一个明智的想法,因为它非常适合生成高达 10^10 左右的素数列表。也可以修改它以快速分解所有素数高达 10^10。两者在后来的 Project Euler 问题中都很有用。
标签: java performance iterator primes java-8