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

AVR prośba o optymalizacje kodu

Marcin_xx1 18 Wrz 2008 03:53 2094 14
  • #1 5545874
    Marcin_xx1
    Poziom 21  
    Witam. Jak to napisać optymalniej bo w obecnym stanie zżera mi dużo pamięci

    if(i+e*10+f*100>=j+k*10+l*100&&j+k*10+l*100!=0)


    Dzieki.

    Dodano po 2 [minuty]:

    język C
  • Pomocny post
    #2 5546002
    mirekk36
    Poziom 42  
    Witam,

    sorki, ale jak widzę tak napisany warunek, to od razu przypomina mi się pewien dowcip z jednej ze stron w necie:

    AVR prośba o optymalizacje kodu
    źródło anegdoty: http://www.e-lab.de/

    co w wolnym tłumaczeniu może brzmieć tak:

    Cytat:
    Programowanie w C polega na pisaniu tak:
    for(;P("\n").R-;P("|"))for(e=3DC;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
    oraz szukaniu błędów wskaźników aż do osiągnięcia sukcesu......


    i tak właśnie twoja, linijka przypomina jako żywo tę właśnie anegdotę. Oczywiście w każdym języku można "tak się załatwić" a jasne i przejrzyste programowanie i cała sztuka nie polega na tym aby jak najwięcej zmieścić w jednej linii.

    .... rozbij to wszystko przed swoim warunkiem if na mniejsze fragmenty obliczeń i porównaj tylko ich wyniki, dzięki czemu poza uzyskaniem dużo większej przejrzystości kodu zapewne osiągniesz szybciej zamierzony cel w tym optymalizację

    pozdrawiam
  • Pomocny post
    #3 5546309
    bobbyAIR
    Poziom 20  
    na początek wystarczy tak
    
    if ( (a = j+k*10+l*100)!=0){
    if ((i+e*10+f*100)>=a){
    
    }
    }
    

    dalej można kombinować z upraszczaniem kolejnych operacji:

    to jak sądzę liczba dziesiętna składana z cyfr. Więc warunek
    
    ( j+k*10+l*100)!=0)
    

    mozna zastąpić
    
    ( j || k || l)
    

    pomija to mnożenie.
    Dalej idąc jeśli a>=b to ten warunek jest spełniony przy dowolnej podstawie systemu obliczeniowego. W niektorych systemach operacje są szybsze. Np przesuwanie bitowe.
    
    (i+e*10+f*100>=j+k*10+l*100)
    

    jest równoważne
    
    (i|(e<<1)|(f<<2))>=(j|(k<<1)|(l<<2))
    

    a raczej szybciej się policzy
  • Pomocny post
    #4 5546312
    serum
    Poziom 16  
    Czy to w ogóle działa? Ja użyłbym tu z 10 nawiasów aby nie pomylić priorytetów operatorów i do tego było by to bardziej przejrzyste. Jak za miesiąc sięgniesz do tego kodu to spędzisz ze 2h odszyfrowując co miałeś na myśli. Staraj się nie używać pojedynczych literek jako nazw zmiennych, używaj nazw opisowych. Możesz spróbować wyliczyć poszczególne części warunku wcześniej wprowadzając nowe zmienne, jak chcesz żeby się szybko liczyło to napisz wstawkę ASM. Właściwie to jak dużo Ci to pamięci zajmuje? Nie wierzę żeby to miało znaczący wpływ na zużycie pamięci.

    Cytat:

    Dalej idąc jeśli a>=b to ten warunek jest spełniony przy dowolnej podstawie systemu obliczeniowego. W niektorych systemach operacje są szybsze. Np przesuwanie bitowe.
    Kod:

    (i+e*10+f*100>=j+k*10+l*100)

    jest równoważne
    Kod:

    (i|(e<<1)|(f<<2))>=(j|(k<<1)|(l<<2))

    a raczej szybciej się policzy


    Coś mi się to nie podoba, bo weź np. i=9, e=9, f=1 ,j=0, k=0, oraz l=2
    liczby jakie to reprezentuje to 199 oraz 200
    po Twoim przekształceniu mamy 31 oraz 8 z czego wynika że pierwsza liczba jest większa, a to nieprawda. Policz to jeszcze raz, może się mylę.
  • Pomocny post
    #5 5546577
    bobbyAIR
    Poziom 20  
    masz rację, dochodzi tu jeszcze kwestia cyfr w obu systemach. Trzeba przesunąc się o conajmniej 4 bit (2^4 > 9). Moja pomyłka, powinno być:
    
    (i|(e<<4)|(f<<8))>=(j|(k<<4)|(l<<8)) 
    

    Jednak dalej twierdzę, że to policzy się trochę szybciej.
  • #6 5546846
    serum
    Poziom 16  
    Oczywiście że się policzy szybciej, bo przesunięcia bitowe uC wykonuje chyba w jednym cyklu o ile się nie mylę. Tylko że autor pisze coś o zajętości pamięci a nie o szybkości wykonywania więc myślę że jego problem leży gdzie inndziej niż w pokazanym kawałku kodu gdyż po skompilowaniu i optymalizacji przez kompilator kod nie powinien zajmować zbyt dużo miejsca.
  • Pomocny post
    #7 5546915
    BoskiDialer
    Poziom 34  
    Marcin_xx1: Optymalizacja nie polega na zamienieniu jednej linijki w inną od tak, ale na maksymalnym wykorzystaniu pewnych założeń, których nie przekazujemy jawnie kompilatorowi.
    Dla przykładu jeśli założymy, że wszystkie zmienne przyjmują wartości od 0 do 9, to wszystkie warunki się upraszczają (można zwiększyć bazę z 10 do (np)16 co już poczynił bobbyAIR).
    Żeby uprościć porównanie z zerem do trzech prostych porównań musi być założenie, że zmienne są nieujemne i że w wyrażeniu nie występuje (celowe) przepełnienie.
    Bez tych założeń jedyna możliwa operacja to wyciągnięcie wyrażenia tak jak zrobił to bobbyAIR - chociaż i tutaj jest potrzebne założenie, że zmienne są w tym momencie stałe (nie są np rejestrami IO lub są zmiennymi lokalnymi).
    Tak więc najpierw napisz jakie są założenia do tych zmiennych.

    serum: Przesunięcie w jednym cyklu? Tylko przy przesuwaniu o jeden bit. Przesunięcie o 4 bity w dowolną stronę da się zrobić przy 2 cyklach przy założeniu, że wartość jest w górnym(r16-r31) rejestrze (swap/andi). O dwa bity to dwie instrukcje (proste połączenie pojedynczych przesunięć).

    bobbyAIR: Przy zwiększeniu bazy do 16 będzie to policzone szybciej (zamiast mnożenia, przesunięcia), warto jednak się zastanowić nad zwiększeniem bazy do 256 - wtedy kompilator może uprościć kod do trzech porównań(z przeniesieniem tj cp+2*cpc) bajtów bez przesuwań, a wynik będzie ten sam.
  • #8 5546923
    Marcin_xx1
    Poziom 21  
    serum napisał:
    Oczywiście że się policzy szybciej, bo przesunięcia bitowe uC wykonuje chyba w jednym cyklu o ile się nie mylę. Tylko że autor pisze coś o zajętości pamięci a nie o szybkości wykonywania więc myślę że jego problem leży gdzie inndziej niż w pokazanym kawałku kodu gdyż po skompilowaniu i optymalizacji przez kompilator kod nie powinien zajmować zbyt dużo miejsca.


    Macie racje, chodzi mi o szybkość wykonywania nie o zajętość pamięci, dzięki za pomoc, pozdrawiam.
  • #9 5546939
    BoskiDialer
    Poziom 34  
    Dodam jeszcze, że porównanie trzech bajtów z zerem można zrealizować w dwóch cyklach tracąc jeden z rejestrów z wartością: można policzyć sumę logiczną ("or rA, rB" + "or rA, rC"), rA będzie równe zero tylko wtedy, gdy wszystkie wartości są równe zero, dodatkowego porównania wartości rA z zerem nie trzeba, flagi są ustawione - nie wiem czy kompilator zoptymalizował by to do tego samego stopnia.
  • #10 5547507
    Marcin_xx1
    Poziom 21  
    To jszcze raz ja , po tym co zaraz przedstawie zarzucicie mi może ze nie wyciągam wszystkich wniosków z Waszych cennych uwag, są to moje pierwsze kroki w programowaniu i proszę o wyrozumiałość.

    Pin 2 portuB jst zadeklarowany nastepująco: DDRB |= _BV(2);

    i,e,f to zmienne lokalne odpowiadajace za bajty wyluskiwane z tablicy jakie trafiaja na siedmiosegmentowy, wyswietlacz led z multiplksowaniem.

    j,k,l - jest to programowana trzy cyfrowa liczba porównywana do aktualnego wskazania licznika

    Zmieniłem poprzedni kod
    if(i+e*10+f*100>=j+k*10+l*100&&j+k*10+l*100!=0){
    	PORTB |= _BV(2);
    	}else{PORTB &=~ _BV(2);}
    //co skutkuje wylaczeniem leda w razie spelnienia warunku

    na następujący:
    
    aa=i+e*10+f*100;
    bb=j+k*10+l*100;
    if(aa>=bb&&bb!=0){
    
    PORTB |= _BV(2);}else{PORTB &=~ _BV(2);}


    w tej postaci działa identycznie jak w poprzedniej(tak samo zmula mi procka)

    natomiast gdy:
    aa=i+e*10+f*100;
    bb=j+k*10+l*100;
    if(aa>=bb&&bb!=0){;}

    - program jest owiele szybszy, po prostu widzę to po częstotliwosci multipleksowania która mam zrealizowana w oparciu o glówną pętle.

    Dodano po 5 [godziny] 55 [minuty]:

    Problem udalo mi sie częsciowo rozwiązać obliczając zmienną bb tylko raz.
    dodaje aktualny kod ktory jest moim poligonem doświadczalnym http://www.nopaste.pl/6ew , docelowo ma postać z tego czegoś : licznik obrotów,prędkościomierz i kontomierz w oparciu o enkoder inkrementalny z miezerą podziałką 120 impulsow na obrót który tez gdzieś na boku powstaje ;)
  • #11 5552238
    serum
    Poziom 16  
    Pierwsze co mnie uderzyło w Twoim programie to deklaracje zmiennych w funkcji main, dlaczego wszystkie mają atrybut register ?? Niech mnie ktoś poprawi jeśli źle mówię, ale jeśli kilkanaście zmiennych ma atrybut register to kompilatorowi szybko zabraknie rejestrów do umieszczania tych zmiennych. Weź je zadeklaruj jako zwykłe zmienne.


    Podziwiam Cię - 750 linijek kodu upchane w jednej funkcji main(), napracowałeś się, ale ja tego bym nie chciał analizować;]
  • Pomocny post
    #12 5552346
    Dr.Vee
    VIP Zasłużony dla elektroda
    serum napisał:
    Podziwiam Cię - 750 linijek kodu upchane w jednej funkcji main(), napracowałeś się, ale ja tego bym nie chciał analizować;]

    Boże, widzisz i nie grzmisz... :cry:

    * Brak formatowania kodu
    * Wszystkie nazwy zmiennych jedno bądź dwuliterowe
    * Instrukcje skoku goto (!)

    I jak tu się dziwić, że niektórzy nazywają C "wysokopoziomowym asemblerem"... Dawno takiego spaghetti nie widziałem :)

    Myślę, że optymalizacja wyrażenia z pierwszego postu to był najmniejszy z Twoich problemów :D

    Pozdrawiam,
    Dr.Vee
  • #14 5555447
    Dr.Vee
    VIP Zasłużony dla elektroda
    No tak, jaki kod, taki prototyp - a może na odwrót? :)
  • Pomocny post
    #15 5557068
    serum
    Poziom 16  
    To nie chodzi o to czy działa, czy nie (chociaż lepiej jak działa). Program pisany w ten sposób jest niemodyfikowalny. Bardzo ciężko dodać do niego nowe funkcje lub wykorzystać funkcje z tego programu w jakimś innym programie. Dlatego powinieneś wziąć do serca rady moje i kolegów i zacząć pisać programy zgodnie ze sztuką programistyczną bo później będziesz płakał. Prototyp jak prototyp, też mi się zdarza robić prototypy gdzie więcej kabelków niż czego innego. Dlatego to się nazywa prototyp;]
REKLAMA