¿Qué significa este booleano "(número & 1) == 0"?

79

En CodeReview publiqué un fragmento de código funcional y pedí sugerencias para mejorarlo. Uno que obtuve fue usar un método booleano para verificar si un ArrayList tenía un número par de índices (que era obligatorio). Este fue el código que se sugirió:

private static boolean isEven(int number)
{
    return (number & 1) == 0;
}

Como ya he molestado a ese usuario en particular para que me ayude, ¡he decidido que es hora de molestar a la comunidad SO! Realmente no entiendo cómo funciona esto. Se llama al método y toma el tamaño de ArrayList como parámetro (es decir, ArrayList tiene diez elementos, número = 10).

Sé que un solo hace &la comparación del número y el 1, pero me perdí después de eso.

De la forma en que lo leo, dice return true si number == 0y 1 == 0. Sé que lo primero no es cierto y lo segundo, obviamente, no tiene sentido. ¿Alguien podría ayudarme?

Editar: probablemente debería agregar que el código funciona, en caso de que alguien se lo pregunte.

Andrés Martín
fuente
2
¿Alguien sabe quién vinculó esto con esa otra publicación (que no tiene nada que ver con esto)? ¿Puedo eliminarlo de alguna manera?
Andrew Martin
1
¡Maldita sea, esto es realmente inteligente!
cauon
2
Esto apareció en Twitter.
Jonathon Reinhart
1
@GrijeshChauhan ¿Podría explicar cómo es esto más rápido que number % 2 == 0?
Vrushank

Respuestas:

114

Tenga en cuenta que "&" es una operación bit a bit. Probablemente sea consciente de esto, pero no me queda del todo claro por la forma en que planteó la pregunta.

Dicho esto, la idea teórica es que tienes algo de int, que se puede expresar en bits por alguna serie de unos y ceros. Por ejemplo:

...10110110

En binario, debido a que es base 2, siempre que la versión bit a bit del número termina en 0, es par, y cuando termina en 1 es impar.

Por lo tanto, hacer un bit a bit & con 1 para lo anterior es:

...10110110 & ...00000001

Por supuesto, esto es 0, por lo que puede decir que la entrada original fue pareja.

Alternativamente, considere un número impar. Por ejemplo, agregue 1 a lo que teníamos arriba. Luego

...10110111 & ...00000001

Es igual a 1 y, por tanto, no es igual a cero. Voila.

Kirby
fuente
13
Gracias, tu explicación lo deja muy claro. Además, cualquier respuesta que termine en Voila merece un voto a favor.
Andrew Martin
1
Probablemente también debería estar al tanto de los números negativos en esta respuesta.
Alvin Wong
3
Además, posiblemente enmendaría esta respuesta para incluir el hecho de que n%k == n&(k-1)para todos los kque tienen un poder positivo de 2. Puede que no sea lo que preguntó el autor de la pregunta, pero es útil saberlo.
esponjoso
1
@fluffy no dice que no funcionaría, pero no todos conocen el complemento de dos.
Alvin Wong
1
@fluffy ¿no debería haber un logo 2^en algún lugar en esa expresión?
Navin
67

Puede determinar que el número es par o impar por el último bit en su representación binaria:

1 -> 00000000000000000000000000000001 (odd)
2 -> 00000000000000000000000000000010 (even)
3 -> 00000000000000000000000000000011 (odd)
4 -> 00000000000000000000000000000100 (even)
5 -> 00000000000000000000000000000101 (odd)
6 -> 00000000000000000000000000000110 (even)
7 -> 00000000000000000000000000000111 (odd)
8 -> 00000000000000000000000000001000 (even)

& entre dos enteros es el operador AND bit a bit:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Entonces, si (number & 1) == 0es true, esto significa que numberes par.


Supongamos que number == 6, entonces:

6 -> 00000000000000000000000000000110 (even)

     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

1 -> 00000000000000000000000000000001

-------------------------------------

0 -> 00000000000000000000000000000000

y cuando number == 7:

7 -> 00000000000000000000000000000111 (odd)

     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

1 -> 00000000000000000000000000000001

-------------------------------------

1 -> 00000000000000000000000000000001
Ing.Fouad
fuente
18

&es el operador AND bit a bit. &&es el operador lógico AND

En binario, si el bit de dígitos está establecido (es decir, uno), el número es impar.

En binario, si el bit de dígitos es cero, el número es par.

(number & 1) es una prueba AND bit a bit del bit de dígitos.

Otra forma de hacer esto (y posiblemente menos eficiente pero más comprensible) es usando el operador de módulo %:

private static boolean isEven(int number)
{
    if (number < 0)
       throw new ArgumentOutOfRangeException();

    return (number % 2) == 0;
}
Trigo Mitch
fuente
2
&también es lógico AND. &&cortocircuitos mientras &que no.
Steve Kuo
5
number % 2no es lo mismo que number & 1si numberes negativo.
dan04
4
si le pasan una longitud negativa, ¡entonces tiene problemas mayores! ;)
Mitch Wheat
4
@RyanAmos "¿Iterar cada bit?" Bitwise AND es una operación única en todas las CPU que he visto; es una de las cosas más fáciles de hacer en paralelo.
esponjoso
2
@MitchWheat No hay razón para tirar en el number < 0caso, mientras que un número negativo impar mod 2 es -1, uno par mod 2 sigue siendo 0.
esponjoso
8

Esta expresión significa "el número entero representa un número par".

Aquí está la razón: la representación binaria de decimal 1es 00000000001. Todos los números impares terminan en 1binario (esto es fácil de verificar: suponga que la representación binaria del número no termina en 1; entonces se compone de potencias de dos distintas de cero, que siempre es un número par). Cuando haces un binario ANDcon un número impar, el resultado es 1; cuando haces un binario ANDcon un número par, el resultado es 0.

Este solía ser el método preferido para decidir los pares / impares en el momento en que los optimizadores eran deficientes o inexistentes, y los %operadores requerían veinte veces el número de ciclos realizados por un &operador. En estos días, si lo hace number % 2 == 0, es probable que el compilador genere código que se ejecute tan rápido como lo (number & 1) == 0hace.

Sergey Kalinichenko
fuente
5

Solo &significa andoperador bit a bit , no comparación

Entonces, este código verifica si el primero bit(el menos significativo / el más correcto) está configurado o no, lo que indica si el número lo es oddo no; porque todos los números impares terminarán con 1el bit menos significativo, por ejemploxxxxxxx1

iTech
fuente
Tenga en cuenta que una sola &se puede utilizar como lógica andsi desea mantener los efectos secundarios de expresiones comof(x) & g(x)
Navin
4

&es una ANDoperación bit a bit .

Para número = 8:

  1000
  0001
& ----
  0000

El resultado es ese (8 & 1) == 0. Este es el caso de todos los números pares, ya que son múltiplos de 2 y el primer dígito binario de la derecha siempre es 0. 1 tiene un valor binario de 1 con ceros a la ANDizquierda , así que cuando lo ponemos con un número par nos quedamos con 0.

Aram Kocharyan
fuente
3

El &operador en Java es el operador and bit a bit. Básicamente, (number & 1)realiza un bit a bit y entre numbery1 . El resultado es 0 o 1, dependiendo de si es par o impar. Luego, el resultado se compara con 0 para determinar si es par.

Aquí hay una página que describe las operaciones bit a bit .

rgettman
fuente
3

Está realizando un binario y contra 1, que devuelve 0 si no se establece el bit menos significativo

por tu ejemplo

00001010 (10)

00000001 (1)

===========

00000000 (0)

Peter Karlsson
fuente