0

スペースで区切られた文字列内の部分文字列をカウントする関数がいくつかあります。

program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils,windows;

//s=string to search in
//t=string to search for
//cs=delimiters

function f0(const s,t:string;const cs:tsyscharset):integer;
var
  p,q:pchar;
  u:string;
begin
  result:=0;
  p:=pointer(s);
  if p<>nil then
    while p^<>#0 do
    begin
      while (p^<>#0) and charinset(p^,cs) do inc(p);
      q:=p;
      while (p^<>#0) and not charinset(p^,cs) do inc(p);
      if p>q then
      begin
        setstring(u,q,p-q);
        //writeln('[',u,']');
        if u=t then inc(result);
      end;
    end;
end;

function f1(const s,t:string;const cs:tsyscharset):integer;
var
  i,j,l:integer;
  u:string;
begin
  result:=0;
  l:=length(s);
  i:=1;
  while i<=l do
  begin
    while (i<=l) and charinset(s[i],cs) do inc(i);
    j:=i;
    while (i<=l) and not charinset(s[i],cs) do inc(i);
    if i>j then
    begin
      u:=copy(s,j,i-j);
      //writeln('[',u,']');
      if u=t then inc(result);
    end;
  end;
end;

function f2(const s,t:string;const cs:tsyscharset):integer;
var
  i,j,l:integer;
  u:string;
begin
  result:=0;
  l:=length(s);
  i:=1;
  while i<=l do
  begin
    while (i<=l) and charinset(s[i],cs) do inc(i);
    j:=i;
    while (i<=l) and not charinset(s[i],cs) do inc(i);
    if i>j then
    begin
      setlength(u,i-j);
      move(s[j],pointer(u)^,(i-j)*2);
      //writeln('[',u,']');
      if u=t then inc(result);
    end;
  end;
end;

type
  tfunc=function(const s,t:string;const cs:tsyscharset):integer;

const
  s='  de foo   de'+#13+' baz blah de  de blah'+#10+' asd de qwe rtz   un f'+#9+' t de ds w de  ';
  t='de';
  cs=[' ',#13,#10,#9];//CR,LF,TAB
  n=5000000;

procedure time(i:integer;f:tfunc);
var
  j,k:integer;
  start,finish,freq:int64;
begin
  QueryPerformanceCounter(start);
  for j := 1 to n do k:=f(s,t,cs);
  QueryPerformanceCounter(finish);
  QueryPerformanceFrequency(freq);
  Writeln(Format('f%u:%u:%.3fs',[i,k,(finish-start)/freq]));
end;

const
  funcs:array[0..2] of tfunc=(f0,f1,f2);
var
  i:integer;
begin
  setpriorityclass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  for i := low(funcs) to high(funcs) do time(i,funcs[i]);
  readln
end.

速度結果は、

f0:7:7,624s
f1:7:8,066s
f2:7:6,454s

私の最初の質問は、なぜ f2 は f0 より速いのですか?

2 番目の質問は、これをさらに最適化する方法を知っていますか (インライン アセンブラーなしで)。

IDE: Delphi XE2 (Unicode)

4

1 に答える 1