Optymalizacja petli

0

1)  for k:=0 to length(matrix[i].bin)-4 do
 
2) h:=length(matrix[i].bin)-4
 for k:=0 to h do

Czy druga metoda jest szybsza czy tak samo wyjdzie ?

Czy za kazdym razem petla sprawdza warynek wyciagajac za kazdym razem dlugosc tablicy?

Czy znacie jakeis PDFy / artykuly o optymalizacji kodu ???

0

druga metoda jest szybsza. w pierwszej za każdym razem się będzie odwoływać do funkcji Length. Dlatego np. w pętli możesz wydłużyć tą tablicę i pętla będzie się wykonywać do nowo nadanej długości tablicy.

napisałem prosty programik do mierzenia czasu, oparty na tym wyżej podanym FAQu.
Z tą różnicą że mój program sprawdza długość działania zewnętrznego programu, a wynik zapisuje w pliku tekstowym.

kodzik:

program Timer;
{$APPTYPE CONSOLE}
uses Windows, SysUtils;

var
  Freq, TimeStart, TimeEnd : Int64;
  S : String;
  F : TextFile;
begin
  if QueryPerformanceFrequency(Freq) then
  begin

    If ParamStr(1) = '0' then
    begin
      AssignFile(F, '!czas.txt');
      Rewrite(F);
      QueryPerformanceCounter(TimeStart);
      WriteLn(F, TimeStart);
      CloseFile(F);
    end  else
    begin
      QueryPerformanceCounter(TimeEnd);
      AssignFile(F, '!czas.txt');
        Reset(F);
        ReadLn(F, TimeStart);
      CloseFile(F);
      AssignFile(F, '!czas.txt');
        rewrite(F);
        S:= 'Wykonanie zajęło: '+
           FloatToStr((TimeEnd-TimeStart)/Freq*1000)+ ' ms';
        WriteLn(F, S);
      CloseFile(F);
    end;
  end;
end.

i teraz jeszcze w pliku .BAT dać takie coś:

Timer.exe 0
Program_do_testu.exe
Timer.exe 1

//dop.
Z książek mogę ci polecić:

  • Algorytmy + struktury danych = programy - Niklaus Wirth
  • Algorytmy i struktury danych - A.V. Aho, J.E.Hopcroft, J.D.Ullman
  • Projektowanie i analiza algorytmów - A.V. Aho, J.E.Hopcroft, J.D.Ullman
  • Algorytmy (struktury danych i techniki programowania) - Piotr Wróblewski.

Trzy pierwsze są z przykładami w Pascalu, a ostatnia w C++.

0

h:=length(matrix[i].bin)-4
for k:=0 to h do

jeszcze szyba powinna być(nigdy nie testowałem) taka implementacja:

h:=length(matrix[i].bin)-4
 for k:=h downto 0 do
0
TeWuX napisał(a)

druga metoda jest szybsza. w pierwszej za każdym razem się będzie odwoływać do funkcji Length. Dlatego np. w pętli możesz wydłużyć tą tablicę i pętla będzie się wykonywać do nowo nadanej długości tablicy.

Nie prawda! Pętla

for to do

wylicza warunek końcowy przed pierwszym wejściem do pętli i nie ulega on zmianie podczas pracy pętli.

Delphi Help napisał(a)

The difference between this [while - dop:Szczawik] construction and the

for...to

statement is that the while

 loop reevaluates <code class="delphi">finalValue

before each iteration. This can result in noticeably slower performance if finalValue

 is a complex expression, and it also means that changes to the value of <code class="delphi">finalValue

within statement can affect execution of the loop.

Najszybszym rodzajem konstrukcji jest

for i:=n downto 0 do

, gdyż bezpośrednio odpowiada pracy procesora (asm: mov ECX, n [..] loop

). Jeśli wewnątrz pętli <code class="delphi">for to do

nie jest wykorzystywany licznik pętli, to kompilator zamienia to na for downto do

. Można to czasem zaobserwować podczas debugowania.
0
Szczawik napisał(a)
TeWuX napisał(a)

druga metoda jest szybsza. w pierwszej za każdym razem się będzie odwoływać do funkcji Length. Dlatego np. w pętli możesz wydłużyć tą tablicę i pętla będzie się wykonywać do nowo nadanej długości tablicy.

Nie prawda! Pętla

for to do

wylicza warunek końcowy przed pierwszym wejściem do pętli i nie ulega on zmianie podczas pracy pętli.

Rzeczywiście, coś mi się pokręciło. Tak działa oczywiście tylko na pętlach repeat i while.
Sorry za wprowadzenie w błąd [browar]

0

DZIEKI wielkie za porade dotyczaca zmiany to na downto dosyc sporo przyspieszylo kolo 25%

Czy macie moze jakeis ksaizki artykuly o optymalizacji kodu?

0
shivanwk napisał(a)

dosyc sporo przyspieszylo kolo 25%

25%? Nie przesadzasz trochę? Ile szacunkowo razy wykonuje się Twoja pętla? I jakie rozkazy są w niej wykonywane (te co dałeś w innym poście?) ?

0

Wykonuje petle

for l:=hot_count-1 downto 0 do
   begin 
              
    j:=0;
    for k:=l downto 0 do if tab[i][2]>tab[i-k-1][2] then j:=j+ww[l+1][k] else j:=j-ww[l+1][k];
    Matrix[mat].tab[i][l+3]:=j;


   end;
  end;

// te 3 linijki to okolo 3000*256 powtorzen :)

0
shivanwk napisał(a)

Wykonuje petle

for l:=hot_count-1 downto 0 do
   begin 
              
    j:=0;
    for k:=l downto 0 do if tab[i][2]>tab[i-k-1][2] then j:=j+ww[l+1][k] else j:=j-ww[l+1][k];
    Matrix[mat].tab[i][l+3]:=j;

   end;
  end;

// te 3 linijki to okolo 3000*256 powtorzen :)

Może to troszkę przyspieszy.

MatTemp:=Matrix[mat];
for l:=hot_count-1 downto 0 do
  begin 
  j:=0;
  for k:=l downto 0 do
    if tab[i][2]>tab[i-k-1][2] then
      inc(j, ww[l+1][k])
    else
      dec(j, ww[l+1][k]);
  MatTemp.tab[i][l+3]:=j;
  end;
0

j:single;
inc(j , 1.5);
= >[Error] Unit1.pas(233): Left side cannot be assigned to

Po co jest tu uzycie MatTemp ? czy to cos daje?

0
shivanwk napisał(a)

j:single;
inc(j , 1.5);

[Error] Unit1.pas(233): Left side cannot be assigned to

Oczywiście, bo procedura Inc działa wyłącznie na liczbach całkowitych.

0
shivanwk napisał(a)

1)j:single;
inc(j , 1.5);
= >[Error] Unit1.pas(233): Left side cannot be assigned to

No tak, ale w kodzie nie zaznaczono, że to single.

shivanwk napisał(a)

Po co jest tu uzycie MatTemp ? czy to cos daje?

Pozwala nie wyliczać za każdym razem wyrażenia Matrix[mat], a przy tylu przejściach pętli to ma znaczenie.

0
Szczawik napisał(a)

Pozwala nie wyliczać za każdym razem wyrażenia Matrix[mat], a przy tylu przejściach pętli to ma znaczenie.

a jak zrobie with matrix[mat] do , czy to bedzie dobrze ?

0

Jeśli będzie zewnątrz pętli to tak - wewnątrz pętli będzie powodowało zwalnianie, by to wyliczyć.

0

Z książek mogę ci polecić:

  • Algorytmy + struktury danych = programy - Niklaus Wirth
  • Algorytmy i struktury danych - A.V. Aho, J.E.Hopcroft, J.D.Ullman
  • Projektowanie i analiza algorytmów - A.V. Aho, J.E.Hopcroft, J.D.Ullman
  • Algorytmy (struktury danych i techniki programowania) - Piotr Wróblewski.

Tewux jestem pod wrażeniem. Ja przeczytałem tylko jedną książke (Podstawy pascala, czy jakoś tak). Ale nie jestem zawodowym programistą, tylko amatorem próbującym samemu coś napisać. W każdym razie, nie o tym chciałem tu ględzić..

Swego czasu pisałem program który szukał odpowiedniego kluczaj i wymagana była szybkość. Jak się okazało pętle bardzo spowalniają dany algorytm, jeśli chcesz naprawdę szybkiej procedury wywal wszystkie pętle!!!

Tak wiem program będzie naprawdę duży, ale da to niesamowite przyśpieszenie. Moja aplikacja po optymalizacji liczyła 220 tys kluczy na sekundę. - prawie tyle samo co napisana w c++. Na początku było to jakieś 15 tys na sekunde.

Może podam jakiś przykład:

Przed optymalizacją:

 for lf := 6 downto 4 do begin
      dd[(lf+2) and $03] := dd[(lf+2) and $03] xor dd[(lf+1) and $03];
      dt := (swpdd((lf+1) and $03) + dd[(lf and $03)]) and $ff;
      dd[lf and $03] := t2[dt];
                              end ;
    for lf := 3 downto 1 do begin
      dd[(lf+2) and $03] := dd[(lf+2) and $03] xor dd[(lf+1) and $03];
      dt := (swpdd((lf+1) and $03) + dd[(lf and $03)]) and $ff;
      dd[lf and $03] := T1[dt]
                              end;
Po optymalizacji:
ddd[0] := dd[0] xor dd[3];
dt := ((dd[3] AND $F) SHL 4);
dt := dt  OR (dd[3] SHR 4) ;
dt := (dt  + dd[2])and $ff; 
dd[2] := t2[dt] ;
dd[3] := dd[3] xor dd[2];
dt := ((dd[2] AND $F) SHL 4);
dt := dt   OR (dd[2] SHR 4);
dt := (dt + dd[1])and $ff;
dd[1] := t2[dt] ;
dd[2] := dd[2] xor dd[1];
dt := ((dd[1] AND $F) SHL 4);
dt := dt OR (dd[1] SHR 4);
dt := (dt + dd[0])and $ff;
dd[0] := t2[dt] ;
//=============================================
dd[1] := dd[1] xor dd[0];
dt := ((dd[0] AND $F) SHL 4);
dt := dt OR (dd[0] SHR 4) ;
dt := (dt  + dd[3])and $ff;
dd[3] := t1[dt] ;
dd[0] := dd[0] xor dd[3];
dt := ((dd[3] AND $F) SHL 4);
dt := dt  OR (dd[3] SHR 4);
dt := (dt + dd[2])and $ff;
dd[2] := t1[dt] ;
dd[3] := dd[3] xor dd[2];
dt := ((dd[2] AND $F) SHL 4);
dt := dt  OR (dd[2] SHR 4);
dt := (dt + dd[1])and $ff;
dd[1] := t1[dt] ;

Nie pamiętam dokładnie, ale takie proste pozbycie się pętli za każdym razem dodaje nam przyśpieszenie, czasami więcej, a czasami mniej.

Może prostszy przykład:
zamiast:

for c := 1 to 8 do tempu[c] := drec[c];

zrobimy sobie:

tempu[1] := drec[1];
tempu[2] := drec[2];
tempu[3] := drec[3];
tempu[4] := drec[4];
tempu[5] := drec[5];
tempu[6] := drec[6];
tempu[7] := drec[7];
tempu[8] := drec[8];

Taka prosta pętelka, ale gdy jest wywoływana ileś tam milionów razy, potrafi znacznie skrócić czas działania (najlepiej popatrzeć w kod asm i policzyć ile zajmuje taktów procesora)

To tyle na dziś, nie wiem czy się przyda komuś, ale uważałem za istotne o tym napisać.

0

Entek: to ja już wolę kupić szybszy procesor...

0

Entek, oczywiście nie przeczytałem tych wszystkich książek od deski do deski, choćby dlatego że wiele tematów w nich się powtarza, ale ostatnio z wakacyjnych nudów coraz częściej do nich zaglądam.

A co do pozbywania się pętli... na pewno taki zabieg przyśpiesza, ale też zwiększa rozmiar programu. Oczywiście przyśpieszenie jak i zwiększenie jest nieznaczne.
Chyba że przekształcimy pętle:

for i:=0 to 2000000000 do
  for j:=0 to 2000000000 do
    for k:=0 to 2000000000 do
      ...

wtedy na pewno rozmiar programu znacznie wzrośnie, nie mówiąc o kodzie źródłowym i jego czytelności [rotfl]

Jeśli nie tworzymy jakiegoś super-optymalnego algorytmu możemy sobie darować te wszystkie sztuczki przyśpieszające, wiele lepiej zainwestować w czytelność kodu.

0

Tak ale wlasnie ja posiadam procedurke ktora jest wykonywana pare mln razy a szybkosc programu jest dla mnie bardzo bardzo wazna :)

hot_count=256
length(tab) kolo 3000

procedure licz (const mat:byte);
var count,i,k,l,o:word; j,temp1:single;
begin with matrix[mat] do begin
count:=length(tab)-1;
if hot_count<count then
begin
for i:=hot_count{o} to count do
Begin
temp1:=tab[i][2];
for l:=hot_count-1 downto 0 do
begin
j:=0;
for k:=l downto 0 do
if temp1>tab[i-k-1][2] then j:=j+ww[l+1][k] else j:=j-ww[l+1][k];
tab[i][l+3]:=j;
end;
end;
end;
end;end;

0

Nie wywołujesz z pętli innych procedur, więc chyba nie ma co tu więcej kombinować.
Jedynie wstawka z assemblera by tu ponogła.

Zerknij jeszcze tu:
http://4programmers.net/article.php?id=106

0
entek napisał(a)

Nie wywołujesz z pętli innych procedur, więc chyba nie ma co tu więcej kombinować.
Jedynie wstawka z assemblera by tu ponogła.

Wlasnie inni mowia ze wstawek sie tu nie oplaca gdyz sa to proste czynnosci i kompilator najlepiej to wykona

entek napisał(a)

Zerknij jeszcze tu:
http://4programmers.net/article.php?id=106

Czytalem dzis rano ten artykul, jest dosyc ciekawy (pierwsza polowa :))

Czy macie moze jakies PDFy lub linki do artykulow o optymalizacji kodu i ustwawieniach kompilatora (na google za wiele tego nie ma)

1 użytkowników online, w tym zalogowanych: 0, gości: 1