Cambio aritmético
Idioma o procesador | Izquierda | Bien. |
---|---|---|
ActionScript 3, Java, JavaScript, Python, PHP, Ruby, C, C++,D, C#, Go, Julia, Rust (tipos firmados solamente), Swift (tipos asignados únicamente) | << | >> |
Ada | Shift_Left | Shift_Right_Arithmetic |
Kotlin | shl | shr |
Standard ML | << | ~>> |
Verilog | <<< | >>> |
Lengua macro OpenVMS | @ | |
Plan | arithmetic-shift | |
Lisp común | ash | |
OCaml | lsl | asr |
Haskell | Data.Bits.shift | |
Assembly, 68k | ASL | ASR |
Assembly, x86 | SAL | SAR |
VHDL | sla | sra |
RISC-V | sll , slli | sra , srai |
Z80 | SLA | SRA |
En la programación informática, un desplazamiento aritmético es un operador de desplazamiento, a veces denominado desplazamiento con signo (aunque no se limita 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 números binarios, es una operación bit a bit que desplaza todos los bits de su operando; cada bit en el operando simplemente se mueve un número dado de posiciones de bit, y las posiciones de bit vacantes se llenan. En lugar de llenarse con ceros, como en el desplazamiento lógico, cuando se desplaza hacia la derecha, el bit más a la izquierda (generalmente el bit de signo en representaciones de enteros con signo) se replica para llenar todas las posiciones vacantes (este es un tipo de extensión de signo).
Algunos autores prefieren los términos sticky right-shift y zero-fill right-shift para desplazamientos aritméticos y lógicos respectivamente.
Los cambios aritméticos pueden ser útiles como formas eficientes de realizar multiplicaciones o divisiones de enteros con signo por potencias de dos. Desplazar a la izquierda n bits en un número binario con o sin signo tiene el efecto de multiplicarlo por 2n. Desplazar a la derecha n bits en un número binario con signo complemento a dos tiene el efecto de dividirlo por 2n< /sup>, 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 enteros con signo (que redondea hacia 0). Esta discrepancia ha provocado errores en varios compiladores.
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. Sin embargo, la instrucción IDIV (dividir 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.
Definición formal
La definición formal de un cambio aritmético, del estándar federal 1037C, es que es:
- Un cambio, aplicado a la representación de un número en un sistema de numeración de radio fijo y en un sistema de representación de punto fijo, y en el que sólo se mueven los caracteres que representan la parte de punto fijo del número. Un cambio aritmético generalmente equivale a multiplicar el número por una potencia integral positiva o negativa del ráx, excepto por el efecto de cualquier redondeo; comparar el cambio lógico con el cambio aritmético, especialmente en el caso de la representación de punto flotante.
Una palabra importante en la definición de FS 1073C es "generalmente".
Equivalencia de desplazamientos aritméticos y lógicos a la izquierda y multiplicación
Los desplazamientos a la izquierda aritméticos son equivalentes a la multiplicación por una potencia (integral positiva) de la raíz (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 desencadenar un desbordamiento aritmético mientras que los desplazamientos lógicos no lo hacen.
No equivalencia de desplazamiento aritmético a la derecha y división
Sin embargo, los desplazamientos aritméticos a la derecha son trampas importantes para los incautos, específicamente en el tratamiento del redondeo de números enteros negativos. Por ejemplo, en la representación habitual en complemento a dos de enteros negativos, −1 se representa como todos los 1. Para un entero de 8 bits con signo, esto es 1111 1111. Un desplazamiento aritmético a la derecha de 1 (o 2, 3,..., 7) produce 1111 1111 nuevamente, que sigue siendo −1. Esto corresponde al redondeo 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 (integral positiva) de la raíz (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 radix se puede optimizar implementándolo como un desplazamiento aritmético a la derecha. (Una palanca de cambios es mucho más simple que un divisor. En la mayoría de los procesadores, las instrucciones de cambio se ejecutarán más rápido que las instrucciones de división). y ANSI hacen tales declaraciones incorrectas.
Los desplazamientos lógicos a la derecha son equivalentes a la división por una potencia de la raíz (generalmente 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 con signo positivo. Los desplazamientos aritméticos a la derecha para números negativos en complemento de N−1 (generalmente complemento a dos) equivalen aproximadamente a la división por una potencia de la base (generalmente 2), donde para números impares se aplica el redondeo hacia abajo (no hacia 0 como normalmente se espera).
Los desplazamientos aritméticos a la derecha para números negativos son equivalentes a la división mediante el redondeo hacia 0 en la representación del complemento a uno de los números con signo, como se usaba en algunas computadoras históricas, pero ya no es de uso general.
Manejo del problema en lenguajes de programación
El estándar 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. Debido a la no equivalencia mencionada anteriormente, el estándar excluye explícitamente de esa definición los desplazamientos a la derecha de números 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 de desplazamiento de valores negativos a la derecha.
Aplicaciones
En aplicaciones en las que se desea un redondeo consistente hacia abajo, 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, el desplazamiento a la derecha en 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 todos a 0 (3 puntos en lugar de 2), dando −2, −1, −1, 0, 0, 0, 1, 1, 2, 2,... en cambio, que es irregular en 0.
Contenido relacionado
Bill Gates
Continuación analítica
Axioma de emparejamiento