Gewichtung einer Binärzahl

Gast #3217194
Lesenswert?

Guten Tag

Ich habe ein kleines Problem mit der Gewichtung einer Variabel.
Das Ziel ist es mit einem möglichst kleinem Code-Aufwand (in C oder C++) 
herauszufinden ob bei einer Variabel ein Bit = 1 ist.
Eine Lösung ist zum Beispiel bei einer 4Bit Variabel:


if((sample==1)||(sample==2)||(sample==4)||(sample==8))
  {
  }
else
  {
  }


Bei einer 8Bit Variabel gibt es dabei schon viel zu schreiben.
Ist das die Lösung oder gibt es noch einen „schöneren“ Weg dies zu 
Lösen?

Vielen Dank und mit freundlichen Grüssen

Simon
Gast #3217258
Lesenswert?

Die Meinung ist nur ein einziges Bit (so wie im Beispiel)

Die Gewichtung soll = 1 sein.

Also z.B. 0b00000100  => TRUE
          0b00101000  => FALSE
          0b01000000  => TRUE


Ich programmiere auf MPLAB und soweit ich weiss reines C.
#3217275
Lesenswert?

Wie wär's dann mit:
1
if( sample & (sample-1) ) //  genau ein Bit in Sample gesetzt?
2
  {
3
  ...
4
  }
5
else // nicht ein einzelnes Bit gesetzt (null oder mehr als eins)
6
  {
7
  ...
8
  }

'x & ( x - 1)' setzt das jeweils niedrigste Bit des Wertes auf 0,
dieser wird also 0, wenn nur ein Bit gesetzt war...
#3217279
Lesenswert?

Natürlich genau falschherum gepostet.....
1
if( sample & (sample-1) ) //  NICHT genau ein Bit in Sample gesetzt?
2
  {
3
  ...
4
  }
5
else // GENAU ein einzelnes Bit gesetzt 
6
  {
7
  ...
8
  }

'x & ( x - 1)' setzt das jeweils niedrigste Bit des Wertes auf 0,
dieser wird also 0, wenn nur ein Bit gesetzt war...
#3217302
Lesenswert?

Liefert 1, wenn in i genau 1 Bit gesetzt, sonst 0 
(Feldgrenzenüberschreitung, wenn i<0 oder i>255):
1
"\x0\x1\x1\x0\x1\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x1\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0"[i]
#3217338
Lesenswert?

Alternative ohne Feld:
1
        ( ( (i & 0x01)!=0 )
2
          +
3
          ( (i & 0x02)!=0 )
4
          +
5
          ( (i & 0x04)!=0 )
6
          +
7
          ( (i & 0x08)!=0 )
8
          +
9
          ( (i & 0x10)!=0 )
10
          +
11
          ( (i & 0x20)!=0 )
12
          +
13
          ( (i & 0x40)!=0 )
14
          +
15
          ( (i & 0x80)!=0 )
16
          ) == 1
Der große Klammerausdruck liefert die Anzahl Bits.
Gast #3217416
Lesenswert?

Am effektivsten wird immer noch Jürgens korrigierte Variante sein:
1
if(sample == 0 || sample & (sample-1) ) //  NICHT genau ein Bit in Sample gesetzt? 
2
{
3
  ...
4
}
5
else // GENAU ein einzelnes Bit gesetzt 
6
{
7
  ...
8
}
#3217431
Lesenswert?

Yo, das geht aber auch schneller, so z.B.,  aus

http://www-graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits

Cheers
Detlef


Compute parity in parallel

unsigned int v;  // word value to compute the parity of
v ^= v >> 16;
v ^= v >> 8;
v ^= v >> 4;
v &= 0xf;
return (0x6996 >> v) & 1;

The method above takes around 9 operations, and works for 32-bit words. 
It may be optimized to work just on bytes in 5 operations by removing 
the two lines immediately following "unsigned int v;". The method first 
shifts and XORs the eight nibbles of the 32-bit value together, leaving 
the result in the lowest nibble of v. Next, the binary number 0110 1001 
1001 0110 (0x6996 in hex) is shifted to the right by the value 
represented in the lowest nibble of v. This number is like a miniature 
16-bit parity-table indexed by the low four bits in v. The result has 
the parity of v in bit 1, which is masked and returned.

Thanks to Mathew Hendry for pointing out the shift-lookup idea at the 
end on Dec. 15, 2002. That optimization shaves two operations off using 
only shifting and XORing to find the parity.
Gast #3217434
Lesenswert?

Oder möglicherweise auch so, damit der Compiler versteht wie er 
optimieren soll:
1
uint8_t temp = sample - 1;
2
if(temp == 255 || sample & temp) //  NICHT genau ein Bit in Sample gesetzt? 
3
{
4
  ...
5
}
6
else // GENAU ein einzelnes Bit gesetzt 
7
{
8
  ...
9
}
Gast #3217450
Lesenswert?

Detlef _a schrieb:
> Yo, das geht aber auch schneller, so z.B.,  aus

Das ist definitiv langsamer als die zweite, Compiler-optimierte Variante 
(Beitrag "Re: Gewichtung einer Binärzahl"). Diese benötigt 
nur 6 Befehle inklusiv aller Sprungbefehle:
1
  uint8_t sample = PIND;
2
  a4:  80 b3         in  r24, 0x10  ; 16
3
  uint8_t temp = sample - 1;
4
  a6:  98 2f         mov  r25, r24
5
  a8:  91 50         subi  r25, 0x01  ; 1
6
  aa:  10 f0         brcs  .+4        ; 0xb0 <main+0xc>
7
  if(temp == 255 || sample & temp ) //  NICHT genau ein Bit in Sample gesetzt? 
8
  ac:  89 23         and  r24, r25
9
  ae:  11 f0         breq  .+4        ; 0xb4 <main+0x10>
10
  {
11
    PORTB = 0;
12
  b0:  18 ba         out  0x18, r1  ; 24
13
  b2:  02 c0         rjmp  .+4        ; 0xb8 <main+0x14>
14
  }
15
  else // GENAU ein einzelnes Bit gesetzt 
16
  {
17
    PORTB = 1;
18
  b4:  81 e0         ldi  r24, 0x01  ; 1
19
  b6:  88 bb         out  0x18, r24  ; 24
Gast #3217482
Lesenswert?

Jürgen Hilker schrieb:
>if( sample & (sample-1) ) //  NICHT genau ein Bit in Sample gesetzt?
>   {
>   ...
>   }
> else // GENAU ein einzelnes Bit gesetzt
>   {
>   ...
>   }
>
> 'x & ( x - 1)' setzt das jeweils niedrigste Bit des Wertes auf 0,
> dieser wird also 0, wenn nur ein Bit gesetzt war...

Danke :-) genau eine solche Lösung habe ich gesucht.

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