Optymalizacja działań matematycznych w Delphi
Mnożenie, potęgowanie, pierwiastkowanie, wszystkie te operacje trwają ułamek sekundy na obecnych maszynach, ułamek sekundy do czasu gdy nie musimy wykonać tysięcy czy miliony iteracji danego działania. W takiej sytuacji odpowiedni dobór użytych funkcji może mieć duży wpływ na czas trwania całej operacji.
W tym wpisie pokaże jakich błędów unikać pisząc w Delphi skomplikowane działania, aby nie marnować czasu użytkownika końcowego naszej aplikacji. Do dzieła!
Stałe
Zacznijmy od rzeczy najprostszej, wykluczania operacji których wynik jest zawsze taki sam. Głupota? Prosty przykład, obliczenia w których występuje liczba PI podniesiona do kwadratu. Wartość tego wyrażenia jest zawsze taka sama, gdyż PI wynosi zawsze tyle samo.
procedure TForm1.Button1Click(Sender: TObject); var k: Double; begin k := GetTickCount * Sqr(PI) + 4; end;
W takiej sytuacji zamiast podnosić 3,14 za każdym razem do kwadratu, najlepiej wyliczyć sobie tą wartość chociażby na systemowym kalkulatorze i zadeklarować nową stałą. Rzecz jasna, jak wcześniej wspomniałem, ma to sens tylko gdy wykonujemy naprawdę dużo obliczeń – inaczej jest to sztuka dla sztuki.
procedure TForm1.Button1Click(Sender: TObject); const PI_2 = 9.8696044010893586188344909998762; var k: Double; begin k := GetTickCount * PI_2 + 4; end;
Unikanie dzielenia
Swego czasu, wyczytałem iż lepiej jest przykładowo mnożyć razy 0,5 niż dzielić przez 2. Próbowałem potwierdzić to różnymi testami, ale za każdym razem dostawałem identyczny wynik. Strzelam że obecne procesory lepiej sobie radzą z dzieleniem w stosunku do mnożenia liczb zmiennoprzecinkowych niż kiedyś.
Dlatego też porada ta nie ma dzisiaj większego sensu, ale warto o niej pamiętać.
Power, Sqr, Sqrt
Funkcja Power, analogicznie do swojej nazwy kryje w sobie dużą moc
, nie mniej, należy się jej wystrzegać jak ognia. Power przyjmuje 2 argumenty, pierwszym jest liczba którą chcemy podnieść do potęgi, a drugim wykładnik potęgi.
Daje to ogromne możliwości z uwagi na fakt iż jest to liczba zmiennoprzecinkowa. Nie mniej, w sytuacji w której podnosimy liczbę do potęgi drugiej, bądź wyciągamy pierwiastek stopnia drugiego bezwzględnie stosujmy funkcje Sqr oraz Sqrt. Pierwiastek 4 stopnia? Zagnieżdżone dwie funkcję Sqrt będą na pewno szybsze niż jeden Power.
Oto małe porównanie szybkości wykonywania się poszczególnych operacji:
| Funkcja | Czas wykonania |
|---|---|
| Sqr(x) | 0,0547ms |
| Sqrt(x) | 0,6396ms |
| Power(x, 2) | 0,8642ms |
| Power(x, 0.5) | 3,9702ms |
I na koniec wynik testu z pierwiastkiem czwartego stopnia:
| Funkcja | Czas wykonania |
|---|---|
| Sqrt(Sqrt(x)) | 1,7472ms |
| Power(x, 0.25) | 4,5896ms |
Podsumowanie
Liczę że te kilka porad pozwoli Wam na optymalizację wielokrotnie wykonywanych działań matematycznych w Delphi. Oczywiście należy też pamiętać o doprowadzeniu danego równania do jak najprostszej postaci przed przystąpieniem do implementacji w programie.
kurczę, aż od razu sprawdziłem. może nie odmierzałem odstępów czasowych, ale obserwowałem zużycie procka przez proces przy wykonywaniu pętli przez timer. mnożenie jest 2 razy szybsze! o_o zatem pamiętać o tym warto