sistema - que pasa si el abs no funciona
¿Por qué es abs(0x80000000)== 0x80000000? (9)
Acabo de empezar a leer Hacker''s Delight y define abs (-2 31 ) como -231. ¿Porqué es eso?
Intenté printf("%x", abs(0x80000000))
en algunos sistemas diferentes y recibí 0x80000000 en todos ellos.
0x8000 .. se almacena como 10000 .... (binario). Esto se conoce como complemento a dos, lo que significa que el bit más alto (el de la izquierda) se usa para almacenar el signo del valor y los valores negativos se almacenan con el binario negativo - 1. La función abs () ahora verifica el signo, ve que está configurado y calcula el valor positivo.
- Para obtener el valor positivo primero niega todos los bits en la variable, lo que resulta en 01111 ...
- Luego agrega 1, que de nuevo resulta en 1000 ... el 0x8000 ... comenzamos con
Ahora este es un número negativo que no queríamos, la razón es un desbordamiento, prueba el número 0x9000 ... que es 10010 ...
- negar los resultados de bits en 01101 ... agregando uno resultados en 01110 ...
- que es 0xE000 ... un número positivo
Con este número, el desbordamiento se detiene con el bit 0 de la derecha
Creo que la manera en que funcionan los abs
es primero verificar el sign bit
de sign bit
del número. Si está claro no hacer nada ya que el número ya es +ve
, devuelve el 2''s complement
de 2''s complement
número. En tu caso, el número es -ve
y necesitamos encontrar su 2''s complement
. Pero el complemento 2 de 0x80000000
pasa a ser 0x80000000
.
Debido a que los enteros se almacenan en la memoria como un número binario de complemento de dos, la versión positiva del valor mínimo se desborda de nuevo a negativo.
Es decir (en .NET, pero aún se aplica):
int.MaxValue + 1 == int.MinValue // Due to overflow.
Y
Math.Abs((long)int.MinValue) == (long)int.MaxValue + 1
En realidad, en C, el comportamiento no está definido. Del estándar C99, §7.20.6.1 / 2:
Las funciones
abs
,labs
yllabs
calculan el valor absoluto de un enteroj
. Si el resultado no se puede representar, el comportamiento no está definido.
y su nota al pie:
El valor absoluto del número más negativo no se puede representar en complemento a dos.
Esto se remonta a cómo se almacenan los números.
Los números negativos se almacenan usando el complemento de dos. El algoritmo es como ...
Voltea todos los bits, luego agrega 1.
Usando números de ocho bits para ejemplos ...
+0 = -0
00000000 -> 11111111, 11111111 + 1 = 100000000
(pero debido a la limitación de bits, esto se convierte en 00000000).
Y...
-128 [alias - (2 ^ 7)] es igual a - (- 128)
10000000 -> 01111111, 01111111 + 1 = 10000000
Espero que esto ayude.
La representación del número de complemento de dos tiene el bit más significativo como número negativo. 0x80000000 es 1 seguido de 31 ceros, el primero 1 representa -2 ^ 31 no 2 ^ 31. Por lo tanto, no hay forma de representar 2 ^ 31 ya que el número positivo más alto es 0x7FFFFFFF, que es 0 seguido de 31 unos, que es igual a 2 ^ 31-1.
abs (0x80000000) por lo tanto no está definido en el complemento de dos porque es demasiado grande, debido a esto la máquina simplemente se da por vencida y te da 0x80000000 de nuevo. Típicamente al menos.
Para un tipo de datos de 32 bits no hay expresión de + 2 ^ 31, porque el mayor número es 2 ^ 31-1 ... lea más sobre el complemento de los dos ...
porque usa la instrucción neg para realizar esta operación.
En el libro de programación del lenguaje del Arte de la Asamblea, dijeron así.
Si el operando es cero, su signo no cambia, aunque esto borra la bandera de acarreo. Negar cualquier otro valor establece el indicador de llevar. Negar un byte que contenga -128, una palabra que contenga -32,768 o una palabra doble que contenga -2,147,483,648 no cambie el operando, pero establecerá el indicador de desbordamiento. Neg siempre actualiza los indicadores A, S, P y Z como si estuvieras usando la instrucción secundaria
fuente: http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-313 Así configurará el indicador de desbordamiento y lo silenciará. Esa es la razón .
Obviamente, matemáticamente, | -2 31 | es 2 31 . Si tenemos 32 bits para representar enteros, podemos representar como máximo 2 32 números. Si queremos una representación simétrica de 0, tenemos que tomar algunas decisiones.
Para lo siguiente, como en su pregunta, estoy asumiendo números amplios de 32 bits. Se debe usar al menos un patrón de bits para 0. Entonces eso nos deja con 2 patrones de 32 -1 o menos bits para el resto de los números. Este número es impar, por lo que podemos tener una representación que no sea exactamente simétrica sobre cero, o tener un número representado con dos representaciones diferentes.
- Si usamos la representación de magnitud de signo , el bit más significativo representa el signo de un número, y el resto de los bits representa la magnitud del número. En este esquema,
0x80000000
es "cero negativo" (es decir, cero) y0x00000000
es "cero positivo" o cero normal. En este esquema, el número más positivo es0x7fffffff
(2147483647) y el número más negativo es0xffffffff
(-2147483647). Este esquema tiene la ventaja de que es fácil para nosotros "decodificar", y que es simétrico. Este esquema tiene la desventaja de que el cálculo dea + b
cuandoa
yb
son de signos diferentes es un caso especial, y debe tratarse especialmente. - Si usamos la representación de complemento de uno , el bit más significativo aún representa el signo. Los números positivos tienen ese bit como 0, y el resto de los bits componen la magnitud del número. Para los números negativos, simplemente invierte los bits de la representación del número positivo correspondiente (toma un complemento con una serie larga de unos, de ahí el complemento de los nombres). En este esquema, el número positivo máximo sigue siendo
0x7fffffff
(2147483647), y el número negativo máximo es0x80000000
(-2147483647). De nuevo hay dos representaciones de 0: el cero positivo es0x00000000
y el cero negativo es0xffffffff
. Este esquema también tiene problemas con los cálculos que involucran números negativos. - Si usamos un esquema de complemento de dos , los números negativos se obtienen tomando la representación de complemento de uno y agregando
1
a ella. En este esquema, solo hay un 0, es decir,0x00000000
. El número más positivo es0x7fffffff
(2147483647) y el número más negativo es0x80000000
(-2147483648). Hay una asimetría en esta representación. La ventaja de este esquema es que uno no tiene que lidiar con casos especiales para el número negativo. La representación se ocupa de darle la respuesta correcta siempre que el resultado no se desborde. Por esta razón, la mayor parte del hardware actual representa enteros en esta representación.
En la representación de complemento de dos, no hay forma de representar 2 31 . De hecho, si nos fijamos en los limits.h
su compilador o en un archivo equivalente, es posible que vea una definición de INT_MIN
de la siguiente manera:
#define INT_MIN (-2147483647 - 1)
Esto hecho en lugar de
#define INT_MIN -2147483648
porque 2147483648 es demasiado grande para caber en una int
en una representación de complemento de dos de 32 bits. En el momento en que el operador unario negativo "obtiene" el número para operar, ya es demasiado tarde: el desbordamiento ya se ha producido y no puede solucionarlo.
Por lo tanto, para responder a su pregunta original, el valor absoluto del número más negativo en una representación complementaria de dos no puede representarse en esa codificación. Además, de lo anterior, para pasar de un valor negativo a un valor positivo en la representación de complemento de dos, usted toma su complemento y luego agrega 1. Entonces, para 0x80000000
:
1000 0000 0000 0000 0000 0000 0000 0000 original number
0111 1111 1111 1111 1111 1111 1111 1111 ones'' complement
1000 0000 0000 0000 0000 0000 0000 0000 + 1
recuperas el número original.