Forum: Compiler & IDEs Schiebeoperation mit int16_t-Variable


von Dennis (Gast)


Lesenswert?

Hallo,

ich möchte eine Division durch 4 mittels Schiebeoperation durchführen, 
da der Compiler (Optimierung -Os), das wohl nicht automatisch macht, 
sondern eine rechenzeitintensivere Division durchführt.
Wenn ich das richtig verstanden habe, funktioniert das Schieben 
folgendermaßen:

1<<3 bedeutet: 0000 0001 -> 0000 1000
3<<4 bedeutet: 0000 0011 -> 0011 0000

Eigentlich sollte ich das dann ja auch einach für eine als int16_t 
deklarierte Variable so anwenden können?

also:
int16_t mean;
mean = mean>>2

Wird das so funktionieren?

von Falk B. (falk)


Lesenswert?

ja

von Dennis (Gast)


Lesenswert?

Alles klar, vielen Dank!

von Andreas K. (a-k)


Lesenswert?

Kommt bloss nicht das gleiche Ergebnis raus. Jedenfalls nicht bei 
negativen Werten. >> rundet nach unten, / gegen 0.

von Steffen (Gast)


Lesenswert?

Bei positiven geht es, bei negativen ist es nicht so einfach, da diese 
(glaube ich) im 2er Komplement oder einer ähnlichen Schweinerei abgelegt 
sind.

Steffen.

von Karl H. (kbuchegg)


Lesenswert?

Dennis wrote:
> Hallo,
>
> ich möchte eine Division durch 4 mittels Schiebeoperation durchführen,
> da der Compiler (Optimierung -Os), das wohl nicht automatisch macht,

Was, zumindest beim gcc, im Übrigen nicht stimmt.
Der Compiler achtet nur darauf, nicht den gleichen Fehler zu
machen und bei negativen Zahlen in die falsche Richtung zu gehen :-)

Wenn die Variable aber sowieso nicht negativ werden kann, erhebt
sich die Frage, warum sie dann ein int16_t ist und kein uint16_t.
Denn dann klappts beim gcc auch wieder mit dem einfachen Schieben.

Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
sinnigerweise dem Compiler. Der kann das besser.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
>sinnigerweise dem Compiler. Der kann das besser.

Nur bedingt. Ich hab vor kurzen ein kleines Projekt gemacht, Soft-PWM 
mit 20 Kanälen. Dort wird im Interrupt ein uint32_t gelesen und 
byteweise auf die Ports geschrieben.

1
ISR(TIMER1_COMPA_vect) {
2
3
    static uint8_t pwm_cnt;
4
    uint32_t tmp;
5
6
7
    OCR1A   += isr_ptr->time[pwm_cnt];
8
    tmp      = isr_ptr->mask[pwm_cnt];
9
    
10
    if (pwm_cnt == 0) {
11
        PORTA = tmp;                            // set ports at begin of PWM
12
        PORTC = tmp>>8;
13
        PORTD = tmp>>16;
14
        pwm_cnt++;
15
    }
16
    else {      
17
        PORTA &= tmp;                       // clear ports
18
        PORTC &= tmp>>8;
19
        PORTD &= tmp>>16;                        
20
        if (pwm_cnt == pwm_cnt_max) {
21
            pwm_sync = 1;                           // update now possible
22
            pwm_cnt=0;
23
        }
24
        else pwm_cnt++;
25
    } 
26
}

GCC ist in allen Optimierungsstufen NICHT clever genug, einfach die 
richtigen Register in die IO-Ports zu schreiben. Er erkennt zwar, dass 
man das per Bytekopie machen kann, kopiert und löscht aber noch 
unsinnigerweise Register, die in der realen Schiebeoperation gelöscht 
werden.

Erst der (halblegale) Trick per Union erreicht das gewünschte, optimale 
Ergebnis.

1
ISR(TIMER1_COMPA_vect) {
2
    typedef union {                 // little trick, to speed up data access
3
        uint32_t d32;
4
        uint8_t ary[4];
5
        } ut_t;
6
7
    static uint8_t pwm_cnt;
8
    ut_t tmp;
9
10
11
    OCR1A   += isr_ptr->time[pwm_cnt];
12
    tmp.d32  = isr_ptr->mask[pwm_cnt];
13
    
14
    if (pwm_cnt == 0) {
15
        PORTA = tmp.ary[0];                         // set ports at begin of PWM
16
        PORTC = tmp.ary[1];
17
        PORTD = tmp.ary[2];
18
        pwm_cnt++;
19
    }
20
    else {      
21
        PORTA &= tmp.ary[0];                        // clear ports
22
        PORTC &= tmp.ary[1];
23
        PORTD &= tmp.ary[2];                        
24
        if (pwm_cnt == pwm_cnt_max) {
25
            pwm_sync = 1;                           // update now possible
26
            pwm_cnt=0;
27
        }
28
        else pwm_cnt++;
29
    } 
30
}

Mfg
Falk

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.