Qual é o nome para armazenar / compactar muitos estados booleanos em um número?


55

É uma espécie de compactação simples, na qual você usa uma variável numérica para armazenar muitos estados booleanos / binários, usando a duplicação e o fato de que todo número de duplicação é 1 + a soma de todos os anteriores.

Tenho certeza de que deve ser uma técnica antiga e bem conhecida. Gostaria de saber como é chamada para se referir a ela corretamente. Fiz várias pesquisas de todas as formas possíveis para descrevê-lo, mas não encontrei nada além de alguns artigos de blog em que os autores do artigo parecem ter descoberto isso por conta própria e também não sabem como chamá-lo ( exemplo 1 , exemplo 2 ).

Por exemplo, aqui está uma implementação muito simples destinada a ilustrar o conceito:

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
}

Você também pode usar operadores bit a bit, análise de número de base 2, enumerações ... Existem muitas maneiras mais eficientes de implementá-lo. Estou interessado no nome da abordagem em geral.


8
Em C #, existem enumse eles podem ter um Flagsatributo. Eles poderiam tornar seu código muito mais simples.
Bernhard Hiller

12
Eu chamaria isso de "simulação de campos de bits". É quase sempre uma má ideia, a menos que a eficiência do espaço seja extremamente importante.
Kilian Foth

7
@KilianFoth A boolgeralmente é armazenado como um inteiro de 32 bits internamente. Como tal, a embalagem pode fazer a diferença de um fator de 32. Isso é realmente muito. Quero dizer, nós programadores estamos sempre prontos para jogar fora metade de nossos recursos, mas geralmente reluto em jogar 97% deles. Esses fatores de desperdício podem facilmente fazer a diferença entre poder executar casos de uso importantes e ficar sem memória.
cmaster

3
Historicamente, as máscaras de bits tipicamente usadas são usadas para declarar, definir e recuperar valores. Usar turnos é estranho e não é realmente a melhor ilustração da abordagem.
21418 JimmyJames

3
@cmaster O motivo pelo qual os bools são armazenados dessa maneira é porque o compartilhamento de um único local de memória (32 ou 64 bits nas máquinas atuais) pode ser muito ruim para o desempenho do cache, a menos que você preste muita atenção ao código do idioma da máquina. Se você tem um número realmente grande de bits, provavelmente vale a pena, mas, se não, provavelmente é melhor não pré-otimizar e apenas empacotar os bits quando estiver pronto para transmitir à rede ou ao disco.
Bill K

Respostas:


107

É mais comumente chamado de campo de bits , e outro termo que você costuma ouvir é máscaras de bits , usadas para obter ou definir valores de bits individuais ou o campo de bits inteiro de uma só vez.

Muitas linguagens de programação possuem estruturas auxiliares para ajudar nisso. Como o @BernhardHiller observa nos comentários, o C # possui enumerações com sinalizadores ; Java tem a classe EnumSet .


4
Eu interpretaria "campo de bits" como usando um recurso de linguagem que permite que bits individuais sejam atribuídos a campos de uma estrutura, em vez de fazê-lo manualmente com operadores bit a bit.
Peter Green

22
@ PeterGreen Isso seria diferente da interpretação padrão.
Eric

11
"Bit Mapping" ou "Bit Mapped", embora comum para conjuntos de registros e processamento de matriz, também pode ser aplicado nesse caso. Ao extrair elementos comuns de vários conjuntos, o valor pode ser decomposto para identificar componentes de um modelo federado. Dizemos até isso de dígitos do modo de arquivo octal. As máscaras de bits (qualquer máscara) tendem a ser filtros (como nas portas IO e nos registros de direção de dados).
Mckenzm #

11
O C # também possui BitArray, o que permite armazenar uma quantidade arbitrária de bits e indexá-los (enquanto os sinalizadores são limitados a um tipo inteiro e devem ser usados ​​como máscaras).
Luaan 16/10/19

Verdadeiro; Acabei de mencionar as duas estruturas com as quais estou mais familiarizado. Provavelmente existem dezenas por aí, especialmente em outros idiomas.
Glorfindel

20

Estranho, termos bastante diferentes aqui, mas não vejo o que veio à mente imediatamente (e está no título da sua pergunta!) - Bit Packing é o que sempre ouvi dizer.

Eu pensei que isso era realmente óbvio, mas estranhamente, quando pesquiso no Google, esse parece ser um termo amplamente usado, mas não oficialmente definido (a Wikipedia parece redirecionar para o campo de bits, que é uma maneira de empacotar bit, mas não um nome para o processo). A busca pela definição parece levar a esta página:

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

O que não é ótimo para fins de SO, mas é a melhor definição / descrição que posso encontrar, incluindo esta descrição sucinta: "Empacotar bit é um conceito simples: use o mínimo possível para armazenar um pedaço de dados".


Você pode fornecer algumas referências? Termo interessante.
Greg Burghardt 15/10

13
O empacotamento de bits é tecnicamente correto, mas também se refere a algo mais geral do que apenas estados booleanos - armazenando dados em geral no menor número de bits possível. Por exemplo, outro uso dela pode significar compactar uma charmatriz colocando dois chars em um int.
Izkata

@GregBurghardt Você sabe, é interessante. Eu não pensei nisso quando publiquei porque o termo era tão predominante nos anos 80/90 quando aprendi programação em C e assembly - agora, embora uma pesquisa no Google encontre MUITAS menções, não há uma página definitiva da Wikipedia para ele. . A primeira resposta no google tem esta definição: "Empacotar bit é um conceito simples: use o mínimo possível para armazenar um dado". kinematicsoup.com/news/2016/9/6/…
Bill K

foi aí que eu aprendi sobre o empacotamento de bits também, embora você possa ficar muito mais louco do que simplesmente redirecionar 0s não utilizados no que seriam nominalmente valores inteiros. alguns anos atrás, encontrei um sistema que armazenava um de seus parâmetros como um flutuador de 8 bits. IIRC 5 bits para uma mantissa não assinada (todos os valores foram positivos, não é necessário armazenar o sinal explicitamente) e mais 3 para um expoente de base 10. Na época, eu achava que era um kludge de hardware legado sem caminho a seguir, mas com o aprendizado de máquina recentemente começando a fazer coisas com int4 x int8, pude ver algumas cargas de trabalho caindo do FP16.
Dan Neely

11
@ DanNeely Esse tipo de coisa também é comumente suportado por GPUs - o comércio entre precisão, memória e computação é bastante importante lá. Isso também foi explorado muito bem com a computação baseada em GPU.
Luaan 16/10/18

14

Existem muitos termos diferentes usados ​​para descrever isso.

Geralmente, os bits são chamados de "sinalizadores de bits" ou "campos de bits".
(No entanto, vale a pena notar que "campos de bits" às vezes se refere a um recurso específico das linguagens C e C ++, que está relacionado, mas não exatamente o mesmo.

O inteiro em si é referido de várias maneiras como "matriz de bits", "conjunto de bits" ou "vetor de bits", dependendo do uso e das circunstâncias.

De qualquer maneira, a extração dos bits do conjunto de bits / vetor / matriz é feita através de deslocamento e mascaramento.
(ou seja, usando uma máscara de bit .)


Para alguns exemplos de cada termo em uso ativo:


Não é realmente pertinente à pergunta, mas eu gostaria de dizer: por favor, não use adição e subtração para definir e limpar bits, pois esses métodos são propensos a erros.
(ou seja, se você fizer num += 1duas vezes, o resultado é equivalente a num += 2.)

Prefira usar as operações bit a bit apropriadas, se o idioma escolhido fornecer:

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

11
this.stateF = (num & 32) ? true : false, etc. Não há necessidade de alterar numenquanto você extrai os valores.
Roger Lipscombe

3
@RogerLipscombe Bom ponto, eu realmente não estava lendo o que o código estava fazendo, apenas reagindo ao uso de +e -. Agora, eu fui um melhor e usei em != 0vez de um ternário, o que eu acho mais conciso enquanto ainda estou sendo expclit.
Pharap
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.