我试图为Project Euler的问题14编写一个解决方案。我的最快 - 不是下面的那个 - 在58秒左右跑了。我发现使用谷歌的最快速度看起来或多或少是这样的:
%% ets:delete(collatz) (from shell) deletes the table.
-module(euler) .
-export([problem_14/1]) .
collatz(X) ->
case ets:lookup(collatz, X) of
[{X, Val}] -> Val ;
[] -> case X rem 2 == 0 of
true ->
ets:insert(collatz, {X, Val = 1+collatz(X div 2)} ) ,
Val ;
false ->
ets:insert(collatz, {X, Val = 1+collatz(3*X+1)} ) ,
Val
end
end .
%% takes 10 seconds for N=1000000 on my netbook after "ets:delete(collatz)".
problem_14(N) ->
case ets:info(collatz) of
undefined ->
ets:new(collatz, [public, named_table]) ,
ets:insert(collatz,{1,1}) ;
_ -> ok
end ,
lists:max([ {collatz(X), X} || X <- lists:seq(1,N) ]) .
但是空表还需要10.5秒。我发现C ++中最快的解决方案只花了0.18秒,快了58倍。所以我想即使Erlang不是为那些东西制作的,也可以写出更好的代码。有没有人知道我可以尝试获得一些速度?
答案 0 :(得分:1)
我加快了你的代码:指定ets为ordered_set
,使用按位运算并实现尾递归函数max_size_index
,而不是将所有结果收集到列表中,然后迭代它找到最大值(如我们的代码所示)。
-module(collatz).
-compile(export_all).
size(1, _) ->
1;
size(N, Hashset) ->
case ets:lookup(Hashset, N) of
[{N, Size}] ->
Size;
[] ->
Size = 1 + size( next(N), Hashset ),
ets:insert(Hashset, {N, Size}),
Size
end.
next(N) when N band 1 == 0 ->
N bsr 1;
next(N) ->
(N bsl 1)+N+1.
max_size_index(1, _Hashset, {Index, MaxSize}) ->
{Index, MaxSize};
max_size_index(N, Hashset, {Index, MaxSize}) ->
CurrSize = size(N, Hashset),
case CurrSize > MaxSize of
true ->
max_size_index(N-1, Hashset, {N, CurrSize});
false ->
max_size_index(N-1, Hashset, {Index, MaxSize})
end.
problem_14(N) ->
Hashset = ets:new(collatz_count, [public, ordered_set]),
max_size_index(N, Hashset, {1,1}).
在shell中测试 - 您的模块euler
和我的模块collatz
()
1> c(euler).
{ok,euler}
2>
2> timer:tc(euler, problem_14, [1000000]).
{4039838,{525,837799}}
3>
3> c(collatz).
{ok,collatz}
4>
4> timer:tc(collatz, problem_14, [1000000]).
{2824109,{837799,525}}
加速的最后一个提示 - 大间隔可以分成较小的,并且每个小间隔的并行生成计算(在其他节点上)。
答案 1 :(得分:0)
通常,原始CPU绑定操作不是Erlang的强项。正如您所注意到的,问题是数据被复制到ETS表和从ETS表复制。中央ETS表还有一个优点,它还可以锁定:原子更新。因此,如果需要,您可以轻松获得更多内核来解决问题。但是,你不会接近C ++或C解决方案的速度。
你遇到的这类问题的另一个问题是可变性。 Erlang在其(顺序)核心中具有(几乎)纯函数语言。所以你不能希望用一个短暂的哈希表或一个数组来打败C ++解决方案,它可以存储它运行的百万个条目。您可以尝试array
模块,但我怀疑它会更快。