2009-01-20 26 views
12

No puedo entender este operador de desplazamiento (Referencia de C#):Comprender el operador de desplazamiento

class MainClass1 
{ 
static void Main() 
    { 
     int i = 1; 
     long lg = 1; 
     Console.WriteLine("0x{0:x}", i << 1); 
     Console.WriteLine("0x{0:x}", i << 33); 
     Console.WriteLine("0x{0:x}", lg << 33); 
    } 
} 

/* 
Output: 
0x2 
0x2 
0x200000000 
*/ 

class MainClass2 
{ 
    static void Main() 
    { 
     int a = 1000; 
     a <<= 4; 
     Console.WriteLine(a); 
    } 
} 

/* 
Output: 
16000 
*/ 

Respuesta

34

<< es el operador izquierdo de cambio; esto toma la representación binaria de un valor, y mueve todos los bits "n" lugares a la izquierda (excepto para "mod", ver "1"), rellenando con ceros.

>> es el operador de desplazamiento a la derecha; esto hace casi lo contrario (moviéndose hacia la derecha), a excepción de los valores con signo (es decir, los que pueden ser negativos) que se rellena con 1s para valores negativos, de lo contrario son ceros.

1:

El operador de desplazamiento es esencialmente "mod" la anchura de los datos. Un int es de 32 bits, por lo que un desplazamiento a la izquierda de 33 (en Int32) es exactamente lo mismo que un cambio a la izquierda de 1. No obtienes todos los ceros. Un long tiene 64 bits, por lo que un desplazamiento a la izquierda de 33 da una respuesta diferente (el original multiplicado por 2^33).

2:

Cada desplazamiento a la izquierda (dentro de la anchura de los datos) es el mismo (para los números enteros) como x2 - así < < 4 es x2x2x2x2 = x16.

Esta es binaria simple:

0000000001 = 1 

< < va a

0000000010 = 2 

< < va a

0000000100 = 4 

< < va a

0000001000 = 8 
+0

Hola, ¿puedo pedirte que lo expliques más? En la primera, ¿por qué tengo 0x200000000 y en la segunda, por qué tengo 16000? muchas gracias –

+0

Eso es como decir "por qué es 1 * 50000 diferente a 1000 * 8" - porque estás haciendo cosas muy diferentes. El primero es 2^33 ("potencia de"), el segundo es 1000 * 16. –

+0

bien entiendo la diferencia entre 2^33 y 1000 * 16 quiero saber por qué 2^32 –

6

Sólo para ampliar la respuesta de Marc un poco (Marc, no dude en incluir esto en la suya y voy a borrar esta respuesta) esto se especifica en el apartado 7.8 de la especificación:


El los operadores de turnos predefinidos se enumeran a continuación.

Shift izquierda:

  • operador int < < (int x, int count);
  • uint operator < < (uint x, int count);
  • operador largo < < (largo x, recuento int);
  • ulong operator < < (ulong x, int count);

El operador < < se desplaza x dejando una cantidad de bits calculados como se describe a continuación.

Los bits de orden superior fuera del rango del tipo de resultado de x se descartan, los bits restantes se desplazan hacia la izquierda y las posiciones de bits vacíos de orden inferior se ponen a cero.

Shift derecha:

  • operador int >> (int x, int count);
  • uint operator >> (uint x, int count);
  • operador largo >> (largo x, recuento int);
  • ulong operator >> (ulong x, int count);

El operador >> se desplaza x en la derecha por una serie de bits calculados como se describe a continuación.

Cuando x es de tipo int o largo, los bits de orden inferior de x se descartan, los bits restantes se desplazan a la derecha y las posiciones de bits vacías de alto orden se ponen a cero si x no es negativo y se establecen a uno si x es negativo.

Cuando x es de tipo uint o ulong, los bits de orden inferior de x se descartan, los bits restantes se desplazan hacia la derecha y las posiciones de bits vacías de orden superior se ponen a cero.

Para los operadores predefinidos, el número de bits a desplazar se calcula como sigue:

Cuando el tipo de x es int o uint, el valor de desplazamiento es dada por el bajo orden de cinco bits de recuento. En otras palabras, el recuento de turnos se calcula a partir del recuento & 0x1F.

Cuando el tipo de x es largo o largo, la cuenta de turno está dada por los seis bits de bajo orden de conteo. En otras palabras, el recuento de turnos se calcula a partir del recuento & 0x3F.

Si el recuento de turnos resultante es cero, los operadores de turno simplemente devuelven el valor de x.


+0

Solicito su ayuda. –

2

Unas cuantas notas para el programador novato:

qué los operadores uso turno? No parecen hacer mucho. Bueno, hay 2 razones:

  1. Son muy rápido, porque casi todas las CPU tienen registros de desplazamiento, es decir, la operación de cambio se hace en el hardware, en la cantidad mínima de esfuerzo (ciclos).

  2. Debido a que son rápidos, muchos protocolos y estándares están diseñados para aprovechar esto. Por ejemplo, operaciones de dirección IP, comprobación de un CRC, operaciones gráficas, etc.

1

"El operador de desplazamiento es esencialmente" mod "el ancho de los datos."

¡Basura! Si la cantidad del desplazamiento es mayor o igual que el ancho de los datos, el resultado no está definido. No espere que la misma operación 'mod' que ha visto haya sucedido, ocurra con diferentes compiladores o versiones diferentes del mismo compilador, o en diferentes situaciones de turnos en el mismo programa, o cuando cambie cualquier otra cosa. Eso es lo que significa "indefinido".

+0

actualy C# 4.0 especificación del lenguaje dice: 1) Cuando el tipo de x es int u uint, el recuento de turnos está dado por los cinco bits de bajo orden de conteo. En otras palabras, el recuento de turnos se calcula a partir del recuento y 0x1F. 2) Cuando el tipo de x es largo o largo, la cuenta de turno está dada por los seis bits de bajo orden de conteo. En otras palabras, el recuento de turnos se calcula a partir de recuento y 0x3F. – Ivan