01 · Punto de partida
5 + 3, columna por columna
Sumar 0101 + 0011 es repetir cuatro veces el sumador completo del Tema 23. La columna 0 da 1 + 1 = 10: escribe 0 y lleva 1. Ese 1 entra a la columna 1 (0 + 1 + 1 = 10), vuelve a llevar, y así hasta la columna 3, que recibe un 1 de entrada y escribe 1. Resultado: 1000 = 8.
Una escena típica. Armás una calculadora de 4 bits con cuatro sumadores completos. 5 + 3 sale bien. 15 + 1 da 0000 y un acarreo extra. 7 + 1 da 1000, que si lo leés como número con signo es −8. ¿Está mal el circuito? No: el circuito suma bien siempre. Lo que cambia es cómo se interpreta el resultado, y por eso un sumador de verdad viene con banderas que avisan cuándo el número no entró.
Encadenar el Cout de cada columna con el Cin de la siguiente se llama ripple-carry (acarreo en onda). Es la forma más simple de sumar números de cualquier ancho, y la base de la que parten todas las demás.
- ¿Cómo viaja el acarreo y por qué eso hace lento al sumador?
- ¿Cómo se convierte el mismo circuito en restador?
- ¿Cuándo el resultado «miente» sin signo, y cuándo con signo?
- ¿Qué son los flags N, Z, C y V de un procesador?
- ¿Cómo se calculan los acarreos en paralelo?
- ¿Cómo se agrandan los números, y cómo se suma en decimal (BCD)?
02 · Ripple-carry
El dominó de acarreos
En un sumador de N bits, la columna 0 es un medio sumador o un completo con Cin = 0. Las demás son sumadores completos, con el Cout de cada una conectado al Cin de la siguiente. La traza de 5 + 3 columna por columna:
| Bit | A | B | Cin | S | Cout |
|---|---|---|---|---|---|
| 0 | 1 | 1 | 0 | 0 | 1 |
| 1 | 0 | 1 | 1 | 0 | 1 |
| 2 | 1 | 0 | 1 | 0 | 1 |
| 3 | 0 | 0 | 1 | 1 | 0 |
Leyendo la columna S de abajo hacia arriba sale 1000 = 8, y los acarreos fueron 1, 1, 1, 0.
- Camino crítico
- El bit 3 no puede dar su resultado definitivo hasta que le llegue el acarreo del bit 2, que espera al del bit 1, que espera al del bit 0. Cada etapa agrega dos niveles de puertas (AND y OR, Tema 23): el acarreo final llega a los 1 + 2N niveles, 9 con 4 bits y 65 con 32.
- El peor caso depende de los datos
- 1111 + 0001 hace que el acarreo atraviese las cuatro etapas. En cambio 0101 + 1010 no genera ningún acarreo: todas las etapas «propagan» pero no hay nada que propagar. El circuito se diseña para el peor caso, aunque casi siempre las cadenas son cortas (Paso 2).
- Mientras viaja, las salidas oscilan
- Al cambiar un operando, las columnas altas muestran valores provisionales hasta que llega el acarreo definitivo (algo parecido a los glitches del Tema 19). Por eso la salida de un sumador se lee después de un tiempo de espera, o con un reloj.
Ripple
Simple, barato y lineal
N sumadores completos y nada más. El retardo crece en proporción a N. Para 4 u 8 bits de un montaje de taller sobra.
Anticipado
Rápido y más grande
Calcula los acarreos en paralelo con lógica adicional. Es la idea de la sección 05.
03 · Sumador-restador
Un XOR por bit y el mismo circuito resta
Del Tema 5: en complemento a dos, A − B = A + ~B + 1. Para obtener ~B hace falta invertir bits, y un XOR es un inversor controlado (Tema 10): B xor 0 = B y B xor 1 = ~B. Con una señal M se elige la operación:
| M | Operación | Cada B pasa por XOR con M | Cin de la primera columna |
|---|---|---|---|
| 0 | A + B | B queda igual | 0 |
| 1 | A − B | B se invierte (~B) | 1 (el «+1») |
La misma señal M gobierna los N XOR y entra al Cin de la primera etapa, dos usos de un solo cable. Con 4 bits son un 74HC283 (sumador de 4 bits) y un 74HC86 (cuatro XOR): dos chips para sumar y restar. Confirmá los pines en las hojas de datos.
- 5 − 3
- M = 1: B = 0011 pasa a 1100 y Cin = 1. 0101 + 1100 + 1 = 10010: la suma da 0010 = 2 y el acarreo final vale 1.
- Qué significa el Cout al restar
- En una resta sin signo, Cout = 1 quiere decir A ≥ B (no hizo falta «pedir prestado»), y Cout = 0 quiere decir A < B (hubo préstamo). Los procesadores llaman «carry» o «borrow» a lo mismo según la arquitectura, y algunas lo invierten: confirmalo en el manual de la que uses.
- Y de gratis, comparar
- Restar y mirar los flags comunica si A = B (resultado cero), si A < B o si A ≥ B. Es la base de los comparadores del próximo tema.
04 · Overflow y flags
Cuando el resultado no entra en los bits
Con N bits se representan 2N valores. Según cómo se lean, esos bits son 0 a 15 (sin signo) o −8 a 7 (con signo en complemento a dos). Un resultado puede entrar en una lectura y no en la otra, así que cada lectura tiene su propia bandera.
- Sin signo
- El resultado no entra cuando Cout = 1 en una suma (15 + 1 = 16 se «va» al quinto bit). En una resta, Cout = 0 indica que A < B.
- Con signo
- Hay overflow cuando el acarreo que entra al bit más alto es distinto del que sale de él (Cin del MSB ≠ Cout del MSB). Equivale a esta regla de signos: dos operandos del mismo signo dan un resultado de signo opuesto.
| Operación (con signo) | A + B | S | c3 | Cout | Overflow con signo | Sin signo |
|---|---|---|---|---|---|---|
| 7 + 1 | 0111 + 0001 | 1000 | 1 | 0 | SÍ (da −8) | 8: bien |
| 5 + 3 | 0101 + 0011 | 1000 | 1 | 0 | SÍ (da −8) | 8: bien |
| −8 + (−1) | 1000 + 1111 | 0111 | 0 | 1 | SÍ (da 7) | 8 + 15 = 23: se pasó |
| −1 + 1 | 1111 + 0001 | 0000 | 1 | 1 | no (da 0) | 15 + 1: se pasó |
| −3 + (−4) | 1101 + 1100 | 1001 | 1 | 1 | no (da −7) | 13 + 12: se pasó |
| 3 + 4 | 0011 + 0100 | 0111 | 0 | 0 | no (da 7) | 7: bien |
Fijate en 5 + 3: sin signo es perfectamente correcto (8 entra en 4 bits), pero con signo 5 + 3 = 8 no entra en el rango −8 a 7. El mismo resultado 1000 es «correcto» o «mentira» según la lectura. Y en −1 + 1 el Cout vale 1 sin que haya ningún problema con signo.
Los cuatro flags de un procesador
| Flag | Nombre | Se calcula como | Sirve para |
|---|---|---|---|
| N | Negative | El bit más alto del resultado | Signo del resultado (con signo) |
| Z | Zero | 1 si el resultado es 0000 | Igualdad: A − B = 0 significa A = B |
| C | Carry | El Cout del bit más alto | Desborde sin signo; comparaciones sin signo |
| V | oVerflow | c3 xor Cout | Desborde con signo |
Con estos cuatro bits se resuelven todas las comparaciones: tras A − B, A < B sin signo es C = 0 (préstamo), A < B con signo es N ≠ V, y A = B es Z = 1. Los saltos condicionales de un procesador son combinaciones de estas banderas.
05 · Acarreo anticipado
Calcular los acarreos en paralelo
El cuello de botella del ripple es que cada acarreo espera al anterior. Pero con P = A⊕B y G = A·B de cada columna (Tema 23), todos los acarreos se pueden escribir directamente en función de las entradas, sin esperar a nadie:
| Acarreo | Ecuación |
|---|---|
| c1 | G0 + P0·c0 |
| c2 | G1 + P1·G0 + P1·P0·c0 |
| c3 | G2 + P2·G1 + P2·P1·G0 + P2·P1·P0·c0 |
| c4 | G3 + P3·G2 + P3·P2·G1 + P3·P2·P1·G0 + P3·P2·P1·P0·c0 |
Cada término se lee así: «la columna j generó un acarreo y todas las de arriba lo propagaron». Una vez que se tienen los acarreos, cada suma es un XOR: Si = Pi ⊕ ci.
- La ganancia
- En el modelo ideal, P y G salen en 1 nivel, cada acarreo en 2 más (AND y OR) y la suma en uno más: el acarreo a los 3 niveles y la suma a los 4, sin importar el ancho. El ripple pasa de 9 niveles con 4 bits a 65 con 32.
- El precio
- El último acarreo con N bits necesita un AND de N + 1 entradas y un OR de N + 1 términos. Esas puertas no existen en un chip real: se limitan a pocas entradas. Por eso el acarreo anticipado se usa en bloques de 4 bits, y los bloques se encadenan o se combinan con un segundo nivel de anticipación.
- Qué hay en los chips
- Los sumadores MSI de 4 bits como el 74HC283 traen acarreo anticipado internamente (confirmalo en la hoja de datos), de modo que sumar 4 bits es rápido; al encadenar dos chips para 8 bits, el acarreo vuelve a «viajar» entre ellos. También existen chips generadores de acarreo anticipado para combinar bloques.
06 · Más ancho
Encadenar chips, extender el signo y sumar en decimal
- Encadenar chips
- Para 8 bits se usan dos sumadores de 4: el C4 (acarreo de salida) del primero va al C0 (acarreo de entrada) del segundo. El primero se ocupa de los bits bajos y el segundo de los altos. En un sumador-restador, M va al C0 del primero y a todos los XOR.
- Extender el signo
- Para sumar sin overflow números de 4 bits con signo, se pasan a 8 bits copiando el bit de signo hacia la izquierda: 0011 pasa a 00000011 y 1101 (−3) pasa a 11111101. El valor no cambia y el rango ya alcanza para cualquier suma. Con 7 + 1 en 8 bits da 00001000 = 8, correcto (Paso 6).
- Saturación
- Algunos sistemas (audio, imágenes) no quieren que 7 + 1 «dé la vuelta» a −8: prefieren quedarse en 7. Es la aritmética saturada: si hay overflow, el resultado se reemplaza por el máximo o el mínimo del rango.
- BCD: la suma decimal
- Un sumador binario no suma bien dígitos decimales codificados (BCD, Tema 5). Si el resultado de un dígito pasa de 9, hay que sumar 6 para saltearse los códigos 1010 a 1111 que no existen en BCD, y generar el acarreo decimal. La condición es «Cout = 1 o S > 9».
| Suma | Binario (S, Cout) | ¿Corrige? | Con +6 | Resultado BCD |
|---|---|---|---|---|
| 5 + 4 | 1001, 0 | no (9) | — | 0 | 9 = 9 |
| 7 + 5 | 1100, 0 | sí (12 > 9) | 1100 + 0110 = 10010 | 1 | 0010 = 12 |
| 9 + 9 | 0010, 1 | sí (Cout = 1) | 0010 + 0110 = 1000 | 1 | 1000 = 18 |
Para varios dígitos, cada dígito pasa por su sumador y su corrección, y el acarreo decimal pasa al dígito siguiente (Paso 5: 47 + 38 = 85).
07 · Simulador
Laboratorio: sumador-restador de 4 bits
El simulador dibuja los cuatro sumadores completos con el bit más alto a la izquierda y el acarreo viajando hacia allí. Con dos deslizadores elegís A y B (0 a 15), con los botones elegís sumar o restar (señal M), y con «Animar acarreo» ves cómo el resultado se va resolviendo etapa por etapa, de derecha a izquierda.
- Cables de acarreo: verde = 1, gris = 0, naranja = los dos acarreos del bit más alto cuando hay overflow con signo (son distintos).
- Cuadros: cada uno muestra los bits que entran a esa columna (con B ya invertido si se resta) y su bit de suma S. Durante la animación, las etapas sin resolver muestran «?».
- Resultados: S en binario y en las dos lecturas, el Cout con su significado, los acarreos y el overflow con signo.
Sumador-restador de 4 bits
5 + 3 = 1000 (8)
5 + 3: S = 1000.
Recorrido guiado (10 minutos)
- 1Mirá el estado inicial: 5 + 3.
S = 1000 = 8 sin signo (correcto) y Cout = 0. Pero con signo el overflow marca SÍ: 8 no entra en −8 a 7, y los dos acarreos del bit más alto (1 y 0) son distintos, en naranja.
- 2Apretá «Animar acarreo».
Las etapas se resuelven de derecha a izquierda: la columna 3 muestra «?» hasta que llega el acarreo de la 2. Es el camino crítico del ripple.
- 3Poné A = 15, B = 1 en suma.
S = 0000 y los cuatro acarreos valen 1: el peor caso, que atraviesa todo el circuito. Sin signo se desbordó (Cout = 1); con signo es −1 + 1 = 0, y no hay overflow porque los acarreos de la columna 3 son iguales (1 y 1).
- 4Pasá a «Resta» con A = 5, B = 3.
B se invierte a 1100 y Cin = 1. S = 0010 = 2 y Cout = 1: A ≥ B, sin préstamo. Sin overflow con signo.
- 5Con resta, poné A = 3, B = 9.
S = 1010 y Cout = 0: hubo préstamo (3 < 9). Pero ojo con la otra lectura: 9 = 1001 es −7 en complemento a dos, y 3 − (−7) = 10 no entra: overflow con signo SÍ.
- 6Con resta, poné A = 8, B = 1.
Con signo es −8 − 1 = −9: no entra. S = 0111 (que sería 7), Cout = 1 y overflow SÍ. Sin signo, 8 − 1 = 7 es correcto.
- 7Con resta, poné A = 9, B = 9.
S = 0000 y Cout = 1: A ≥ B (y el resultado cero, Z = 1, indica igualdad). Así se prueba la igualdad con un sumador.
- 8Probá una suma sin conflicto: A = 3, B = 4.
S = 0111 = 7, Cout = 0 y overflow NO. Es el caso feliz: entra en las dos lecturas.
- 9Recorré varios casos y mirá la última línea de estado.
Siempre compara la regla c3 ≠ Cout con la definición «el valor con signo no entra en −8 a 7». Debe coincidir en los 256 pares y en las dos operaciones.
- 10Probá la resta con A < B (por ejemplo 2 − 5).
S = 1101 (13 sin signo, −3 con signo), Cout = 0 (préstamo). El mismo patrón de bits es el −3 correcto con signo: la resta funciona sin ningún circuito especial.
Preguntas para pensar
- Con A = 7, B = 1 en suma, ¿qué dan S, Cout y overflow? ¿Por qué «miente» con signo?
- Con resta, A = 5, B = 3: ¿cuánto vale Cout y qué significa?
- Con suma, A = 15, B = 1: ¿qué lectura tiene problemas, la de con signo o la de sin signo?
- ¿Cuándo da 1 el Cout al restar sin que A ≥ B?
Ver respuestas sugeridas
- S = 1000, Cout = 0, overflow SÍ. 0111 + 0001 hace que entre un acarreo al bit de signo (1) y no salga ninguno (0). Dos positivos dan un «negativo»: 8 no entra en −8..7. Sin signo, 8 es correcto.
- S = 0010 y Cout = 1. Al restar, Cout = 1 significa A ≥ B (sin préstamo).
- La de sin signo: 15 + 1 = 16 no entra (Cout = 1). Con signo es −1 + 1 = 0, correcto, sin overflow.
- Nunca: al restar, Cout = 1 equivale a A ≥ B. Si Cout = 0 hubo préstamo (A < B).
08 · Cascada en código
Ripple, sumador-restador con flags, acarreo anticipado, BCD y extensión de signo
Los bloques reproducen la traza columna por columna y comprueban el ripple contra la suma de enteros, miden qué tan largas son las cadenas de acarreo en datos al azar, arman el sumador-restador con los flags N Z C V (verificando la regla del overflow con las dos fórmulas y las comparaciones), implementan el acarreo anticipado y lo comparan con el ripple, suman en BCD con la corrección +6 y encadenan chips de 4 bits con extensión de signo.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
Paso 1: el ripple columna por columna
def completo(a, b, cin):
return a ^ b ^ cin, (a & b) | (a & cin) | (b & cin)
def ripple(a, b, cin=0, n=4):
s, carries = 0, []
for i in range(n):
si, cin = completo((a >> i) & 1, (b >> i) & 1, cin)
s |= si << i
carries.append(cin) # carries[i] = acarreo que sale del bit i
return s, carries
def traza(a, b, n=4):
s, car = ripple(a, b, 0, n)
print(f"{a:0{n}b} + {b:0{n}b} = {s:0{n}b} (acarreo final {car[-1]})")
print("bit A B Cin | S Cout")
for i in range(n):
cin = 0 if i == 0 else car[i - 1]
ai, bi = (a >> i) & 1, (b >> i) & 1
print(f" {i} {ai} {bi} {cin} | {(s >> i) & 1} {car[i]}")
traza(5, 3)
print()
traza(15, 1)
ok = all(ripple(a, b)[0] == (a + b) % 16 and ripple(a, b)[1][-1] == (a + b) // 16
for a in range(16) for b in range(16))
print()
print("coincide con a + b en las 256 parejas (resultado y acarreo final):", ok)
5 + 3 da 1000 con acarreos 1, 1, 1, 0 (la tabla de la sección 02). 15 + 1 da 0000 con los cuatro acarreos en 1. El ripple coincide con la suma de enteros en las 256 parejas.
Paso 2: ¿qué tan largas son las cadenas de acarreo?
import random
def cadena_max(a, b, n):
# racha más larga de etapas seguidas cuyo acarreo de salida vale 1
c, mejor, racha = 0, 0, 0
for i in range(n):
ai, bi = (a >> i) & 1, (b >> i) & 1
c = (ai & bi) | (ai & c) | (bi & c)
racha = racha + 1 if c else 0
mejor = max(mejor, racha)
return mejor
print("1111 + 0001 -> cadena de", cadena_max(15, 1, 4), "de 4 etapas")
print("0101 + 1010 -> cadena de", cadena_max(5, 10, 4), "(no genera ningún acarreo)")
print()
rnd = random.Random(7)
print("bits cadena máxima promedio")
for n in (4, 8, 16, 32):
if n <= 8:
pares = [(a, b) for a in range(2 ** n) for b in range(2 ** n)]
else:
pares = [(rnd.getrandbits(n), rnd.getrandbits(n)) for _ in range(20000)]
cs = [cadena_max(a, b, n) for a, b in pares]
print(f"{n:4d} {max(cs):13d} {sum(cs) / len(cs):8.2f}")
El peor caso es una cadena de N etapas (1111 + 0001 con 4 bits, 255 + 1 con 8: con 4 y 8 bits se prueban todas las parejas). Pero el promedio con datos al azar es muy inferior a N cuando N es grande y crece muy despacio con el ancho: casi siempre el acarreo viaja poco, aunque el circuito deba diseñarse para el peor caso.
Paso 3: sumador-restador con flags
def sumar_restar(a, b, m, n=4):
mascara = (1 << n) - 1
be = (b ^ (mascara if m else 0)) & mascara # XOR controlado por M
cin, s, car = m, 0, []
for i in range(n):
ai, bi = (a >> i) & 1, (be >> i) & 1
si = ai ^ bi ^ cin
cout = (ai & bi) | (ai & cin) | (bi & cin)
s |= si << i
car.append(cout)
cin = cout
msb = n - 1
v = car[msb - 1] ^ car[msb] # c3 xor Cout
v_signos = int(((a >> msb) & 1) == ((be >> msb) & 1) and ((s >> msb) & 1) != ((a >> msb) & 1))
return {"s": s, "C": car[msb], "V": v, "Vs": v_signos, "N": (s >> msb) & 1, "Z": int(s == 0)}
con_signo = lambda x: x - 16 if x >= 8 else x
ok = {"suma y resta": True, "C": True, "V (definición)": True, "V (signos)": True,
"igual": True, "menor sin signo": True, "menor con signo": True}
for a in range(16):
for b in range(16):
for m in (0, 1):
r = sumar_restar(a, b, m)
esperado = (a - b) if m else (a + b)
sa, sb = con_signo(a), con_signo(b)
exacto = (sa - sb) if m else (sa + sb)
ok["suma y resta"] &= r["s"] == esperado % 16
ok["C"] &= r["C"] == (int(a >= b) if m else int(a + b >= 16))
ok["V (definición)"] &= r["V"] == int(not -8 <= exacto <= 7)
ok["V (signos)"] &= r["V"] == r["Vs"]
if m:
ok["igual"] &= r["Z"] == int(a == b)
ok["menor sin signo"] &= (1 - r["C"]) == int(a < b)
ok["menor con signo"] &= (r["N"] ^ r["V"]) == int(sa < sb)
for nombre, v in ok.items():
print(f"{nombre:<18} {v}")
print()
print("operación S (con signo) N Z C V")
for a, b, m in [(7, 1, 0), (5, 3, 0), (8, 15, 0), (15, 1, 0), (5, 3, 1), (3, 9, 1), (8, 1, 1), (7, 15, 1), (9, 9, 1)]:
r = sumar_restar(a, b, m)
op = "-" if m else "+"
print(f"{con_signo(a):3d} {op} {con_signo(b):3d} {r['s']:04b} ({con_signo(r['s']):3d}) {r['N']} {r['Z']} {r['C']} {r['V']}")
Las siete comprobaciones dan True en las 512 combinaciones: el resultado, el C, el V con las dos fórmulas (c3 xor Cout y la de signos) y las tres comparaciones (igual, menor sin signo con C, menor con signo con N xor V). La tabla de ejemplos incluye 7 + 1 y 5 + 3 con V = 1, 15 + 1 con C = 1 y V = 0, y 3 − 9 con C = 0 (préstamo) y V = 1 (porque 9 = −7).
Paso 4: acarreo anticipado frente al ripple
def anticipado(a, b, c0, n=4):
p = [((a >> i) ^ (b >> i)) & 1 for i in range(n)]
g = [((a >> i) & (b >> i)) & 1 for i in range(n)]
c = [c0]
for k in range(n):
total = 0
for j in range(k + 1): # término G_j · P_(j+1) ... P_k
t = g[j]
for m in range(j + 1, k + 1):
t &= p[m]
total |= t
t = c0 # término P_0 ... P_k · c0
for m in range(k + 1):
t &= p[m]
c.append(total | t)
s = 0
for i in range(n):
s |= (p[i] ^ c[i]) << i
return s, c[n]
def ripple(a, b, c0, n=4):
t = a + b + c0
return t & ((1 << n) - 1), t >> n
ok = all(anticipado(a, b, c0) == ripple(a, b, c0) for a in range(16) for b in range(16) for c0 in (0, 1))
print("acarreo anticipado = suma real en las 512 combinaciones (4 bits):", ok)
print("también con 8 bits (muestra):",
all(anticipado(a, b, c0, 8) == ripple(a, b, c0, 8) for a in range(0, 256, 7) for b in range(0, 256, 5) for c0 in (0, 1)))
print()
print("bits ripple: niveles del acarreo anticipado: acarreo / suma entradas del AND mayor")
for n in (4, 8, 16, 32):
print(f"{n:4d} {1 + 2 * n:26d} {3:13d} / {4} {n + 1:20d}")
Las ecuaciones anticipadas reproducen la suma real. En el modelo ideal el acarreo sale a los 3 niveles y la suma a los 4 sin importar el ancho, pero el último término necesita un AND de N + 1 entradas (5 con 4 bits, 33 con 32): por eso en la práctica se agrupa de a 4 y se combinan los grupos.
Paso 5: suma BCD con corrección +6
def sumador4(a, b, cin): # el chip: suma binaria pura de 4 bits
t = a + b + cin
return t & 15, t >> 4
def bcd_digito(a, b, cin=0):
s, c = sumador4(a, b, cin)
if c or s > 9: # fuera de BCD o acarreo decimal: sumar 6
s, _ = sumador4(s, 6, 0)
return s, 1
return s, 0
ok = all(bcd_digito(a, b, c) == divmod(a + b + c, 10)[::-1]
for a in range(10) for b in range(10) for c in (0, 1))
print("suma BCD de un dígito = suma decimal (200 casos):", ok)
for a, b in ((5, 4), (7, 5), (9, 9)):
s, c = bcd_digito(a, b)
print(f"{a} + {b}: binario {sumador4(a, b, 0)[0]:04b} (Cout {sumador4(a, b, 0)[1]}) -> BCD acarreo {c}, dígito {s:04b} = {s}")
def sumar_bcd(x, y): # listas de dígitos, menos significativo primero
r, c = [], 0
for a, b in zip(x, y):
d, c = bcd_digito(a, b, c)
r.append(d)
return r, c
for x, y in ((47, 38), (99, 1)):
dx = [int(ch) for ch in reversed(f"{x:02d}")]
dy = [int(ch) for ch in reversed(f"{y:02d}")]
r, c = sumar_bcd(dx, dy)
texto = ("1" if c else "") + "".join(str(d) for d in reversed(r))
print(f"{x} + {y} = {texto}")
La corrección +6 reproduce la suma decimal en los 200 casos de un dígito. 5 + 4 no corrige, 7 + 5 (12 > 9) da acarreo 1 y dígito 2, y 9 + 9 (con Cout = 1 en binario) da acarreo 1 y dígito 8. Para dos dígitos: 47 + 38 = 85 y 99 + 1 = 100.
Paso 6: encadenar chips y extender el signo
def suma4(a, b, cin):
t = a + b + cin
return t & 15, t >> 4
def suma8(a, b, cin=0): # dos sumadores de 4 bits: C4 del bajo -> C0 del alto
bajo, c = suma4(a & 15, b & 15, cin)
alto, c = suma4(a >> 4, b >> 4, c)
return (alto << 4) | bajo, c
ok = all(suma8(a, b) == ((a + b) & 255, (a + b) >> 8) for a in range(256) for b in range(256))
print("dos sumadores de 4 bits encadenados = suma de 8 bits (65536 parejas):", ok)
def extender(x, n=4, m=8):
if (x >> (n - 1)) & 1: # bit de signo en 1: se copia hacia la izquierda
return x | (((1 << (m - n)) - 1) << n)
return x
con_signo4 = lambda x: x - 16 if x >= 8 else x
con_signo8 = lambda x: x - 256 if x >= 128 else x
print()
print("7 + 1 en 4 bits:", f"{suma4(7, 1, 0)[0]:04b}", "=", con_signo4(suma4(7, 1, 0)[0]), "(overflow)")
r8 = suma8(extender(7), extender(1))[0]
print("7 + 1 extendidos a 8 bits:", f"{r8:08b}", "=", con_signo8(r8), "(correcto)")
a8, b8 = extender(13), extender(12) # 13 = 1101 = -3, 12 = 1100 = -4
r8 = suma8(a8, b8)[0]
print(f"-3 + -4: {a8:08b} + {b8:08b} = {r8:08b} = {con_signo8(r8)}")
ok = all(con_signo8(suma8(extender(a), extender(b))[0]) == con_signo4(a) + con_signo4(b)
for a in range(16) for b in range(16))
print("con signo extendido nunca hay overflow, para los 256 pares de 4 bits:", ok)
Dos chips de 4 bits con el C4 del bajo en el C0 del alto suman 8 bits correctamente. 7 + 1 en 4 bits da −8 (overflow); extendidos a 8 bits da 8. −3 + −4 con signo extendido da 11111001 = −7.
09 · Analogía de programador
Dominó, flags y prefix sums
| En software | En el sumador en cascada |
|---|---|
Un bucle sobre los bits con una variable carry | El ripple: Cout de una etapa en el Cin de la siguiente |
| Una cadena de dependencias secuenciales (latencia O(n)) | El camino crítico del acarreo |
x - y como x + (~y) + 1 | XOR con M en cada bit de B y M en el Cin inicial |
a + b en C con int8_t: wraparound o comportamiento indefinido | Overflow con signo: el resultado miente en silencio |
(a + b) & 0xFF en Python (que no desborda) | El módulo 2N que el hardware hace solo, y el Cout que se pierde |
Flags de una CPU (ADD actualiza N Z C V) | Las salidas auxiliares del sumador-restador |
jl, jb, je tras un cmp | Combinaciones de N, Z, C y V tras la resta |
| Prefix sum (scan) paralelo | El acarreo anticipado con los operadores G y P |
Aritmética saturada (min / max) | Reemplazar el resultado cuando V = 1 |
Decimal frente a float/int | BCD con corrección +6 |
Promover un int8_t a int16_t | Extensión de signo |
- 1Ripple = dominó.
Cada ficha espera a la anterior: la latencia crece con el número de fichas. El acarreo anticipado avisa a todas a la vez, con más lógica.
- 2Resta = suma del opuesto.
Tu
intresta sumando el complemento a dos: es exactamente este circuito con un XOR por bit. - 3Flags = metadatos del cálculo.
El sumador devuelve el resultado y cuatro bits que dicen cómo leerlo. Un programa que ignora los flags es un programa que ignora el overflow.
Una diferencia con el software: Python no desborda (los enteros crecen), pero el hardware sí, y siempre. Cualquier cuenta con ancho fijo (contadores, temporizadores, direcciones) tiene que decidir qué pasa cuando el resultado no entra: envolver, saturar o avisar.
10 · Comprensión
Confusiones frecuentes
«El Cout es el overflow»
Solo sin signo. Con signo, el overflow es c3 ≠ Cout: 7 + 1 no tiene acarreo final y desborda, y −1 + 1 tiene Cout = 1 y no desborda.
«5 + 3 entra en 4 bits, no hay problema»
Depende de la lectura. Sin signo, 8 entra (rango 0..15). Con signo no, porque el rango es −8..7: el resultado 1000 se lee como −8. Antes de sumar hay que saber qué interpretación se usa.
«Restar necesita un restador»
El mismo sumador, con un XOR por bit sobre B y la señal M al Cin inicial. Con 4 bits son un 283 y un 86.
«Más bits, igual de rápido»
En un ripple, cada bit agrega dos niveles de puertas al camino del acarreo: 32 bits son unos 65 niveles frente a los 9 de 4 bits. Por eso existe el acarreo anticipado.
«Un Cout = 0 al restar es un error»
Es información: significa A < B (hubo préstamo). En una resta sin signo es el resultado normal cuando el minuendo es menor, y el patrón de bits que sale es el correcto módulo 2N.
«Un sumador binario suma bien BCD»
Solo hasta 9. Si el dígito pasa de 9 (o hay Cout), hay que sumarle 6 para saltear los códigos inexistentes y llevar el acarreo decimal.
«El acarreo anticipado es gratis»
Cuesta puertas de muchas entradas: el último acarreo de N bits necesita un AND de N + 1 entradas. Se usa en bloques pequeños y se combina por niveles.
11 · Práctica guiada
Ejercicios de cascada
Ejercicio 1: 9 + 6 a mano
Sumá 1001 + 0110 columna por columna con los acarreos. ¿Cuánto da, hay acarreo final y overflow con signo?
Ver solución razonada
Columna 0: 1 + 0 = 1; columna 1: 0 + 1 = 1; columna 2: 0 + 1 = 1; columna 3: 1 + 0 = 1. Ningún acarreo: S = 1111 = 15, Cout = 0. Con signo: 9 = −7 y 6 = 6, suman −1 = 1111 ✓, sin overflow (c3 = 0 y Cout = 0).
Ejercicio 2: 3 − 9
Calculá 0011 − 1001 como 0011 + ~1001 + 1. ¿Cuánto da, qué indica el Cout y qué dice la lectura con signo?
Ver solución razonada
~1001 = 0110, entonces 0011 + 0110 + 1 = 1010 con acarreos 1, 1, 1, 0. S = 1010, Cout = 0: sin signo hubo préstamo (3 < 9) y 1010 = 10 es −6 módulo 16. Con signo: 1001 es −7, y 3 − (−7) = 10 no entra en −8..7: c3 = 1 y Cout = 0, overflow SÍ. Ojo: es tentador leer 1010 = −6 como «la respuesta de 3 − 9», pero eso olvida que 9 no existe en 4 bits con signo.
Ejercicio 3: overflow en tres sumas
Para 6 + 3, −5 + (−4) y −6 + (−2) en 4 bits con signo, calculá S, c3 y Cout, y decidí si hay overflow.
Ver solución razonada
6 + 3: 0110 + 0011 = 1001 con c3 = 1 y Cout = 0: overflow (9 no entra). −5 + (−4): 1011 + 1100 = 0111 con c3 = 0 y Cout = 1: overflow (−9 no entra). −6 + (−2): 1010 + 1110 = 1000 con c3 = 1 y Cout = 1: sin overflow, da −8, que sí entra.
Ejercicio 4: overflow con un 283
Un sumador-restador de 8 bits usa dos 74HC283 y ocho XOR. El 283 no entrega el acarreo que entra al último bit. ¿Cómo se calcula V y cuántos chips hacen falta en total?
Ver solución razonada
Con los signos: V = (A₇ = B′₇) y (S₇ ≠ A₇), con B′ la salida de los XOR. Se arma con unas pocas puertas (un XNOR, un XOR y un AND). Chips: 2 de 74HC283, 2 de 74HC86 (ocho XOR) y uno más para la lógica de V: cinco chips con holgura.
Ejercicio 5: suma BCD de 6 + 7
Sumá los dígitos BCD 6 y 7 con el sumador binario y aplicá la corrección. ¿Cuál es el resultado en BCD?
Ver solución razonada
6 + 7 = 1101 en binario (13 > 9): hay que corregir. 1101 + 0110 = 10011: dígito 0011 = 3 y acarreo decimal 1, es decir 0001 0011 = 13.
Ejercicio 6: ripple frente a anticipado con 16 bits
Con el modelo de niveles, ¿cuántos niveles tarda el acarreo final de 16 bits en ripple y con acarreo anticipado ideal? ¿Qué entradas necesita el AND mayor y por qué no se usa así?
Ver solución razonada
Ripple: 1 + 2·16 = 33 niveles. Anticipado ideal: 3 niveles (P y G, AND, OR). El último término, P₁₅···P₀·c0, es un AND de 17 entradas, y el OR final tiene 17 términos. Las puertas reales tienen pocas entradas, así que se agrupa de a 4 bits y los grupos se combinan por niveles. Verificalo con el Paso 4.
12 · Síntesis
Ideas para recordar
- Ripple-carry: Cout de cada columna al Cin de la siguiente. El acarreo final llega a los 1 + 2N niveles: el retardo es lineal en el ancho.
- El peor caso es una cadena de N etapas (1111 + 0001); en promedio las cadenas son cortas.
- Sumador-restador: B′ = B xor M y Cin₀ = M. A − B = A + ~B + 1. Al restar sin signo, Cout = 1 significa A ≥ B.
- Sin signo el resultado no entra cuando Cout = 1 (suma). Con signo hay overflow cuando c3 ≠ Cout, o cuando dos operandos del mismo signo dan resultado de signo opuesto.
- Flags: N (signo), Z (cero), C (carry), V (overflow). Con ellos: A = B es Z, A < B sin signo es C = 0 y A < B con signo es N ≠ V.
- Acarreo anticipado: c_k en función de G, P y c0 sin esperar acarreos intermedios; acarreo a 3 niveles, pero con puertas de N + 1 entradas.
- Para agrandar: encadenar chips (C4 al C0 siguiente) y extender el signo copiando el bit más alto. BCD pide corregir con +6 si Cout o S > 9.
- El circuito es el mismo; lo que cambia es la interpretación del resultado.
¿Listo para el Tema 25?
Podés avanzar si sos capaz de responder esto sin mirar:
- Trazar 0101 + 0011 columna por columna con sus acarreos.
- Armar un sumador-restador con XOR y explicar la señal M.
- Decidir si hay overflow con signo y sin signo para una suma dada.
- Explicar qué indican N, Z, C y V, y cómo se comparan dos números con ellos.
- Escribir c2 con generate y propagate.
- Corregir la suma BCD de un dígito.
Con una resta y cuatro flags ya podés comparar números. En el próximo tema, los comparadores, ese caso especial se convierte en un circuito propio, más simple y más rápido.