hey zusammen... wie bekomme ich den Wert eines Bits an der Stelle x? hat da irgendwer eine idee? z.B. 0001001010101 Stelle 0 = 1 Stelle 1 = 0 Stelle 2 = 1 usw. lg stefan
Das ergibt nicht 0 wenn die Stelle 1 ist, 0 wenn sie 0 ist:
1 | wert & (1 << stelle) |
Wenn wirklich nach 1/0 gefragt ist:
1 | wert & (1 << stelle) ? 1 : 0 |
Bitmanipulation
d'oh schrieb: > "1 & (wert >> stelle)" ergibt direkt den wert, ohne short-if ist zwar kürzer in C dürfte jdeoch mehr Flash und CPU kosten.
Bei Intelprozessortypen gibt es seit dem 386er den Befehl BT. Man gibt die Position an, und der Wert wird ins Carryflag übertragen. Oder man setzt ein paar And-Befehle und tests hintereinander. 0101 and 0001 ---- 0001 cmp xyz,1 jz ... oder von links: nach links rotieren und gucken, ob carryflag gesetzt. auf diese Weise könnte man nebenbei auch gleich nach ASCII konvertieren: rcl ebx,1 adc Ausgabebyte,30h
d'oh schrieb:
> "1 & (wert >> stelle)" ergibt direkt den wert, ohne short-if
Diese "Abfrage" liefert nicht das Ergebnis "0" oder "1", sondern "0" und
irgedwas verschieden von "0".
Wenn man der Reihe nach die die Stellen abfragen will, nimmt man eine
Schleife in der eine Variable bei jedem Durchlauf verdoppelt wird
(Linksschieben ist nichts anderes als ein Multiplikation mit 2;
Rechtschieben eine Division).
Diese Variable vergleicht mal dann artihmetisch ("&", einfaches
Undzeichen) mit der Quellvariablen.
STK500-Besitzer schrieb: > d'oh schrieb: >> "1 & (wert >> stelle)" ergibt direkt den wert, ohne short-if > > Diese "Abfrage" liefert nicht das Ergebnis "0" oder "1", sondern "0" und > irgedwas verschieden von "0". Wie das? (Das 1 & übersehen?)
Samuel K. schrieb: > d'oh schrieb: >> "1 & (wert >> stelle)" ergibt direkt den wert, ohne short-if > > ist zwar kürzer in C dürfte jdeoch mehr Flash und CPU kosten. 9: ergebnis = wert & (1 << stelle) ? 1 : 0; 8189 LDD R24,Y+1 //Load $(wert) 812A LDD R18,Y+2 //Load $(stelle) E090 LDI R25,0x00 //Load zero for carry reset C002 RJMP PC+0x0003 //Enter loop 9595 ASR R25 //Clear carry 9587 ROR R24 //Rotate right $(wert) 952A DEC R18 //Decrement $(stelle) F7E2 BRPL PC-0x03 //Loop while $(stelle) >= 0 7081 ANDI R24,0x01 //Mask LSB 838B STD Y+3,R24 //Store $(ergebnis) 9: ergebnis = 1&(wert >> stelle); 8189 LDD R24,Y+1 Load indirect with displacement 812A LDD R18,Y+2 Load indirect with displacement E090 LDI R25,0x00 Load immediate C002 RJMP PC+0x0003 Relative jump 9595 ASR R25 Arithmetic shift right 9587 ROR R24 Rotate right through carry 952A DEC R18 Decrement F7E2 BRPL PC-0x03 Branch if plus 7081 ANDI R24,0x01 Logical AND with immediate 838B STD Y+3,R24 Store indirect with displacement Hab's gerade mal auf 'nem xmega kompiliert. Es ist schlichtweg Jacke wie Hose, ob man es nun so oder so schreibt. Der Compiler ist pfiffig genug und optimiert beide Varianten. Das Ergebnis ist exakt das selbe, wobei meine Schreibweise eher die Vorgehensweise des Codes widergespiegelt :-p
Pfiffig ist der Compiler nicht - das ist ja purer Schrott. Selbst mit konstanter Stelle produziert er aufgeblähten Code, obwohl 3 Befehle reichen würden. Ich würde es in Assembler so schreiben:
1 | bst r24, stelle |
2 | clr r24 |
3 | bld r24, 0 |
Folgendes in Assembler übersetzt geht ebenfalls in 3 Befehlen:
1 | wert & (1 << stelle) ? 1 : 0 |
1 | clr r24 |
2 | sbrc r24, stelle |
3 | inc r24 |
Wie du schon richtig sagst... Wenn die Stelle konstant ist, mag das stimmen. Wenn nicht, funktioniert dein Code nicht, da die Bitoperationen neben dem Register einen konstanten Bit Wert erwarten. Und eigentlich wollte ich nur zum Ausdruck bringen, dass es egal ist wie man es in diesem Fall in C ausdrückt, das Endprodukt ist das selbe. Ob es nun per Hand im Assembler besser geht oder nicht sei mal dahingestellt. ^ | Vergiss das! Ich hab mir nochmal die Mühe gemacht und einen Vergleich zwischen deinem und meinem Code gemacht, für den Fall, dass die Stelle konstant ist... Mein Fazit: Gib dem Compiler lesbaren Code und er belohnt dich mit besserem Kompilat. Und insgesamt finde ich schon, dass der Compiler einen guten Job macht und der Code ist auch bei konstanten Werten nicht aufgebläht. (Zumindet mit meinem Code) Für konstante Werte erzeugt er hier auch nur 2-4 Instruktionen(Ohne den ld/st overhead) Für deine Schreibweise sieht der Code zum Teil so aus als sei die Stelle variabel mit zum Teil 3 Register Loads wie oben.
1 | 9: ergebnis = 1&(wert >> 1); |
2 | LSR R24 Logical shift right |
3 | ANDI R24,0x01 Logical AND with immediate |
4 | 9: ergebnis = wert & (1 << 1) ? 1 : 0; |
5 | LSR R25 Logical shift right |
6 | ROR R24 Rotate right through carry |
7 | ANDI R24,0x01 Logical AND with immediate |
8 | |
9 | 9: ergebnis = 1&(wert >> 2); |
10 | LSR R24 Logical shift right |
11 | LSR R24 Logical shift right |
12 | ANDI R24,0x01 Logical AND with immediate |
13 | 9: ergebnis = wert & (1 << 2) ? 1 : 0; |
14 | LSR R25 Logical shift right |
15 | ROR R24 Rotate right through carry |
16 | LSR R25 Logical shift right |
17 | ROR R24 Rotate right through carry |
18 | ANDI R24,0x01 Logical AND with immediate |
19 | |
20 | 9: ergebnis = 1&(wert >> 3); |
21 | LSR R24 Logical shift right |
22 | LSR R24 Logical shift right |
23 | LSR R24 Logical shift right |
24 | ANDI R24,0x01 Logical AND with immediate |
25 | 9: ergebnis = wert & (1 << 3) ? 1 : 0; |
26 | LSR R25 Logical shift right |
27 | ROR R24 Rotate right through carry |
28 | DEC R18 Decrement |
29 | BRNE PC-0x03 Branch if not equal |
30 | ANDI R24,0x01 Logical AND with immediate |
31 | |
32 | 9: ergebnis = 1&(wert >> 4); |
33 | SWAP R24 Swap nibbles |
34 | ANDI R24,0x01 Logical AND with immediate |
35 | 9: ergebnis = wert & (1 << 4) ? 1 : 0; |
36 | LSR R25 Logical shift right |
37 | ROR R24 Rotate right through carry |
38 | DEC R18 Decrement |
39 | BRNE PC-0x03 Branch if not equal |
40 | ANDI R24,0x01 Logical AND with immediate |
41 | |
42 | 9: ergebnis = 1&(wert >> 5); |
43 | SWAP R24 Swap nibbles |
44 | LSR R24 Logical shift right |
45 | ANDI R24,0x01 Logical AND with immediate |
46 | 9: ergebnis = wert & (1 << 5) ? 1 : 0; |
47 | LSR R25 Logical shift right |
48 | ROR R24 Rotate right through carry |
49 | DEC R18 Decrement |
50 | BRNE PC-0x03 Branch if not equal |
51 | ANDI R24,0x01 Logical AND with immediate |
52 | |
53 | 9: ergebnis = 1&(wert >> 6); |
54 | SWAP R24 Swap nibbles |
55 | LSR R24 Logical shift right |
56 | LSR R24 Logical shift right |
57 | ANDI R24,0x01 Logical AND with immediate |
58 | 9: ergebnis = wert & (1 << 6) ? 1 : 0; |
59 | LSR R25 Logical shift right |
60 | ROR R24 Rotate right through carry |
61 | DEC R18 Decrement |
62 | BRNE PC-0x03 Branch if not equal |
63 | ANDI R24,0x01 Logical AND with immediate |
64 | |
65 | 9: ergebnis = 1&(wert >> 7); |
66 | ROL R24 Rotate Left Through Carry |
67 | CLR R24 Clear Register |
68 | ROL R24 Rotate Left Through Carry |
69 | 9: ergebnis = wert & (1 << 7) ? 1 : 0; |
70 | ROL R24 Rotate Left Through Carry |
71 | CLR R24 Clear Register |
72 | ROL R24 Rotate Left Through Carry |
Samuel K. schrieb: > ist zwar kürzer in C dürfte jdeoch mehr Flash ... kosten. welche Version? 11? Alles andere dürfte in diesem Forum wohl nicht passen, auch wenn die Diskussion erquickend ist.
Was mich am Compiler stört ist, das variable schieben bei konstanter Stelle. Das kostet nämlich eine Menge CPU. Ich finde die andi variante besser, da man bei konstanter Stelle nicht schieben muss. Wenn man in einer Schleife nacheinander Bits abfragen muss ist es sowieso besser die Bits rauszuschieben. Ich denke man braucht fast nie die 1<<x Schleife.
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.