- Los ordenadores operan internamente con números binarios, usando reglas muy simples de suma, resta, multiplicación y división, basadas solo en los dígitos 0 y 1.
- El complemento a uno y especialmente el complemento a dos permiten representar números negativos y convertir restas en sumas, simplificando el diseño de la ALU.
- Las operaciones lógicas bit a bit (AND, OR, NOT, NAND, NOR, XOR, XNOR) manipulan directamente los bits y son esenciales para máscaras, comparaciones y control de hardware.
- Comprender estas operaciones binaras ayuda a entender cómo trabaja la unidad aritmético-lógica de la CPU cuando ejecuta cualquier instrucción de un programa.
Si te paras a pensarlo, un ordenador no deja de ser una calculadora brutalmente rápida que solo entiende ceros y unos. Con esa base tan simple, es capaz de dibujar en pantalla, reproducir música, ejecutar videojuegos o manejar una red completa. Todo eso se apoya en un puñado de reglas muy claras: las operaciones aritméticas y lógicas en binario.
En las próximas líneas vas a ver, con calma y con muchos ejemplos paso a paso, cómo se realizan sumas, restas, multiplicaciones, divisiones y operaciones lógicas bit a bit en binario, además de cómo se representan números negativos usando complementos a uno y a dos. La idea es que, al terminar, entiendas qué hace realmente una ALU (Unidad Aritmético-Lógica) por dentro cuando la CPU ejecuta instrucciones como ADD, SUB, AND o XOR.
Por qué los ordenadores usan binario y cómo convertir entre decimal y binario
La electrónica digital trabaja con dos niveles de tensión bien diferenciados que se interpretan como 0 y 1; eso encaja como un guante con el sistema de numeración binario (base 2). Nosotros, en cambio, estamos acostumbrados al sistema decimal (base 10), así que lo primero es saber pasar de uno a otro.
- 13 ÷ 2 = 6, resto 1
- 6 ÷ 2 = 3, resto 0
- 3 ÷ 2 = 1, resto 1
- 1 ÷ 2 = 0, resto 1
Los restos se leen de abajo arriba: 1310 = 11012. En otras palabras, donde en decimal contarías 0, 1, 2, …, 12, 13, en binario la secuencia equivalente sería 0, 1, 10, 11, 100, 101, 110, 111, 1000, …, 1101.
Para hacer la conversión inversa (de binario a decimal) se descompone el número como suma de potencias de 2 ponderadas por cada bit. Tomando de nuevo 11012:
- 1 · 23 = 8
- 1 · 22 = 4
- 0 · 21 = 0
- 1 · 20 = 1
Sumando: 8 + 4 + 0 + 1 = 13, así que 11012 representa el mismo valor que 1310. Esta forma de ver los bits como potencias de dos es clave para entender todo lo que viene después.
Operaciones aritméticas básicas en binario
La ALU de la CPU se encarga de realizar operaciones aritméticas con números codificados en binario: suma, resta, multiplicación y división. Las reglas básicas son muy sencillas porque únicamente hay dos cifras posibles: 0 y 1.
La suma y la resta funcionan de forma análoga a las que haces en decimal en papel, solo que los “llevamos” y “prestamos” se hacen en base 2. Por su parte, la multiplicación y la división se pueden ver como sumas y restas repetidas, aunque el hardware las optimiza mucho más.
Suma binaria: reglas, tabla y ejemplos
Para sumar en decimal de memoria necesitas muchas combinaciones (0+0, 0+1, …, 9+9). En binario, en cambio, solo hay cuatro casos posibles de suma de un bit más otro, lo que simplifica muchísimo las cosas y hace que la tabla de sumar binaria sea extremadamente corta:
- 0 + 0 = 0
- 0 + 1 = 1
- 1 + 0 = 1
- 1 + 1 = 10 (es decir, 0 y se arrastra 1 a la siguiente posición)
Ese último caso es el único un poco especial: cuando sumas 1 + 1 en binario obtienes 10, que en decimal es 2. Escribes el 0 y te llevas 1 a la columna siguiente, exactamente igual que cuando 9 + 1 = 10 en decimal y escribes 0 y te llevas 1.
Veamos un ejemplo con arrastres intermedios:
0102 + 1012
Se alinean las cifras y se suma de derecha a izquierda:
- 0 + 1 = 1 (sin llevar)
- 1 + 0 = 1 (sin llevar)
- 0 + 1 = 1 (sin llevar)
El resultado es 1112, que corresponde a 210 + 510 = 710.
Con otro ejemplo algo más largo, 0011012 + 1001012:
- 1 + 1 = 10 → se escribe 0 y se lleva 1
- 0 + 0 + 1 (arrastre) = 1
- 1 + 1 = 10 → 0 y se lleva 1
- 1 + 0 + 1 (arrastre) = 10 → 0 y se lleva 1
- 0 + 0 + 1 (arrastre) = 1
- 0 + 1 = 1
El resultado final es 1100102, que equivale a 1310 + 3710 = 5010. El procedimiento es siempre el mismo, solo hay que ser cuidadoso con los “me llevo 1”.
Resta binaria directa y uso del préstamo
- 0 − 0 = 0
- 1 − 0 = 1
- 1 − 1 = 0
- 0 − 1: no se puede, así que se toma prestado 1 de la siguiente posición
Cuando se presenta 0 − 1, se pide prestado 1 de la columna de la izquierda. Ese 1 prestado vale 2 en binario (102), así que realmente lo que haces es 10 − 1 = 1 y marcas que le debes 1 a la columna siguiente, que se reducirá en 1.
Ejemplo: 1112 − 1012 (710 − 510):
- Columna de la derecha: 1 − 1 = 0
- Columna central: 1 − 0 = 1
- Columna izquierda: 1 − 1 = 0
La diferencia es 0102, es decir, 2 en decimal. Nada raro hasta aquí.
Otro caso algo más entretenido: 100012 − 010102 (1710 − 1010):
- 1 − 0 = 1 (columna menos significativa)
- 0 − 1 → hay que pedir prestado de la siguiente columna, que es 0, por lo que la cadena de préstamos se propaga hacia la izquierda hasta encontrar un 1
- El 1 más a la izquierda se convierte en 0, la columna inmediata pasa a ser 2 (102), presta 1 a la siguiente, etc.
Realizando el proceso con cuidado se obtiene 001112, lo que corresponde a 710. Cuando las restas se alargan, la gestión de los préstamos se vuelve propensa a errores… y aquí es donde entran en juego los complementos a uno y dos para simplificar la operación.
Complemento a dos: representar negativos y simplificar restas
El complemento a dos es la codificación estándar en casi cualquier procesador moderno para representar números negativos en binario. Además, permite transformar una resta en una suma, que resulta mucho más sencilla de implementar en hardware.
Formalmente, el complemento a dos de un número N de n bits se puede definir como C2N = 2n − N. Es decir, se toma la potencia de dos inmediatamente superior al rango del número (con el mismo ancho en bits) y se resta el valor.
Por ejemplo, sea N = 1011012 (6 bits), que en decimal es 45. Con n = 6, se tiene 26 = 64, así que:
C2N = 64 − 45 = 19 = 0100112
En la práctica, sin embargo, no hace falta irse a las potencias de dos. Se utiliza una regla operativa mucho más simple basada en el complemento a uno, como verás enseguida, y que permite calcular el complemento a dos “a ojo” casi sin pensar.
Complemento a uno: invertir bits y relación con el complemento a dos
El complemento a uno de un número binario N con n bits se define como una unidad menos que su complemento a dos, es decir:
C1N = C2N − 1 y C2N = C1N + 1
La definición matemática está bien, pero en la práctica hay un truco mucho más cómodo: el complemento a uno se calcula simplemente invirtiendo cada bit, cambiando todos los 0 por 1 y todos los 1 por 0.
Por ejemplo, si N = 1101001012:
- Su complemento a uno es C1N = 0010110102 (todos los bits invertidos)
- Para obtener el complemento a dos solo hay que sumar 1: C2N = 0010110102 + 12 = 0010110112
Con otro ejemplo, N = 01101101012:
- C1N = 10010010102
- C2N = 10010010102 + 12 = 10010010112
Así que, en resumen, para obtener el complemento a dos de un número basta con invertir todos los bits (complemento a uno) y sumar 1 al resultado. Esta operación tan sencilla está cableada en la mayoría de ALUs.
Restar en binario usando el complemento a dos
La gran ventaja del complemento a dos es que permite realizar restas como si fueran sumas. En lugar de hacer “minuendo − sustraendo” directamente, se calcula el complemento a dos del sustraendo y se suma al minuendo. El bit de desborde que pueda aparecer se descarta.
Imagina que quieres realizar 91 − 46 = 45, pero todo en binario. Con números ya pasados a binario y del mismo ancho:
- 9110 = 10110112
- 4610 = 01011102 (mismo número de bits)
Si hicieras la resta directa, aparecerían varios préstamos encadenados. Sin embargo, usando complemento a dos:
- Calculas C2(46), sumando el complemento a uno de 0101110 y luego 1
- Sumas 10110112 + C2(0101110)
El resultado de la suma generará un bit adicional por la izquierda (desbordamiento) que simplemente se ignora, quedando como valor correcto 01011012, que es 4510. A la ALU esto le viene genial porque puede reutilizar el mismo circuito de suma tanto para sumar como para restar.
Otro ejemplo interesante: 219 − 23 = 196. En binario y con 8 bits:
- 21910 = 110110112
- 2310 = 000101112
- Complemento a dos de 23: C223 = 111010012
Se realiza la suma: 110110112 + 111010012 = 1 110001002. El bit más a la izquierda se descarta, dejando 110001002, que equivale a 19610. Todo el lío de los préstamos desaparece y la operación es lineal.
Multiplicación binaria paso a paso
En binario, multiplicar es más agradecido que en decimal, porque las tablas de multiplicar se reducen a cuatro combinaciones muy simples:
- 0 × 0 = 0
- 0 × 1 = 0
- 1 × 0 = 0
- 1 × 1 = 1
Cada “fila” parcial de la multiplicación se obtiene multiplicando el multiplicando por un solo bit del multiplicador, de derecha a izquierda, desplazando una posición hacia la izquierda cada vez que avanzas una columna (igual que al multiplicar 123 × 45 en papel, donde desplazas al escribir la fila de las decenas).
Por ejemplo, multiplica 1012 (510) por 112 (310):
1012
× 112
──────
- Primera fila: 101 × 1 = 101 (sin desplazamiento)
- Segunda fila: 101 × 1 = 101, pero desplazado una posición a la izquierda: 1010
Se suman las filas parciales: 1012 + 10102 = 11112. Esto equivale a 1510, que es exactamente 5 × 3.
En hardware, la multiplicación se puede implementar como un proceso de sumas repetidas con arrastres, aunque las ALUs modernas usan multiplicadores más sofisticados. Aun así, la idea fundamental sigue siendo: cada 1 del multiplicador “activa” una copia desplazada del multiplicando, que luego se suman entre sí.
División binaria: similar a la división larga en decimal
La división en binario sigue el mismo patrón que la división larga que aprendiste en el cole, solo que aquí el cociente únicamente puede contener 0 o 1. El proceso se basa en ir restando el divisor del dividendo parcial mientras sea posible, anotando un 1 cada vez que “cabe” y un 0 cuando no.
Pongamos como ejemplo 10112 ÷ 102, que corresponde a 11 ÷ 2 en decimal. Sabemos que el resultado debe ser 5 con resto 1.
- Tomamos los dos primeros bits del dividendo: 10, y el divisor: 10. Como 10 ≥ 10, cabe una vez, así que la primera cifra del cociente es 1.
- Restamos: 10 − 10 = 00.
- Bajamos el siguiente bit del dividendo: ahora el dividendo parcial es 01. Como 01 < 10, aquí el cociente lleva un 0.
- Bajamos el último bit: tenemos 11. Ahora 11 ≥ 10, así que colocamos un 1 en el cociente y restamos: 11 − 10 = 1.
El cociente queda 1012 y el resto 12, lo que en decimal es 5 con resto 1, como se esperaba. El procedimiento general para una división larga binaria más grande es exactamente el mismo, solo que con más columnas y restas sucesivas.
Operaciones lógicas binarias bit a bit
Además de sumar, restar y demás, los procesadores utilizan constantemente operaciones lógicas sobre bits individuales. Estas operaciones (AND, OR, NOT, XOR, etc.) se aplican bit a bit (bitwise) entre dos operandos o sobre uno solo, y se basan en la lógica booleana donde 0 equivale a falso y 1 a verdadero.
Si tomamos como ejemplo A = 1010 y B = 1100 como dos números binarios de 4 bits:
- A = 1010
- B = 1100
Podemos explorar cómo se comporta cada operación lógica con ellos. Cada bit de la salida depende únicamente de los bits de entrada en la misma posición, lo que hace que estas operaciones sean ideales para enmascarar, combinar o invertir conjuntos de bits.
Operación AND (Y lógico)
La operación AND (Y) devuelve 1 únicamente cuando ambos bits de entrada son 1. En cualquier otra combinación (0 y 0, 0 y 1, 1 y 0) la salida es 0. La tabla de verdad de AND es la siguiente:
- 0 AND 0 = 0
- 0 AND 1 = 0
- 1 AND 0 = 0
- 1 AND 1 = 1
Si aplicamos AND bit a bit a A = 1010 y B = 1100:
- Bit 1 (más a la izquierda): 1 AND 1 = 1
- Bit 2: 0 AND 1 = 0
- Bit 3: 1 AND 0 = 0
- Bit 4: 0 AND 0 = 0
El resultado es 10002. Dicho de otro modo, solo permanecen a 1 los bits que eran 1 en ambos operandos. Esto se usa, por ejemplo, para filtrar bits mediante máscaras.
Operación OR (O lógico inclusivo)
La operación OR (O inclusivo) produce un 1 en la salida si al menos uno de los dos bits de entrada vale 1. Únicamente cuando los dos son 0, la salida es 0. La tabla de verdad se resume así:
- 0 OR 0 = 0
- 0 OR 1 = 1
- 1 OR 0 = 1
- 1 OR 1 = 1
Con A = 1010 y B = 1100:
- Bit 1: 1 OR 1 = 1
- Bit 2: 0 OR 1 = 1
- Bit 3: 1 OR 0 = 1
- Bit 4: 0 OR 0 = 0
El resultado con OR es 11102. Suele emplearse para activar determinados bits sin alterar los que ya están a 1 (por ejemplo, para encender flags o LEDs en paralelo).
Operación NOT (negación lógica)
La operación NOT (negación) se aplica a un único operando y simplemente invierte cada bit: los 0 pasan a 1 y los 1 pasan a 0. Es exactamente lo mismo que calcular el complemento a uno del número.
Si partimos de A = 1010:
- NOT 1 = 0
- NOT 0 = 1
- NOT 1 = 0
- NOT 0 = 1
NOT 1010 = 0101. Esta operación se usa mucho para invertir máscaras, negar condiciones o calcular complementos a uno como parte de otras transformaciones.
Otras operaciones lógicas: NAND, NOR, XOR y XNOR
Además de AND, OR y NOT, en lógica digital aparecen combinaciones derivadas como NAND, NOR, XOR y XNOR, que también tienen un papel importante tanto en hardware (puertas lógicas físicas) como en software (operaciones bit a bit).
La puerta NAND (NOT AND) devuelve 0 solo cuando ambos bits son 1; en todos los demás casos la salida es 1. Dicho de otra manera, primero se aplica una AND y luego se niega el resultado con NOT:
- NAND(A, B) = NOT(AND(A, B))
Si AND(1010, 1100) = 1000, entonces NAND(1010, 1100) = NOT(1000) = 0111. Esta operación se utiliza mucho porque, desde el punto de vista de diseño de circuitos, solo con puertas NAND se puede construir cualquier otra operación lógica.
La puerta NOR (NOT OR) es la negación de OR. La salida es 1 únicamente cuando ambos bits de entrada son 0; en cualquier otro caso la salida es 0. Formalmente:
- NOR(A, B) = NOT(OR(A, B))
Con OR(1010, 1100) = 1110, se obtiene NOR(1010, 1100) = NOT(1110) = 0001. NOR también es funcionalmente completa, igual que NAND, y con solo puertas NOR se puede construir cualquier circuito lógico combinacional.
La operación XOR (O exclusivo) da 1 cuando los bits de entrada son distintos entre sí y 0 cuando son iguales. La tabla de verdad sería:
- 0 XOR 0 = 0
- 0 XOR 1 = 1
- 1 XOR 0 = 1
- 1 XOR 1 = 0
Aplicándolo a A = 1010 y B = 1100:
- Bit 1: 1 XOR 1 = 0
- Bit 2: 0 XOR 1 = 1
- Bit 3: 1 XOR 0 = 1
- Bit 4: 0 XOR 0 = 0
La salida es 01102. XOR se usa muchísimo para detectar diferencias entre dos patrones, hacer operaciones de paridad o incluso para ciertos esquemas de cifrado sencillos.
Por último, XNOR es la negación de XOR. Produce 1 cuando los bits de entrada son iguales y 0 cuando son distintos. Matemáticamente:
- XNOR(A, B) = NOT(XOR(A, B))
Si XOR(1010, 1100) = 0110, entonces XNOR(1010, 1100) = NOT(0110) = 1001. Es útil para comprobar igualdad bit a bit entre dos valores binarios, algo muy habitual en comparadores digitales.
Cómo se usan estas operaciones en una CPU real
En un procesador comercial, todas estas operaciones se integran en la ALU (Unidad Aritmético-Lógica), que recibe instrucciones del conjunto de instrucciones (ISA) como ADD, SUB, MUL, DIV, AND, OR, XOR o NOT. Cada una de esas instrucciones realiza la operación aritmética o lógica correspondiente sobre los registros de la CPU.
Por ejemplo, una suma básica en ensamblador podría verse así (en pseudocódigo estilo x86):
MOV AX, 101B ; Carga 5 en binario en AX ADD AX, 11B ; Suma 3 en binario; AX pasa a contener 8
A nivel de hardware, la ALU está aplicando la tabla de la suma binaria que has visto antes, propagando los arrastres entre bits. Esa misma estructura, con pequeñas variaciones, sirve para implementar la resta mediante complemento a dos.
Algo similar ocurre con la resta, fundamental en contadores o temporizadores:
MOV AX, 1010B ; Carga 10 en binario SUB AX, 1B ; Resta 1; AX pasa a 1001B (9 decimal)
La multiplicación entera suele delegarse en una instrucción específica (MUL), que internamente puede usar sumas repetidas y hardware especializado:
MOV AX, 10B ; AX = 2 en binario MOV BX, 11B ; BX = 3 en binario MUL BX ; AX = AX × BX = 110B (6 decimal)
La división, por su parte, aplica un algoritmo de restas sucesivas más avanzado, pero conceptualmente se basa en lo mismo que la división larga que hemos visto en binario:
MOV AX, 1010B ; AX = 10 en binario MOV BX, 10B ; BX = 2 en binario DIV BX ; Cociente = 5, resto = 0
Las operaciones lógicas sirven, entre otras cosas, para gestionar banderas, máscaras de bits o configuraciones de hardware. Por ejemplo, NOT para invertir un conjunto de bits:
MOV AL, 1010B ; AL = 1010 NOT AL ; AL = 0101 tras la inversión bit a bit
O AND para “apagar” ciertos bits y quedarte solo con los que te interesan (enmascarado):
MOV AL, 1010B ; Valor original AND AL, 1100B ; Filtra; resultado: 1000B
Con OR se pueden activar bits concretos sin tocar el resto:
MOV AL, 1010B ; Valor base OR AL, 1100B ; Activa bits; resultado: 1110B
Y con XOR puedes detectar diferencias o incluso alternar bits (muy usado, por ejemplo, para hacer “toggles”):
MOV AL, 1010B ; Patrón A XOR AL, 1100B ; A XOR B = 0110B
Visto todo junto, se entiende mejor que, detrás de un videojuego o de un navegador web, lo que ocurre a nivel más bajo es una avalancha de sumas, restas, multiplicaciones, divisiones y operaciones lógicas en binario encadenadas miles de millones de veces por segundo. Aunque por fuera solo veas iconos, ventanas y gráficos, por dentro todo se reduce a bits entrando y saliendo de la ALU siguiendo estas reglas tan sencillas.
Dominar estas operaciones aritméticas y lógicas en binario, junto con los conceptos de complemento a uno y a dos, no solo te ayuda a aprobar exámenes de sistemas digitales o arquitectura de computadores, sino que te da una visión clara de cómo piensa realmente una CPU cuando ejecuta cualquier programa, desde el más simple hasta el más complejo.
