resta - shift function in c
Desplazar a la derecha los nĂºmeros negativos en C (6)
A-1: Sí. 0xffff >> 1 es 0x7fff o 32767. No estoy seguro de lo que hace -0xffff. Eso es peculiar.
A-2: Cambiar no es lo mismo que dividir. Se trata de un cambio de bit, una operación binaria primitiva. Que a veces se puede usar para algunos tipos de división es conveniente, pero no siempre lo mismo.
Tengo un código C en el que hago lo siguiente.
int nPosVal = +0xFFFF; // + Added for ease of understanding
int nNegVal = -0xFFFF; // - Added for valid reason
Ahora cuando intento
printf ("%d %d", nPosVal >> 1, nNegVal >> 1);
yo obtengo
32767 -32768
Es esto esperado?
Soy capaz de pensar algo como
65535 >> 1 = (int) 32767.5 = 32767
-65535 >> 1 = (int) -32767.5 = -32768
Es decir, -32767.5 se redondea a -32768.
¿Es este entendimiento correcto?
Cuando se desplaza hacia la derecha, se descarta el bit menos significativo.
0xFFFF = 0 1111 1111 1111 1111, que se desplaza a la derecha para dar 0 0111 1111 1111 1111 = 0x7FFF
-0xFFFF = 1 0000 0000 0000 0001 (complemento 2s), que se desplaza a la derecha a 1 1000 0000 0000 0000 = -0x8000
Debajo del nivel C, las máquinas tienen un núcleo de CPU que es enteramente entera o escalar . Aunque en la actualidad cada CPU de escritorio tiene una FPU, este no siempre era el caso, e incluso hoy en día los sistemas integrados se hacen sin instrucciones de coma flotante.
Los paradigmas de programación de hoy y los diseños de CPU e idiomas datan de la época en que la FPU ni siquiera existía.
Por lo tanto, las instrucciones de CPU implementan operaciones de punto fijo , generalmente tratadas como operaciones puramente enteras . Solo si un programa declara elementos de float o double existirán fracciones. (Bueno, puedes usar las operaciones de CPU para "punto fijo" con fracciones, pero eso es ahora y siempre fue bastante raro).
Independientemente de lo que requería un comité de estándares de idiomas hace años, todas las máquinas razonables propagan el bit de signo en los cambios a la derecha de los números con signo. Los cambios a la derecha de los valores sin signo cambian en ceros a la izquierda. Los bits desplazados a la derecha se dejan caer al suelo.
Para comprender mejor, deberá investigar "aritmética de dos poros".
La especificación C no especifica si el bit de signo está desplazado o no. Depende de la implementación.
No, no obtienes números fraccionarios como 0.5 cuando trabajas con enteros. Los resultados se pueden explicar fácilmente cuando observa las representaciones binarias de los dos números:
65535: 00000000000000001111111111111111
-65535: 11111111111111110000000000000001
El bit se desplaza hacia la derecha y se extiende a la izquierda (tenga en cuenta que esto depende de la implementación, gracias a Trent):
65535 >> 1: 00000000000000000111111111111111
-65535 >> 1: 11111111111111111000000000000000
Convertir de nuevo a decimal:
65535 >> 1 = 32767
-65535 >> 1 = -32768
Parece que su implementación probablemente está realizando un desplazamiento de bits aritmético con dos números de complemento. En este sistema, desplaza todos los bits hacia la derecha y luego rellena los bits superiores con una copia de lo que fue el último bit. Entonces para su ejemplo, tratando int como 32 bits aquí:
nPosVal = 00000000000000001111111111111111
nNegVal = 11111111111111110000000000000001
Después del turno, tienes:
nPosVal = 00000000000000000111111111111111
nNegVal = 11111111111111111000000000000000
Si convierte esto de nuevo a decimal, obtiene 32767 y -32768 respectivamente.
Efectivamente, un cambio a la derecha gira hacia el infinito negativo.
Editar: según la Sección 6.5.7 del último borrador del estándar , este comportamiento en números negativos depende de la implementación:
El resultado de E1 >> E2 es E1 posiciones de bit E2 desplazadas a la derecha. Si E1 tiene un tipo sin signo o si E1 tiene un tipo firmado y un valor no negativo, el valor del resultado es la parte integral del cociente de E1 / 2 E2 . Si E1 tiene un tipo firmado y un valor negativo, el valor resultante está definido por la implementación.
Su declarado rational para esto:
El Comité C89 afirmó la libertad en la implementación otorgada por K & R para no requerir que la operación de cambio de la derecha firmada se extienda, ya que tal requisito podría ralentizar el código rápido y dado que la utilidad de los cambios de signo extendido es marginal. (¡Cambiar un entero de complemento de dos negativo aritméticamente a la derecha no es lo mismo que dividir por dos!)
De modo que depende de la implementación en teoría. En la práctica, nunca he visto una implementación que no haga un desplazamiento aritmético cuando se firma el operando izquierdo.