Не совсем отвечаю на вопрос, но так как я провел несколько раз, сравнивая различные комбинации ...
Вы можете получить лучшую производительность, если будете использовать Iterator
, ArrayBuffer
и избегать takeWhile
во внутреннем цикле, чтобы минимизировать распределение памяти.
def primes2(): Stream[Int] = {
def sieve(p: Int, ps: ArrayBuffer[Int]): Stream[Int] = {
def hasNoDivisor(prime_? :Int, j: Int = 0): Boolean = {
val n = ps(j)
if (n*n > prime_?) true
else if (prime_? % n == 0) false else hasNoDivisor(prime_?, j+1)
}
p #:: {
val nextprime = Iterator.from(ps.last + 2, 2).find(hasNoDivisor(_)).get
sieve(nextprime, ps += nextprime)
}
}
sieve(3, ArrayBuffer(3))
}
Вот версия с Iterator
вместо Stream
, она быстрее, и вы всегда можете использовать primes3().toStream
, чтобы получить поток, если это необходимо.
def primes3() = List(2,3).iterator ++ new Iterator[Int] {
val ps = ArrayBuffer[Int](3)
def hasNoDivisor(prime_? :Int, j: Int = 0): Boolean = {
val n = ps(j)
if (n*n > prime_?) true
else if (prime_? % n == 0) false else hasNoDivisor(prime_?, j+1)
}
def hasNext = true
def next() = {
val nextprime = Iterator.from(ps.last + 2, 2).find(hasNoDivisor(_)).get
ps += nextprime
nextprime
}
}
Результаты:
primes : warming...
primes : running...
primes : elapsed: 3.711
res39: Int = 283145
primes2: warming...
primes2: running...
primes2: elapsed: 1.039
res40: Int = 283145
primes3: warming...
primes3: running...
primes3: elapsed: 0.530
res41: Int = 283146
Я также пытался заменить from
, find
и hasNoDivisor
на пару while
петель, и это было быстрее, но менее понятно.