Bit-Shift auffüllen mit Einsen/Nullen

Gast #4127088
Lesenswert?

Hallo zusammen,
um Bits für ein 32-Bit Schieberegister "vorzubereiten" möchte ich eine 
32-Bit Variable bitweise (nach rechts) verschieben. Dafür sollten die 
links weggeschobenen Bits mit Einsen aufgefüllt werden. Bisher rücken 
Nullen nach.
Wie kann ich das ändern bzw. gibt es einen weiteren Bitshift-Operator 
als >> der mit Einsen auffüllt?
Ich nutze den GCC mit AtmelStudio 6, Controller ist ein ATmega328.

Danke und Gruß,
shifter
(Firma: Brainit GmbH) #4127108
Lesenswert?

der "arithmetic shift right" macht fast was du willst: der 
berücksichtigt nämlich das Vorzeichen. Wenn das höchste Bit 1 ist, wird 
mit 1 aufgefüllt, sonst mit 0

allerdings müsstest du den ersten Shift "normal" ausführen und dann das 
höchste Bit "zu Fuß" auf 1 setzen.

arithmetic shift sollte vom Compiler automatisch beim shiften von signed 
ints verwendet werden.
Gast #4127113
Lesenswert?

Hallo!

Dr. Sommer schrieb:
> uint32_t x = ...;
> x = (1UL << 31) | (x >> 1);

Das funktioniert in meinem Fall leider nicht, ich möchte beispielsweise 
so eine Bitfolge um x Bits nach rechts verschieben:
1
uint32_t shiftedVar = 0b11000111000111111111111111111111 >> x;

(Und raus kommt dann blöderweise so etwas (x=2):
1
0b00110001110001111111111111111111
)
Gast #4127118
Lesenswert?

Michael Reinelt schrieb:
> der "arithmetic shift right" macht fast was du willst: der
> berücksichtigt nämlich das Vorzeichen. Wenn das höchste Bit 1 ist, wird
> mit 1 aufgefüllt, sonst mit 0
>
> allerdings müsstest du den ersten Shift "normal" ausführen und dann das
> höchste Bit "zu Fuß" auf 1 setzen.

Das hört sich gut an, aber wenn ich die Variable signed deklariere geht 
mir mein 32. Bit verloren :-(
Gast #4127130
Lesenswert?

Shifter schrieb:
> Das funktioniert in meinem Fall leider nicht, ich möchte beispielsweise
> so eine Bitfolge um x Bits nach rechts verschieben:
Ach du möchtest um mehrere Bit schieben. Dann kannst du einfach mit 
einer Schleife mehrfach um 1 Bit schieben (denn nichts anderes macht der 
Compiler aus einem Shift um mehrere Bits, da AVR immer nur um 1 bit 
shiften kannst).
Just for fun hier aber eine Variante die auch mehrere Bits kann:
1
uint32_t multishift (uint32_t in, uint8_t bits) {
2
  uint32_t mask = (bits == 32) ? 0xFFFFFFFF : ((((uint32_t) 1) << bits) - 1);
3
  return (in >> bits) | (mask << (32-bits));
4
}
(Firma: Brainit GmbH) #4127133
Lesenswert?

Shifter schrieb:
> Das hört sich gut an, aber wenn ich die Variable signed deklariere geht
> mir mein 32. Bit verloren :-(

Nein, nicht unbedingt. Dir wird nur (tmeporär) der Wert negativ.

ich glaube aber dass die Lösung von Dr. Sommer schöner ist, du musst die 
Schleife halt "zu Fuß" ausprogrammieren. Das ist aber kein 
(Performance-) Nachteil, da der AVR ohnehin keinen Barrel-Shifter hat.

so in etwa
1
uint32 shift_me(uint32_t val, uint8_t x)
2
{
3
   while (x-- > 0) {
4
      val = (val >> 1) | (1UL << 31);
5
   }
6
   return val;
7
}
#4127147
Lesenswert?

Michael Reinelt schrieb:
> und nachdem der AVR ja einen COM (One's Complement) befehl hat, dürfte
> das sogar recht effizient sein.

Das Problem sind nicht die einlaufenden Bits, sondern der Shift. Ein 
32-Bit Shift wird bei AVRs recht gern zur Schleife, weshalb das Setzen 
des obersten Bits auch nicht viel an der Sache ändert. Optimal übersetzt 
sind das bei unbekanntem n in deiner Version 8*n statt 7*n+8, und ist 
kürzer.
Moderator (Firma: Titel) Persönliche Seite #4127152
Lesenswert?

A. K. schrieb:
> Ein 32-Bit Shift wird bei AVRs recht gern zur Schleife
Da hilft es dann auch nichts, wenn alles hübsch in 1 einzige C-Zeile 
passt...

Weil der AVR 1. ein 8-Bit Prozessor ist und 2. keinen Barrelshifter hat, 
ist es sowieso oft sinnvoll zu fragen, ob so ein (variabler) 
Schiebevorgang schon nötig ist, oder ob sich das nicht anders lösen 
lässt.
(Firma: Brainit GmbH) #4127160
Lesenswert?

A. K. schrieb:
> Ein
> 32-Bit Shift wird bei AVRs recht gern zur Schleife

nicht nur recht gern, sondern eigentlich (fast) immer (siehe 
Beitrag "GCC optimiert 32bit Bitoperationen schlecht/gar nicht?") und in seinem Fall mit 
Variable sowieso.

A. K. schrieb:
> in deiner Version 8*n statt 7*n+8

Aber deine sieht so lässig aus, das kompensiert mindestens 27 Zyklen ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren