[erlang-questions] speeding up 3N+1
June Kim
juneaftn@REDACTED
Sat Apr 7 15:18:59 CEST 2007
Hello,
First of all, please keep in mind that I am a newbie in Erlang. (sorry
if the codes annoy you)
Please have a look at this famous problem. http://acm.uva.es/p/v1/100.html
The input number can be upto 1,000,000. (let's just suppose 1 million
is included, even though the problem states the maximal input is less
than 1 million) Let's see the worst case(when the start/end pair is
{1, 1000000}) time performance of the program.
Following is a trial at solving this problem:
-module(tnp1_process_dict).
-compile(export_all).
cycle(1) ->
1;
cycle(N) ->
case get(N) of
undefined ->
SN = if
N rem 2 =:= 0 ->
1 + cycle(N div 2);
true ->
2 + cycle((3 * N + 1) div 2)
end,
put(N, SN),
SN;
Cached ->
Cached
end.
max(A, B) ->
lists:max(lists:map(fun cycle/1, lists:seq(A, B))).
Actually, it's from a friend of mine, who is also in the same Erlang
community(we are all just novices though) with me. It's quite
effiecient.
1> timer:tc(tnp1_process_dict,max,[1,1000000]).
{2547000,525}
Less than 3 seconds on my sluggish machine. Good.
However, I didn't quite like the solution. It uses the process
dictionary. From reading Erlang books and manuals, I thought the
process dictionary should be the last resort for this kind of usage. I
thought I could deal the problem without using the process dictionary,
without trading off the speed.
Following is my trial:
-module(tnp1_functional).
-compile(export_all).
newCache()->
dict:from_list([{1,1}]).
store(K,V,Cache)->
dict:store(K,V,Cache).
find(K,Cache)->
dict:find(K,Cache).
nn(N) when N rem 2 =:= 0 ->
N div 2;
nn(N) ->
3*N+1.
update([],_,Cache)->
Cache;
update([H|ToStore],V,Cache)->
Cache2=store(H,V+1,Cache),
update(ToStore,V+1,Cache2).
cl(N,Cnt,Cache,ToStore)->
case find(N,Cache) of
{ok,V} ->
Cache2=update(ToStore,V,Cache),
{Cnt+V,Cache2};
error ->
cl(nn(N),Cnt+1,Cache,[N|ToStore])
end.
maxcl(From,To,Cache,Max) when From>To ->
{Max,Cache};
maxcl(From,To,Cache,Max)->
{Cl,Cache2}=cl(From,0,Cache,[]),
maxcl(From+1,To,Cache2,lists:max([Cl,Max])).
maxcl(From,To)->
Cache=newCache(),
maxcl(From,To,Cache,1).
max(From,To)->
{V,_}=maxcl(From,To),
V.
It's much longer. And much slower; I'd say excruciatingly.
1> timer:tc(tnp1_functional,max,[1,100000]).
{7953000,351}
See? It's 100,000, not one million, even. When I ran it with one
million, it didn't end at least in a couple of minutes.
Maybe my choice of using dict is wrong? Could ets be substantially
better? Or my approach totally wrong? I don't know yet. (I'll
experiment with other data structures and approaches, though)
Okay, that's it. I would appreciate any suggestions for improvement.
June
More information about the erlang-questions
mailing list