2013-04-11 21 views
14

Se ho una maschera di bit di base ...Bitmask: come determinare se un solo bit è impostato

cat = 0x1; 
dog = 0x2; 
chicken = 0x4; 
cow = 0x8; 

// OMD has a chicken and a cow 
onTheFarm = 0x12; 

... come posso controllare se un solo animale (vale a dire un bit) è impostato?

Il valore di onTheFarm deve essere 2 n, ma come posso verificarlo a livello di codice (preferibilmente in Javascript)?

+0

Dai un'occhiata a [questa domanda] (http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer). Non specifico per javascript, ma interessante. –

+0

Grazie Rob, ho appena trovato questo (sembra un po 'più diretto) http://stackoverflow.com/questions/1053582/how-does-this-bitwise-operation-check-for-a-power-of-2 – Tim

+2

Solo FYI, 'OMD' = [' Old MacDonald'] (https://en.wikipedia.org/wiki/Old_MacDonald_Had_a_Farm). – rvighne

risposta

9

È possibile contare il numero di bit che sono impostati in un valore intero non negativo con questo codice (adattato a JavaScript da this answer):

function countSetBits(i) 
{ 
    i = i - ((i >> 1) & 0x55555555); 
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333); 
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; 
} 

Dovrebbe essere molto più efficiente dell'esame di ogni singolo bit. Tuttavia, non funziona se il bit di segno è impostato su i.

EDIT (tutto il credito al commento di Pointy):

function isPowerOfTwo(i) { 
    return i > 0 && (i & (i-1)) === 0; 
} 
+1

Wow è abbastanza buono. Guardando a ciò, ho trovato [questo riferimento] (http://aggregate.org/MAGIC/#Is%20Power%20of%202) per questa particolare domanda, e sembra ancora meglio! – Pointy

2

Devi controllare pezzo per pezzo, con una funzione più o meno così:

function p2(n) { 
    if (n === 0) return false; 
    while (n) { 
    if (n & 1 && n !== 1) return false; 
    n >>= 1; 
    } 

    return true; 
} 

Alcune CPU set di istruzioni hanno incluso un'operazione di "contare impostare i bit" (l'antica serie CDC Cyber ​​è stato uno) . È utile per alcune strutture dati implementate come raccolte di bit. Se hai un set implementato come una stringa di numeri interi, con posizioni di bit corrispondenti a elementi del tipo di dati impostato, ottenere la cardinalità implica contare i bit.

modificare wow esaminando la risposta di Ted Hopp mi sono imbattuto in questo:

function p2(n) { 
    return n !== 0 && (n & (n - 1)) === 0; 
} 

Questo è da this awesome collection of "tricks". Cose come questo problema sono buone ragioni per studiare la teoria dei numeri :-)

0

Se stai cercando di vedere se solo si trova un singolo bit, è possibile usufruire di logarithms, come segue:

var singleAnimal = (Math.log(onTheFarm)/Math.log(2)) % 1 == 0; 

Math.log(y)/Math.log(2) trova x in 2^x = y e x % 1 ci dice se x è un numero intero. x sarà un numero intero solo se è impostato un singolo bit e, quindi, viene selezionato un solo animale.

+1

Ignorando inequivocabilmente il roundoff in virgola mobile, si concluderebbe che (1 << 29) avrebbe più di un bit impostato: 'console.log ((Math.log (1 << 29)/Math.log (2))% 1) 'stampa 3.552713678800501e-15 sulla mia macchina. –

+0

Interessante. Suppongo che l'uso di 'log' in generale sarebbe molto meno efficiente rispetto alle altre tecniche delineate come risposte comunque.Conosci un modo per gestire l'errore di arrotondamento in virgola mobile? – cmptrgeekken

+0

Non per questo problema. Puoi leggere una buona panoramica dei problemi in [questo articolo] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). È piuttosto pesante dal punto di vista tecnico, ma vale la pena lottare se si desidera una solida comprensione di ciò che sta accadendo sotto il cofano con un punto di virgola mobile. La versione TL; DR è: ogni operazione in virgola mobile (anche semplicemente rappresentando un numero) ha un errore; progetta il tuo codice di conseguenza. –