Forum: Mikrocontroller und Digitale Elektronik Bits tauschen?!


von C - Anfänger (Gast)


Lesenswert?

Hallöle,

bin gerade etwas überfordert.
Möchte gerne diese ganze "if abfragerei" in einer "for" Schleife 
erledigen..
Muss doch funktionierten oder?
1
static inline uint8_t swapBits(uint8_t byte)
2
{
3
  uint8_t tmp = 0;
4
  if(byte&1<<7) tmp|=1<<0;
5
  if(byte&1<<6) tmp|=1<<1;
6
  if(byte&1<<5) tmp|=1<<2;
7
  if(byte&1<<4) tmp|=1<<3;
8
  if(byte&1<<3) tmp|=1<<4;
9
  if(byte&1<<2) tmp|=1<<5;
10
  if(byte&1<<1) tmp|=1<<6;
11
  if(byte&1<<0) tmp|=1<<7;
12
  return tmp;
13
}

von Sheeva P. (sheevaplug)


Lesenswert?

C - Anfänger schrieb:
> bin gerade etwas überfordert.
> Möchte gerne diese ganze "if abfragerei" in einer "for" Schleife
> erledigen..

Was ist eigentlich eine Zählschleife? ;-)

von C - Anfänger (Gast)


Lesenswert?

Die Schleife an sich verstehe Ich. Es geht um die Rechnerei.

von Teo D. (teoderix)


Lesenswert?

Beitrag "Re: Bits drehen bzw. spiegeln"
1
for ( i = 0; i < 8; i++ )
2
{
3
   gespiegelt >>= 1;
4
   gespiegelt |= original & 0x80;
5
   original <<= 1;
6
}

von bascom lover (Gast)


Lesenswert?

Mit den Behinderungen in Bascom könnte man es so machen. If ist nicht 
notwendig.

For I = 0 To 7
  K = 7 - I
  Tmp.i = Half_word.k
Next I

von Hans (Gast)


Lesenswert?


von C - Anfänger (Gast)


Lesenswert?

Teo D. schrieb:
> Beitrag "Re: Bits drehen bzw. spiegeln"
> for ( i = 0; i < 8; i++ )
> {
>    gespiegelt >>= 1;
>    gespiegelt |= original & 0x80;
>    original <<= 1;
> }

Die Lösung ist Prima. Danke!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

je nach Architektur bietet der GCC dafür "builtins" an, zB für AVR das 
__builtin_avr_insert_bits:
1
// reverse bit order
2
static uint8_t mirror(const uint8_t bits)
3
{
4
    return __builtin_avr_insert_bits(0x01234567, bits, 0);
5
}

von Teo D. (teoderix)


Lesenswert?

C - Anfänger schrieb:
> Die Lösung ist Prima. Danke!

Der Dank geht wohl an ARM-Fan (Gast), Florian (Gast) und Google. 8-)

Aber danke für dir Rückmeldung das es funst. ;)

von Markus F. (mfro)


Lesenswert?

wer Platz hat, nimmt eine Lookup-Tabelle:
1
static const uint8_t lut = { 0xff, 0xfe, 0xfd, ... }
2
3
uint8_t bitrev(uint8_t bits) {
4
    return lut[bits];
5
}

... und wer keinen hat, der kann das auch in zwei 4-bit Lookups mit 
entsprechenden Shifts (und dem damit verbundenen Performanceverlust) 
aufteilen.

... und wer einen ColdFire hat, nimmt BITREV, die ARM-Fraktion RBIT...


C - Anfänger schrieb:
> Teo D. schrieb:
>> Beitrag "Re: Bits drehen bzw. spiegeln"
>> for ( i = 0; i < 8; i++ )
>> {
>>    gespiegelt >>= 1;
>>    gespiegelt |= original & 0x80;
>>    original <<= 1;
>> }
>
> Die Lösung ist Prima. Danke!

Die Lösung ist m.E. suboptimal. Wenn "orginal" 0 wird, kann man 
'fertigshiften' und aufhören. Macht man dennoch weiter, erzeugt man nur 
noch unnötig Wärme ;)

: Bearbeitet durch User
von Herbert P. (Gast)


Lesenswert?

Hmm. Vergleicht man die beiden Ansätze:
1
typedef unsigned char uint8_t; // damit er uint8_t kennt
2
3
uint8_t swapBits(uint8_t byte)
4
{
5
  uint8_t tmp = 0;
6
  if(byte&1<<7) tmp|=1<<0;
7
  if(byte&1<<6) tmp|=1<<1;
8
  if(byte&1<<5) tmp|=1<<2;
9
  if(byte&1<<4) tmp|=1<<3;
10
  if(byte&1<<3) tmp|=1<<4;
11
  if(byte&1<<2) tmp|=1<<5;
12
  if(byte&1<<1) tmp|=1<<6;
13
  if(byte&1<<0) tmp|=1<<7;
14
  return tmp;
15
}
16
17
uint8_t swap2(uint8_t original)
18
{
19
    uint8_t gespiegelt = 0;
20
    for (int i = 0; i < 8; i++ )
21
    {
22
        gespiegelt >>= 1;
23
        gespiegelt |= original & 0x80;
24
        original <<= 1;
25
    }
26
    return gespiegelt;
27
}

z.B. im Compiler-Explorer (https://godbolt.org/#) und wählt die Option 
-O3 aus, so zeigt sich sowohl für AVR- als auch ARM-Compiler (die 
anderen habe ich nicht untersucht), dass durch die Optimierung die erste 
Lösung deutlich kürzer wird als die Schleife (Stichwort: 
Loop-Unrolling).

Nur so als Anregung...

Gruß
Herby

von Stefan F. (Gast)


Lesenswert?

Mit der Lookup Tabelle hat man die beste Performance. Kostet aber 256 
Bytes RAM.

von A. S. (Gast)


Lesenswert?

Stefan U. schrieb:
> Kostet aber 256
> Bytes RAM.

oder ensprechend ROM

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich werfe mal die in den Raum:
1
unsigned char reverse(unsigned char b) {
2
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
3
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
4
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
5
   return b;
6
}

oder auch diese mit lediglich 16 Bytes Lookup-Table.
1
static unsigned char lookup[16] = {
2
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
3
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };
4
5
uint8_t reverse(uint8_t n) {
6
   return (lookup[n&0b1111] << 4) | lookup[n>>4];
7
}

Quelle: 
https://stackoverflow.com/questions/2602823/in-c-c-whats-the-simplest-way-to-reverse-the-order-of-bits-in-a-byte

von spess53 (Gast)


Lesenswert?

Hi

Ich finde die Lösung von PeDa eleganter:

Beitrag "Re: reihenfolge der bits in einem byte umdrehen"

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Mist. Zu spät.

MfG Spess

von Possetitjel (Gast)


Lesenswert?

Frank M. schrieb:

> Ich werfe mal die in den Raum: [...]

Ungünstig, wenn die Zielplattform nur um ein Bit
je Befehl schieben kann.


> oder auch diese mit lediglich 16 Bytes Lookup-Table.

Könnte man pimpen, wenn getrennte Tabellen für
High- und Low-Nibble verwendet werden.

von S. R. (svenska)


Lesenswert?

Possetitjel schrieb:
>> oder auch diese mit lediglich 16 Bytes Lookup-Table.
> Könnte man pimpen, wenn getrennte Tabellen für
> High- und Low-Nibble verwendet werden.

Ist bei einer 16 Byte-Tabelle schon geschehen, sonst bräuchte man ja 256 
Byte.

Vermutlich ist das Compiler-Builtin die sinnvollste Variante. Wenn ein 
Compiler ohne passendes Builtin benutzt werden soll, dann kann man ja 
immernoch gcc's builtin disassemblieren...

von Possetitjel (Gast)


Lesenswert?

S. R. schrieb:

> Possetitjel schrieb:
>>> oder auch diese mit lediglich 16 Bytes Lookup-Table.
>> Könnte man pimpen, wenn getrennte Tabellen für
>> High- und Low-Nibble verwendet werden.
>
> Ist bei einer 16 Byte-Tabelle schon geschehen, [...]

Missverständnis.

Ich sprach davon, eine 16-Byte-Tabelle für das
High-Nibble und zusätzlich eine weitere 16-Byte-Tabelle
für das Low-Nibble zu verwenden. Das spart die Shifts
komplett ein.

von A. S. (Gast)


Lesenswert?

Possetitjel schrieb:
> Das spart die Shifts komplett ein.

Ich finde Deine Idee gut. Führt man sie weiter, könnte man auch 2 * 8 
+1*4 Einträge nehmen (2*3Bit, 1*2Bit), 4*4 oder 8*2. Wobei letzteres 
dann wieder der Ursprungslösung entspricht ;-)
1
unsigned char bswap(unsigned char x)
2
{
3
   /* 8 literal tables of 2 values */
4
   return (unsigned char)
5
         ((x&128?  1:0)
6
         |(x& 64?  2:0)
7
         |(x& 32?  4:0)
8
         |(x& 16?  8:0)
9
         |(x&  8? 16:0)
10
         |(x&  4? 32:0)
11
         |(x&  2? 64:0)
12
         |(x&  1?128:0));
13
}

von S. R. (svenska)


Lesenswert?

Possetitjel schrieb:
> Das spart die Shifts komplett ein.

Sind die 4 Bit-Shifts nicht auf den betroffenen 8 Bit-Architekturen 
beinahe kostenlos (wegen SWAP)? Auf größeren Systemen kann man gleich 
die volle Tabelle nehmen.

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.