Bit a bit y en lugar de operador de módulo

91

Sabemos que por ejemplo el módulo de potencia de dos se puede expresar así:

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

Ejemplos:

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

¿Qué pasa con el no poder general de dos números?

Digamos:

x% 7 ==?

dato datuashvili
fuente
8
@Neil - Modulo y Binary Y son operaciones bastante fundamentales, supongo que son casi iguales en cualquier lenguaje informático.
James Kolpack
1
Me canso un poco de no ver el lenguaje publicado :) Aunque supongo que, por lo general, si no especifican, supongo que eso significa C ++ o C. Me pregunto qué tan cierto es eso ..
Garet Claborn
1
Solo para cualquiera que tenga dificultades para entender esto, eche un vistazo a stackoverflow.com/a/13784820/1414639 . Ah, y en JS con V8 obtengo un ligero aumento de rendimiento al usar operadores bit a bit.
Bardi Harborow
1
@JamesKolpack Una operación bit a bit se puede realizar MUCHO más rápido en una CPU que en un módulo. De hecho, un truco común de ensamblador para poner a cero un registro es XOR con él mismo (debido a este hecho). Hoy en día, un compilador podría optimizar un módulo de una potencia de dos, pero no lo sé
Kaiser Keister

Respuestas:

70

Primero que nada, en realidad no es exacto decir que

x % 2 == x & 1

Contraejemplo simple: x = -1. En muchos lenguajes, como Java, -1 % 2 == -1. Es decir, %no es necesariamente la definición matemática tradicional de módulo. Java lo llama el "operador de resto", por ejemplo.

Con respecto a la optimización bit a bit, en aritmética bit a bit sólo se pueden realizar "fácilmente" potencias de módulo de dos. En términos generales, sólo las potencias de módulo de base b se pueden hacer "fácilmente" con la representación de números en base b .

En base 10, por ejemplo, para no negativo N, N mod 10^ksolo se toman los kdígitos menos significativos .

Referencias

poligenelubricantes
fuente
1
-1 = -1 (mod 2), no estoy seguro de lo que quiere decir, ¿quiere decir que no es lo mismo que el resto de IEEE 754?
BlueRaja - Danny Pflughoeft
2
@BlueRaja: el residuo común para -1 en el mod 2 es 1 en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants
@BlueRaja: Si permite números negativos, de lo que básicamente puede estar seguro (particularmente porque no se mencionó ningún idioma) es que (a / b) / b + a % b == a, para los operadores de tipo C, a y b enteros, b distintos de cero, y también que abs(a % b) < abs(b)con las mismas condiciones.
David Thornley
1
@DavidThornley: asume que te refieres a (a / b)* b + a % b == a.
sfjac
40

Solo hay una forma sencilla de encontrar el módulo de 2 ^ i números utilizando bit a bit.

Hay una manera ingeniosa de resolver los casos de Mersenne según el enlace , como n% 3, n% 7 ... Hay casos especiales para n% 5, n% 255 y casos compuestos como n% 6.

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

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

Los más complicados son difíciles de explicar. Lea solo si tiene mucha curiosidad.

Sriram Murali
fuente
1
voto ++; Excelente enlace, gracias por la referencia. Aconsejo a los demás que le echen un vistazo, vale la pena leerlo aunque sea un poco complicado.
varzeak
el enlace es la mejor parte de la respuesta.
Amit Kumar
n% 2 ^ i = n & (1 << i - 1)
Kartik Singh
18

Esto solo funciona para potencias de dos (y con frecuencia solo positivas) porque tienen la propiedad única de tener solo un bit establecido en '1' en su representación binaria. Dado que ninguna otra clase de números comparte esta propiedad, no puede crear expresiones bit a bit para la mayoría de las expresiones de módulo.

VeeArr
fuente
2
Si está operando en una arquitectura ternaria, eso cambia un poco las cosas ... sin embargo, las posibilidades son nulas.
Noldorin
Me gusta cómo lo estás expresando: "eso cambia un poco las cosas "
j3141592653589793238
12

Este es específicamente un caso especial porque las computadoras representan números en base 2. Esto es generalizable:

(número) base % base x

es equivalente a los últimos x dígitos de la base (número) .

jdmichal
fuente
5

Hay módulos distintos de las potencias de 2 para los que existen algoritmos eficientes.

Por ejemplo, si x es 32 bits unsigned int entonces x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)

David Harris
fuente
4

Módulo "7" sin operador "%"

int a = x % 7;

int a = (x + x / 7) & 7;
ashuwp
fuente
3
No funciona para 10% 2 = 0. (10 + 10/2) & 2 = 15 & 2 = 2, del mismo modo 10% 6 = 4. (10 + 10/6) & 6 = 11 & 6 = 2
Sriram Murali
10
Además, ¿por qué querría dividir cuando quiere evitar usar módulo? AFAIK, la instrucción para dividir es la misma que para obtener el resto.
Horse SMith
2
@SriramMurali Eso es porque usaste un mod par, por supuesto que no funcionaría, esta es una solución para los impares como dijo el OP.
ylun.ca
3

No se usa el &operador bit a bit y ( ) en binario, no lo hay. Bosquejo de la prueba:

Suponga que hay un valor k tal que x & k == x % (k + 1), pero k! = 2 ^ n - 1 . Entonces, si x == k , la expresión x & kparece "operar correctamente" y el resultado es k . Ahora, considere x == ki : si hubiera bits "0" en k , hay algo de i mayor que 0, el cual ki solo puede expresarse con bits 1 en esas posiciones. (Por ejemplo, 1011 (11) debe convertirse en 0111 (7) cuando se le ha restado 100 (4), en este caso el bit 000 se convierte en 100 cuando i = 4. ) Si un bit de la expresión de k debe cambiar de cero a uno para representar ki, entonces no puede calcular correctamente x% (k + 1) , que en este caso debería ser ki , pero no hay forma de bit a bit booleano y producir ese valor dada la máscara.

Heath Hunnicutt
fuente
2

En este caso específico (mod 7), todavía podemos reemplazar% 7 con 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, este código es probablemente menos eficiente que un simple x% 7, y ciertamente menos legible.

Eric Bainville
fuente
1

Usando bitwise_and, bitwise_or y bitwise_not puede modificar cualquier configuración de bit a otra configuración de bit (es decir, este conjunto de operadores está "funcionalmente completo"). Sin embargo, para operaciones como módulo, la fórmula general sería necesariamente bastante complicada, ni siquiera me molestaría en intentar recrearla.

Mentira Ryan
fuente