Cómo funciona el complemento a dos
Los ordenadores no tienen signo menos, solo bits. El complemento a dos es la convención que usa casi toda CPU para guardar enteros negativos: el bit superior (el bit de signo) cuenta como 2ⁿ⁻¹ negativo en lugar de positivo. En 8 bits, el bit superior vale −128, así que 1111 1111 = −128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = −1, y 1000 0000 es −128.
Los mismos bits leídos sin signo son 255 y 128. Que un valor sea «realmente» negativo lo decide el tipo en tu código (int8_t frente a uint8_t), no los bits. Por eso esta herramienta muestra siempre ambas lecturas.
Negar un número a mano
- Escribe el valor positivo en binario con la anchura completa (42 =
0010 1010). - Invierte cada bit (
1101 0101). - Suma 1 (
1101 0110). Eso es −42, es decir, 0xD6 o 214 sin signo.
El truco funciona en ambos sentidos: aplicado a −42 devuelve 42. La herramienta de arriba muestra estos pasos para cualquier entrada.
Por qué está diseñado así
Con el complemento a dos, el hardware no necesita un restador aparte. Sumar un número negativo es una suma binaria normal en la que se descarta el acarreo del bit superior: 42 + (−42) = 0010 1010 + 1101 0110 = 1 0000 0000, se descarta el noveno bit, resultado 0. Además solo hay un cero, a diferencia del signo-magnitud o el complemento a uno.
Rangos de valores
| Anchura | Con signo | Sin signo | Tipo típico |
|---|---|---|---|
| 8 | −128 … 127 | 0 … 255 | int8_t, byte |
| 16 | −32.768 … 32.767 | 0 … 65.535 | int16_t, short |
| 32 | −2.147.483.648 … 2.147.483.647 | 0 … 4.294.967.295 | int32_t, int |
| 64 | −9,22 × 10¹⁸ … 9,22 × 10¹⁸ | 0 … 1,84 × 10¹⁹ | int64_t, long |
El rango negativo es uno mayor que el positivo porque el cero ocupa uno de los patrones «positivos». Por eso -INT_MIN desborda: 128 no cabe en un byte con signo.
Preguntas
¿Cuánto es −1 en complemento a dos?
Todo unos: 0xFF en 8 bits, 0xFFFF en 16, 0xFFFFFFFF en 32. Invertir 0000 0001 da 1111 1110, y sumar 1 da 1111 1111.
¿Cómo sé si un número binario es negativo?
Por el bit más a la izquierda en la anchura declarada. Si es 1 y el valor tiene signo, el número es negativo. 1000 0000 es −128 como int8 pero 128 como uint8; los bits por sí solos no lo deciden.
¿Por qué 127 + 1 da −128?
Desbordamiento con signo. 0111 1111 + 1 = 1000 0000, lo que activa el bit de signo. En C es comportamiento indefinido; en la mayoría de los otros lenguajes el valor da la vuelta a −128.
¿Qué es la extensión de signo?
Ensanchar un valor con signo copiando el bit de signo en los nuevos bits superiores, de modo que −1 (0xFF) se convierte en 0xFFFF, no en 0x00FF. Un cast de int8 a int16 lo hace automáticamente; un cast de un valor sin signo rellena con ceros. Cambia la anchura arriba con un número negativo escrito para verlo.
¿El bit de signo es solo una bandera?
No. En complemento a dos el bit de signo tiene un valor (−2ⁿ⁻¹) y participa en la aritmética. Eso lo distingue del signo-magnitud, donde el bit superior solo marca el signo, y de la coma flotante, donde el signo es una bandera aparte.