Simple Faster
Case文の高速化
ソースのみspeed2.lzh(8.39kbyte)
仮想コンピュータ、マクロ、中間コードインタプリタなどの高速化
case文とif else、procedure配列のうちどれが一番速いか気になったので
テストをしてみました。
プログラムの説明
“計算”と書かれたボタンを押すと、
@:ランダムに中間コードが生成されます。
A:その中間コードに基づいて、Case文の場合procedure配列の場合
それぞれについて計算が行われ、それぞれの計算にかかった時間が表示されます。
B:@〜Aが4回ずつ行われ、計算の結果と高速化率が表示されます。
(高速化率=(Case文の場合−procedure配列の場合)/Case文の場合)
中間コードはCase文の場合procedure配列の場合で同じものが生成されるため
実行結果はそれぞれの回数では同じ値になります。
Case文の部分
宣言:
var
ari:array[1..500000] of integer;{命令を格納するところ}
xx:integer;{計算値}
i:integer;{制御変数}
初期化の部分:
for i:=1 to 500000 do
begin
ari[i]:= random(8);
end;
実行部分:
xx:=0;
for i:=1 to 500000 do
begin
case ari[i] of
0:
begin
xx:=xx+1;
end;
1:
begin
xx:=xx-1;
end;
2:
begin
xx:=xx div 2;
end;
3:
begin
xx:=xx * 2;
end;
4:
begin
xx:=xx+1;
end;
5:
begin
xx:=xx-1;
end;
6:
begin
xx:=xx div 2;
end;
7:
begin
xx:=xx * 2;
end;
end;
procedure配列の部分
宣言:
type
procedure aa;
procedure cc;
procedure bb;
procedure ee;
procedure ff;
procedure gg;
procedure hh;
procedure ii;
var
arp:array[1..500000] of procedure;{命令を格納するところ}
i:integer;{制御変数}
xx:integer;{計算値}
procedure aa;
begin
xx:=xx+1;
end;
procedure cc;
begin
xx:=xx-1;
end;
procedure bb;
begin
xx:=xx div 2;
end;
procedure ee;
begin
xx:=xx * 2;
end;
procedure ff;
begin
xx:=xx+1;
end;
procedure gg;
begin
xx:=xx-1;
end;
procedure hh;
begin
xx:=xx div 2;
end;
procedure ii;
begin
xx:=xx * 2;
end;
初期化の部分:
for i:=1 to 500000 do
begin
case random(8) of
0:
begin
arp[i]:=aa;
end;
1:
begin
arp[i]:=cc;
end;
2:
begin
arp[i]:=bb;
end;
3:
begin
arp[i]:=ee;
end;
4:
begin
arp[i]:=ff;
end;
5:
begin
arp[i]:=gg;
end;
6:
begin
arp[i]:=hh;
end;
7:
begin
arp[i]:=ii;
end;
end;
実行部分:
for i:=1 to 500000 do
begin
arp[i];
end;
if else文の部分
宣言:
var
ari:array[1..500000] of integer;{命令を格納するところ}
xx:integer;{計算値}
i:integer;{制御変数}
初期化の部分:
for i:=1 to 500000 do
begin
ari[i]:= random(8);
end;
実行部分:
xx:=0;
for i:=1 to 500000 do
begin
if ari[i]=0 then
begin
xx:=xx+1;
end
else if ari[i]=1 then
begin
xx:=xx-1;
end
else if ari[i]=2 then
begin
xx:=xx div 2;
end
else if ari[i]=3 then
begin
xx:=xx * 2;
end
else if ari[i]=4 then
begin
xx:=xx+1;
end
else if ari[i]=5 then
begin
xx:=xx-1;
end
else if ari[i]=6 then
begin
xx:=xx div 2;
end
else if ari[i]=7 then
begin
xx:=xx * 2;
end;
end;
これらは、それぞれ分岐数が8の場合ですがプログラムでは
4、16、32、64の場合についても出来ます。
Case文は、分岐数が少ないうち(8、16)はif else文よりも
遅いという結果が出ましたが、case文は分岐数が増えるにつれて
速度が上がっていき32、64ではif elseよりも速いという結果が出ました。
4は少しだけ遅かったです。
Procedure配列は分岐数に影響を受けず常に同じ速度で、一番速かったです。
Case文はアセンブラコードを見ると、まず範囲の最大値を超えているかどうか
判定してから、アドレスの配列からアドレスをえて、ジャンプするということ
になっていました。If elseはそのまんま、procedure配列はただcallするだけ
でした。
実験結果
分岐数4
case文 672.5 (ms)
procedure配列 597.5
if else文 652.75
分岐数8
case文 1927.25(ms)
procedure配列 599.75
if else文 770.25
分岐数16
case文 1507
procedure配列 600
if else文 1007.5
分岐数32
case文 857.5
procedure配列 598
if else文 1464.25
分岐数64
case文 787.75
procedure配列 597
if else文 2377.5
・環境
PC-9821Xa16
CPU Pentium166Mhz
secondcache 245kbyte
mainmemory 32Mbyte
遅くなる原因は、よくはわかりませんが、分岐予測を失敗してそのために
遅くなっているのではと、推測しています。
著作権について
このソースをプログラムに組み込んで使用したり、
改変したりすることは営利目的、個人目的にかかわらず自由です。
上へ
目次へ