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?
Kommt bloss nicht das gleiche Ergebnis raus. Jedenfalls nicht bei negativen Werten. >> rundet nach unten, / gegen 0.
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.
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.
@ 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.