Obwohl es mehrere Möglichkeiten gibt, die Bitreihenfolge in einem Byte umzukehren, bin ich gespannt, was für einen Entwickler am "einfachsten" zu implementieren ist. Und mit Umkehren meine ich:
1110 -> 0111
0010 -> 0100
Dies ist ähnlich, aber kein Duplikat dieser PHP-Frage.
Dies ist ähnlich, aber kein Duplikat dieser C-Frage. Diese Frage stellt die einfachste Methode dar, die von einem Entwickler implementiert werden kann. Der "beste Algorithmus" befasst sich mit der Speicher- und CPU-Leistung.
c++
c
bit-manipulation
Nathan
quelle
quelle
Antworten:
Wenn Sie über ein einzelnes Byte sprechen, ist eine Tabellensuche wahrscheinlich die beste Wahl, es sei denn, Sie haben aus irgendeinem Grund keine 256 Bytes zur Verfügung.
quelle
unsigned int rtable[] = {0x800, 0x4000, ...};
. Dann werfen Sie das Skript weg und vergessen Sie, dass Sie es jemals hatten. Das Schreiben ist viel schneller als der entsprechende C ++ - Code und wird immer nur einmal ausgeführt, sodass Sie in Ihrem C ++ - Code eine O (1) -Laufzeit erhalten.Das sollte funktionieren:
Zuerst werden die linken vier Bits gegen die rechten vier Bits ausgetauscht. Dann werden alle benachbarten Paare ausgetauscht und dann alle benachbarten Einzelbits. Dies führt zu einer umgekehrten Reihenfolge.
quelle
Ich denke, eine Nachschlagetabelle muss eine der einfachsten Methoden sein. Sie benötigen jedoch keine vollständige Nachschlagetabelle.
Dies ist ziemlich einfach zu codieren und visuell zu überprüfen.
Letztendlich könnte dies sogar schneller sein als ein voller Tisch. Das Bit Arith ist billig und die Tabelle passt leicht in eine Cache-Zeile.
quelle
b0001(1) -> b1000(0x8)
,b0010(2) -> b0100(0x4)
,b1010(10) -> b0101(0x5)
. Sehen Sie das Muster? Es ist einfach genug, dass Sie es in Ihrem Kopf berechnen können (wenn Sie binär lesen können, benötigen Sie sonst Papier, um es zu erarbeiten). Was den Sprung betrifft, ist das Umkehren einer 8-Bit-Ganzzahl dasselbe wie das Umkehren von 4-Bit-Teilen und das anschließende Vertauschen dieser Teile. Ich beanspruche Erfahrung und Intuition (oder Magie).Sehen Sie sich die kleinen Hacks an viele Lösungen. Copypasting von dort ist offensichtlich einfach zu implementieren. =)
Zum Beispiel (auf einer 32-Bit-CPU):
Wenn mit „einfach zu implementieren“ etwas gemeint ist, das ohne Referenz in einer Prüfung oder einem Vorstellungsgespräch durchgeführt werden kann, ist die sicherste Wette wahrscheinlich das ineffiziente Kopieren von Bits nacheinander in eine andere Variable in umgekehrter Reihenfolge (bereits in anderen Antworten gezeigt) ).
quelle
Da niemand eine vollständige Tabellensuchlösung veröffentlicht hat, ist hier meine:
quelle
BEARBEITEN:
Konvertierte es in eine Vorlage mit der optionalen Bitanzahl
quelle
sizeof(T)*8
mitsizeof(T)*CHAR_BITS
.sizeof(T)*CHAR_BIT
durchstd::numeric_limits<T>::digits
(fast 4 Jahre Pedanterie später).CHAR_BIT
nicht seinCHAR_BITS
.Zwei Linien:
oder falls Sie Probleme mit dem Teil "0b1" haben:
"original" ist das Byte, das Sie umkehren möchten. "umgekehrt" ist das Ergebnis, initialisiert auf 0.
quelle
Obwohl wahrscheinlich nicht portabel, würde ich Assemblersprache verwenden.
Viele Assemblersprachen haben Anweisungen, ein bisschen in das Übertragsflag zu drehen und das Übertragsflag in das Wort (oder Byte) zu drehen.
Der Algorithmus ist:
Der Hochsprachencode hierfür ist viel komplizierter, da C und C ++ das Drehen zum Übertragen und das Drehen vom Übertragen nicht unterstützen. Das Carry Flag muss modelliert werden.
Bearbeiten: Assemblersprache zum Beispiel
quelle
Ich finde die folgende Lösung einfacher als die anderen Bit-Fiddling-Algorithmen, die ich hier gesehen habe.
Es erhält jedes Bit im Byte und verschiebt es entsprechend, beginnend vom ersten zum letzten.
Erläuterung:
quelle
Der einfachste Weg ist wahrscheinlich, über die Bitpositionen in einer Schleife zu iterieren:
quelle
CHAR_BIT
wenn Siechar
8 Bits annehmen ?Für den sehr begrenzten Fall einer konstanten 8-Bit- Eingabe kostet diese Methode zur Laufzeit weder Speicher noch CPU:
Ich habe dies für ARINC-429 verwendet, bei dem die Bitreihenfolge (Endianness) des Labels dem Rest des Wortes gegenüberliegt. Das Etikett ist oft eine Konstante und üblicherweise oktal.
Hier ist, wie ich es verwendet habe, um eine Konstante zu definieren, da die Spezifikation diese Bezeichnung als Big-Endian 205-Oktal definiert.
Mehr Beispiele:
quelle
Sie könnten interessiert sein an
std::vector<bool>
(das ist etwas voll) undstd::bitset
Es sollte das einfachste sein, wie gewünscht.
Andere Optionen sind möglicherweise schneller.
EDIT: Ich schulde dir eine Lösung mit
std::vector<bool>
Das zweite Beispiel erfordert die Erweiterung c ++ 0x (um das Array mit zu initialisieren
{...}
). Der Vorteil der Verwendung von abitset
oder astd::vector<bool>
(oder aboost::dynamic_bitset
) besteht darin, dass Sie nicht auf Bytes oder Wörter beschränkt sind, sondern eine beliebige Anzahl von Bits umkehren können.HTH
quelle
std::vector<bool> b = { ... }; std::vector<bool> rb ( b.rbegin(), b.rend());
- Reverse Iteratoren direkt zu verwenden?Es gibt viele Möglichkeiten, Bits umzukehren, je nachdem, was Sie als "einfachsten Weg" bezeichnen.
Durch Drehen umkehren
Das wahrscheinlich logischste besteht darin, das Byte zu drehen, während eine Maske auf das erste Bit angewendet wird
(n & 1)
:1) Da die Länge eines Zeichens ohne Vorzeichen 1 Byte beträgt, was 8 Bit entspricht, bedeutet dies, dass jedes Bit gescannt wird
while (byte_len--)
2) Wir prüfen zuerst, ob b ein bisschen ganz rechts mit ist
(b & 1)
; Wenn ja, setzen wir Bit 1 auf r mit|
und verschieben es nur 1 Bit nach links, indem wir r mit 2 mit multiplizieren(r << 1)
3) Dann teilen wir unser vorzeichenloses Zeichen b durch 2 mit
b >>=1
, um das Bit ganz rechts von der Variablen b zu löschen. Zur Erinnerung, b >> = 1; ist äquivalent zu b / = 2;In einer Zeile umkehren
Diese Lösung wird Rich Schroeppel im Abschnitt Programming Hacks zugeschrieben
1) Die Multiplikationsoperation (b * 0x0202020202ULL) erstellt fünf separate Kopien des 8-Bit-Bytemusters, um sie auf einen 64-Bit-Wert aufzufächern.
2) Die UND-Operation (& 0x010884422010ULL) wählt die Bits aus, die sich in der richtigen (umgekehrten) Position befinden, relativ zu jeder 10-Bit-Gruppe von Bits.
3) Zusammen kopieren die Multiplikations- und die UND-Operation die Bits aus dem ursprünglichen Byte, so dass sie jeweils nur in einem der 10-Bit-Sätze erscheinen. Die umgekehrten Positionen der Bits aus dem ursprünglichen Byte stimmen mit ihren relativen Positionen innerhalb eines 10-Bit-Satzes überein.
4) Der letzte Schritt (% 0x3ff), bei dem der Modul durch 2 ^ 10 - 1 geteilt wird, führt dazu, dass jeder Satz von 10 Bits (von den Positionen 0-9, 10-19, 20-29, ...) zusammengeführt wird. im 64-Bit-Wert. Sie überlappen sich nicht, sodass sich die der Modulteilung zugrunde liegenden Additionsschritte wie ODER-Operationen verhalten.
Lösung teilen und erobern
Dies ist die am besten bewertete Antwort, und trotz einiger Erklärungen denke ich, dass es für die meisten Menschen schwierig ist, sich vorzustellen, was 0xF0, 0xCC, 0xAA, 0x0F, 0x33 und 0x55 wirklich bedeuten.
'0b', eine GCC-Erweiterung, die seit dem C ++ 14-Standard, der im Dezember 2014 veröffentlicht wurde, enthalten ist, wird nicht genutzt. Eine Weile nach dieser Antwort aus dem April 2010
Bitte überprüfen Sie die folgenden Codeausschnitte, um sich an diese Lösung zu erinnern und sie noch besser zu verstehen, bei der wir uns halb um die Hälfte bewegen:
NB: Die
>> 4
liegt daran, dass 1 Byte 8 Bits enthält, was ein vorzeichenloses Zeichen ist, also wollen wir die andere Hälfte nehmen und so weiter.Wir könnten diese Lösung leicht auf 4 Bytes mit nur zwei zusätzlichen Zeilen anwenden und der gleichen Logik folgen. Da sich beide Masken ergänzen, können wir sogar ~ verwenden, um Bits zu wechseln und etwas Tinte zu sparen:
[Nur C ++] Alle vorzeichenlosen (Vorlage) umkehren
Die obige Logik kann mit einer Schleife zusammengefasst werden, die für jede Art von vorzeichenlosem funktioniert:
Probieren Sie es selbst aus, indem Sie die obige Funktion einbeziehen:
Mit asm flüchtig umkehren
Last but not least, wenn das Einfachste weniger Linien bedeutet, warum nicht versuchen, die Inline-Montage durchzuführen?
Sie können das folgende Code-Snippet testen, indem Sie
-masm=intel
beim Kompilieren Folgendes hinzufügen :Erklärungen Zeile für Zeile:
quelle
Tabellensuche oder
bearbeiten
Suchen Sie hier nach anderen Lösungen, die für Sie möglicherweise besser funktionieren
quelle
eine langsamere aber einfachere Implementierung:
quelle
Kann das eine schnelle Lösung sein?
Beseitigt die Hektik der Verwendung einer for-Schleife! Aber Experten sagen mir bitte, ob dies effizient und schneller ist.
quelle
Überprüfen Sie vor der Implementierung einer algorithmischen Lösung die Assemblersprache auf die von Ihnen verwendete CPU-Architektur. Ihre Architektur kann Anweisungen enthalten, die bitweise Manipulationen wie diese handhaben (und was könnte einfacher sein als eine einzelne Montageanweisung?).
Wenn eine solche Anweisung nicht verfügbar ist, würde ich empfehlen, die Route der Nachschlagetabelle zu verwenden. Sie können ein Skript / Programm schreiben, um die Tabelle für Sie zu generieren, und die Suchvorgänge wären schneller als alle hier beschriebenen Bitumkehralgorithmen (auf Kosten der Speicherung der Nachschlagetabelle irgendwo).
quelle
Diese einfache Funktion verwendet eine Maske, um jedes Bit im Eingangsbyte zu testen und in einen verschiebbaren Ausgang zu übertragen:
quelle
Dieser basiert auf dem einen BobStein-VisiBone bereitgestellten
Ich mag dieses sehr, weil der Compiler die Arbeit automatisch für Sie erledigt und daher keine weiteren Ressourcen benötigt.
Dies kann auch auf 16-Bit erweitert werden ...
quelle
b
in Klammern setzen, falls es sich um einen komplexeren Ausdruck als eine einzelne Zahl handelt, und das Makro vielleicht auch umbenennen,REVERSE_BYTE
um darauf hinzuweisen, dass Sie dort wahrscheinlich keinen komplexeren (Laufzeit-) Ausdruck haben möchten. Oder machen Sie es zu einer Inline-Funktion. (Aber insgesamt mag ich dies als einfach genug, dass Sie es leicht aus dem Gedächtnis mit sehr geringer Wahrscheinlichkeit von Fehlern tun können.)Angenommen, Ihr Compiler lässt unsigned long long zu :
Hier entdeckt
quelle
Wenn Sie einen kleinen Mikrocontroller verwenden und eine Hochgeschwindigkeitslösung mit geringem Platzbedarf benötigen, können dies Lösungen sein. Es ist möglich, es für C-Projekte zu verwenden, aber Sie müssen diese Datei als Assembler-Datei * .asm zu Ihrem C-Projekt hinzufügen. Anleitung: Fügen Sie im C-Projekt diese Deklaration hinzu:
Rufen Sie diese Funktion von C aus auf
Dies ist der Code, er ist nur für 8051 Core geeignet. Im CPU-Register r0 befinden sich Daten von byteInput . Code rechts drehen r0 Cross Carry und dann Carry links nach r1 drehen . Wiederholen Sie diesen Vorgang 8 Mal für jedes Bit. Dann wird das Register r1 als ByteOutput an c zurückgegeben. In 8051 ist der Kern nur möglich, um den Akku a zu drehen .
PROS: Es ist klein, es ist schnell. Nachteile: Es ist kein wiederverwendbarer Code, es ist nur für 8051
011101101-> tragen
101101110 <-tragen
quelle
Das umgekehrte Byte befindet sich im bl- Register
quelle
quelle
uint8_t
für die 1-Bit-Felder etwas hässlich, da es zunächst zu sagen scheint, dass es 8 Bit dauern wird, aber dann am Ende der Zeile als nur ein einzelnes Bit definiert wird. Ich würdeunsigned b0:1
usw. verwendenquelle
Ich denke das ist einfach genug
oder
quelle
quelle
Ich werde meine Lösung einbinden, da ich so etwas in den Antworten bisher nicht finden kann. Es ist vielleicht etwas überarbeitet, aber es generiert die Nachschlagetabelle mit C ++ 14
std::index_sequence
in der Kompilierungszeit.https://godbolt.org/z/cSuWhF
quelle
Hier ist eine einfache und lesbare Lösung, die auf alle konformen Plattformen portierbar ist, einschließlich solcher mit
sizeof(char) == sizeof(int)
:quelle
Ich weiß, dass diese Frage veraltet ist, aber ich denke immer noch, dass das Thema für einige Zwecke relevant ist, und hier ist eine Version, die sehr gut funktioniert und lesbar ist. Ich kann nicht sagen, dass es das schnellste oder effizienteste ist, aber es sollte eines der saubersten sein. Ich habe auch eine Hilfsfunktion zum einfachen Anzeigen der Bitmuster hinzugefügt. Diese Funktion verwendet einige der Standardbibliotheksfunktionen, anstatt einen eigenen Bitmanipulator zu schreiben.
Und es gibt die folgende Ausgabe.
quelle
Dieser half mir mit 8x8 Punktmatrix-Arrays.
quelle