logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

AVR - operacje "* / %" czy dodawanie / odejmowanie?

tehaceole 07 Lut 2012 08:36 1677 5
  • #1 10507427
    tehaceole

    Poziom 28  
    Witam Kolegów

    Nurtuje mnie pewien problem.

    Mam w programie zmienna uint16 przechowującą czas w sekundach. Maksymalna wartość to 5400 sek. co odpowiada 90 minutom.

    No i teraz treść problemu: w pewnych miejscach potrzebuję przeliczyć wartość mojej zmiennej "CzasWsekundach" na czas w postaci minuty:sekundy. W innej części programu potrzebuję robić przeliczenie odwrotne. Do tej pory stosowałem następujący zapis:
    minuty=CzasWsekundach/60;
    sekundy=CzasWsekundach%60;

    i analogicznie w drugą stronę:
    CzasWsekundach=(minuty*60)+sekundy


    Czy dla podanej wartości maksymalnej zmiennej "CzasWsekundach" warto jest przerabiać te procedury na coś mniej więcej takiego:
    T.CzasMin=0;
    T.CzasSek=0;
    while(T.CzasWsekundach>60)
    {
    T.CzasWsekundach-=60;
    T.CzasMin+=1;
    }
    T.CzasSek=T.CzasWsekundach; 

    oraz przeliczanie odwrotne:
    T.CzasWsekundach=0;
    while(T.CzasMin>0)
    {
    T.CzasMin--;
    T.CzasWsekundach+=60;
    }
    T.CzasWsekundach+=T.CzasSek; 

    Oczywiście pomijam tutaj całkowicie sposób deklaracji funkcji, przekazywania argumentów i wyników, ponieważ nie to jest sednem sprawy. Dla jasności podam tylko, że użyte w pętlach zmienne to następująca struktura:
    struct Tajmes{
    	uint16_t CzasWsekundach;
    	uint8_t CzasSek;
    	uint8_t CzasMin;
    }T;



    Na pierwszy rzut oka mój przerobiony zapis jest dłuższy od pierwowzoru, jednak zawsze wydawało mi się, że operacje dodawania i odejmowania są dużo wydajniejsze (szybsze) niż operacje mnożenia i dzielenia. Co oczywiście nie znaczy, że mam w tej kwestii bezsprzeczną rację. Prosiłbym Kolegów o konstruktywną dyskusję.
  • #2 10507725
    tmf
    VIP Zasłużony dla elektroda
    Są wydajniejsze, ale realizujesz je w pętli, czyli efekt końcowy jest zależny od wartości argumentu. Raz będzie szybciej, raz zdecydowanie wolniej. Pytanie w ogóle - po co ci takie dziwaczne optymalizacje? Procesor się niewyrabia? Jeśli się wyrabia, to problemu nie ma. Jeśli masz problem z wydajnością to lepszy skutek przyniesie przemyślenie całego algorytmu i programu, niż takie dziwaczne optymalizacje. Albo zastosowanie wydajniejszego procesora.
  • #3 10507755
    Krotki
    Poziom 14  
    Bazując na twoim drugim przykładzie.
    Jeżeli minuty to zmienna 8 bitowa to mnożenie zajmuje 2 cykle procesora oraz dodawanie 1 cykl czyli w sumie coś koło 3-4 cykli. Nawet jeżeli będzie to liczba 16bitowa to mówimy tu o max 10-15 cyklach.

    Pętla będzie wykonywać się dużo dłużej. W kolejności szacunkowo: odejmowanie 1, dodawanie (tu będzie kilka cykli ze względu na 16bit), porównanie i przeniesienie 2-3 cykle, czyli strzelając 10 cykli razy ilość pętli równa się dużo za dużo :)

    Dokładnie można oszacować na podstawie listingu asmblerowego po skompilowaniu kodu.
  • #4 10507895
    tmf
    VIP Zasłużony dla elektroda
    Takie wyliczenia są OKDR. To jest c - język stworzony nie po to, żeby było szybciej, lecz po to, żeby było wygodniej. To jak powyższy przykład zostanie skompilowany zależy od tysiąca różnych rzeczy. Raz może być lepiej tak, a raz inaczej. Dlatego liczenie cykli w c sensu po prostu nie ma, co najwyżej można orientacyjnie coś podać, lub wyliczyć najlepsze możliwe warunki.
  • #5 10508005
    mirekk36
    Poziom 42  
    Gdyby chodziło o jakieś na prawdę krytyczne czasowo procedury np gdzieś w przerwaniach , gdzie miałbyś takie przeliczenia robić i zależałoby ci na każdym takcie zegara to wtedy też rozumiałbym jakieś próby optymalizacji tego o co pytasz. Ale wtedy do albo bym sięgnął po wstawkę asemblerową w przerwaniu albo jak pisze tmf, w ogóle bym sobie głowy nie zawracał tylko użył bardziej wydajnego procka.

    Natomiast jeśli to są przekształcenia robione gdzieś tam w pętli głównej programu czy w jakieś mało krytycznej czasowo funkcji - to taka ich optymalizacja chyba właśnie mija się z celem.

    Najlepiej weź sobie skompiluj swoją jedną i drugą propozycję i zajrzyj do pliku *.lss jak to wygląda w asemblerze. Żebyś się nie zdziwił co może się okazać. Bo w efekcie końcowym wg mnie albo to nie będzie się różniło w ogóle jeśli chodzi o czas albo nawet wyjdzie nieco dłużej.... No ale jak mówię, wystarczy odpowiednio sobie zamarkować jakoś bloki tych fragmentów programu i dawaj do podglądu ASM ;) .... szybko ci wyjdzie, szydło z worka.

    Z drugiej strony spróbuj sobie porównać to co dostajesz

    Dodano po 34 [sekundy]:


    ale na końcu i tak wyjdzie to co napisał niżej kolega ;)
    tmf napisał:
    Raz może być lepiej tak, a raz inaczej. Dlatego liczenie cykli w c sensu po prostu nie ma, co najwyżej można orientacyjnie coś podać, lub wyliczyć najlepsze możliwe warunki.
  • #6 10508127
    tehaceole

    Poziom 28  
    Po analizie kodu asm i wypowiedziach Kolegów rzeczywiście stwierdzam, że dzierganie tego co kompilator pięknie robi za mnie w tym konkretnym przypadku do którego jest mi to potrzebne - mija się całkowicie z celem. Dziękuję Kolegom za udział w dyskusji i rozwianie moich wątpliwości. Temat zamykam.



    Już po zamknięciu tematu otrzymałem wiadomość od jednego z Użytkowników Elektrody. Treść poniżej:

    Za wcześnie zamknąłeś temat...
    
    minuty=CzasWsekundach/60; 
    sekundy=CzasWsekundach%60;
    
    Ten kod prawie na pewno powoduje dwukrotne przeprowadzenie czasochłonnego dzielenia. Można go zastąpić takim:
    
    minuty = CzasWsekundach/60; 
    sekundy = CzasWsekundach - minuty*60;
    
    który wykonuje jeden raz dzielenie i jeden raz o wiele szybsze mnożenie.
    

    Jeszcze raz dziękuję Kolegom za zainteresowanie tematem.
REKLAMA