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


     遅くなる原因は、よくはわかりませんが、分岐予測を失敗してそのために
    遅くなっているのではと、推測しています。

  • 著作権について
  • このソースをプログラムに組み込んで使用したり、
    改変したりすることは営利目的、個人目的にかかわらず自由です。

    上へ
    目次へ


    GigaHit