Bits bestrafen

Gast #2186122
Lesenswert?

Hallo,
ich habe ein Byte (hier Var) und möchte aufgrund der gesetzten Bits eine 
Zahl (hier Zahl) "bestrafen".

Hier z.B. ein Byte
1
unsigned char Var=0b101000;
2
//      Var=10|10|00


Und hier nun die Logik:

Zahl=0;

1. Paket (Bits 1&2 ):
Wenn die ersten beiden Bits 00, dann Zahl=Zahl+1;
Wenn die ersten beiden Bits 10, dann Zahl=Zahl+2;

2. Paket (Bits 3&4):
Wenn die zweiten beiden Bits 00, dann Zahl=Zahl+1;
Wenn die zweiten beiden Bits 10, dann Zahl=Zahl+2;

usw.

Bei dem Beispiel müsste die "Zahl" dann den Wert 5 aufweisen.
Wie kann man so etwas auf einem uController am effektivsten realisieren, 
ohne große If abfragen?


Grüße
#2186138
Lesenswert?

Unwissender69 schrieb:
> Wenn die ersten beiden Bits 00, dann Zahl=Zahl+1;
> Wenn die ersten beiden Bits 10, dann Zahl=Zahl+2;

uint8_t result = 0;
if(var & (1 << 6))
  result |= ((var >> 1) + (1 << 6)) & ((1 << 6) | (1 << 7));

Unwissender69 schrieb:
> Wenn die zweiten beiden Bits 00, dann Zahl=Zahl+1;
> Wenn die zweiten beiden Bits 10, dann Zahl=Zahl+2;

if(var & (1 << 4))
  result |= ((var >> 1) + (1 << 4)) & ((1 << 4) | (1 << 5));

Unwissender69 schrieb:
> Bei dem Beispiel müsste die "Zahl" dann den Wert 5 aufweisen.
> Wie kann man so etwas auf einem uController am effektivsten realisieren,
> ohne große If abfragen?

Ganz ohne würde ich es nicht machen. Aber eine pro Paket ist ja nicht so 
schlimm.
#2186158
Lesenswert?

Unwissender69 schrieb:
> Dankeschön Samuel,
> das dauert mir zu lange bei 20 Variablen. Der uC ist ja nur mit schieben
> beschäftigt.
Warum denn? Nur einmal pro Rechnung. Und wenn man diese Var >> 1 
temporär speichert ist es nur einmal schieben.
Die (1 << 4) werden vom Compiler ersetzt.

> Werde es in den Speicher legen und geeignet darauf zugreifen.
Oder meinst du das damit?
Moderator #2186165
Lesenswert?

Sollen wie im Beispiel immer nur 3 Bitpaare (also die Bits 0 bis 5)
betrachtet werden?

Oder was soll bspw. mit Var=0b10101000 passieren?

Nur aus Neugier: Warum bezeichnest du das Addieren von 1 oder 2 als
"bestrafen"?

Was meinst du mit am "effektivsten"?

Unabhängig davon: Eine sehr schnelle Methode wäre eine Tabelle (Array)
mit 256 Einträgen, von denen jeder das gesamte "Strafmaß" für das
entsprechende Byte enthält.
#2186168
Lesenswert?

Ich merke gerade, dass man die if-Abfrage negieren muss.

Und wenn ich schon dabei bin. Ein bisschen optimierter:

uint8_t result = 0, x = (1 << 6), y = (1 << 6) | (1 << 7);
uint8_t varl1 = var >> 1;

do
{

  if(!(var & x))
    result |= (varl1 + x) & y;
  x = x >> 2;
  y = y >> 2;
}
while(x);


Oder in einer Anweisung:

#define mask 0b01010101
var = !(var & mask) * ((var >> 1) & mask + 1);

Ich gebe aber keine Garantie, dass das funktioniert.



Mir fällt gerade auf: Deine Idee funktioniert gar nicht: 0b10 + 2 ergibt 
einen überlauf.
Gast #2186401
Lesenswert?

Stefan schrieb:
> Hat dein Byte nur 6 Bit?

Ja, die restlichen Bits werden nicht betrachtet.

Stefan schrieb:
> Können die Bitkombinationen 01 und 11 nicht auftreten?

01 kann auftreten, ist aber ein don't care und 11 tritt nicht auf.

Yalu X. schrieb:
> Sollen wie im Beispiel immer nur 3 Bitpaare (also die Bits 0 bis 5)
> betrachtet werden?

Ja, es sollen nur 3 Bit-Paare verglichen werden.

Yalu X. schrieb:
> soll bspw. mit Var=0b10101000 passieren?

don't care! Nur die ersten 6 bits, und auch da nur paarweise.

Yalu X. schrieb:
> Nur aus Neugier: Warum bezeichnest du das Addieren von 1 oder 2 als
> "bestrafen"?

Weil damit bestimmte Zustände in einem Algorithmus "bestraft" werden 
sollen. Dies bedeutet, je höher die Zahl ist umso unwahrscheinlicher 
wird dieser Zustand. Die Zustände sind einschrittig Kodiert.

Yalu X. schrieb:
> Eine sehr schnelle Methode wäre eine Tabelle (Array)
> mit 256 Einträgen, von denen jeder das gesamte "Strafmaß" für das
> entsprechende Byte enthält.

So hatte ich es vor. Da einige Berechnungen durchgeführt werden, möchte 
ich den Overhead, z.B. für Bitoperationen, so klein als möglich halten.

Yalu X. schrieb:
> Was meinst du mit am "effektivsten"?

Schnelle Abarbeitungszeit.
#2186573
Lesenswert?

Korrigiert:
1
#define mask 0b01010101
2
var = (~(var & mask)) * ((var >> 1) & mask + mask);

Ich lerne zwar noch Asm, aber ich komme auf 8 Takte für bis zu 4 Pakete 
in einem Byte (ldi nicht mitgerechnet, mul braucht 2 Takte):
1
.def var r16
2
.def var2 r17
3
.def mask r18
4

5
ldi mask, 0b01010101
6

7
mov var, var2
8
and var, mask
9
com var
10

11
lsr var2
12
and var2, mask
13
add var2, mask
14

15
mul var, var2

Das Ergebnis wäre dann in r0.

Würde der Asm funktionieren (ist mein erster Versuch asm zu schreiben)?
#2186877
Lesenswert?

Samuel K. schrieb:
>
1
> .def var r16
2
> .def var2 r17        ; var2 ist vermutlich Dein Eingangsregister
3
                       ; im Beispiel des TO wird dies auf 0b101000 = 40 gesetzt
4
> .def mask 0b01010101 ; = 85
5
> 
6

7
    ; Nach der Operation:   var    var2 (dezimal)
8
> mov var, var2        ;    40     40
9
> andi var, mask       ;    0      40
10
> com var              ;    255    40
11
>                      ; 
12
> lsr var2             ;    255    20
13
> addi var2, mask      ;    255    105
14
> subi var2, 255-mask  ;    255    191(-65)
15
>                      ; 
16
> mul var, var2        ;    R0:R1 = 48705 = High 190 ; Low 65
17
>

... und wo kommt da nun 5 heraus?


Wenn es wirklich schnell gehen soll, dann eine Tabelle mit 64 Einträgen.


Gruß

Jobst
#2187415
Lesenswert?

Jobst M. schrieb:
> ... und wo kommt da nun 5 heraus?

sry, ich habe es falsch verstanden. Ich dachte die Zahl soll dem PAket 
dazugerechnet werden.
Ok noch mal überlegen.
1
.def var r16
2
.def res r17
3

4
ldi res, 0
5

6
sbrc var, 6
7
rjmp next1
8
inc res
9
sbrc var, 7
10
inc res
11
next1:
12
sbrc var, 4
13
rjmp next2
14
inc res
15
sbrc var, 5
16
inc res
17
next2:
18
sbrc var, 2
19
rjmp next3
20
inc res
21
sbrc var, 3
22
inc res
23
next3:

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