Qual è il nome per memorizzare / imballare molti stati booleani in un numero?


55

È una sorta di semplice compressione in cui usi una variabile numerica per memorizzare molti stati booleani / binari, usando il raddoppio e il fatto che ogni numero raddoppiato è 1 + la somma di tutti i precedenti.

Sono sicuro che deve essere una vecchia tecnica ben nota, mi piacerebbe sapere come si chiama per riferirsi ad esso correttamente. Ho fatto diverse ricerche su tutti i modi in cui mi viene in mente di descriverlo, ma non ho trovato nulla oltre ad alcuni articoli del blog in cui gli autori dell'articolo sembrano averlo capito da soli e non sanno nemmeno come chiamarlo ( esempio 1 , esempio 2 ).

Ad esempio, ecco un'implementazione molto semplice intesa a illustrare il concetto:

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
}

Potresti anche usare operatori bit per bit, analisi dei numeri di base 2, enum ... Ci sono molti modi più efficienti per implementarlo, mi interessa il nome dell'approccio più in generale.


8
In C # ci sono enumse possono avere un Flagsattributo. Potrebbero rendere il tuo codice molto più semplice.
Bernhard Hiller,

12
Definirei "campi bit di simulazione". È quasi sempre una cattiva idea a meno che l'efficienza dello spazio non sia estremamente importante.
Kilian Foth,

7
@KilianFoth A boolviene generalmente memorizzato come numero intero a 32 bit internamente. Pertanto, l'imballaggio può fare la differenza di un fattore 32. È davvero molto. Voglio dire, noi programmatori siamo sempre pronti a buttare via metà delle nostre risorse, ma sono generalmente riluttante a buttare via il 97% di esse. Tali fattori di spreco possono facilmente fare la differenza tra la capacità di eseguire casi d'uso importanti e l'esaurimento della memoria.
cmaster

3
Storicamente, in genere le maschere di bit vengono utilizzate per dichiarare, impostare e recuperare valori. L'uso dei turni è strano e non è proprio la migliore illustrazione dell'approccio.
JimmyJames,

3
@cmaster Il motivo per cui i bool sono archiviati in questo modo è perché la condivisione di una singola posizione di memoria (32 o 64 bit sui computer di oggi) può essere molto negativa per le prestazioni della cache a meno che non si presti molta attenzione al codice del linguaggio del computer. Se hai un numero davvero enorme di bit probabilmente ne vale la pena, ma in caso contrario stai probabilmente meglio non pre-ottimizzare e impacchettare i bit quando sei pronto per la trasmissione su rete o su disco.
Bill K,

Risposte:


107

Viene comunemente indicato come un campo di bit e un altro termine che sentirai spesso è maschere di bit , che vengono utilizzate per ottenere o impostare singoli valori di bit o l'intero campo di bit contemporaneamente.

Molti linguaggi di programmazione hanno strutture ausiliarie per aiutare in questo. Come osserva @BernhardHiller nei commenti, C # ha enumerazioni con flag ; Java ha la classe EnumSet .


4
Interpreterei "bit field" come se usassi una funzione di linguaggio che consente ai singoli bit di essere assegnati ai campi di una struttura piuttosto che farlo manualmente con operatori bit a bit.
Peter Green,

22
@PeterGreen Sarebbe diverso dall'interpretazione standard.
Eric,

1
In questo caso si possono applicare anche "Bit Mapping" o "Bit Mapped", sebbene comuni per i recordset e l'elaborazione dell'array. Quando si estraggono elementi comuni da più insiemi, il valore può essere scomposto per identificare i componenti di un modello federato. Diciamo anche questo delle cifre della modalità file ottale. Le maschere di bit (qualsiasi maschera) tendono ad essere filtri (come per le porte IO e i registri di direzione dei dati).
mckenzm,

1
C # ha anche BitArray, che consente di memorizzare una quantità arbitraria di bit e indicizzarli (mentre i flag sono limitati a un tipo intero e intesi per essere utilizzati come maschere).
Luaan,

Vero; Ho appena citato le due strutture con cui ho più familiarità. Probabilmente ce ne sono dozzine là fuori, specialmente in altre lingue.
Glorfindel,

20

Strano, un po 'di termini diversi qui, ma non vedo quello che mi è venuto subito in mente (ed è nel titolo della tua domanda!) - Bit Packing è quello che ho sempre sentito definito.

Avevo pensato che fosse davvero ovvio ma stranamente quando lo google sembra che questo sia un termine ampiamente usato ma non definito ufficialmente (Wikipedia sembra reindirizzare al bit field che è un modo per fare il bit packing, ma non un nome per il processi). La ricerca della definizione sembra condurre a questa pagina:

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

Il che non è eccezionale per gli scopi SO ma è la migliore definizione / descrizione che posso trovare includendo questa descrizione sintetica: "L'imballaggio di bit è un concetto semplice: utilizzare il minor numero di bit possibile per memorizzare un dato".


Potete fornire dei riferimenti? Termine interessante.
Greg Burghardt,

13
Il pacchetto di bit è tecnicamente corretto ma si riferisce anche a una cosa più generale dei soli stati booleani: la memorizzazione dei dati in generale nel minor numero di bit possibile. Ad esempio, un altro uso potrebbe significare comprimere un chararray inserendo due chars in uno int.
Izkata,

@GregBurghardt Sai, è interessante. Non ci ho pensato quando ho pubblicato perché il termine era così diffuso negli anni '80 / '90 quando ho imparato a programmare in C e assembly - ora anche se una ricerca su Google trova MOLTE menzioni, non esiste una pagina Wikipedia definitiva per questo . La prima risposta in Google ha questa definizione: "L'imballaggio dei bit è un concetto semplice: utilizzare il minor numero possibile di bit per memorizzare un dato". kinematicsoup.com/news/2016/9/6/…
Bill K,

è allora che ho imparato anche a impacchettare i bit, anche se puoi diventare molto più folle che semplicemente riproporre 0 inutilizzati in quelli che sarebbero nominalmente valori interi. qualche anno fa mi imbattei in un sistema che memorizzava uno dei suoi parametri come float a 8 bit. IIRC 5 bit per una mantissa senza segno (tutti i valori erano positivi non è necessario memorizzare il segno esplicitamente) e altri 3 per un esponente di base 10. All'epoca immaginavo che si trattasse di un kludge hardware legacy senza percorso, ma con l'apprendimento automatico che ha recentemente iniziato a fare cose con int4 vs int8, ho potuto vedere alcuni carichi di lavoro calare da FP16.
Dan Neely,

1
@DanNeely Questo genere di cose è anche comunemente supportato dalle GPU - il trading tra precisione, memoria e calcolo è piuttosto importante lì. Questo è stato sfruttato abbastanza bene anche con l'elaborazione basata su GPU.
Luaan,

14

Ci sono molti termini diversi usati per descriverlo.

Più comunemente i bit sono chiamati "bit flags" o "bit points".
(Tuttavia, vale la pena notare che i "campi bit" a volte si riferiscono a una caratteristica specifica dei linguaggi C e C ++, che è correlata ma non esattamente la stessa.)

L'intero stesso viene indicato in vari modi come "array di bit", "set di bit" o "vettore di bit", a seconda degli usi e delle circostanze.

In entrambi i casi, l'estrazione dei bit dal set di bit / vettore / array avviene tramite spostamento e mascheramento.
(cioè usando una maschera di bit .)


Per alcuni esempi di ciascun termine in uso attivo:


Non è proprio pertinente alla domanda, ma vorrei dire: per favore non usare addizioni e sottrazioni per impostare e cancellare bit poiché questi metodi sono inclini a errori.
(cioè se lo fai num += 1due volte, il risultato è equivalente a num += 2.)

Preferisci invece utilizzare le operazioni bit per bit appropriate, se la lingua scelta le fornisce:

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, ecc. Non è necessario effettuare la mutazione numdurante l'estrazione dei valori.
Roger Lipscombe,

3
@RogerLipscombe Bene, non stavo davvero leggendo cosa stava facendo il codice, reagendo solo all'uso di +e -. Ora sono andato meglio e usato al != 0posto di un ternario, che ritengo più conciso pur essendo ancora escluso.
Pharap,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.