Bien qu'il existe plusieurs façons d'inverser l'ordre des bits dans un octet, je suis curieux de savoir quelle est la "plus simple" à implémenter pour un développeur. Et en inversant je veux dire:
1110 -> 0111
0010 -> 0100
Ceci est similaire, mais pas un double de celui-ci question PHP.
Ceci est similaire, mais pas une copie de cette question C. Cette question demande la méthode la plus simple à mettre en œuvre par un développeur. Le «meilleur algorithme» concerne les performances de la mémoire et du processeur.
c++
c
bit-manipulation
Nathan
la source
la source
Réponses:
Si vous parlez d'un seul octet, une recherche de table est probablement le meilleur choix, sauf si pour une raison quelconque vous n'avez pas 256 octets disponibles.
la source
unsigned int rtable[] = {0x800, 0x4000, ...};
. Ensuite, jetez le script et oubliez que vous l'avez jamais eu. Il est beaucoup plus rapide à écrire que le code C ++ équivalent, et il ne s'exécutera qu'une seule fois, donc vous obtenez le runtime O (1) dans votre code C ++.Cela devrait fonctionner:
Tout d'abord, les quatre bits de gauche sont échangés avec les quatre bits de droite. Ensuite, toutes les paires adjacentes sont permutées, puis tous les bits simples adjacents. Cela entraîne un ordre inversé.
la source
Je pense qu'une table de consultation doit être l'une des méthodes les plus simples. Cependant, vous n'avez pas besoin d'une table de recherche complète.
C'est assez simple à coder et à vérifier visuellement.
En fin de compte, cela pourrait même être plus rapide qu'une table complète. Le bit arith est bon marché et la table tient facilement sur une ligne de cache.
la source
b0001(1) -> b1000(0x8)
,b0010(2) -> b0100(0x4)
,b1010(10) -> b0101(0x5)
. Vous voyez le modèle? C'est assez simple pour que vous puissiez le calculer dans votre tête (si vous pouvez lire le binaire, sinon vous aurez besoin de papier pour le résoudre). Quant au saut, l'inversion d'un entier de 8 bits équivaut à inverser des parties de 4 bits puis à les échanger; Je revendique l'expérience et l'intuition (ou la magie).Voir les hacks twiddling bit pour de nombreuses solutions. Le copypast à partir de là est évidemment simple à mettre en œuvre. =)
Par exemple (sur un processeur 32 bits):
Si par «simple à mettre en œuvre», on entend quelque chose qui peut être fait sans référence dans un examen ou un entretien d'embauche, alors le pari le plus sûr est probablement la copie inefficace des bits un par un dans une autre variable dans l'ordre inverse (déjà indiqué dans d'autres réponses ).
la source
Puisque personne n'a publié de solution complète de recherche de table, voici la mienne:
la source
ÉDITER:
Je l'ai converti en modèle avec le nombre de bits optionnel
la source
sizeof(T)*8
parsizeof(T)*CHAR_BITS
.sizeof(T)*CHAR_BIT
parstd::numeric_limits<T>::digits
(presque 4 ans de pédanterie plus tard).CHAR_BIT
, nonCHAR_BITS
.Deux lignes:
ou en cas de problème avec la partie "0b1":
"original" est l'octet que vous souhaitez inverser. "inversé" est le résultat, initialisé à 0.
la source
Bien que probablement pas portable, j'utiliserais le langage d'assemblage.
De nombreux langages d'assemblage ont des instructions pour tourner un peu dans le drapeau de retenue et pour faire pivoter le drapeau de retenue dans le mot (ou l'octet).
L'algorithme est:
Le code de langage de haut niveau pour cela est beaucoup plus compliqué, car C et C ++ ne prennent pas en charge la rotation pour porter et la rotation à partir de carry. Le drapeau de portage doit être modélisé.
Edit: langage d'assemblage par exemple
la source
Je trouve la solution suivante plus simple que les autres algorithmes de bidouillage que j'ai vus ici.
Il récupère chaque bit de l'octet et le décale en conséquence, du premier au dernier.
Explication:
la source
Le moyen le plus simple consiste probablement à parcourir les positions des bits dans une boucle:
la source
CHAR_BIT
quand vous supposezchar
avoir 8 bits?Vous pourriez être intéressé par
std::vector<bool>
(c'est-à-dire en bits) etstd::bitset
Ce devrait être le plus simple demandé.
D'autres options peuvent être plus rapides.
EDIT: je vous dois une solution utilisant
std::vector<bool>
Le deuxième exemple nécessite l'extension c ++ 0x (pour initialiser le tableau avec
{...}
). L'avantage d'utiliser unbitset
ou unstd::vector<bool>
(ou unboost::dynamic_bitset
) est que vous n'êtes pas limité aux octets ou aux mots mais que vous pouvez inverser un nombre arbitraire de bits.HTH
la source
std::vector<bool> b = { ... }; std::vector<bool> rb ( b.rbegin(), b.rend());
utilisiez directement des itérateurs inversés?Dans le cas très limité d' une entrée constante de 8 bits , cette méthode ne coûte ni mémoire ni CPU au moment de l'exécution:
J'ai utilisé ceci pour ARINC-429 où l'ordre des bits (endianness) de l'étiquette est opposé au reste du mot. L'étiquette est souvent une constante, et classiquement en octal.
Voici comment je l'ai utilisé pour définir une constante, car la spécification définit cette étiquette comme big-endian 205 octal.
Plus d'exemples:
la source
Il existe de nombreuses façons d'inverser les bits en fonction de ce que vous entendez par la «manière la plus simple».
Inverser par rotation
Probablement le plus logique, consiste à faire tourner l'octet tout en appliquant un masque sur le premier bit
(n & 1)
:1) Comme la longueur d'un caractère unsigner est de 1 octet, ce qui est égal à 8 bits, cela signifie que nous allons scanner chaque bit
while (byte_len--)
2) On vérifie d'abord si b est un peu à l'extrême droite avec
(b & 1)
; si c'est le cas, nous positionnons le bit 1 sur r avec|
et le déplaçons juste 1 bit vers la gauche en multipliant r par 2 avec(r << 1)
3) Ensuite, nous divisons notre caractère non signé b par 2 avec
b >>=1
pour effacer le bit situé à l'extrême droite de la variable b. Pour rappel, b >> = 1; équivaut à b / = 2;Inverser en une seule ligne
Cette solution est attribuée à Rich Schroeppel dans la section Programming Hacks
1) L'opération de multiplication (b * 0x0202020202ULL) crée cinq copies distinctes du modèle d'octets 8 bits à déplier en une valeur 64 bits.
2) L'opération ET (& 0x010884422010ULL) sélectionne les bits qui sont dans les positions correctes (inversées), par rapport à chaque groupe de bits de 10 bits.
3) Ensemble, les opérations multiplication et ET copient les bits de l'octet d'origine afin qu'ils apparaissent chacun dans un seul des ensembles de 10 bits. Les positions inversées des bits de l'octet d'origine coïncident avec leurs positions relatives dans tout ensemble de 10 bits.
4) La dernière étape (% 0x3ff), qui implique la division du module par 2 ^ 10 - 1 a pour effet de fusionner chaque ensemble de 10 bits (à partir des positions 0-9, 10-19, 20-29, ...) dans la valeur 64 bits. Ils ne se chevauchent pas, de sorte que les étapes d'addition sous-jacentes à la division du module se comportent comme des opérations OR.
Solution Diviser et Conquérir
C'est la réponse la plus votée et malgré quelques explications, je pense que pour la plupart des gens, il est difficile de visualiser ce que signifie vraiment 0xF0, 0xCC, 0xAA, 0x0F, 0x33 et 0x55.
Il ne profite pas de '0b' qui est une extension GCC et est inclus depuis la norme C ++ 14, sortie en décembre 2014, donc un peu après cette réponse datant d'avril 2010
Veuillez vérifier les extraits de code ci-dessous pour vous souvenir et comprendre encore mieux cette solution où nous nous déplaçons de moitié par moitié:
NB: C'est
>> 4
parce qu'il y a 8 bits dans 1 octet, ce qui est un caractère non signé donc nous voulons prendre l'autre moitié, et ainsi de suite.Nous pourrions facilement appliquer cette solution à 4 octets avec seulement deux lignes supplémentaires et en suivant la même logique. Étant donné que les deux masques se complètent, nous pouvons même utiliser ~ pour changer de bits et économiser de l'encre:
[C ++ uniquement] Inverser tout non signé (modèle)
La logique ci-dessus peut être résumée avec une boucle qui fonctionnerait sur n'importe quel type de non signé:
Essayez-le vous-même avec l'inclusion de la fonction ci-dessus:
Inverser avec asm volatile
Enfin, si le plus simple signifie moins de lignes, pourquoi ne pas essayer l'assemblage en ligne?
Vous pouvez tester l'extrait de code ci-dessous en ajoutant
-masm=intel
lors de la compilation:Explications ligne par ligne:
la source
Recherche de table ou
Éditer
Recherchez ici d'autres solutions qui pourraient mieux fonctionner pour vous
la source
une implémentation plus lente mais plus simple:
la source
Cela peut-il être une solution rapide?
Débarrassez-vous de la hâte d'utiliser une boucle for! mais les experts s'il vous plaît me dire si c'est efficace et plus rapide?
la source
Avant d'implémenter une solution algorithmique, vérifiez le langage d'assemblage pour quelle que soit l'architecture de processeur que vous utilisez. Votre architecture peut inclure des instructions qui gèrent des manipulations au niveau du bit comme celle-ci (et quoi de plus simple qu'une seule instruction d'assemblage?).
Si une telle instruction n'est pas disponible, je suggérerais de suivre l'itinéraire de la table de recherche. Vous pouvez écrire un script / programme pour générer la table pour vous, et les opérations de recherche seraient plus rapides que n'importe quel algorithme d'inversion de bits ici (au prix de devoir stocker la table de recherche quelque part).
la source
Cette fonction simple utilise un masque pour tester chaque bit de l'octet d'entrée et le transférer dans une sortie décalée:
la source
Celui - ci est basé sur une BobStein-VisiBone fourni
J'aime beaucoup celui-ci car le compilateur gère automatiquement le travail pour vous, donc ne nécessite aucune ressource supplémentaire.
cela peut également être étendu à 16 bits ...
la source
b
entre parenthèses au cas où il s'agirait d' une expression plus complexe qu'un seul nombre, et peut-être également renommer la macroREVERSE_BYTE
en un indice que vous ne voulez probablement pas avoir une expression plus complexe (runtime). Ou faites-en une fonction en ligne. (Mais dans l'ensemble, j'aime cela comme étant assez simple pour que vous puissiez le faire de mémoire facilement avec très peu de chances d'erreur.)En supposant que votre compilateur autorise non signé long long :
Découvert ici
la source
Si vous utilisez un petit microcontrôleur et avez besoin d'une solution haute vitesse avec un faible encombrement, cela pourrait être des solutions. Il est possible de l'utiliser pour un projet C, mais vous devez ajouter ce fichier en tant que fichier assembleur * .asm, à votre projet C. Instructions: Dans le projet C, ajoutez cette déclaration:
Appelez cette fonction depuis C
Ceci est le code, il ne convient que pour le noyau 8051. Dans le registre CPU r0 se trouvent les données de byteInput . Code tournez à droite r0 cross carry puis tournez à gauche jusqu'à r1 . Répétez cette procédure 8 fois, pour chaque bit. Ensuite, le registre r1 est renvoyé à la fonction c en tant que byteOutput. Dans 8051 le noyau est seulement possible de faire tourner un accumulateur a .
AVANTAGES: c'est un faible encombrement, c'est une vitesse élevée CONS: ce n'est pas du code réutilisable, c'est seulement pour 8051
011101101-> porter
101101110 <-porter
la source
l'octet inversé sera au registre bl
la source
la source
uint8_t
pour les champs 1 bit un peu moche, car il semble d'abord dire que cela prendra 8 bits, mais à la fin de la ligne, le définit comme un seul bit. J'utiliseraisunsigned b0:1
etc.la source
Je pense que c'est assez simple
ou
la source
la source
Je vais ajouter ma solution, car je ne trouve rien de tel dans les réponses jusqu'à présent. C'est peut-être un peu sur-conçu, mais il génère la table de recherche en utilisant C ++ 14
std::index_sequence
au moment de la compilation.https://godbolt.org/z/cSuWhF
la source
Voici une solution simple et lisible, portable sur toutes les plateformes conformes, y compris celles avec
sizeof(char) == sizeof(int)
:la source
Je sais que cette question est datée mais je pense toujours que le sujet est pertinent à certaines fins, et voici une version qui fonctionne très bien et qui est lisible. Je ne peux pas dire que ce soit le plus rapide ou le plus efficace, mais il devrait être l'un des plus propres. J'ai également inclus une fonction d'assistance pour afficher facilement les modèles de bits. Cette fonction utilise certaines des fonctions standard de la bibliothèque au lieu d'écrire votre propre manipulateur de bits.
Et cela donne la sortie suivante.
la source
Celui-ci m'a aidé avec un ensemble de tableaux matriciels 8x8.
la source