Pregunta

En C, son los operadores de desplazamiento (<<, >>) aritmética o lógica?

¿Fue útil?

Solución

De acuerdo a K&R 2ª edición los resultados dependen de la implementación de derecho turnos de valores con signo.

Wikipedia dice que C/C++ 'normalmente' implementa una operación aritmética cambio en los valores con signo.

Básicamente, usted necesita para probar su compilador o no confiar en ella.Mi VS2008 ayuda para el actual MS compilador de C++, dice que su compilador realiza una media aritmética de turno.

Otros consejos

Cuando se desplaza a la izquierda, no hay ninguna diferencia entre la aritmética y la lógica de turno.Cuando se desplaza a la derecha, el tipo de cambio depende del tipo de valor que se desplaza.

(Como telón de fondo para aquellos lectores no familiarizados con la diferencia, de una "lógica" a la derecha cambio de 1 bit desplaza todos los bits a la derecha y rellenos en el extremo izquierdo de bits con un 0.Una "aritmética" de turno deja el valor original de la izquierda bits.La diferencia se vuelve importante cuando se trabaja con números negativos.)

Cuando se cambia un valor sin signo, el >> operador en C es un cambio lógico.Cuando se cambia un valor con signo, el >> operador es una media aritmética de turno.

Por ejemplo, suponiendo que un equipo de 32 bits:

signed int x1 = 5;
assert((x1 >> 1) == 2);
signed int x2 = -5;
assert((x2 >> 1) == -3);
unsigned int x3 = (unsigned int)-5;
assert((x3 >> 1) == 0x7FFFFFFD);

TL;DR

Considere la posibilidad de i y n a los operandos izquierdo y derecho, respectivamente, de un cambio de operador;el tipo de i, después de entero de la promoción, se T.Suponiendo n para estar en [0, sizeof(i) * CHAR_BIT) — no definida de otra manera — hemos de estos casos:

| Direction  |   Type   | Value (i) | Result                   |
| ---------- | -------- | --------- | ------------------------ |
| Right (>>) | unsigned |    ≥ 0    | −∞ ← (i ÷ 2ⁿ)            |
| Right      | signed   |    ≥ 0    | −∞ ← (i ÷ 2ⁿ)            |
| Right      | signed   |    < 0    | Implementation-defined†  |
| Left  (<<) | unsigned |    ≥ 0    | (i * 2ⁿ) % (T_MAX + 1)   |
| Left       | signed   |    ≥ 0    | (i * 2ⁿ) ‡               |
| Left       | signed   |    < 0    | Undefined                |

† la mayoría de los compiladores de implementar esta medida aritmética de cambio
‡ indefinido si el valor sobrepasa el resultado de tipo T;promovido tipo de i


Cambio de

La primera es la diferencia entre la lógica y la aritmética se desplaza de un punto de vista matemático, sin preocuparse del tamaño del tipo de datos.Lógico cambios siempre llena descarta bits con ceros, mientras que la aritmética cambio rellena con ceros sólo para el desplazamiento a la izquierda, sino por el derecho de cambiar las copias de la MSB, conservando así el signo del operando (suponiendo una complemento a dos codificación para valores negativos).

En otras palabras, el cambio lógico se ve en el pasado operando como una secuencia de bits y moverlos, sin preocuparse por el signo del valor resultante.Aritmética cambio se ve como un (firmado) número y conserva el signo de los turnos de hecho.

A la izquierda de la aritmética cambio de un número X por n es equivalente a multiplicar X por 2n y es por lo tanto equivalente a la lógica de desplazamiento a la izquierda;un cambio lógico que también le daría el mismo resultado ya MSB de todos modos cae fuera de la final y no hay nada que conservar.

Un derecho aritmética cambio de un número X por n es equivalente a la división entera de X por 2n SÓLO si X es un número no negativo!La división entera no es sino la matemática de la división y ronda hacia 0 (trunc).

Para los números negativos, representado por el complemento a dos de codificación, el desplazamiento a la derecha por n bits tiene el efecto de que, matemáticamente, dividiéndolo por 2n y redondeo hacia −∞ (piso);por ello el cambio es diferente para los no-negativos y los valores negativos.

para X ≥ 0, X >> n = X / 2n = trunc(X ÷ 2n)

para X < 0, X >> n = floor(X ÷ 2n)

donde ÷ es matemático, división, / es la división entera.Veamos un ejemplo:

37)10 = 100101)2

37 ÷ 2 = 18.5

37 / 2 = 18 (redondeo 18.5 hacia 0) = 10010)2 [resultado de la aritmética a la derecha mayús]

-37)10 = 11011011)2 (teniendo en cuenta un complemento a dos de 8 bits de la representación)

-37 ÷ 2 = -18.5

-37 / 2 = -18 (redondeo 18.5 hacia 0) = 11101110)2 [NO es el resultado de la aritmética a la derecha mayús]

-37 >> 1 = -19 (redondeo 18.5 hacia −∞) = 11101101)2 [resultado de la aritmética a la derecha mayús]

Como Guy Steele señaló, esta discrepancia ha llevado a errores en más de un compilador.Aquí no negativo (matemáticas) puede ser asignado a unsigned y signed no valores negativos (C);ambos son tratados de la misma y a la derecha-cambio de ellos se hace por división de enteros.

Tan lógica y la aritmética son equivalentes en la izquierda de desplazamiento y para los no-valores negativos en la derecha cambiando;es en la derecha cambio de valores negativos, que se diferencian.

Operando y Tipos de Resultado

Estándar C99 §6.5.7:

Cada uno de los operandos deben tener los tipos enteros.

El entero de las promociones se realizan en cada uno de los operandos.El tipo del resultado es que de los promovido a la izquierda del operando.Si el valor del operando derecho es negativo o mayor que o igual a la anchura de los promovido a la izquierda del operando, el comportamiento es indefinido.

short E1 = 1, E2 = 3;
int R = E1 << E2;

En el fragmento anterior, ambos operandos convertido en int (debido a entero promoción);si E2 fue negativo o E2 ≥ sizeof(int) * CHAR_BIT a continuación, la operación no está definida.Esto es debido a cambio más que la disposición de los bits es, sin duda va a desbordar.Había R sido declarado como short, el int resultado de la transición de la operación sería convertir implícitamente short;una conversión de restricción, lo que puede conducir a la aplicación definida por el comportamiento si el valor no es representable en el tipo de destino.

Desplazamiento A La Izquierda

El resultado de E1 << E2 E1 desplazado a la izquierda E2 posiciones de bits;desocupado bits se llenan con ceros.Si E1 tiene un entero de tipo, el valor del resultado es E1×2E2, la reducción de modulo uno más que el máximo valor representable en el tipo de resultado.Si E1 tiene firmado el tipo y el valor no negativo, y E1×2E2 es representable en el tipo de resultado, entonces ese es el valor resultante;de lo contrario, el comportamiento es indefinido.

A la izquierda de los turnos de la misma para ambos, el desocupado bits son simplemente rellena con ceros.Se establece que para ambos sin firmar y firmados tipos es una media aritmética de turno.Estoy de interpretarla como la aritmética cambio desde la lógica de los turnos no te preocupes por el valor que representan los bits, sólo se ve como una secuencia de bits;pero la norma no habla en términos de bits, pero por definición en términos del valor obtenido por el producto de E1 con 2E2.

La advertencia aquí es que para firma de tipos el valor debe ser no negativo y el valor resultante debe ser representable en el tipo de resultado.De lo contrario la operación no está definida. El tipo de resultado que sería el tipo de la E1 después de aplicar la promoción integral y no el destino (la variable que va a contener el resultado) de tipo.El valor resultante se convierte implícitamente al tipo de destino;si no es representable en ese tipo, entonces la conversión de la implementación definido (C99 §6.3.1.3/3).

Si E1 es firmado un tipo con un valor negativo, a continuación, el comportamiento de la izquierda desplazamiento es indefinido. Esta es una ruta fácil para un comportamiento indefinido que puede fácilmente pasar por alto.

Mayús Derecha

El resultado de E1 >> E2 E1 derecho desplazado a la E2 posiciones de bits.Si E1 tiene un entero de tipo o si E1 ha firmado un tipo y un valor no negativo, el valor del resultado es la parte integral del cociente de E1/2E2.Si E1 ha firmado un tipo y un valor negativo, el valor resultante es de aplicación definido.

Mayús derecha para unsigned y signed no valores negativos son bastante recta hacia adelante;la vacante de bits se rellenan con ceros. Para firma de los valores negativos, el resultado de la derecha de funciones es de aplicación definido. Dicho esto, la mayoría de las implementaciones como GCC y Visual C++ implementar derecho de desplazamiento como la aritmética desviación preservar el bit de signo.

Conclusión

A diferencia de Java, que tiene un operador especial >>> para el lógico desplazamiento aparte de la habitual >> y <<, C y C++ tienen sólo la aritmética cambiando con algunas áreas de la izquierda indefinida y definida por implementación.La razón por la que considero como la aritmética es debido a que el texto estándar de la operación, matemáticamente, en lugar de tratar el pasado operando como una secuencia de bits;esta es quizás la razón por la que deja esas áreas de la onu/aplicación definida por el lugar de la definición de todos los casos, como es lógico turnos.

En términos de tipo de cambio que quieres conseguir, lo importante es el tipo del valor que se está cambiando.Un clásico de la fuente de errores es cuando cambias de una literal a, digamos, la mascara de bits.Por ejemplo, si usted quería soltar más a la izquierda de los bits de un entero sin signo, entonces usted puede intentar esto como su máscara:

~0 >> 1

Desafortunadamente, esto va a meter en problemas, porque la máscara tendrá todos sus bits, ya que el valor que se desplaza (~0) está firmado, por lo que una aritmética de cambio se realiza.En su lugar, usted quiere forzar un cambio lógico por declarar explícitamente el valor sin signo, es decir,por hacer algo como esto:

~0U >> 1;

Aquí están las funciones de garantizar el derecho lógico de cambio y de desplazamiento aritmético a la derecha de un int en C:

int logicalRightShift(int x, int n) {
    return (unsigned)x >> n;
}
int arithmeticRightShift(int x, int n) {
    if (x < 0 && n > 0)
        return x >> n | ~(~0U >> n);
    else
        return x >> n;
}

Cuando usted hace - desplazamiento a la izquierda por 1 se multiplica por 2 - derecho de cambiar el 1 de dividir por 2

 x = 5
 x >> 1
 x = 2 ( x=5/2)

 x = 5
 x << 1
 x = 10 (x=5*2)

Bueno, me miró en wikipedia, y que tiene esto que decir:

C, sin embargo, sólo tiene un derecho de turno operador >>.Muchos compiladores de C elegir que cambio a realizar en función en qué tipo de entero está siendo cambió de lugar;a menudo enteros son cambió el uso de la aritmética de cambio, y los enteros sin signo se desplazan mediante el cambio lógico.

Así que parece que esto depende de su compilador.También en ese artículo, tenga en cuenta que el desplazamiento a la izquierda es el mismo para aritméticas y lógicas.Yo recomendaría hacer una prueba sencilla con algunos firmados y sin firmar números en el caso de la frontera (conjunto de bits de curso) y ver lo que el resultado es de su compilador.También recomiendo evitar en función de que sea uno o el otro, ya que parece que C no tiene ningún estándar, al menos si es razonable y posible evitar la dependencia.

Desplazamiento a la izquierda <<

Esto es de alguna manera fácil y cada vez que utilice el operador de desplazamiento, es siempre un bit a bit de la operación, por lo que no puede utilizar con un double y float operación.Siempre que salimos de cambio de uno a cero, siempre se añade el bit menos significativo (LSB).

Pero en mayús derecha >> tenemos que seguir una regla adicional y que la regla se llama "bit de signo copia".Significado de "bit de signo copia", es si el bit más significativo (MSB) se establece, a continuación, después de un desplazamiento derecha de nuevo el MSB se establecerá si es cero, entonces es restablecer de nuevo, significa que si el valor anterior era cero, a continuación, después del cambio de nuevo, el bit es cero, si el anterior fue uno, a continuación, después de que el cambio es de nuevo uno.Esta regla no es aplicable para un desplazamiento a la izquierda.

El ejemplo más importante en mayús derecha, si usted cambia cualquier número negativo para mayús derecha, a continuación, después de algunas cambiando el valor, finalmente, llegar a cero y, a continuación, después de esto si los cambios -1 cualquier número de veces que el valor seguirá siendo el mismo.Por favor consulte.

normalmente uso lógico de turnos en el unsigned variables y para la izquierda-turnos de trabajo firmado variables.El desplazamiento aritmético a la derecha es la verdaderamente importante, porque va a firmar extender la variable.

se hará uso de este cuando sea aplicable, como otros compiladores son propensos a hacer.

GCC ¿

  1. para -ve - > Aritmética Cambio

  2. Para +ve -> Cambio Lógico

De acuerdo a muchos compiladores:

  1. << es una media aritmética de desplazamiento a la izquierda o a la izquierda en modo bit shift.
  2. >> es una aritmético a la derecha shiftor bit a bit a la derecha mayús.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top