¿Cuál es el nombre para almacenar / empaquetar muchos estados booleanos en un solo número?


55

Es una especie de compresión simple en la que utiliza una variable numérica para almacenar muchos estados booleanos / binarios, utilizando la duplicación y el hecho de que cada número de duplicación es 1 + la suma de todos los anteriores.

Estoy seguro de que debe ser una técnica antigua y bien conocida, me gustaría saber cómo se llama para referirme a ella correctamente. Hice varias búsquedas en todas las formas en que puedo pensar para describirlo, pero no encontré nada más allá de algunos artículos de blog en los que los autores del artículo parecen haberlo descubierto ellos mismos y tampoco saben cómo llamarlo ( ejemplo 1 , ejemplo 2 ).

Por ejemplo, aquí hay una implementación muy simple destinada a ilustrar el concepto:

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
}

También podría usar operadores bit a bit, análisis de números de base 2, enumeraciones ... Hay muchas maneras más eficientes de implementarlo, estoy interesado en el nombre del enfoque en general.


8
En C #, hay enums, y pueden tener un Flagsatributo. Podrían hacer que su código sea mucho más simple.
Bernhard Hiller

12
Yo llamaría a esto "simular campos de bits". Casi siempre es una mala idea a menos que la eficiencia del espacio sea abrumadoramente importante.
Kilian Foth

77
@KilianFoth A boolgeneralmente se almacena internamente como un entero de 32 bits. Como tal, el embalaje puede marcar la diferencia de un factor de 32. Eso es realmente mucho. Quiero decir, los programadores siempre estamos listos para tirar la mitad de nuestros recursos, pero generalmente soy reacio a tirar el 97% de ellos. Tales factores de desperdicio pueden hacer fácilmente la diferencia entre poder ejecutar casos de uso importantes y quedarse sin memoria.
cmaster

3
Históricamente, la forma típica de las máscaras de bits se utilizan para declarar, establecer y recuperar valores. El uso de turnos es extraño y no es realmente la mejor ilustración del enfoque.
JimmyJames

3
@cmaster La razón por la que los bools se almacenan de esa manera es porque compartir una sola ubicación de memoria (32 o 64 bits en las máquinas actuales) puede ser muy malo para el rendimiento de la memoria caché a menos que preste mucha atención al código del lenguaje de la máquina. Si tiene una cantidad realmente masiva de bits, probablemente valga la pena, pero si no, probablemente sea mejor no optimizar previamente y simplemente empaquetar los bits cuando esté listo para transmitir a la red o al disco.
Bill K

Respuestas:


107

Se conoce comúnmente como un campo de bits , y otro término que a menudo escuchará es máscaras de bits , que se utilizan para obtener o establecer valores de bits individuales o todo el campo de bits a la vez.

Muchos lenguajes de programación tienen estructuras auxiliares para ayudar con esto. Como @BernhardHiller señala en los comentarios, C # tiene enumeraciones con banderas ; Java tiene la clase EnumSet .


44
Interpretaría "campo de bits" como el uso de una función de lenguaje que permite asignar bits individuales a los campos de una estructura en lugar de hacerlo manualmente con operadores bit a bit.
Peter Green

22
@PeterGreen Eso sería diferente a la interpretación estándar.
Eric

1
"Bit Mapping" o "Bit Mapped", aunque son comunes para conjuntos de registros y procesamiento de matrices, también pueden aplicarse en este caso. Al extraer elementos comunes de múltiples conjuntos, el valor se puede descomponer para identificar componentes de un modelo federado. Incluso decimos esto de los dígitos del modo de archivo octal. Las máscaras de bits (cualquier máscara) tienden a ser filtros (como para puertos IO y registros de dirección de datos).
mckenzm

1
C # también tiene BitArray, lo que permite almacenar una cantidad arbitraria de bits e indexarlos (mientras que las banderas están limitadas a un tipo entero y están destinadas a ser utilizadas como máscaras).
Luaan

Cierto; Acabo de mencionar las dos estructuras con las que estoy más familiarizado. Probablemente hay docenas por ahí, especialmente en otros idiomas.
Glorfindel

20

Extraño, hay muchos términos diferentes aquí, pero no veo el que me vino a la mente de inmediato (¡y está en el título de su pregunta!) - Bit Packing es lo que siempre he escuchado llamarlo.

Pensé que esto era realmente obvio, pero extrañamente, cuando lo busco en Google, este parece ser un término que se usa ampliamente pero no está definido oficialmente (Wikipedia parece redirigir al campo de bits, que es una forma de empaquetar bits, pero no un nombre para el proceso). La búsqueda de la definición parece conducir a esta página:

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

Lo que no es bueno para fines SO, pero es la mejor definición / descripción que puedo encontrar, incluida esta breve descripción: "El empaquetado de bits es un concepto simple: use la menor cantidad posible para almacenar una pieza de datos".


¿Puedes proporcionar algunas referencias? Término interesante
Greg Burghardt

13
El empaquetamiento de bits es técnicamente correcto, pero también se refiere a algo más general que solo los estados booleanos: almacenar datos en general en el menor número de bits posible. Por ejemplo, otro uso de este podría significar comprimir una charmatriz al poner dos chars en uno int.
Izkata

@ GregBurghardt Sabes, es interesante. No pensé en ello cuando publiqué porque el término era muy frecuente en los años 80/90 cuando aprendí a programar en C y ensamblado; ahora, aunque una búsqueda en Google encuentra MUCHAS menciones, no hay una página definitiva de Wikipedia para ello. . La primera respuesta en Google tiene esta definición: "El empaquetado de bits es un concepto simple: utilice la menor cantidad posible de bits para almacenar un dato". kinematicsoup.com/news/2016/9/6/…
Bill K

Fue entonces cuando aprendí sobre el empaquetado de bits también, aunque puede volverse mucho más loco que simplemente reutilizar 0 no utilizados en lo que nominalmente serían valores enteros. Hace algunos años me encontré con un sistema que almacenaba uno de sus parámetros como un flotante de 8 bits. IIRC 5 bits para una mantisa sin signo (todos los valores fueron positivos, no es necesario almacenar el signo explícitamente), y 3 más para un exponente de base 10. En el momento en que supuse que era un error de hardware heredado sin camino hacia adelante, pero con el aprendizaje automático que recientemente comenzó a hacer cosas con int4 vs int8, pude ver algunas cargas de trabajo cayendo desde FP16.
Dan Neely

1
@DanNeely Este tipo de cosas también es comúnmente compatible con las GPU: el intercambio entre precisión, memoria y cálculo es bastante importante allí. Esto también se ha explotado bastante bien con la informática basada en GPU.
Luaan

14

Hay muchos términos diferentes utilizados para describir esto.

Lo más común es que los bits se denominen "banderas de bits" o "campos de bits".
(Sin embargo, vale la pena señalar que los "campos de bits" a veces se refieren a una característica específica de los lenguajes C y C ++, que está relacionada pero no es exactamente la misma).

El entero en sí mismo se conoce como "matriz de bits", "conjunto de bits" o "vector de bits", según los usos y las circunstancias.

De cualquier manera, la extracción de los bits del conjunto de bits / vector / matriz se realiza mediante desplazamiento y enmascaramiento.
(es decir, usando una máscara de bits ).


Para algunos ejemplos de cada término en uso activo:


No es realmente pertinente para la pregunta, pero me gustaría decir: por favor, no use la suma y la resta para establecer y borrar bits, ya que esos métodos son propensos a errores.
(es decir, si lo hace num += 1dos veces, el resultado es equivalente a num += 2).

En su lugar, prefiere utilizar las operaciones bit a bit apropiadas, si su idioma elegido las proporciona:

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);
}

1
this.stateF = (num & 32) ? true : false, etc. No es necesario mutar nummientras extrae los valores.
Roger Lipscombe

3
@RogerLipscombe Buen punto, en realidad no estaba leyendo lo que estaba haciendo el código, solo reaccionaba al uso de +y -. Ahora me he vuelto mejor y he usado en != 0lugar de un ternario, lo que creo que es más conciso y aún así es explícito.
Pharap el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.