Bits tauschen?!

Gast #5326280
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
}
#5326327
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 ;)
Gast #5327303
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
Moderator Persönliche Seite #5327360
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
#5329780
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...
Gast #5329968
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.
Gast #5330157
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
}

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