Quel est le nom pour stocker / emballer plusieurs états booléens en un seul numéro?

55

C'est une sorte de compression simple dans laquelle vous utilisez une variable numérique pour stocker plusieurs états booléens / binaires, en utilisant le doublage et le fait que chaque nombre de doublage est égal à 1 + la somme de tous les précédents.

Je suis sûr que ce doit être une vieille technique bien connue, j'aimerais savoir comment on l'appelle pour s'y référer correctement. J'ai fait plusieurs recherches sur tous les moyens possibles pour le décrire, mais je n'ai rien trouvé au-delà de certains articles de blog où les auteurs de l'article semblent l'avoir compris eux-mêmes et ne savent pas comment l'appeler ( exemple 1 , exemple 2 ).

Par exemple, voici une implémentation très simple destinée à illustrer le concept:

packStatesIntoNumber () {
  let num = 0
  if (this.stateA) num += 1
  if (this.stateB) num += 2
  if (this.stateC) num += 4
  if (this.stateD) num += 8
  if (this.stateE) num += 16
  if (this.stateF) num += 32
  return num
}

unpackStatesFromNumber (num) {
  assert(num < 64)
  this.stateF = num >= 32; if (this.stateF) num -= 32
  this.stateE = num >= 16; if (this.stateE) num -= 16
  this.stateD = num >= 8; if (this.stateD) num -= 8
  this.stateC = num >= 4; if (this.stateC) num -= 4
  this.stateB = num >= 2; if (this.stateB) num -= 2
  this.stateA = num >= 1; if (this.stateA) num -= 1
}

Vous pouvez également utiliser des opérateurs au niveau des bits, l'analyse du nombre de base 2, les énumérations ... Il existe de nombreuses manières plus efficaces de l'implémenter. Je m'intéresse plus généralement au nom de l'approche.

utilisateur56reinstatemonica8
la source
8
En C #, il y enumsen a et ils peuvent avoir un Flagsattribut. Ils pourraient rendre votre code beaucoup plus simple.
Bernhard Hiller
12
J'appellerais cela "simuler des champs de bits". C'est presque toujours une mauvaise idée à moins que l'efficacité de l'espace ne soit extrêmement importante.
Kilian Foth
7
@KilianFoth A boolest généralement stocké en interne sous la forme d'un entier de 32 bits. En tant que tel, l'emballage peut faire la différence d'un facteur 32. C'est beaucoup. Je veux dire, nous, les programmeurs, sommes toujours prêts à jeter la moitié de nos ressources, mais je suis généralement réticent à en rejeter 97%. De tels facteurs de gaspillage peuvent facilement faire la différence entre la capacité d'exécuter des cas d'utilisation importants et le manque de mémoire.
cmaster
3
Historiquement, les masques de bits sont généralement utilisés pour déclarer, définir et récupérer des valeurs. L'utilisation des changements est étrange et n'est pas vraiment la meilleure illustration de l'approche.
JimmyJames
3
@cmaster La raison pour laquelle les bools sont stockés de cette façon est que le partage d'un seul emplacement de mémoire (32 ou 64 bits sur les machines actuelles) peut être très mauvais pour les performances du cache, sauf si vous portez une attention particulière au code de langage machine. Si vous avez vraiment un nombre massif de bits, cela en vaut probablement la peine, mais sinon, vous feriez mieux de ne pas pré-optimiser et de simplement les ranger lorsque vous êtes prêt à transmettre au réseau ou au disque.
Bill K

Réponses:

107

C'est le plus souvent appelé champ de bits , et un autre terme que vous entendrez souvent est celui de masques de bits , qui sont utilisés pour obtenir ou définir des valeurs de bits individuelles ou le champ de bits entier à la fois.

De nombreux langages de programmation ont des structures auxiliaires pour aider à cela. Comme @BernhardHiller le note dans les commentaires, C # a des énumérations avec des drapeaux ; Java a la classe EnumSet .

Glorfindel
la source
4
J'interpréterais le terme "champ de bits" comme utilisant une fonctionnalité de langage qui permet d'attribuer des bits individuels aux champs d'une structure plutôt que de le faire manuellement avec des opérateurs au niveau du bit.
Peter Green
22
@ Peter Green Cela serait différent de l'interprétation standard.
Eric
1
"Bit Mapping" ou "Bit Mapped", bien qu'ils soient communs aux jeux d'enregistrements et au traitement de tableaux, peuvent également s'appliquer dans ce cas. Lors de l'extraction d'éléments communs de plusieurs ensembles, la valeur peut être décomposée pour identifier les composants d'un modèle fédéré. Nous disons même cela de chiffres octaux en mode fil. Les masques binaires (tous les masques) ont tendance à être des filtres (comme pour les ports d'E / S et les registres de direction des données).
mckenzm
1
C # a également BitArray, ce qui permet de stocker une quantité arbitraire de bits et de les indexer (alors que les indicateurs sont limités à un type entier et sont destinés à être utilisés comme masques).
Luaan
Vrai; Je viens de mentionner les deux structures que je connais le mieux. Il y en a probablement des dizaines, surtout dans d'autres langues.
Glorfindel
20

Étrange, pas mal de termes différents ici mais je ne vois pas celui qui m’a tout de suite préoccupé (et c’est dans le titre de votre question!) - Bit Packing est ce que j’ai toujours entendu dire.

J’avais pensé que c’était vraiment évident, mais étrangement, quand j’ai cherché sur Google, c’est un terme qui est largement utilisé mais qui n’est pas défini officiellement (Wikipédia semble rediriger vers un champ processus). La recherche de la définition semble mener à cette page:

http://www.kinematicsoup.com/news/2016/9/6/data-compression-bit-packing-101

Ce qui n’est pas génial pour SO, mais c’est la meilleure définition / description que je puisse trouver, y compris cette description succincte: "La compression de bits est un concept simple: utilisez aussi peu que possible pour stocker une donnée."

Bill K
la source
Pouvez-vous fournir des références? Terme intéressant.
Greg Burghardt
13
La compression de bits est techniquement correcte, mais fait également référence à une chose plus générale que les états booléens: stocker des données en général dans le plus petit nombre de bits possible. Par exemple, une autre utilisation de celui-ci pourrait consister à compresser un chartableau en mettant deux chars en un int.
Izkata
@ GregBurghardt Vous savez, c'est intéressant. Je n'y avais pas pensé lorsque j'ai posté car le terme était si répandu dans les années 80/90 lorsque j'ai appris la programmation en C et en assemblage - bien qu'une recherche sur Google trouve de nombreuses mentions, il n'y a pas de page Wikipédia définitive pour cela. . La première réponse dans Google a cette définition: "La compression de bits est un concept simple: utilisez le moins de bits possible pour stocker une donnée." kinematicsoup.com/news/2016/9/6/…
Bill K
C’est là que j’ai aussi appris à utiliser l’emballage de bits, même si vous pouvez être beaucoup plus fou que de simplement réutiliser des 0 inutilisés dans ce qui serait nominalement des valeurs entières. Il y a quelques années, j'ai rencontré un système qui stockait l'un de ses paramètres sous forme de float 8 bits. IIRC 5 bits pour une mantisse non signée (toutes les valeurs étaient positives, il n'est pas nécessaire de stocker explicitement le signe) et 3 autres pour un exposant en base 10. À l'époque, j'avais supposé qu'il s'agissait d'un kludge matériel hérité sans chemin à parcourir, mais l'apprentissage automatique ayant récemment commencé à faire des choses avec int4 vs int8, je pouvais voir certaines charges de travail diminuer de FP16.
Dan Neely
1
@DanNeely Ce genre de chose est également généralement supporté par les GPU - le commerce entre précision, mémoire et calcul y est très important. Ceci a été assez bien exploité avec l'informatique basée sur GPU.
Luaan
14

Il existe de nombreux termes différents utilisés pour décrire cela.

Le plus souvent, les bits sont appelés "indicateurs de bits" ou "champs de bits".
(Toutefois, il convient de noter que les "champs de bits" font parfois référence à une fonctionnalité spécifique des langages C et C ++, qui est liée mais pas tout à fait la même.)

L'entier lui-même est désigné indifféremment comme un "tableau de bits", un "ensemble de bits" ou un "vecteur de bits", en fonction des usages et des circonstances.

Dans les deux cas, l'extraction des bits de l'ensemble de bits / du vecteur / de la matrice s'effectue par décalage et masquage.
(ie en utilisant un masque de bits .)


Pour quelques exemples de chaque terme en utilisation active:


Ce n'est pas vraiment pertinent pour la question, mais j'aimerais dire: n'utilisez pas d'addition et de soustraction pour définir et effacer des bits, car ces méthodes sont sujettes aux erreurs.
(Par exemple, si vous faites num += 1deux fois, le résultat est équivalent à num += 2.)

Préférez utiliser les opérations appropriées au niveau des bits, si la langue de votre choix les fournit:

packStatesIntoNumber ()
{
  let num = 0
  if (this.stateA) num |= 1
  if (this.stateB) num |= 2
  if (this.stateC) num |= 4
  if (this.stateD) num |= 8
  if (this.stateE) num |= 16
  if (this.stateF) num |= 32
  return num
}

unpackStatesFromNumber (num)
{
  this.stateF = ((num & 32) != 0);
  this.stateE = ((num & 16) != 0);
  this.stateD = ((num & 8) != 0);
  this.stateC = ((num & 4) != 0);
  this.stateB = ((num & 2) != 0);
  this.stateA = ((num & 1) != 0);
}
Pharap
la source
1
this.stateF = (num & 32) ? true : false, etc. Pas besoin de muter numpendant l'extraction des valeurs.
Roger Lipscombe
3
@RogerLipscombe Bon point, je ne lisais pas vraiment ce que faisait le code, je ne faisais que réagir à l'utilisation de +et -. Je suis maintenant allé mieux et utilisé à la != 0place d'un ternaire, ce qui me semble plus concis tout en restant exposé.
Pharap