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

AVR mnożenie liczb większych niż 8 bit.

majster256 07 Sie 2008 23:26 3135 9
  • #1 5419029
    majster256
    Poziom 21  
    witam

    właśnie zauważyłem ze AVR może mnożyć tylko 8 bit * 8 bit

    czy znacie jakiś trick żeby mnożyć 16 bit * 8 bit?? od biedy starczyło by mi mnożenie * 10, ale gdyby dało się robić normalne operacje to było by bez kombinowania

    żeby uprzedzić innych forumowiczów, testy przeprowadzałem na zmiennych 32 i 64 bitowych i zawsze to samo, po prostu sprzętowe mnożenie nie przyjmuje nic więcej jak 8 bit na daną:(

    można by dodawać ileś tam razy to samo do siebie ale zależy mi żeby rozwiązać to w max 20 cyklach zegara:(
  • #2 5419126
    markosik20
    Poziom 33  
    majster256 napisał:


    właśnie zauważyłem ze AVR może mnożyć tylko 8 bit * 8 bit



    No wiesz..nic w tym dziwnego...wszak AVR (oprócz rodziny AVR32) to 8-bitowce.

    majster256 napisał:

    czy znacie jakiś trick żeby mnożyć 16 bit * 8 bit?? od biedy starczyło by mi mnożenie * 10, ale gdyby dało się robić normalne operacje to było by bez kombinowania


    Pamiętam z podstawówki taki słupek do wykonywania mnożenia większych liczb na kartce :wink:.....ale wydaje mi się większym kominatorstwem jest właśnie rozkładanie takiego możenia. Liczba_8bit * liczba_16bit to raptem 6cykli .
  • #3 5419143
    majster256
    Poziom 21  
    no dobra ale jak to pomnozyc??


    a ze AVR sa 8 bitowe to doskonale wiem:) ale np w dodawaniu radzi sobie świetnie dasz
    
    uint64_t i;
    i =  300 + 300;
    

    i mamy 600

    dajesz
    
    uint64_t i;
    i =  65536 + 65536;
    

    i mamy 131072

    a teraz dajemy

    
    uint64_t i;
    i =  256 * 256;
    

    i mamy 0

    dajemy

    
    uint64_t i;
    i =  258 * 258;
    

    i mamy 4

    rozumiesz o co mi chodzi?
  • #4 5419151
    __Grzegorz__
    Poziom 30  
    kolega słyszał o typie long ?

    Zastosować i niech kompilator się martwi co z tym dalej....

    Albo zrobić sobie rozpiskę:

    (a*256+b) * (c*256+d) =
    a*c*256*256+
    (a*d+b*c)*256 +
    b*d


    ...
  • #5 5419160
    majster256
    Poziom 21  
    słyszał :D ale jakoś przyzwyczaiłem sie do stosowania tych które w nazwie maja określoną wielkość:) wzięło się to stąd że kiedyś na forum nikt nie był mi w stanie podać jaka zmienna jest 8 bitowa:)

    kompilator działa tak samo z long i int64_t

    a co do rozpiski to
    (a*d+b*c)*256 oraz a*c*256*256 nie może być:( bo to przekroczy 256 po pierwszym mnożeniu i już kolejnego mnożenia nie zrobię poprawnie
  • Pomocny post
    #6 5419293
    __Grzegorz__
    Poziom 30  
    W C mnożenie dwóch intów zawsze da int, rzutowanie tego do long później nie ma sensu...

    Ale jeżeli w mnożeniu bierze udział chociaż jeden long.... :)

    ...

    czyli zamiast

    i = 258*258

    spróbuj:

    i=258l*258

    :)

    Pozdrawiam.

    P.S. W rozpisce chodzi o to żeby uniknąć mnożeń przez 256, czyli z wejścia wziąc a,b,c i d. obliczyć ich iloczyny, a dopiero później na tych iloczynach dokonać "mnożenia przez 256" które jest zwykłym przesunięciem wyniku o 1 bajt (2 bajty dla 256*256) ...
  • #7 5419298
    majster256
    Poziom 21  
    no i bajer:D

    dzięki wielkie

    powiedz mi jeszcze jak długo sie to wykonuje?

    Dodano po 2 [minuty]:

    kurcze nie bajer;p bo działa jak sprawdzałem ale w funkcji mam zmienne... i jak to do zmiennej dodać?
  • Pomocny post
    #8 5419310
    __Grzegorz__
    Poziom 30  
    zadeklaruj w funkcji zmienne jako long...
  • #9 5419599
    markosik20
    Poziom 33  
    __Grzegorz__ napisał:
    zadeklaruj w funkcji zmienne jako long...


    Nie trzeba. Zmienne są 16-bitowe więc żeby uzyskać wynik ich mnożenia musimy użyć tylko większej zmiennej na wynik (np: 32-bitowa).
    Należy pamiętać że działanie typu


    jest dla kompilatora z włączoną optymalizacją zupełnym bezsensem.
    Dodatkowo jak zmienna F w dalszej części kodu też nie jest nigdzie użyta to ....kompilator poprostu ominie takie działanie.
    Rozbijanie mnożenia (16bit*16bit) na dodawanie i monożenie częściowe..to tak jakby samemu wyręczać kompilator :wink:.

    poprostu:

    unsigned int a,b;
    unsigned long wynik;
    ...
    ....
    ...
    ....
    
    wynik = a;
    wynik *=b;
    ....


    Ktoś powie co to za różnica , przecież może być tylko

    wynik = a * b;


    i powiem że ma rację tylko że mój kompilator (WINAVR wersja z końcówką 25) czasami nie "kuma" co to niejawne rzutowanie :wink: .
  • #10 5419791
    __Grzegorz__
    Poziom 30  
    markosik20 napisał:

    unsigned int a,b;
    unsigned long wynik;
    wynik = a;
    wynik *=b;
    ....

    Ktoś powie co to za różnica , przecież może być tylko
    wynik = a * b;

    i powiem że ma rację tylko że mój kompilator (WINAVR wersja z końcówką 25) czasami nie "kuma" co to niejawne rzutowanie :wink: .



    Różnica jest zasadnicza.
    W pierwszym przypadku pojawia się niejawne rzutowanie int na long,
    dzięki czemu drugie działanie (int * long) zawsze wykonane będzie poprawnie (wynik będzie typu long).
    W drugim przypadku kod zadziała źle dla argumentów > 256.
    Wg ANSI C wynik mnożenia int * int jest int.
    Jeżeli kompilator "domyśli" się jaki ma być wynik, to fajnie...
    A jeżeli nie... to kwas.

    Dla WINAVR polecam w makefile dopisać opcję "-pedantic". Kompilator stanie się wówczas baaardzo rozmowny...
    M.in. w temacie niejawnych rzutowań w programie...
    :)
REKLAMA