Bitwise e al posto del modulo operatore


91

Sappiamo che ad esempio modulo di potenza di due può essere espresso così:

  x % 2 inpower n == x & (2 inpower n - 1).

Esempi:

x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7 

Che dire del generale non potere di due numeri?

Diciamo:

x% 7 ==?


8
@Neil - Modulo e binario E sono operazioni piuttosto fondamentali, immagino siano più o meno le stesse in qualsiasi linguaggio informatico.
James Kolpack

1
Mi stanco un po 'di non vedere la lingua pubblicata :) Anche se immagino che di solito se non specificano, presumo che significhi C ++ o C. Mi chiedo quanto sia vero ..
Garet Claborn

1
Solo per chiunque abbia difficoltà a capirlo, dai un'occhiata a stackoverflow.com/a/13784820/1414639 . Oh, e in JS con V8 ottengo un leggero aumento delle prestazioni utilizzando operatori bit per bit.
Bardi Harborow

1
@JamesKolpack Un'operazione bit per bit può essere eseguita MOLTO più velocemente su una CPU rispetto a un modulo. In effetti, un trucco di assemblaggio comune per azzerare un registro è XOR con se stesso (per questo fatto). Al giorno d'oggi un compilatore potrebbe essere in grado di ottimizzare un modulo di una potenza di due, ma non lo so
Kaiser Keister

Risposte:


70

Prima di tutto, in realtà non è esatto dirlo

x % 2 == x & 1

Controesempio Semplice: x = -1. In molte lingue, tra cui Java, -1 % 2 == -1. Cioè, %non è necessariamente la tradizionale definizione matematica di modulo. Java lo chiama "operatore resto", per esempio.

Per quanto riguarda l'ottimizzazione bit per bit, solo le potenze modulo di due possono essere "facilmente" eseguite in aritmetica bit per bit. In generale, solo le potenze modulo di base b possono essere "facilmente" eseguite con la rappresentazione dei numeri in base b .

In base 10, ad esempio, per non negativo N, N mod 10^ksi prendono solo le kcifre meno significative .

Riferimenti


1
-1 = -1 (mod 2), non sei sicuro di cosa stai ottenendo - vuoi dire che non è lo stesso del resto IEEE 754?
BlueRaja - Danny Pflughoeft

2
@BlueRaja: il residuo comune per -1 in mod 2 è 1 en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants

@BlueRaja: Se permetti i numeri negativi, quello di cui puoi essere sostanzialmente certo (soprattutto perché non è stata menzionata alcuna lingua) è che (a / b) / b + a % b == a, per gli operatori di tipo C, aeb interi, b diverso da zero, e anche quello abs(a % b) < abs(b)con le stesse condizioni.
David Thornley

1
@DavidThornley - supponi di voler dire (a / b)* b + a % b == a.
sfjac

40

C'è solo un modo semplice per trovare il modulo di 2 ^ i numeri usando bit per bit.

Esiste un modo ingegnoso per risolvere i casi di Mersenne in base al collegamento come n% 3, n% 7 ... Esistono casi speciali per n% 5, n% 255 e casi compositi come n% 6.

Per i casi 2 ^ i, (2, 4, 8, 16 ...)

n % 2^i = n & (2^i - 1)

Quelle più complicate sono difficili da spiegare. Leggi solo se sei molto curioso.


1
voto ++; Ottimo collegamento, grazie per il riferimento. Consiglio ad altri di dare un'occhiata, vale la pena leggerlo anche se è un po 'complicato.
varzeak

il collegamento è la parte migliore della risposta.
Amit Kumar

n% 2 ^ i = n & (1 << i - 1)
Kartik Singh

18

Questo funziona solo per potenze di due (e spesso solo quelle positive) perché hanno la proprietà unica di avere un solo bit impostato su "1" nella loro rappresentazione binaria. Poiché nessun'altra classe di numeri condivide questa proprietà, non è possibile creare espressioni bit per bit per la maggior parte delle espressioni di modulo.


2
Se ti capita di operare su un'architettura ternaria, allora le cose cambiano un po '... le probabilità sono comunque nulle.
Noldorin

Mi piace come lo esprimi: "questo cambia un po 'le cose "
j3141592653589793238

12

Questo è specificamente un caso speciale perché i computer rappresentano i numeri in base 2. Questo è generalizzabile:

(numero) base % base x

è equivalente alle ultime x cifre di (numero) base .


5

Esistono moduli diversi dalle potenze 2 per i quali esistono algoritmi efficienti.

Ad esempio, se x è 32 bit senza segno int, x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)


4

Modulo "7" senza operatore "%"

int a = x % 7;

int a = (x + x / 7) & 7;

3
Non funziona per il 10% 2 = 0. (10 + 10/2) e 2 = 15 e 2 = 2, allo stesso modo 10% 6 = 4. (10 + 10/6) e 6 = 11 e 6 = 2
Sriram Murali

10
Inoltre, perché dovresti dividere quando vuoi evitare di usare il modulo? Per quanto ne so, l'istruzione per dividere è la stessa di quella per ottenere il resto.
Horse SMith

2
@SriramMurali Questo perché hai usato un mod pari, ovviamente non funzionerebbe, questa è una soluzione alternativa per dispari come ha detto l'OP.
ylun.ca

3

Non usando l'operatore bit a bit and ( &) in binario, non c'è. Schizzo di prova:

Supponiamo che ci fosse un valore k tale che x & k == x % (k + 1), ma k! = 2 ^ n - 1 . Allora se x == k , l'espressione x & ksembra "funzionare correttamente" e il risultato è k . Consideriamo ora x == ki : se ci fossero dei bit "0" in k , ci sarebbe qualche i maggiore di 0 che ki può essere espresso solo con 1 bit in quelle posizioni. (Ad esempio, 1011 (11) deve diventare 0111 (7) quando gli è stato sottratto 100 (4), in questo caso il bit 000 diventa 100 quando i = 4. ) Se un bit dell'espressione di k deve cambiare da zero a uno per rappresentare il ki, quindi non può calcolare correttamente x% (k + 1) , che in questo caso dovrebbe essere ki , ma non c'è modo per bit a bit booleano e per produrre quel valore data la maschera.


2

In questo caso specifico (mod 7), possiamo ancora sostituire% 7 con operatori bit per bit:

// Return X%7 for X >= 0.
int mod7(int x)
{
  while (x > 7) x = (x&7) + (x>>3);
  return (x == 7)?0:x;
}

Funziona perché 8% 7 = 1. Ovviamente, questo codice è probabilmente meno efficiente di un semplice x% 7, e sicuramente meno leggibile.


1

Utilizzando bitwise_and, bitwise_or e bitwise_not è possibile modificare qualsiasi configurazione di bit in altre configurazioni di bit (ovvero, questi set di operatori sono "funzionalmente completi"). Tuttavia, per operazioni come il modulo, la formula generale sarebbe necessariamente piuttosto complicata, non mi preoccuperei nemmeno di provare a ricrearla.

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.