我正在学习Erlang.作为练习,我选择了生成素数的Eratosthenes算法.这是我的代码:
-module(seed2). -export([get/1]). get(N) -> WorkList = lists:duplicate(N, empty), get(2, N, WorkList, []). get(thats_the_end, _N, _WorkList, ResultList) -> lists:reverse(ResultList); get(CurrentPrime, N, WorkList, ResultList) -> ModWorkList = markAsPrime(CurrentPrime, N, WorkList), NextPrime = findNextPrime(CurrentPrime + 1, N, WorkList), get(NextPrime, N, ModWorkList, [CurrentPrime|ResultList]). markAsPrime(CurrentPrime, N, WorkList) when CurrentPrime =< N -> WorkListMod = replace(CurrentPrime, WorkList, prime), markAllMultiples(CurrentPrime, N, 2*CurrentPrime, WorkListMod). markAllMultiples(_ThePrime, N, TheCurentMark, WorkList) when TheCurentMark > N -> WorkList; markAllMultiples(ThePrime, N, TheCurrentMark, WorkList) -> WorkListMod = replace(TheCurrentMark, WorkList, marked), markAllMultiples(ThePrime, N, TheCurrentMark + ThePrime, WorkListMod). findNextPrime(Iterator, N, _WorkList) when Iterator > N -> thats_the_end; findNextPrime(Iterator, N, WorkList) -> I = lists:nth(Iterator, WorkList), if I =:= empty -> Iterator; true -> findNextPrime(Iterator + 1, N, WorkList) end. replace(N, L, New)-> {L1, [_H|L2]} = lists:split(N - 1, L), lists:append(L1, [New|L2]).
这段代码实际上工作:).问题是我觉得这不是最好的实现.
我的问题是实施"Eratosthenes筛"的"erlangish"方式是什么
编辑:好的,安德烈亚斯解决方案非常好,但速度很慢.任何想法如何改善?
这是一个简单(但不是非常快)的筛选实现:
-module(primes). -export([sieve/1]). -include_lib("eunit/include/eunit.hrl"). sieve([]) -> []; sieve([H|T]) -> List = lists:filter(fun(N) -> N rem H /= 0 end, T), [H|sieve(List)]; sieve(N) -> sieve(lists:seq(2,N)).
这是我的筛选实现,它使用列表推导并尝试尾递归.我在最后反转列表,以便对素数进行排序:
primes(Prime, Max, Primes,Integers) when Prime > Max -> lists:reverse([Prime|Primes]) ++ Integers; primes(Prime, Max, Primes, Integers) -> [NewPrime|NewIntegers] = [ X || X <- Integers, X rem Prime =/= 0 ], primes(NewPrime, Max, [Prime|Primes], NewIntegers). primes(N) -> primes(2, round(math:sqrt(N)), [], lists:seq(3,N,2)). % skip odds
在我的2ghz mac上计算大约2 mil的质量需要大约2.8 ms.