Operadores bit a bit

Los operadores bit a bit permiten la evaluación y la manipulación de bits específicos dentro de un integer.

Operadores bit a bit
Ejemplo Nombre Resultado
$a & $b And (y) Los bits que están activos en ambos $a y $b son activados.
$a | $b Or (o inclusivo) Los bits que están activos ya sea en $a o en $b son activados.
$a ^ $b Xor (o exclusivo) Los bits que están activos en $a o en $b, pero no en ambos, son activados.
~ $a Not (no) Los bits que están activos en $a son desactivados, y viceversa.
$a << $b Shift left(desplazamiento a izquierda) Desplaza los bits de $a, $b pasos a la izquierda (cada paso quiere decir "multiplicar por dos").
$a >> $b Shift right (desplazamiento a derecha) Desplaza los bits de $a, $b pasos a la derecha (cada paso quiere decir "dividir por dos").

El desplazamiento de bits en PHP es aritmético. Los bits desplazados por fuera de cualquiera de los extremos son descartados. Desplazamientos de izquierda tienen ceros desplazados a la derecha mientras que el bit de signo es desplazado fuera a la izquierda, es decir que no se conserva el signo de un operando. Desplazamientos a la derecha tienen copias del bit de signo desplazado a la izquierda, es decir que se conserva el signo de un operando.

Utilice paréntesis para garantizar la precedencia deseada. Por ejemplo, $a & $b == true evalúa la equivalencia y luego el bit a bit, mientras que ($a & $b) == true evalúa el bit a bit y luego la equivalencia.

Si los operandos para los operadores &, | y ^ son string, la operación se realizará con los valores ASCII de los caracteres que componen dichos string, y el resultado será también un string. En todos los demás casos, ambos operandos serán convertidos a valores de tipo integer y el resultado será también un integer.

Si el operando del operados ~ es un string, la operación se realizará con valores los ASCII de los caracteres que componen dicho string, y el resultado también será un string; en caso contrario, el operando y el resultado serán tratados como valores de tipo integer.

Ambos operandos y el resultado de lo operadores << y >> siempre son tratados como valores de tipo integer.

      El ajuste ini error_reporting utiliza valores a nivel de bit,
      lo que ofrece una demostración del mundo real de desactivar
      bits. Para mostrar todos los errores, a excepción de los avisos,
      las instrucciones del archivo php.ini dicen utilizar:
      E_ALL & ~E_NOTICE
     

      Esto funciona iniciando con E_ALL:
      00000000000000000111011111111111
      Luego se toma el valor de E_NOTICE ...
      00000000000000000000000000001000
      ... y se invierte por medio de ~:
      11111111111111111111111111110111
      Finalmente, se utiliza AND (&) para encontrar los bits que se
      activaron en ambos valores:
      00000000000000000111011111110111
     

      Otra forma de lograrlo es mediante XOR (^)
      para encontrar los bits que están activados en sólo el primer valor o en el otro:
      E_ALL ^ E_NOTICE
     

      error_reporting también se puede utilizar para demostrar la activación de bits.
      La forma para mostrar sólo los errores y los errores recuperables es:
      E_ERROR | E_RECOVERABLE_ERROR
     

      Este proceso combina E_ERROR
      00000000000000000000000000000001
      y
      00000000000000000001000000000000
      usando el operador OR (|)
      para obtener los bits activados en cualquiera de estos valores:
      00000000000000000001000000000001
     

Ejemplo #1 Operaciones AND, OR y XOR bit a bit sobre integers

<?php
/*
 * Ignore la sección superior,
 * es sólo el formateado para hacer la salida más clara.
 */

$format '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
        
' %3$s (%4$2d = %4$04b)' "\n";

echo <<<EOH
 ---------     ---------  -- ---------
 resultado     valor      op prueba
 ---------     ---------  -- ---------
EOH;


/*
 * Aquí están los ejemplos.
 */

$values = array(01248);
$test 4;

echo 
"\n AND bit a bit \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'&'$test);
}

echo 
"\n OR inclusivo bit a bit \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'|'$test);
}

echo 
"\n OR exclusivo (XOR) bit a bit \n";
foreach (
$values as $value) {
    
$result $value $test;
    
printf($format$result$value'^'$test);
}
?>

El resultado del ejemplo sería:

 ---------     ---------  -- ---------
 resultado     valor      op prueba
 ---------     ---------  -- ---------
 AND bit a bit
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)

 OR inclusivo bit a bit
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)

 OR exclusivo (XOR) bit a bit
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)

Ejemplo #2 Operaciones XOR bit a bit sobre strings

<?php
echo 12 9// Sale '5'

echo "12" "9"// Sale el caracter de retroceso (ascii 8)
                 // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" "hello"// Salen los valores ascii #0 #4 #0 #0 #0
                        // 'a' ^ 'e' = #4

echo "3"// Sale 1
              // 2 ^ ((int)"3") == 1

echo "2" 3// Sale 1
              // ((int)"2") ^ 3 == 1
?>

Ejemplo #3 Desplazamiento de bits sobre integers

<?php
/*
 * Aquí están los ejemplos.
 */

echo "\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---\n";

$val 4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'copia del bit de signo desplazado hacia el lado izquierdo');

$val 4;
$places 2;
$res $val >> $places;
p($res$val'>>'$places);

$val 4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'bits desplazados fuera del lado derecho');

$val 4;
$places 4;
$res $val >> $places;
p($res$val'>>'$places'mismo resultado que arriba; no se puede desplazar más allá del 0');


echo 
"\n--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---\n";

$val = -4;
$places 1;
$res $val >> $places;
p($res$val'>>'$places'copia del bit de signo desplazado al lado izquierdo');

$val = -4;
$places 2;
$res $val >> $places;
p($res$val'>>'$places'bits desplazados fuera del lado derecho');

$val = -4;
$places 3;
$res $val >> $places;
p($res$val'>>'$places'mismo resultado que arriba; no se puede desplazar más allá del -1');


echo 
"\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---\n";

$val 4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'ceros rellenan en el lado derecho');

$val 4;
$places = (PHP_INT_SIZE 8) - 4;
$res $val << $places;
p($res$val'<<'$places);

$val 4;
$places = (PHP_INT_SIZE 8) - 3;
$res $val << $places;
p($res$val'<<'$places'bit de signo resulta desplazado fuera');

$val 4;
$places = (PHP_INT_SIZE 8) - 2;
$res $val << $places;
p($res$val'<<'$places'bit de signo desplazado fuera del lado izquierdo');


echo 
"\n--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---\n";

$val = -4;
$places 1;
$res $val << $places;
p($res$val'<<'$places'ceros rellenan en el lado derecho');

$val = -4;
$places = (PHP_INT_SIZE 8) - 3;
$res $val << $places;
p($res$val'<<'$places);

$val = -4;
$places = (PHP_INT_SIZE 8) - 2;
$res $val << $places;
p($res$val'<<'$places'bits desplazados fuera del lado izquierdo, incluyendo el bit de signo');


/*
 * Ignore this bottom section,
 * it is just formatting to make output clearer.
 */

function p($res$val$op$places$note '') {
    
$format '%0' . (PHP_INT_SIZE 8) . "b\n";

    
printf("Expression: %d = %d %s %d\n"$res$val$op$places);

    echo 
" Decimal:\n";
    
printf("  val=%d\n"$val);
    
printf("  res=%d\n"$res);

    echo 
" Binary:\n";
    
printf('  val=' $format$val);
    
printf('  res=' $format$res);

    if (
$note) {
        echo 
" NOTE: $note\n";
    }

    echo 
"\n";
}
?>

El resultado del ejemplo en equipos de 32 bit sería:


--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000010
 NOTE: copia del bit de signo desplazado hacia el lado izquierdo

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bits desplazados fuera del lado derecho

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0


--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111110
 NOTE: copia del bit de signo desplazado al lado izquierdo

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: bits desplazados fuera del lado derecho

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1


--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000001000
 NOTE: ceros rellenan en el lado derecho

Expression: 1073741824 = 4 << 28
 Decimal:
  val=4
  res=1073741824
 Binary:
  val=00000000000000000000000000000100
  res=01000000000000000000000000000000

Expression: -2147483648 = 4 << 29
 Decimal:
  val=4
  res=-2147483648
 Binary:
  val=00000000000000000000000000000100
  res=10000000000000000000000000000000
 NOTE: bit de signo resulta desplazado fuera

Expression: 0 = 4 << 30
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bit de signo desplazado fuera del lado izquierdo


--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111000
 NOTE: ceros rellenan en el lado derecho

Expression: -2147483648 = -4 << 29
 Decimal:
  val=-4
  res=-2147483648
 Binary:
  val=11111111111111111111111111111100
  res=10000000000000000000000000000000

Expression: 0 = -4 << 30
 Decimal:
  val=-4
  res=0
 Binary:
  val=11111111111111111111111111111100
  res=00000000000000000000000000000000
 NOTE: bits desplazados fuera del lado izquierdo, incluyendo el bit de signo

El resultado del ejemplo en equipos de 64 bit sería:


--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS POSITIVOS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000010
 NOTE: copia del bit de signo desplazado hacia el lado izquierdo

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits desplazados fuera del lado derecho

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: mismo resultado que arriba; no se puede desplazar más allá del 0


--- DESPLAZAMIENTO DE BITS A LA DERECHA SOBRE ENTEROS NEGATIVOS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111110
 NOTE: copia del bit de signo desplazado al lado izquierdo

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: bits desplazados fuera del lado derecho

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: mismo resultado que arriba; no se puede desplazar más allá del -1


--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS POSITIVOS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000001000
 NOTE: ceros rellenan en el lado derecho

Expression: 4611686018427387904 = 4 << 60
 Decimal:
  val=4
  res=4611686018427387904
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0100000000000000000000000000000000000000000000000000000000000000

Expression: -9223372036854775808 = 4 << 61
 Decimal:
  val=4
  res=-9223372036854775808
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=1000000000000000000000000000000000000000000000000000000000000000
 NOTE: bit de signo resulta desplazado fuera

Expression: 0 = 4 << 62
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bit de signo desplazado fuera del lado izquierdo


--- DESPLAZAMIENTO DE BITS A LA IZQUIERDA SOBRE ENTEROS NEGATIVOS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111000
 NOTE: ceros rellenan en el lado derecho

Expression: -9223372036854775808 = -4 << 61
 Decimal:
  val=-4
  res=-9223372036854775808
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1000000000000000000000000000000000000000000000000000000000000000

Expression: 0 = -4 << 62
 Decimal:
  val=-4
  res=0
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits desplazados fuera del lado izquierdo, incluyendo el bit de signo

Advertencia

Desplazar un integer por valores mayores o iguales al ancho del tipo long integer del sistema resultará en un comportamiento indefinido. En otras palabras, no desplace más de 31 bit en sistemas de 32 bit, y no desplace más de 63 bit en sistemas de 64 bit.

Use funciones de la extensión gmp para manipular a nivel de bit números mayores que PHP_INT_MAX.

Ver también pack(), unpack(), gmp_and(), gmp_or(), gmp_xor(), gmp_testbit(), gmp_clrbit()