Casi d'uso reali di operatori bit a bit [chiuso]


224

Quali sono alcuni casi d'uso reali dei seguenti operatori bit per bit?

  • E
  • XOR
  • NON
  • O
  • Spostamento sinistro / destro

1
Ricordo che quando li ho saputi per la prima volta mi è sembrato che fossero usati solo per c di basso livello ... ma da allora sono entrati dalla cassetta degli attrezzi e li uso spesso, anche quando faccio programmazione "di alto livello". Sono come + e * per me adesso.
Oak,

2
@Anon .: Nella mia mente, il mondo reale avrebbe dovuto significare tutto tranne che una programmazione di basso livello che è l'uso più ovvio degli operatori bit per bit.
Olivier Lalonde,



Puoi anche utilizzare XOR binario per trovare un numero mancante in una permutazione: martinkysel.com/codility-permmissingelem-solution
Janac Meena

Risposte:


216
  • Campi bit (flag)
    Sono il modo più efficiente di rappresentare qualcosa il cui stato è definito da diverse proprietà "sì o no". Le ACL sono un buon esempio; se hai, diciamo, 4 permessi discreti (leggi, scrivi, esegui, modifica politica), è meglio archiviarlo in 1 byte piuttosto che sprecare 4. Questi possono essere associati ai tipi di enumerazione in molte lingue per una maggiore comodità.

  • La comunicazione su porte / socket
    implica sempre checksum, parità, bit di stop, algoritmi di controllo del flusso e così via, che di solito dipendono dai valori logici dei singoli byte rispetto ai valori numerici, poiché il supporto potrebbe essere in grado di trasmettere solo un bit a un tempo.

  • Compressione, crittografia
    Entrambi dipendono fortemente dagli algoritmi bit a bit. Guarda l' algoritmo deflate per un esempio: tutto è in bit, non in byte.

  • Macchine a stati finiti
    Sto parlando principalmente del tipo incorporato in alcuni componenti hardware, sebbene possano essere trovati anche nel software. Questi sono combinatoria in natura - si potrebbe letteralmente essere sempre "compilato" verso il basso per un gruppo di porte logiche, quindi devono essere espresso come AND, OR, NOT, etc.

  • Grafica Non c'è abbastanza spazio qui per entrare in ogni area in cui questi operatori vengono utilizzati nella programmazione grafica. XOR(o ^) è particolarmente interessante qui perché l'applicazione dello stesso input una seconda volta annullerà la prima. Le vecchie GUI si basavano su questo per evidenziare la selezione e altri overlay, al fine di eliminare la necessità di costosi ridisegni. Sono ancora utili nei protocolli di grafica lenta (cioè desktop remoto).

Questi sono stati solo i primi esempi che mi sono venuti in mente - questo non è certo un elenco esaustivo.


Ciao @Aaronaught, hai davvero condiviso un'ottima conoscenza con noi. Sono interessato a saperne di più sui casi del mondo reale di Bitwise Operator. Ti dispiacerebbe condividere il tuo riferimento con noi, sarebbe davvero utile leggerne di più.
Heena Hussain,

Le operazioni bit a bit sono utili per i calcoli vettorializzabili?
Aaron Franke,

47

È strano?

(value & 0x1) > 0

È divisibile per due (pari)?

(value & 0x1) == 0

3
A seconda del valore della lingua e 0x1> 0 potrebbe essere analizzato come valore & (0x1> 0)
leeeroy,

3
@leeeroy - Abbastanza vero. Aggiunte alcune parentesi.
Seth,

I moderni ottimizzatori convertiranno automaticamente espressioni come (valore% 2)! = 0 nelle espressioni sopra. godbolt.org/z/mYEBH4
Ferrarezi

26

Ecco alcuni modi di dire comuni che si occupano di flag memorizzati come singoli bit.

enum CDRIndicators {
  Local = 1 << 0,
  External = 1 << 1,
  CallerIDMissing = 1 << 2,
  Chargeable = 1 << 3
};

unsigned int flags = 0;

Imposta la bandiera addebitabile:

flags |= Chargeable;

Cancella ID chiamanteMissing flag:

flags &= ~CallerIDMissing;

Verifica se sono impostati CallerIDMissing e Chareable:

if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {

}

25

Ho usato operazioni bit per bit nell'implementazione di un modello di sicurezza per un CMS. Aveva pagine a cui gli utenti potevano accedere se fossero in gruppi appropriati. Un utente potrebbe essere in più gruppi, quindi è necessario verificare se esiste un'intersezione tra i gruppi di utenti e i gruppi di pagine. Quindi abbiamo assegnato a ciascun gruppo un identificativo univoco di potenza di 2, ad esempio:

Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100

OR di questi valori insieme e memorizziamo il valore (come un singolo int) con la pagina. Ad esempio, se ai gruppi A e B è possibile accedere a una pagina, memorizziamo il valore 3 (che in binario è 00000011) come controllo dell'accesso alle pagine. Allo stesso modo, memorizziamo un valore di identificatori di gruppo ORed con un utente per rappresentare in quali gruppi si trovano.

Quindi, per verificare se un determinato utente può accedere a una determinata pagina, devi solo ANDARE insieme i valori e verificare se il valore è diverso da zero. Questo è molto veloce poiché questo controllo è implementato in una singola istruzione, nessun loop, nessun round trip di database.


24

La programmazione di basso livello è un buon esempio. Ad esempio, potrebbe essere necessario scrivere un bit specifico in un registro mappato in memoria per fare in modo che un componente hardware faccia ciò che si desidera:

volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t          value;
uint32_t          set_bit   = 0x00010000;
uint32_t          clear_bit = 0x00001000;

value = *register;            // get current value from the register
value = value & ~clear_bit;   // clear a bit
value = value | set_bit;      // set a bit
*register = value;            // write it back to the register

Inoltre, htonl()e htons()sono implementati usando gli operatori &e |(su macchine il cui endianness (ordine di byte) non corrisponde all'ordine di rete):

#define htons(a) ((((a) & 0xff00) >> 8) | \
                  (((a) & 0x00ff) << 8))

#define htonl(a) ((((a) & 0xff000000) >> 24) | \
                  (((a) & 0x00ff0000) >>  8) | \
                  (((a) & 0x0000ff00) <<  8) | \
                  (((a) & 0x000000ff) << 24))

7
Non tutti parlano in macchina. Cosa sta facendo il tuo secondo esempio?
ChaosPandion,

7
htons()e htonl()sono funzioni POSIX per scambiare a shorto a dall'endianness longhost ( h) all'ordine nbyte di rete ( ).
Carl Norum,

È possibile utilizzare un metodo simile per eseguire un'inversione di bit nelle operazioni O (logN).
Mike DeSimone,

lol quando l'ho visto per la prima volta ho pensato che fosse assemblaggio!
0x499602D2

Non è htonl()per un intvalore a 32 bit ? longsignifica 64 bit in molte lingue.
Aaron Franke,

21

Li uso per ottenere valori RGB (A) da valori cromatici compressi, ad esempio.


E lo fa davvero in fretta!
Callum Rogers,

In C # è uno di quei casi in cui è davvero la soluzione migliore, per leggibilità e velocità.
Capitano Casey il

4
Sulla mia macchina, (a & b) >> cè più di 5 volte più veloce di a % d / e(entrambi i modi per estrarre un singolo valore di colore da un int che rappresenta ARGB). Rispettivamente, 6,7 e 35,2 per 1 miliardo di iterazioni.
Benji XVI,

@BenjiXVI C # ha ottimizzazioni del compilatore per questo. Il motivo per cui si osserva una differenza di velocità è perché, in C #, %non è l'operatore Modulus, è l'operatore Remainder. Sono equivalenti per valori positivi ma differiscono da quelli negativi. Se si forniscono le restrizioni appropriate (passando un uintanziché intad esempio), i due esempi dovrebbero avere la stessa velocità.
Aaron Franke,

scusa so che è passato molto tempo. Potete per favore mostrare un esempio di come usarli per ottenere ogni singolo valore RGB?
Jinx,

14

Quando ho un sacco di bandiere booleane, mi piace memorizzarle tutte in un int.

Li tiro fuori usando bitwise-AND. Per esempio:

int flags;
if (flags & 0x10) {
  // Turn this feature on.
}

if (flags & 0x08) {
  // Turn a second feature on.
}

eccetera.


23
Spero che in realtà siano costanti nel tuo codice reale e non numeri magici :)
Earlz,

1
Un esempio dell'uso di flag booleani nel mondo non di basso livello è fare cose con varie piattaforme GUI. Ad esempio, potresti utilizzare my_button.Style | = STYLE_DISABLED per disattivarlo.
MauriceL,

1
So che questo argomento è indipendente dal linguaggio, ma C fornisce un modo semplice per farlo con bit-field in modo da poter usare cose come if (flags.feature_one_is_one) { // turn on feature }. È nello standard ANSI C, quindi la portabilità non dovrebbe essere un problema.
polandeer,

sarebbe bello avere una spiegazione di cosa fa questo frammento di codice, perché i flag non sono inizializzati, cosa intendi con "memorizzali tutti in un int", qual è la notazione usata ...
Angelo Oparah

12

& = AND:
maschera bit specifici.
Stai definendo i bit specifici che dovrebbero essere visualizzati o non visualizzati. 0x0 e x cancelleranno tutti i bit in un byte mentre 0xFF non cambierà x. 0x0F visualizzerà i bit nel bocconcino inferiore.

Conversione:
per eseguire il cast di variabili più brevi in ​​più lunghe con identità bit è necessario regolare i bit poiché -1 in un int è 0xFFFFFFFF mentre -1 in un lungo è 0xFFFFFFFFFFFFFFFF. Per conservare l'identità si applica una maschera dopo la conversione.

| = O
Imposta bit. I bit verranno impostati indipendentemente se sono già impostati. Molte strutture dati (campi di bit) hanno flag come IS_HSET = 0, IS_VSET = 1 che possono essere impostati indipendentemente. Per impostare i flag, si applica IS_HSET | IS_VSET (in C e assembly è molto comodo da leggere)

^ = XOR
Trova bit uguali o diversi.

~ = NOT
capovolgere i bit.

Si può dimostrare che tutto possibili operazioni di bit locali possono essere implementate da queste operazioni. Quindi, se lo desideri, puoi implementare un'istruzione ADD solo tramite operazioni a bit.

Alcuni meravigliosi hack:

http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html


Di seguito è riportato un link che fornisce eccellenti esempi di utilizzo di operatori bit a bit in AS3 per operazioni matematiche super veloci (ma potrebbe essere applicato alla maggior parte delle lingue): lab.polygonal.de/2007/05/10/bitwise-gems-fast- integer-math
fortemente coinvolto il

Penso che "NON" dovrebbe essere = ~, no |=, che è OR.
Mike DeSimone,

Per & = AND- Perché dovrei voler cancellare tutti i bit, perché dovrei voler ottenere una versione non modificata del byte e cosa devo fare con il nibble inferiore?
confused00

1
@ confused00 giusto, il modo più veloce / semplice per annullare un risultato è xorda solo. Posso pensare a diversi motivi per cui potresti voler estrarre il bocconcino inferiore. Soprattutto se quel bocconcino inferiore fa parte di una struttura di dati e si desidera utilizzarlo come maschera o ORcon un'altra struttura.
James M. Lay

11

La crittografia è tutte operazioni bit per bit.


4
Veramente? È probabile che le implementazioni di crittografia utilizzino operazioni bit per bit, ma gli algoritmi di crittografia sono generalmente descritti in termini numerici e non in termini di rappresentazioni di bit.
Constantin,

1
Quindi cosa fai con algoritmi diversi da implementarli? Sono curioso.
ricorsivo il

2
@Constantin: vedi, ad esempio, la descrizione di come viene implementato il DES: ( en.wikipedia.org/wiki/…
Wayne Conrad,

1
@recursive, se mi chiedi di me personalmente, non progetto algoritmi crittografici né li implemento. Ma le persone fanno molte cose, come analizzarle per debolezze teoriche.
Constantin,

@Constantin: dai un'occhiata a questo, questo è solo un esempio tra i tanti su come (in parte) gli algoritmi crittografici sono tipicamente descritti: en.wikipedia.org/wiki/Substitution_box
SyntaxT3rr0r

9

Puoi usarli come un modo rapido e sporco per eseguire l'hash dei dati.

int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;

8

Ho appena usato bitwise-XOR ( ^) circa tre minuti fa per calcolare un checksum per la comunicazione seriale con un PLC ...


7

Bit a bit e viene utilizzato per mascherare / estrarre una determinata parte di un byte.

1 byte variabile

 01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
 --------
 00000010

Soprattutto gli operatori di turno (<< >>) vengono spesso utilizzati per i calcoli.


6

Questo è un esempio per leggere i colori da un'immagine bitmap in formato byte

byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */

//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */

//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF;  /* This now returns a red colour between 0x00 and 0xFF.

Spero che questo piccolo esempio aiuti ...


5

Nel mondo astratto del linguaggio moderno di oggi, non troppi. Il file IO è semplice che viene in mente, anche se sta esercitando operazioni bit per bit su qualcosa di già implementato e non sta implementando qualcosa che utilizza operazioni bit per bit. Tuttavia, come semplice esempio, questo codice dimostra la rimozione dell'attributo di sola lettura su un file (in modo che possa essere utilizzato con un nuovo FileStream che specifica FileMode.Create) in c #:

//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
    FileAttributes attributes = File.GetAttributes(targetName);

    if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));

    File.Delete(targetName);
}

Per quanto riguarda le implementazioni personalizzate, ecco un esempio recente: ho creato un "centro messaggi" per inviare messaggi sicuri da un'installazione della nostra applicazione distribuita a un'altra. Fondamentalmente, è analogo all'e-mail, completo di Posta in arrivo, Posta in uscita, Posta inviata, ecc., Ma ha anche la consegna garantita con le conferme di lettura, quindi ci sono sottocartelle aggiuntive oltre a "Posta in arrivo" e "Inviata". Ciò equivaleva a un requisito per me definire in modo generico cosa "nella posta in arrivo" o "nella cartella inviata". Della cartella inviata, devo sapere cosa viene letto e cosa non letto. Di ciò che non è letto, ho bisogno di sapere cosa è ricevuto e cosa non è ricevuto. Uso queste informazioni per creare una clausola where dinamica che filtra un'origine dati locale e visualizza le informazioni appropriate.

Ecco come viene messo insieme l'enum:

    public enum MemoView :int
    {
        InboundMemos = 1,                   //     0000 0001
        InboundMemosForMyOrders = 3,        //     0000 0011
        SentMemosAll = 16,                  //     0001 0000
        SentMemosNotReceived = 48,          //     0011
        SentMemosReceivedNotRead = 80,      //     0101
        SentMemosRead = 144,                //     1001
        Outbox = 272,                       //0001 0001 0000
        OutBoxErrors = 784                  //0011 0001 0000
    }

Vedi cosa fa questo? Andando (&) con il valore enum "Posta in arrivo", InboundMemos, so che InboundMemosForMyOrders è nella posta in arrivo.

Ecco una versione ridotta del metodo che crea e restituisce il filtro che definisce una vista per la cartella attualmente selezionata:

    private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
    {
        string filter = string.Empty;
        if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
        {
            filter = "<inbox filter conditions>";

            if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
            {
                filter += "<my memo filter conditions>";
            }
        }
        else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
        {
            //all sent items have originating system = to local
            filter = "<memos leaving current system>";

            if((view & MemoView.Outbox) == MemoView.Outbox)
            {
                ...
            }
            else
            {
                //sent sub folders
                filter += "<all sent items>";

                if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
                {
                    if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
                    {
                        filter += "<not received and not read conditions>";
                    }
                    else
                        filter += "<received and not read conditions>";
                }
            }
        }

        return filter;
    }

Estremamente semplice, ma un'implementazione ordinata a un livello di astrazione che in genere non richiede operazioni bit per bit.


4

La codifica Base64 è un esempio. La codifica Base64 viene utilizzata per rappresentare i dati binari come caratteri stampabili per l'invio tramite sistemi di posta elettronica (e altri scopi). La codifica Base64 converte una serie di byte a 8 bit in indici di ricerca dei caratteri a 6 bit. Le operazioni con i bit, lo spostamento e il "o" o "niente" sono molto utili per implementare le operazioni sui bit necessarie per la codifica e la decodifica Base64.

Questo ovviamente è solo 1 degli innumerevoli esempi.



4

Di solito le operazioni bit a bit sono più veloci rispetto alla moltiplicazione / divisione. Quindi, se hai bisogno di moltiplicare una variabile x per dire 9, lo farai x<<3 + xche sarebbe qualche ciclo più veloce di x*9. Se questo codice si trova all'interno di un ISR, risparmierai sui tempi di risposta.

Allo stesso modo, se si desidera utilizzare un array come una coda circolare, sarebbe più veloce (e più elegante) gestire assegni circolari con operazioni poco sagge. (la dimensione dell'array dovrebbe essere una potenza di 2). Ad esempio: è possibile utilizzare tail = ((tail & MASK) + 1)invece di tail = ((tail +1) < size) ? tail+1 : 0, se si desidera inserire / eliminare.

Inoltre, se si desidera che un flag di errore contenga più codici di errore, ogni bit può contenere un valore separato. Puoi AND con un singolo codice di errore come controllo. Questo è usato nei codici di errore Unix.

Anche una bitmap n-bit può essere una struttura dati davvero interessante e compatta. Se si desidera allocare un pool di risorse di dimensione n, è possibile utilizzare un n-bit per rappresentare lo stato corrente.


3

Nessuno sembra aver menzionato la matematica a virgola fissa.

(Sì, sono vecchio, ok?)


3

Un numero ha xuna potenza di 2? (Utile ad esempio negli algoritmi in cui un contatore viene incrementato e un'azione deve essere eseguita solo il numero logaritmico di volte)

(x & (x - 1)) == 0

Qual è il bit più alto di un numero intero x? (Questo ad esempio può essere usato per trovare la potenza minima di 2 che è maggiore di x)

x |= (x >>  1);
x |= (x >>  2);
x |= (x >>  4);
x |= (x >>  8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift

Qual è il 1bit più basso di un numero intero x? (Aiuta a trovare il numero di volte divisibile per 2.)

x & -x

lo spostamento a destra senza segno viene eseguito in C lanciando l'LHS nel tipo senza segno. L'ultima formula non trova il bit [set] più basso, controlla se X è una potenza di 2. Per trovare il bit set più basso, esegui x & -x.
Potatoswatter,

Hmm, hai ragione, in qualche modo ho sostituito x & -x con il primo frammento, grazie per la modifica
Dimitris Andreou,

3

Gli operatori bit a bit sono utili per le matrici in loop di lunghezza pari a 2. Come molte persone hanno menzionato, gli operatori a bit sono estremamente utili e vengono utilizzati in Flag , Grafica , Networking , Crittografia . Non solo, ma sono estremamente veloci. Il mio uso preferito personale è di eseguire il loop di un array senza condizionali . Supponiamo di avere un array basato su indice zero (ad es. L'indice del primo elemento è 0) e che è necessario eseguirne il ciclo indefinitamente. Con indefinitamente intendo passare dal primo elemento all'ultimo e tornare al primo. Un modo per implementare questo è:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    if (i >= arr.length) 
        i = 0;
}

Questo è l'approccio più semplice, se si desidera evitare un'istruzione if , è possibile utilizzare l' approccio del modulo in questo modo:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    i = i % arr.length;
}

Il lato negativo di questi due metodi è che l'operatore del modulo è costoso, poiché cerca un resto dopo la divisione dei numeri interi. E il primo metodo esegue un'istruzione if su ogni iterazione. Con l'operatore bit a bit, tuttavia, se la lunghezza dell'array è una potenza di 2, è possibile generare facilmente una sequenza come 0 .. length - 1utilizzando l' &operatore (bit a bit e) in questo modo i & length. Sapendo questo, il codice dall'alto diventa

int[] arr = new int[8];
int i = 0;
while (true){
    print(arr[i]);
    i = i + 1;
    i = i & (arr.length - 1);
}

Ecco come funziona. Nel formato binario ogni numero che è potenza di 2 sottratto da 1 viene espresso solo con quelli. Ad esempio 3 in binario è 11, 7 è 111, 15 è 1111e così via, si ottiene l'idea. Ora, cosa succede se si &dispone di un numero qualsiasi rispetto a un numero composto solo da quelli binari? Diciamo che facciamo questo:

num & 7;

Se numè minore o uguale a 7, il risultato sarà numperché ogni bit& - con 1 è esso stesso. Se numè maggiore di 7, durante l' &operazione il computer considererà gli zeri iniziali di 7 che ovviamente rimarranno come zeri dopo l' &operazione rimarrà solo la parte finale. Come in caso di 9 & 7binario sembrerà

1001 & 0111

il risultato sarà 0001 che è 1 in decimale e indirizza il secondo elemento nell'array.


La tua osservazione a metà del testo se la lunghezza dell'array è una potenza di 2 dovrebbe essere inserita nella prima frase. È una limitazione molto seria all'utilizzo di questo trucco. Personalmente non lo implementerei comunque, il codice è più difficile da capire rispetto agli approcci if o mod .
Jan Doggen,

@JanDoggen Hai ragione, lo inserirò nella prima frase. Per quanto riguarda l'array essendo la potenza di due, nella mia esperienza ci sono state più di poche volte in cui ha funzionato. Probabilmente perché era legato alla rete e alla grafica.
user3552161

1
Lo scopo di questo post era mostrare che gli operatori bit a bit sono utili per generare sequenze di numeri, la sequenza 0, 1, 2, 3, 0, 1, 2 ... è stata solo la prima che mi è venuta in mente.
user3552161

2

Li uso per opzioni di selezione multipla, in questo modo memorizzo solo un valore anziché 10 o più


2

può anche essere utile in un modello relazionale sql, diciamo che hai le seguenti tabelle: BlogEntry, BlogCategory

tradizionalmente potresti creare una relazione tra loro usando una tabella BlogEntryCategory o quando non ci sono molti record BlogCategory che potresti usare un valore in BlogEntry per collegarti a più record BlogCategory proprio come faresti con gli enumerati, nella maggior parte dei RDBMS ci sono anche un operatore molto veloce per selezionare su quella colonna "segnalata" ...


2

Quando si desidera modificare solo alcuni bit delle uscite di un microcontrollore, ma il registro in cui scrivere è un byte, si fa qualcosa del genere (pseudocodice):

char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs

Naturalmente, molti microcontrollori ti consentono di cambiare ogni bit singolarmente ...


che lingua dovrebbe essere?
Carson Myers,

@Carson: nessuna lingua, questo è pseudocodice. Quando l'ho fatto qualche anno fa era l'Assemblea, ma suppongo che sia facile farlo in C. Grazie per il testa a testa, aggiornerò per renderlo più chiaro
Emilio M Bumachar

Ho modificato la risposta per modificare i commenti in modo che l'evidenziazione non fosse così confusa. E vedo, ho pensato che potesse essere C ma hai usato 0b ... notazione che vorrei fosse disponibile in C.
Carson Myers,

2

Se vuoi mai calcolare il tuo numero mod (%) una certa potenza di 2, puoi usare yourNumber & 2^N-1, che in questo caso è lo stesso di yourNumber % 2^N.

number % 16 = number & 15;
number % 128 = number & 127;

Questo è probabilmente utile solo in alternativa al funzionamento del modulo con un dividendo molto grande che è 2 ^ N ... Ma anche in questo caso il suo aumento di velocità rispetto all'operazione del modulo è trascurabile nel mio test su .NET 2.0. Sospetto che i compilatori moderni eseguano già ottimizzazioni come questa. Qualcuno sa di più su questo?


I compilatori usano questa ottimizzazione ... ma se non sapevi dell'ottimizzazione, potresti non riuscire a scegliere un divisore che abbia una potenza esatta di 2.
Ben Voigt

Dipende dalla situazione. In C # questo in realtà produce risultati diversi, così come %l'operazione Remainder, trattano i negativi in ​​modo diverso. Tuttavia, se si passa uinta %, il compilatore C # produrrà effettivamente il codice macchina usando bit-bit AND quando il secondo argomento è una potenza nota di due.
Aaron Franke,

1

Li ho visti usati nei sistemi di controllo di accesso basati sui ruoli.


1

C'è un uso del mondo reale nella mia domanda qui -
Rispondere solo alla prima notifica WM_KEYDOWN?

Quando si consuma un messaggio WM_KEYDOWN nel bit API 30 di Windows, viene specificato lo stato della chiave precedente. Il valore è 1 se la chiave è inattiva prima dell'invio del messaggio, oppure è zero se la chiave è attiva


1

Sono principalmente usati per operazioni bit a bit (sorpresa). Ecco alcuni esempi reali trovati nella base di codice PHP.

Codifica dei caratteri:

if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {

Strutture dati:

ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;

Driver di database:

dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);

Implementazione del compilatore:

opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;

1

Ogni volta che ho iniziato la programmazione in C, ho capito le tabelle di verità e tutto il resto, ma non è stato sufficiente fare clic su come utilizzarlo fino a quando non ho letto questo articolo http://www.gamedev.net/reference/articles/article1563.asp (che fornisce esempi di vita reale)


1
No, non è lo stesso. In C, se x == 1e y == 2, quindi x || yrestituisce 1 e x | yrestituisce 0. Non vedo perché x^truesia superiore a !xin alcun modo. È più dattiloscritto, meno idiomatico, e se xnon boollo è è inaffidabile.
David Thornley,

oh aspetta .. sì, è stupido da parte mia .. Non riesco a pensare subito oggi.
Earlz,

x | y valuta 3 (modifica: nvm, vedo che stavi parlando di qualcosa che è stato rimosso!)
Pod

1
@DavidThornley: Un caso in cui x^trueè superiore a !xè some->complicated().member->lookup ^= true; Non ci sono versioni composto-assegnazione degli operatori unari.
Ben Voigt,

1

Non penso che questo valga come bit a bit, ma l'array di ruby ​​definisce le operazioni di set attraverso i normali operatori bit a bit di interi. Così [1,2,4] & [1,2,3] # => [1,2]. Allo stesso modo per a ^ b #=> set differencee a | b #=> union.


1

La soluzione lineare della Torre di Hanoi utilizza operazioni bit per risolvere il problema.

public static void linear(char start, char temp, char end, int discs)
{
    int from,to;
    for (int i = 1; i < (1 << discs); i++) {
        from = (i & i-1) % 3;
        to = ((i | i-1) + 1) % 3;
        System.out.println(from+" => "+to);
    }
}

La spiegazione di questa soluzione può essere trovata qui

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.