上記で提案したアルゴリズムのパフォーマンスに関するより正確な情報を取得しようとしました。Stemm の非常に興味深いソリューションを読んで、tc:timer/3 関数を使用することにしました。大きな欺瞞:o)。私のラップトップでは、時間の精度が非常に悪くなりました。そこで、自宅の PC を使用するために、corei5 (2 コア * 2 スレッド) + 2Gb DDR3 + Windows XP 32 ビットを残すことにしました: Phantom (6 コア) + 8Gb + Linux 64 ビット。
tc:timer が期待どおりに動作するようになり、100 000 000 の整数のリストを操作できるようになりました。各ステップで長さ関数を呼び出すために多くの時間を失っていることがわかったので、それを避けるためにコードを少しリファクタリングしました。
-module(finder).
-export([test/2,find/2,insert/2,remove/2,new/0]).
%% interface
new() -> {0,[]}.
insert(V,{S,L}) ->
{R,P} = locate(V,L,S,undefined,-1),
insert(V,R,P,L,S).
find(V,{S,L}) ->
locate(V,L,S,undefined,-1).
remove(V,{S,L}) ->
{R,P} = locate(V,L,S,undefined,-1),
remove(V,R,P,L,S).
remove(_,_,-1,L,S) -> {S,L};
remove(V,V,P,L,S) ->
{L1,[V|L2]} = lists:split(P,L),
{S-1,L1 ++ L2};
remove(_,_,_,L,S) ->{S,L}.
%% local
insert(V,V,_,L,S) -> {S,L};
insert(V,_,-1,L,S) -> {S+1,[V|L]};
insert(V,_,P,L,S) ->
{L1,L2} = lists:split(P+1,L),
{S+1,L1 ++ [V] ++ L2}.
locate(_,[],_,R,P) -> {R,P};
locate (V,L,S,R,P) ->
S1 = S div 2,
S2 = S - S1 -1,
{L1,[M|L2]} = lists:split(S1, L),
locate(V,R,P,S1+1,L1,S1,M,L2,S2).
locate(V,_,P,Le,_,_,V,_,_) -> {V,P+Le};
locate(V,_,P,Le,_,_,M,L2,S2) when V > M -> locate(V,L2,S2,M,P+Le);
locate(V,R,P,_,L1,S1,_,_,_) -> locate(V,L1,S1,R,P).
%% test
test(Max,Iter) ->
{A,B,C} = erlang:now(),
random:seed(A,B,C),
L = {Max+1,lists:seq(0,100*Max,100)},
Ins = test_insert(L,Iter,[]),
io:format("insert:~n~s~n",[stat(Ins,Iter)]),
Fin = test_find(L,Iter,[]),
io:format("find:~n ~s~n",[stat(Fin,Iter)]).
test_insert(_L,0,Res) -> Res;
test_insert(L,I,Res) ->
V = random:uniform(1000000000),
{T,_} = timer:tc(finder,insert,[V,L]),
test_insert(L,I-1,[T|Res]).
test_find(_L,0,Res) -> Res;
test_find(L,I,Res) ->
V = random:uniform(1000000000),
{T,_} = timer:tc(finder,find,[V,L]),
test_find(L,I-1,[T|Res]).
stat(L,N) ->
Aver = lists:sum(L)/N,
{Min,Max,Var} = lists:foldl(fun (X,{Mi,Ma,Va}) -> {min(X,Mi),max(X,Ma),Va+(X-Aver)*(X-Aver)} end, {999999999999999999999999999,0,0}, L),
Sig = math:sqrt(Var/N),
io_lib:format(" average: ~p,~n minimum: ~p,~n maximum: ~p,~n sigma : ~p.~n",[Aver,Min,Max,Sig]).
ここにいくつかの結果があります。
1> finder:test(1000,10)。入れる:
平均: 266.7,
最小: 216,
最大: 324,
シグマ : 36.98121144581393。
探す:
average: 136.1,
最小: 105,
最大: 162,
シグマ : 15.378231367748375。
わかった
2> finder:test(100000,10).
入れる:
平均: 10096.5,
最小: 9541、
最大: 12222,
シグマ : 762.5642595873478.
探す:
average: 5077.4,
最小: 4666、
最大: 6937,
シグマ : 627.126494417195.
わかった
3> finder:test(1000000,10).
入れる:
平均: 109871.1,
最小: 94747、
最大: 139916,
シグマ : 13852.211285206417.
検索: 平均: 40428.0,
最小: 31297、
最大: 56965,
シグマ : 7797.425562325042。
わかった
4> ファインダー: テスト (100000000,10).
入れる:
平均: 8067547.8,
最小: 6265625、
最大: 16590349,
シグマ : 3199868.809140206。
探す:
average: 8484876.4,
最小: 5158504、
最大: 15950944、
シグマ : 4044848.707872872.
わかった
100 000 000 リストでは遅く、マルチプロセス ソリューションはこの二分法アルゴリズムでは役に立ちません。とにかくマルチコアを使用することができます。
パスカル。