编辑:eratosthenes筛选erlang中最高的主要因素

时间:2013-02-26 14:24:09

标签: erlang heap

我编辑了程序以便它可以工作(数字很小)但是我不明白如何按照建议实现累加器。原因是因为P在整个过程中发生了变化,因此我不知道在哪个粒度上我应该拆分母列表。 eratophenes的Sieve只能生成较小的素数,所以也许我应该选择不同的算法来使用。任何人都可以推荐一个合适的算法来计算600851475143的最高素因子?请不要给我代码我更喜欢维基百科的那种性质的文章。

    -module(sieve).
    -export([find/2,mark/2,primes/1]).

    primes(N) -> [2|lists:reverse(primes(lists:seq(2,N),2,[]))].

    primes(_,bound_reached,[_|T]) -> T;
    primes(L,P,Primes) -> NewList = mark(L,P),
        NewP = find(NewList,P),
        primes(NewList,NewP,[NewP|Primes]).

    find([],_) -> bound_reached;
    find([H|_],P) when H > P -> H;
    find([_|T],P) -> find(T,P). 


    mark(L,P) -> lists:reverse(mark(L,P,2,[])).

    mark([],_,_,NewList) -> NewList;
    mark([_|T],P,Counter,NewList) when Counter rem P =:= 0 -> mark(T,P,Counter+1,[P|NewList]);
    mark([H|T],P,Counter,NewList) -> mark(T,P,Counter+1,[H|NewList]). 

我发现写这篇文章非常困难,我知道有一些不太优雅的事情,例如我有2个硬编码作为素数的方式。所以我会感谢任何C& C以及如何解决这些问题的建议。我看看其他实现,我绝对不知道作者是如何以这种方式思考的,而是我想要掌握的东西。

新:我已经知道我可以忘记列表,直到找到最新的素数,但我不知道我应该如何产生一个结束(微妙的幽默)。我认为我可能会使用像列表一样的东西:seq(P,something)和计数器能够处理它,因为我使用modulo而不是每次都将它重置为0。我只做了AS级数学,所以我不知道这是什么。

New2.0:我甚至不能这样做吗?因为我必须从整个列表中删除2的倍数。我认为除非我将数据缓存到硬盘驱动器,否则这个算法不起作用,所以我回来寻找更好的算法。

New2.5:我现在正在考虑编写一个只使用计数器的算法,并保留一个素数列表,这些素数是与先前生成的素数不均匀的数字,这是一个很好的方法吗?

New3.0:这是我写的新算法,我认为它应该可以工作但是我得到以下错误“sieve2.erl:7:调用本地/导入函数is_prime / 2是非法的守卫”我认为这只是我不明白的erlang的一个方面。但是我不知道我怎么能找到关于它的材料。 [我故意不使用更高阶函数等,因为我只在readnyousomeerlang.org中读取了递归的位]

    -module(sieve2).
    -export([primes/1]).

    primes(N) -> primes(2,N,[2]).

    primes(Counter,Max,Primes) when Counter =:= Max -> Primes;
    primes(Counter,Max,Primes) when is_prime(Counter,Primes) -> primes(Counter+1,Max,[Counter|Primes]);
    primes(Counter,Max,Primes) -> primes(Counter+1,Max,Primes).

    is_prime(X, []) -> true;
    is_prime(X,[H|T]) when X rem H =:= 0 -> false;
    is_prime(X,[H|T]) -> prime(X,T).

编辑3.5:第二个算法没有崩溃,但运行速度太慢,我认为我应该重新实现第一个但是这次忘记了最近发现的素数之前的数字,有人知道我可以用什么作为终点?在查看其他解决方案之后,人们似乎有时会设置一个限制条件,即200万(这是我真的不想做的事情。其他人使用“懒惰”实现,这就是我认为我正在做的事情。

3 个答案:

答案 0 :(得分:4)

此:

lists:seq(2,N div 2)

分配一个列表,正如efficiency guide所说,列表每个元素至少需要两个字的内存。 (一个字是4或8个字节,具体取决于您是否有32位或64位Erlang虚拟机。)因此,如果N为600851475143,如果我正确计数,则需要48 TB的内存。 (与Haskell不同,Erlang不做懒惰的评估。)

因此,您需要使用累加器来实现此功能,类似于您在Counter函数中对mark所做的操作。对于递归函数的停止条件,您不会检查列表是否为空,而是检查累加器是否达到最大值。

答案 1 :(得分:1)

顺便说一下,您不需要测试最多N / 2的所有数字。只需测试sqrt(N)即可。

Here I wrote a version that takes 20 seconds to find the answer on my machine.它使用了一些延迟的素数列表并折叠它们。这很有趣,因为我很久以前使用Haskell解决了一些项目问题,并且在Erlang上使用相同的方法有点奇怪。

答案 2 :(得分:0)

在您的update3上:

primes(Counter,Max,Primes) when Counter =:= Max -> Primes;
primes(Counter,Max,Primes) when is_prime(Counter,Primes) -> primes(Counter+1,Max,[Counter|Primes]);
primes(Counter,Max,Primes) -> primes(Counter+1,Max,Primes).

您不能像在Haskell中那样使用自己定义的函数作为保护子句。你必须重写它以在case语句中使用它:

primes(Counter,Max,Primes) when Counter =:= Max ->
    Primes;
primes(Counter,Max,Primes) ->
    case is_prime(Counter,Primes) of
        true ->
            primes(Counter+1,Max,[Counter|Primes]);
        _ ->
            primes(Counter+1,Max,Primes)
    end.