En programación informática , un desplazamiento aritmético es un operador de desplazamiento , a veces denominado desplazamiento con signo (aunque no está restringido a los operandos con signo). Los dos tipos básicos son el desplazamiento aritmético a la izquierda y el desplazamiento aritmético a la derecha . Para los números binarios, es una operación bit a bit que desplaza todos los bits de su operando; cada bit del operando simplemente se mueve un número determinado de posiciones de bit y las posiciones de bit vacantes se rellenan. En lugar de rellenarse con todos los 0, como en el desplazamiento lógico , al desplazarse hacia la derecha, el bit más a la izquierda (normalmente el bit de signo en las representaciones de números enteros con signo) se replica para rellenar todas las posiciones vacantes (esto es un tipo de extensión de signo ).
Algunos autores prefieren los términos desplazamiento a la derecha fijo y desplazamiento a la derecha con relleno de ceros para desplazamientos aritméticos y lógicos respectivamente. [7]
Los desplazamientos aritméticos pueden ser útiles como formas eficientes de realizar la multiplicación o división de números enteros con signo por potencias de dos. Desplazar n bits hacia la izquierda en un número binario con signo o sin signo tiene el efecto de multiplicarlo por 2 n . Desplazar n bits hacia la derecha en un número binario con signo en complemento a dos tiene el efecto de dividirlo por 2 n , pero siempre se redondea hacia abajo (hacia el infinito negativo). Esto es diferente de la forma en que se suele realizar el redondeo en la división de números enteros con signo (que se redondea hacia 0). Esta discrepancia ha provocado errores en varios compiladores. [8]
Por ejemplo, en el conjunto de instrucciones x86 , la instrucción SAR (desplazamiento aritmético a la derecha) divide un número con signo por una potencia de dos, redondeando hacia el infinito negativo. [9] Sin embargo, la instrucción IDIV (división con signo) divide un número con signo, redondeando hacia cero. Por lo tanto, una instrucción SAR no puede sustituirse por una instrucción IDIV por potencia de dos ni viceversa.
La definición formal de un desplazamiento aritmético, según la Norma Federal 1037C , es que es:
Una palabra importante en la definición de FS 1073C es "generalmente".
Los desplazamientos aritméticos a la izquierda son equivalentes a la multiplicación por una potencia (positiva, integral) del radio (por ejemplo, una multiplicación por una potencia de 2 para números binarios). Los desplazamientos lógicos a la izquierda también son equivalentes, excepto que la multiplicación y los desplazamientos aritméticos pueden provocar un desbordamiento aritmético, mientras que los desplazamientos lógicos no lo hacen [ cita requerida ] .
Sin embargo, los desplazamientos aritméticos a la derecha son trampas importantes para los incautos, especialmente en el tratamiento del redondeo de números enteros negativos. Por ejemplo, en la representación habitual de complemento a dos de números enteros negativos, −1 se representa como todos los 1. Para un entero con signo de 8 bits, esto es 1111 1111. Un desplazamiento aritmético a la derecha de 1 (o 2, 3, ..., 7) da como resultado 1111 1111 nuevamente, que sigue siendo −1. Esto corresponde a redondear hacia abajo (hacia el infinito negativo), pero no es la convención habitual para la división.
Con frecuencia se afirma que los desplazamientos aritméticos a la derecha son equivalentes a la división por una potencia (positiva, integral) de la base (por ejemplo, una división por una potencia de 2 para números binarios) y, por lo tanto, esa división por una potencia de la base se puede optimizar implementándola como un desplazamiento aritmético a la derecha. (Un desplazador es mucho más simple que un divisor. En la mayoría de los procesadores, las instrucciones de desplazamiento se ejecutarán más rápido que las instrucciones de división). Una gran cantidad de manuales de programación, manuales y otras especificaciones de las décadas de 1960 y 1970 de empresas e instituciones como DEC , IBM , Data General y ANSI hacen afirmaciones incorrectas [10] [ página necesaria ] .
Los desplazamientos lógicos a la derecha son equivalentes a la división por una potencia de la base (normalmente 2) solo para números positivos o sin signo. Los desplazamientos aritméticos a la derecha son equivalentes a los desplazamientos lógicos a la derecha para números positivos con signo. Los desplazamientos aritméticos a la derecha para números negativos en complemento de N (normalmente complemento a dos ) son aproximadamente equivalentes a la división por una potencia de la base (normalmente 2), donde para los números impares se aplica el redondeo hacia abajo (no hacia 0 como se espera habitualmente).
Los desplazamientos aritméticos a la derecha para números negativos son equivalentes a la división que utiliza redondeo hacia 0 en la representación del complemento a uno de números con signo, como lo usaban algunas computadoras históricas, pero esto ya no se usa de manera general.
La norma ISO (1999) para el lenguaje de programación C define el operador de desplazamiento a la derecha en términos de divisiones por potencias de 2. [11] Debido a la falta de equivalencia mencionada anteriormente, la norma excluye explícitamente de esa definición los desplazamientos a la derecha de números con signo que tienen valores negativos. No especifica el comportamiento del operador de desplazamiento a la derecha en tales circunstancias, sino que requiere que cada compilador de C individual defina el comportamiento del desplazamiento de valores negativos a la derecha. [nota 8]
Al igual que C, C++ tenía un desplazamiento a la derecha definido por la implementación para números enteros con signo hasta C++20. A partir del estándar C++20, el desplazamiento a la derecha de un número entero con signo se define como un desplazamiento aritmético. [13]
En aplicaciones en las que se desea un redondeo descendente uniforme, los desplazamientos aritméticos a la derecha para valores con signo son útiles. Un ejemplo es la reducción de escala de las coordenadas ráster por una potencia de dos, lo que mantiene un espaciado uniforme. Por ejemplo, un desplazamiento a la derecha de 1 envía 0, 1, 2, 3, 4, 5, ... a 0, 0, 1, 1, 2, 2, ..., y −1, −2, −3, −4, ... a −1, −1, −2, −2, ..., manteniendo el espaciado uniforme como −2, −2, −1, −1, 0, 0, 1, 1, 2, 2, ... Por el contrario, la división de enteros con redondeo hacia cero envía −1, 0 y 1 a 0 (3 puntos en lugar de 2), lo que produce −2, −1, −1, 0, 0, 0, 1, 1, 2, 2, ... en su lugar, que es irregular en 0.
>>
operador en C y C++ no es necesariamente un desplazamiento aritmético. Por lo general, solo es un desplazamiento aritmético si se utiliza con un tipo entero con signo en su lado izquierdo. Si, en cambio, se utiliza con un tipo entero sin signo, será un desplazamiento lógico .arithmetic-shift
se puede hacer tanto desplazamiento a la izquierda como a la derecha, dependiendo del segundo operando, muy similar al lenguaje de macros OpenVMS, aunque Scheme R6RS añade ambos -right
y -left
variantes.Bits
clase del módulo de Haskell Data.Bits
define tanto shift
la posibilidad de tomar un argumento con signo como shiftL
la shiftR
de tomar argumentos sin signo. Estas son isomorfas ; para las nuevas definiciones, el programador necesita proporcionar solo una de las dos formas y la otra forma se definirá automáticamente en términos de la proporcionada.Este artículo incorpora material de dominio público de la Norma Federal 1037C. Administración de Servicios Generales . Archivado desde el original el 22 de enero de 2022.
{{cite book}}
: |work=
ignorado ( ayuda )