Operador bit a bit e no lugar do módulo

89

Sabemos que, por exemplo, o módulo de potência de dois pode ser expresso assim:

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

Exemplos:

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

E quanto ao não-poder geral de dois números?

Digamos:

x% 7 ==?

dato datuashvili
fonte
8
@Neil - Módulo e Binário E são operações bastante fundamentais, estou supondo que sejam as mesmas em qualquer linguagem de computador.
James Kolpack
1
Eu fico um pouco cansado de não ver a linguagem postada :) Embora eu ache que geralmente se eles não especificarem, eu presumo que isso signifique C ++ ou C. Eu me pergunto o quão verdadeiro isso é ..
Garet Claborn
1
Apenas para quem está lutando para entender isso, dê uma olhada em stackoverflow.com/a/13784820/1414639 . Ah, e em JS com V8, obtenho um ligeiro aumento de desempenho usando operadores bit a bit.
Bardi Harborow
1
@JamesKolpack Uma operação bit a bit pode ser executada MUITO mais rápido em uma CPU do que em um módulo. Na verdade, um truque comum de montagem para zerar um registrador é fazer um XOR com ele mesmo (devido a esse fato). Hoje em dia, um compilador pode ser capaz de otimizar um módulo de uma potência de dois, mas não sei
Kaiser Keister

Respostas:

68

Em primeiro lugar, não é correto dizer que

x % 2 == x & 1

Contra-exemplo simples: x = -1. Em muitas linguagens, incluindo Java -1 % 2 == -1,. Ou seja, %não é necessariamente a definição matemática tradicional de módulo. Java o chama de "operador de resto", por exemplo.

Com relação à otimização bit a bit, apenas potências de módulo de dois podem "facilmente" ser feitas em aritmética bit a bit. De um modo geral, apenas potências de módulo de base b podem "facilmente" ser feitas com representação de números de base b .

Na base 10, por exemplo, para não negativos N, N mod 10^kfica apenas pegando os kdígitos menos significativos .

Referências

poligenelubrificantes
fonte
1
-1 = -1 (mod 2), não tenho certeza do que você quer dizer - você quer dizer que não é o mesmo que o restante do IEEE 754?
BlueRaja - Danny Pflughoeft
2
@BlueRaja: o resíduo comum para -1 no mod 2 é 1 en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants
@BlueRaja: Se você permitir números negativos, o que basicamente pode ter certeza (particularmente porque nenhuma linguagem foi mencionada) é que (a / b) / b + a % b == a, para operadores do tipo C, inteiros aeb, b diferentes de zero, e também abs(a % b) < abs(b)com as mesmas ressalvas.
David Thornley
1
@DavidThornley - suponha que você queira dizer (a / b)* b + a % b == a.
sfjac
37

Existe apenas uma maneira simples de encontrar o módulo de 2 ^ i números usando bit a bit.

Há uma maneira engenhosa de resolver os casos de Mersenne de acordo com o link , como n% 3, n% 7 ... Existem casos especiais para n% 5, n% 255 e casos compostos, como n% 6.

Para os casos 2 ^ i, (2, 4, 8, 16 ...)

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

Os mais complicados são difíceis de explicar. Leia somente se você estiver muito curioso.

Sriram Murali
fonte
1
vote ++; Excelente link, obrigado pela referência. Aconselho os outros a darem uma olhada, vale a pena ler mesmo que seja um pouco complicado.
varzeak
o link é a melhor parte da resposta.
Amit Kumar
n% 2 ^ i = n & (1 << i - 1)
Kartik Singh
18

Isso só funciona para potências de dois (e freqüentemente apenas positivas) porque eles têm a propriedade única de ter apenas um bit definido como '1' em sua representação binária. Como nenhuma outra classe de números compartilha essa propriedade, você não pode criar expressões bit a bit para a maioria das expressões de módulo.

VeeArr
fonte
1
Se acontecer de você estar operando em uma arquitetura ternária, isso muda um pouco as coisas ... as chances são quase nulas, entretanto.
Noldorin de
12

Este é especificamente um caso especial porque os computadores representam números na base 2. Isso é generalizável:

(número) base % base x

é igual aos últimos x dígitos da base (número) .

jdmichal
fonte
5

Existem módulos diferentes de potências de 2 para os quais existem algoritmos eficientes.

Por exemplo, se x tem 32 bits sem sinal int, então x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)

David Harris
fonte
4

Módulo "7" sem operador "%"

int a = x % 7;

int a = (x + x / 7) & 7;
Ashuwp
fonte
3
Não funciona para 10% 2 = 0. (10 + 10/2) & 2 = 15 & 2 = 2, Da mesma forma 10% 6 = 4. (10 + 10/6) & 6 = 11 & 6 = 2
Sriram Murali
10
Além disso, por que você deseja dividir quando deseja evitar o uso do módulo? AFAIK, a instrução para dividir é a mesma para obter o resto.
Cavalo SMith
1
@SriramMurali Isso é porque você usou um mod par, claro que não funcionaria, esta é uma solução alternativa para ímpar como o OP disse.
ylun.ca
3

Não usando o &operador bit a bit-and ( ) em binário, não há. Esboço da prova:

Suponha que houvesse um valor k tal que x & k == x % (k + 1), mas k! = 2 ^ n - 1 . Então, se x == k , a expressão x & kparece "operar corretamente" e o resultado é k . Agora, considere x == ki : se houvesse algum bit "0" em k , há algum i maior que 0, o qual ki só pode ser expresso com bits 1 nessas posições. (Por exemplo, 1011 (11) deve se tornar 0111 (7) quando 100 (4) foi subtraído dele, neste caso o bit 000 torna-se 100 quando i = 4. ) Se um bit da expressão de k deve mudar de zero para um para representar ki, então ele não pode calcular corretamente x% (k + 1) , que neste caso deveria ser ki , mas não há como o booleano bit a bit e produzir esse valor dada a máscara.

Heath Hunnicutt
fonte
2

Neste caso específico (mod 7), ainda podemos substituir% 7 por operadores bit a bit:

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

Funciona porque 8% 7 = 1. Obviamente, esse código é provavelmente menos eficiente do que um simples x% 7 e, certamente, menos legível.

Eric Bainville
fonte
1

Usando bitwise_and, bitwise_or e bitwise_not você pode modificar qualquer configuração de bit para outras configurações de bit (isto é, este conjunto de operadores é "funcionalmente completo"). Porém, para operações como módulo, a fórmula geral seria necessariamente muito complicada, eu nem me daria ao trabalho de tentar recriá-la.

Mentira ryan
fonte