Bitweisen vertikalen Counter auswerten

OP #4086092
Lesenswert?
• ▲
▼
Hallo allerseits,

da mein Gehirn schon einen Knoten hat, hoffe ich, dass einer von euch 
eine gute Idee hat zu folgender Knobelaufgabe:

Ich habe mir für meinen Algorithmus (an der Stelle unwichtig) einen 
"vertikalen" Counter gebaut, bestehend aus 5 32Bit-Variablen, die 
jeweils für eine Bitposition stehen. Hierdurch entsteht ein separater 
Counter für jede Bitposition. Das ganze ist vorstellbar als 32 Werte mit 
jeweils 5 Bit, nur "transponiert" (so ähnlich wie in der 
Taster-Entprellroutine von Peter Dannegger: Entprellung).

Angenommen ich habe also für jede Bitposition einen anderen Counterwert, 
wie kann ich parallel für alle Bitpositionen die Counterwerte auf einen 
Bestimmten Bereich prüfen? Also x < Counter < y ist okay, deshalb Flag 
setzen in einer anderen Variable, ansonsten das Flag löschen. Nur eben 
parallel für alle Counter/Bitpositionen.

Ich habe es zuerst mit Boolescher Algebra versucht, die alle Bits auf 
geeignete Weise verUNDet und verODERt, das hat auch gut funktioniert, 
nur leider ist diese Variante sehr statisch hinsichtlich des Bereichs. 
Diesen würde ich gern über Defines festlegen, sodass er variabel bleibt.



Ich hoffe, das war jetzt nicht zu kompliziert, vielen Dank im Voraus!


Viele Grüße,
Christoph
#4086250
Lesenswert?
• ▲
▼
Sind es jetzt 5 counter zu je 32Bit oder 32 Counter zu je 5Bit?
Wenn letzteres, warum nutzt du dafür nicht auch 32 Variable?

Dein funktionierender, aber unflexibler Algorithmus würde sicher für das 
Verständnis sinnvoll sein. Auch das Ziel, welches Du erreichen willst, 
wäre nicht schlecht.

Ansonsten:
Betrachte jedes Bit für sich und baue Deine Makros zum Ändern und 
vergleichen getrennt für jedes Bit.
#4086377
Lesenswert?
• ▲
▼
Christoph B. schrieb:
> Angenommen ich habe also für jede Bitposition einen anderen Counterwert,
> wie kann ich parallel für alle Bitpositionen die Counterwerte auf einen
> Bestimmten Bereich prüfen? Also x < Counter < y

> Ich habe es zuerst mit Boolescher Algebra versucht, die alle Bits auf
> geeignete Weise verUNDet und verODERt, das hat auch gut funktioniert,
> nur leider ist diese Variante sehr statisch hinsichtlich des Bereichs.

Ungeprüfte Idee für einen Ansatz:
Vergleiche deine Zähler (ich nehme an, sie sind als Array uint32_t[5] 
organisiert) mit einem zweiten Array gleicher Struktur, das jeweils den 
Vergleichswert enthält. Für den Vergleich müsstest du einen "vertikalen 
Addierer" bauen, der für das Ergebnis einen Satz Flags (Zero, Negativ, 
etc) bereitstellt. Den Vergleichswert erzeugst du jeweils über eine 
geeignete Funktion. Das könnte dann so aussehen:
1
typedef uint32_t[5] carr_data_t;
2
typedef uint32_t[2] carr_flags_t;
3

4
carr_data_t counter;
5
carr_data_t compare;
6
carr_flags_t flags;
7

8
void carr_set(carr_data_t carr, uint8_t wert);
9

10
void carr_cmp(carr_data_t carra, carrb);
11

12
void main(void)
13
{
14
carr_set(counter, 5);
15
carr_set(compare, 7);
16

17
carr_cmp(counter, compare, flags);
18

19
/* Flags enthält jetzt das Ergebnis für jeden Zähler */

Die Alternative, die Matrix erst zu transponieren und dann 32 Vergleiche 
zu machen, dürfte wesentlich aufwendiger sein.

Grüße

Stefan
Moderator #4086463
Lesenswert?
• ▲
▼
Stefan Wagner schrieb:
> Vergleiche deine Zähler (ich nehme an, sie sind als Array uint32_t[5]
> organisiert) mit einem zweiten Array gleicher Struktur, das jeweils den
> Vergleichswert enthält.

Ja, genau so.

Ich habe das hier mal als C-Programm umgesetzt. Die Funktion
lessorequal macht den eignetlichen Vergleich:

1
#include <stdio.h>
2
#include <string.h>
3
#include <stdint.h>
4
#include <inttypes.h>
5

6
void transpose(uint32_t in[], int nin, uint32_t out[], int nout) {
7
  uint32_t elemin, mask;
8
  int i, j;
9

10
  memset(out, 0, nout * sizeof (uint32_t));
11
  mask = 1;
12
  for(i=0; i<nin; i++) {
13
    elemin = in[i];
14
    for(j=0; j<nout; j++) {
15
      if(elemin & 1)
16
        out[j] |= mask;
17
      elemin >>= 1;
18
    }
19
    mask <<= 1;
20
  }
21
}
22

23
uint32_t lessorequal(uint32_t a[], uint32_t b[], int n) {
24
  uint32_t y;
25
  int i;
26

27
  y = ~0;
28
  for(i=0; i<n; i++)
29
    y = ~a[i] & (b[i] | y) | b[i] & y;
30
  return y;
31
}
32

33
void show(uint32_t arr[], int n) {
34
  int i;
35

36
  for(i=0; i<n; i++)
37
    printf("%2d: %10"PRIu32"\n", i, arr[i]);
38
}
39

40
uint32_t inrange(uint32_t tvalue[], uint32_t tlower[], uint32_t tupper[], int nbits) {
41
  return lessorequal(tlower, tvalue, nbits) & lessorequal(tvalue, tupper, nbits);
42
}
43

44
#define NVALUES 32
45
#define NBITS  5
46

47
// 32 Zählerwerte à 5 Bit
48
uint32_t value[NVALUES] = {
49
   0,  1,  2,  3,  4,  5,  6,  7,
50
   8,  9, 10, 11, 12, 13, 14, 15,
51
  16, 17, 18, 19, 20, 21, 22, 23,
52
  24, 25, 26, 27, 28, 29, 30, 31
53
};
54

55
// 32 Untere Grenzen
56
uint32_t lower[NVALUES] = {
57
   8,  8,  8,  8,  9,  9,  9,  9,
58
  10, 10, 10, 10, 11, 11, 11, 11,
59
  12, 12, 12, 12, 13, 13, 13, 13,
60
  14, 14, 14, 14, 15, 15, 15, 15
61
};
62

63
// 32 Obere Grenzen
64
uint32_t upper[NVALUES] = {
65
  16, 16, 16, 16, 17, 17, 17, 17,
66
  18, 18, 18, 18, 19, 19, 19, 19,
67
  20, 20, 20, 20, 21, 21, 21, 21,
68
  22, 22, 22, 22, 23, 23, 23, 23
69
};
70

71
uint32_t tvalue[NBITS];
72
uint32_t tlower[NBITS];
73
uint32_t tupper[NBITS];
74

75
int main(void) {
76
  uint32_t y;
77

78
  // Zählerwerte und Grenzen in vertikale Darstellung transponieren
79
  transpose(value, NVALUES, tvalue, NBITS);
80
  transpose(lower, NVALUES, tlower, NBITS);
81
  transpose(upper, NVALUES, tupper, NBITS);
82

83
  // Prüfen, welche der 32 Zählerwerte im erlaubten Bereich liegen
84
  y = inrange(tvalue, tlower, tupper, NBITS);
85

86
  // Bit i von y ist 1 gdw lower[i] <= value[i] <= upper[i]
87
  printf("%08"PRIx32"\n", y);
88

89
  return 0;
90
}
Gast #4086466
Lesenswert?
• ▲
▼
Oder einfach so eine Art binäre Suche?
1
5. Bit gesetzt ?
2
Ja
3
  Vergleichswert > 16 ?
4
    Nein -> fertig, true
5
    Ja
6
      4. Bit gesetzt?
7
      Ja
8
        Vergleichswert > 20 ?
9
        Nein -> fertig, true
10
        ...
11
Nein
12
  Vergleichswert >= 16 ?
13
    Ja -> fertig, false
14
    ...

Sind ja nur 32 Varianten
#4086503
Lesenswert?
• ▲
▼
Stefan Wagner schrieb:
> Vergleiche deine Zähler (ich nehme an, sie sind als Array uint32_t[5]
> organisiert) mit einem zweiten Array gleicher Struktur, das jeweils den
> Vergleichswert enthält.

Die eigentliche Frage war doch nach einer flexiblen Lösung, die er per 
Makro variieren kann. Die gezeigten Lösungen sind effektiv. Aber aus 
meiner Sicht wurde nicht gezeigt, wie man daraus flexible Makros macht.

Ich habe die Flexibilität so verstanden, dass er außer den Zählerwerten, 
welche zu einem Bitwechsel führen, auch die Anzahl der Counterbits je 
bit und global auch die Anzahl der Counter variieren will.

Christoph B. schrieb:
> Ich habe es zuerst mit Boolescher Algebra versucht, die alle Bits auf
> geeignete Weise verUNDet und verODERt, das hat auch gut funktioniert,

@Stefan
Ich gehe mal davon aus, dass er mit seiner Aussage eine Lösung hat, die 
deinem Vorschlag nahe kommt.

Oder habe ich ihn falsch verstanden?

Edit:

Yalu X. schrieb:
> Ich habe das hier mal als C-Programm umgesetzt. Die Funktion
> lessorequal macht den eignetlichen Vergleich:

Die Vergleichs-Tabellen anfangs zu berechnen hatte ich bei dem Vorschlag 
von Stefan übersehen.
OP #4087045
Lesenswert?
• ▲
▼
Yalu X. schrieb:
1
uint32_t lessorequal(uint32_t a[], uint32_t b[], int n) {
2
  uint32_t y;
3
  int i;
4

5
  y = ~0;
6
  for(i=0; i<n; i++)
7
    y = ~a[i] & (b[i] | y) | b[i] & y;
8
  return y;
9
}

Das klingt interessant, an so eine Art und Weise hatte ich gedacht. 
Hättest du auch noch eine kleine Erklärung zu den Bitoperationen, bzw. 
eine Quelle? Konnte leider im Netz auf Anhieb nix finden...
Gast #4087118
Lesenswert?
• ▲
▼
Christoph B. schrieb:

> Angenommen ich habe also für jede Bitposition einen
> anderen Counterwert, wie kann ich parallel für alle
> Bitpositionen die Counterwerte auf einen Bestimmten
> Bereich prüfen?

Rückfrage: Der Bereich soll für alle Counter identisch
sein?

Nach meinem laienhaften Verständnis hat Yalu den allgemeinen
Fall mit unterschiedlichen Intervallen je Counter bearbeitet.
Das könnte man evtl. noch vereinfachen.
Moderator #4087155
Lesenswert?
• ▲
▼
Es ist a<b genau dann, wenn bei der binären Subtraktion a-b ein Übertrag
(Borgen) entsteht (auf diese Weise funktioniert auch der CMP-Befehl der
meisten Prozessoren).

Die Wahrheitstabelle für den Übertrag c_i+1 bei der Subtraktion der
i-ten Binärstelle in Abhängigkeit von den Binärziffern a_i und b_i und
dem alten Übertrag c_i lautet:

1
a_i  b_i  c_i | c_i+1    (c_i+1 = 1  <=>  a_i - b_i - c_i < 0)
2
—————————————————————
3
 0    0    0  |   0
4
 0    0    1  |   1
5
 0    1    0  |   1
6
 0    1    1  |   1
7
 1    0    0  |   0
8
 1    0    1  |   0
9
 1    1    0  |   0
10
 1    1    1  |   1
11
—————————————————————

Dieser logische Zusammenhang wird – beginnend mit der niederwertigsten
Stelle – nacheinander auf die 5 Ziffern der Zahlen angewandt (i=0..4).
Der initiale Übertrag c_0 wird dabei auf 0 gesetzt. Der als letztes
berechnete Übertrag c_5 ist das gesuchte Ergebnis.

Man könnte damit die Bereichsprüfung als Ungleichung u<x<o realisieren.
Will man aber für x den kompletten Wertebereich von 0 bis 31 zulassen,
müsste die untere Grenze u=-1 und die obere o=32 sein. Beide Werte sind
aber mit 5 Bits nicht darstellbar.

Dieses Problem umgeht man, indem man stattdessen die Ungleichung u≤x≤o
verwendet. Dazu braucht man die Relation a≤b. Diese erhält man dadurch,
dass man in a<b die Operanden vertauscht (b<a bzw. a>b) und das Ergebnis
negiert (a≯b bzw. a≤b). Die negierten Überträge seien y genannt (y=¬c).
Die entsprechende Wahrheitstabelle lässt sich damit auf einfache Weise
aus der obigen für a<b ableiten:

1
b_i  a_i  y_i | y_i+1
2
—————————————————————
3
 0    0    1  |   1
4
 0    0    0  |   0
5
 0    1    1  |   0
6
 0    1    0  |   0
7
 1    0    1  |   1
8
 1    0    0  |   1
9
 1    1    1  |   1
10
 1    1    0  |   0
11
—————————————————————

Durch scharfes Hinsehen oder Verwendung eines KV-Diagramms ergibt sich
daraus der logische Term

  yi'  =  ¬ai ∧ bi  ∨  ¬ai ∧ yi  ∨  bi ∧ yi
       =  ¬ai ∧ (bi ∨ yi)  ∨  bi ∧ yi

Das ist genau der Term, welcher in der Funktion lessorequal verwendet
wird. Da c den Initialwert 0 hat, muss y wegen y=¬c entsprechend mit ¬0
starten.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.