No artigo anterior, aprendemos como ler e escrever números em diferentes bases, como o binário e o hexadecimal. Agora, vamos dar vida a esses números. Afinal, computadores não apenas armazenam dados; eles os processam.
A boa notícia é que você não precisa reaprender matemática. As regras de soma e subtração que você aprendeu no ensino fundamental para a base decimal (base 10) são universais. O conceito de “vai-um” (carry) ou de “pegar emprestado” funciona exatamente da mesma maneira, quer você esteja contando maçãs (decimal) ou pulsos elétricos (binário).
Neste artigo, vamos revisitar essas operações fundamentais na base 10 para isolar o algoritmo e, em seguida, aplicar exatamente a mesma lógica para realizar cálculos como um computador.
Base decimal #
A base decimal, também conhecida como base 10, é o sistema numérico mais utilizado no dia a dia. Ele é composto pelos dígitos de 0 a 9 e utiliza um sistema posicional, onde o valor de cada dígito depende de sua posição dentro do número.
Soma na base decimal - regra prática #
A soma de números decimais segue um processo posicional, onde os dígitos são somados coluna por coluna, começando pela unidade (direita) e avançando para a esquerda.
O “segredo” aqui é generalizar a regra: o “vai-um” ocorre sempre que a soma atinge ou ultrapassa o valor da Base. No caso decimal, se deu 10 ou mais, vai um.
Exemplo: Soma \(67 + 84\) na base 10
Passo a passo:
- Somamos a coluna das unidades: \(7 + 4 = 11\). Como o resultado tem dois dígitos (passou da base), colocamos o 1 na posição das unidades e levamos o outro 1 para a próxima coluna (chamado de “vai-um”).
- Somamos a coluna das dezenas: \(6 + 8 = 14\) e somamos o “vai-um”, ficando \(14 + 1 = 15\). Como não há mais colunas, o 15 é colocado como resultado final.
Portanto, o resultado da soma é 151.
O Movimento Vai-Um (Carry) #
O “vai-um” ocorre quando a soma de dois dígitos resulta em um valor maior que 9, já que 10 é a base do sistema decimal e o “vai-um” ocorre sempre que a soma atinge ou ultrapassa a base, como já vimos. Nesse caso, mantemos o dígito das unidades na coluna correspondente e levamos o dígito das dezenas para a próxima coluna.
Exemplo: Soma \(489 + 276\) na base 10
- Unidades: \(9 + 6 = 15\), escrevemos o 5 e levamos 1 para a coluna das dezenas.
- Dezenas: \(8 + 7 = 15\), somamos o “vai-um” (\(15 + 1 = 16\)), escrevemos 6 e levamos 1 para a próxima coluna.
- Centenas: \(4 + 2 = 6\), somamos o “vai-um” (\(6 + 1 = 7\)), resultando em 7.
O resultado final é 765.
Soma na base decimal - algoritmo formal #
A soma de números decimais segue um processo posicional, como vimos. Para entender melhor como isso funcionará em outras bases, vamos analisar o algoritmo formal: somamos a coluna e verificamos o resultado.
Se o valor for maior ou igual à base (neste caso, 10), não podemos representá-lo com um único dígito. Por isso, subtraímos o valor da base (10 no caso) para encontrar o que fica na coluna atual e, em troca, enviamos 1 para a próxima coluna (o carry ou “vai-um”).
Vamos repetir o exemplo anterior, mas agora detalhando o algoritmo formalmente.
Exemplo: Soma \(67 + 84\) na base 10 (Algoritmo Formal)
Passo a passo pelo algoritmo:
- Unidades: \(7 + 4 = 11\). Como \(11 \ge 10\), fazemos \(11 - 10 = 1\). O 1 fica e geramos um “vai-um”.
- Dezenas: \(6 + 8 = 14\). Somamos o “vai-um” (\(15\)). Como \(15 \ge 10\), fazemos \(15 - 10 = 5\). O 5 fica e geramos um “vai-um” para a próxima coluna (centenas).
Subtração na Base Decimal - Regra Prática #
A subtração também segue um processo posicional. Neste artigo, adotaremos o método conhecido como “carry sub” (ou método da compensação/adições iguais).
Sempre que for preciso “emprestar”, ao invés de diminuir o valor do topo, nós adicionamos 1 na casa imediatamente superior do subtraendo (o número de baixo). Isso mantém a diferença correta, mas deixa o visual da conta mais limpo.
Talvez você tenha aprendido na escola o método de “pedir emprestado” riscando o número de cima (ex: o 7 vira 6 para emprestar 1 para o 5). Ambos os métodos são matematicamente equivalentes. Usaremos o método da compensação aqui porque ele facilita a organização visual em algoritmos computacionais. Ele tem história própria e uma ligação direta com o próximo artigo desta série: é uma variação do método dos complementos, a mesma ideia que o hardware usa para não precisar subtrair.
Exemplo: Subtração \(75 - 38\) (carry sub)
Passo a passo:
- Unidades: \(5 - 8\) não é possível. Para contornar isso, somamos 10 ao minuendo na casa das unidades (o \(5\) vira 15) e acrescentamos 1 à casa das dezenas do subtraendo (o \(3\) vira 4). Assim, a diferença permanece inalterada.
- Agora subtraímos as unidades: \(15 - 8 = 7\).
- Dezenas: após o ajuste (o 3 virou 4), subtraímos \(7 - 4 = 3\).
No final, obtemos \(37\) como resultado.
O Processo de Pegar Emprestado - carry sub #
No método “carry sub”, sempre que a casa superior não for suficiente para a subtração, adicionamos 10 (valor da base) ao algarismo do minuendo nessa casa e, simultaneamente, acrescentamos 1 à casa imediata do subtraendo.
Exemplo: Subtração \(402 - 189\) (carry sub)
- Unidades: precisamos fazer \(2 - 9\). Como \(2 < 9\), somamos 10 ao 2 (fica 12) e adicionamos 1 à casa das dezenas do subtraendo (8 vira 9). Agora subtraímos: \(12 - 9 = 3\).
- Dezenas: temos agora \(0 - 9\). Novamente não é possível sem “carregar”: somamos 10 ao 0 (vira 10) e acrescentamos 1 à casa das centenas do subtraendo (1 vira 2). Então fazemos \(10 - 9 = 1\).
- Centenas: restou \(4 - 2\), que é \(2\).
Dessa forma, obtemos o resultado \(213\).
Subtração na Base Decimal - Algoritmo Formal #
A subtração também segue um processo posicional. No método de compensação (carry sub), a lógica algorítmica é clara: se o dígito de cima é menor que o de baixo, somamos o valor da base (10 no caso) ao dígito de cima para tornar a subtração possível.
Para manter a equação equilibrada, devemos compensar adicionando 1 à próxima coluna do número de baixo (subtraendo).
Exemplo: Subtração \(75 - 38\) na base 10 (Algoritmo Formal)
Passo a passo pelo algoritmo:
- Unidades: \(5 - 8\) não é possível. Somamos a base ao 5 (\(5 + 10 = 15\)). Agora fazemos \(15 - 8 = 7\). Compensamos adicionando \(+1\) ao vizinho de baixo (o 3).
- Dezenas: Agora temos \(7\) em cima e \(3 + 1 = 4\) em baixo. Fazemos \(7 - 4 = 3\).
Outras bases #
Soma em diferentes bases #
A soma em bases diferentes segue o mesmo princípio da base decimal, o “vai-um” ocorre sempre que o resultado de uma soma ultrapassa o maior valor permitido na base. Agora, o algoritmo formal fica mais evidente: se o valor da soma é maior ou igual à base, subtraímos o valor da base para encontrar o que fica na coluna atual e enviamos 1 para a próxima coluna.
Vamos aos exemplos práticos:
Exemplo: Soma na base 9
A base 9 tem dígitos de 0 a 8. Sempre que a soma é maior ou igual à base (9), o “vai-um” é adicionado à próxima coluna.
$$ \begin{array}{c c c c} {\scriptscriptstyle 1} & \scriptscriptstyle 1 & & {} \\ {} & 6 & 7 & {} \\ {} + & 8 & 4 & {} \\ \hline 1 & (15) & (11) & {} \\ {} - & 9 & 9 & {\text{ subtraindo a base}} \\ \hline 1 & 6 & 2 & {} \end{array} $$Passo a passo:
- Unidades: \(7 + 4 = 11\). Escrevemos 2, resultado de \(11 - 9\) (base), e levamos 1 para a próxima coluna.
- Dezenas: \(6 + 8 = 14\). Somamos o “vai-um” e temos \(14 + 1 = 15\). O resultado é 6 e levamos 1 para a próxima coluna.
Portanto, o resultado da soma \(67 + 84\) na base 9 é \(162_9\).
Exemplo: Soma na base 16
A base 16 tem dígitos de 0 a F (representando 15). Sempre que a soma é maior ou igual à base (16), o “vai-um” é adicionado à próxima coluna.
$$ \begin{array}{c c c c c} {\scriptscriptstyle 1} & & \scriptscriptstyle 1 & & {} \\ {} & F & 1 & A & {} \\ {} + & E & 0 & 9 & {} \\ \hline 1 & (29) & 2 & (19) & {} \\ {} - & 16 & & 16 & {\text{ subtraindo a base}} \\ \hline 1 & D & 2 & 3 & {} \end{array} $$Resultado: \(\mathtt{F1A} + \mathtt{E09} = \mathtt{1D23_{16}}\).
Antes de ver os exemplos em base 2, vale a pena ter em mente a “tabuada” básica da soma binária, que é onde a maioria das confusões acontece:
- \(0 + 0 = 0\)
- \(0 + 1 = 1\)
- \(1 + 0 = 1\)
- \(1 + 1 = 10_2\) (Fica 0 e vai 1)
- \(1 + 1 + 1 = 11_2\) (Fica 1 e vai 1)
Exemplo: Soma na base 2
A base 2 tem dígitos 0 e 1. Sempre que a soma é maior ou igual à base (2), o “vai-um” é adicionado à próxima coluna.
$$ \begin{array}{c c c c c c c} \scriptscriptstyle 1 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & & {} \\ {} & 1 & 0 & 1 & 1 & 1 & {} \\ {} + & 1 & 1 & 0 & 1 & 1 & {} \\ \hline & (3) & (2) & (2) & (3) & (2) & {} \\ {} - & 2 & 2 & 2 & 2 & 2 & {\text{ subtraindo a base}} \\ \hline 1 & 1 & 0 & 0 & 1 & 0 & {} \end{array} $$Resultado: \(10111_2 + 11011_2 = 110010_2\).
Na base 2, vimos que \(1_2 + 1_2 = 10_2\) e \(1_2 + 1_2 + 1_2 = 11_2\). Assim, pode ser mais fácil somar números binários se lembrarmos dessas contas de cabeça.
Exemplo: Soma na base 2 usando conhecimento dos valores de 2 e 3 na base
Três casos que testam o entendimento #
Os exemplos acima têm, no máximo, um “vai-um” isolado por coluna. Três situações fogem desse padrão e valem a pena, porque é nelas que a conta costuma descarrilar.
Dois dígitos máximos na mesma coluna. Em base 8, o maior dígito é 7. Somar \(77_8 + 77_8\) coloca o algoritmo no pior caso possível em todas as colunas:
$$ \begin{array}{c c c c} \scriptscriptstyle 1 & \scriptscriptstyle 1 & & {} \\ {} & 7 & 7 & {} \\ {} + & 7 & 7 & {} \\ \hline & (15) & (14) & {} \\ {} - & 8 & 8 & {\text{ subtraindo a base}} \\ \hline 1 & 7 & 6 & {} \end{array} $$Resultado: \(77_8 + 77_8 = 176_8\). Confira em decimal: \(77_8 = 63\), e \(63 + 63 = 126 = 176_8\) (\(1 \times 64 + 7 \times 8 + 6\)).
Vai-um em cadeia. Em \(2\mathtt{FF}_{16} + 1\mathtt{FE}_{16}\), o “vai-um” não fica preso a uma coluna: ele nasce nas unidades e atravessa a conta inteira.
$$ \begin{array}{c c c c c} {} & \scriptscriptstyle 1 & \scriptscriptstyle 1 & & {} \\ {} & 2 & F & F & {} \\ {} + & 1 & F & E & {} \\ \hline {} & 4 & (31) & (29) & {} \\ {} - & {} & 16 & 16 & {\text{ subtraindo a base}} \\ \hline {} & 4 & F & D & {} \end{array} $$Resultado: \(2\mathtt{FF}_{16} + 1\mathtt{FE}_{16} = 4\mathtt{FD}_{16}\). Em decimal: \(767 + 510 = 1277\), e \(4 \times 256 + 15 \times 16 + 13 = 1277\).
Em binário esse efeito de cadeia fica ainda mais nítido, e vale ver desenhado. A figura abaixo acompanha o pior caso possível de uma soma de 8 bits, \(01111111_2 + 00000001_2\) — ou seja, \(127 + 1\). O “vai-um” nasce na coluna mais à direita e precisa atravessar, uma a uma, todas as sete colunas seguintes antes que o resultado esteja pronto. Os três painéis de baixo destacam os três momentos dessa travessia:

É daqui que vem o nome ripple carry (“vai-um em ondulação”): cada coluna só consegue terminar depois que a anterior entregou o seu transporte. No papel isso é só trabalho; no hardware, é tempo — e é por isso que processadores modernos usam somadores mais espertos, que tentam adivinhar o vai-um em vez de esperar por ele.
Somar três números de uma vez. Aqui mora a armadilha mais bonita do algoritmo. Todo mundo aprende “vai-um” — mas o vai-um só vale um porque estamos somando dois números. Com três parcelas, uma coluna pode gerar transporte 2.
$$ \begin{array}{c c c c c c c c} {} & {} & \scriptscriptstyle 2 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & \scriptscriptstyle 1 & {} \\ {} & {} & {} & 1 & 0 & 1 & 0 & 0 \\ {} & {} & {} & 1 & 1 & 1 & 0 & 1 \\ {} + & {} & {} & 1 & 1 & 0 & 1 & 1 \\ \hline {} & 1 & 0 & 0 & 1 & 1 & 0 & 0 \end{array} $$Acompanhe a coluna que estoura: na quinta posição temos \(1 + 1 + 1 = 3\), mais o transporte 1 que chegou da coluna anterior, dá \(4\). Como \(4 = 100_2\), fica \(0\) na coluna e vão 2 para a próxima. Resultado: \(10100_2 + 11101_2 + 11011_2 = 1001100_2\), ou \(20 + 29 + 27 = 76\).
A regra geral não é “escreva o resto e leve 1”, e sim: escreva o resto da divisão pela base e leve o quociente. Com duas parcelas o quociente nunca passa de 1, e a regra simplificada funciona. Com três ou mais, ele pode valer 2 ou mais — e é exatamente aí que a conta feita no automático erra.
Subtração em diferentes bases #
A subtração em bases diferentes segue o mesmo princípio que vimos na base decimal (carry sub/compensação): se o dígito de cima for menor que o de baixo, somamos a base ao de cima e compensamos somando 1 ao vizinho de baixo.
Novamente, o algoritmo formal fica mais evidente: se o valor da subtração é negativo, somamos o valor da base ao dígito de cima para tornar a subtração possível e adicionamos 1 à próxima coluna do número de baixo (subtraendo) para manter a equação equilibrada.
Exemplo: Subtração na base 8
Na base 8, os dígitos vão de 0 a 7. Sempre que a subtração resulta em um número negativo, emprestamos 1 da próxima coluna.
$$ \begin{array}{c c c} {} & 5 & 2^{\scriptscriptstyle+8} \\ {} - & 1^{\scriptscriptstyle+1} & 7 \\ \hline {} & 3 & 3 \end{array} $$Passo a passo:
- Unidades: \(2 - 7\) não é possível. Somamos a base (8) ao dígito de cima — o \(2\) passa a valer \(10\) — e compensamos com \(+1\) na próxima coluna do subtraendo (o \(1\) vira \(2\)). Agora \(10 - 7 = 3\).
- Próxima coluna: \(5 - 2 = 3\).
Resultado: \(52_8 - 17_8 = 33_8\).
Dica de verificação: \(52_8 = 42\) e \(17_8 = 15\); \(42 - 15 = 27\), que em base 8 é \(3 \times 8 + 3 = 33_8\).
Exemplo: Subtração na base 16
Na base 16, os dígitos vão de 0 a F. Sempre que a subtração resulta em um número negativo, emprestamos 1 da próxima coluna.
$$ \begin{array}{c c c} {} & 5 & 2^{\scriptscriptstyle+16} \\ {} - & 1^{\scriptscriptstyle+1} & 7 \\ \hline {} & 3 & B \end{array} $$Passo a passo:
- Unidades: \(2 - 7\) não é possível. Somamos a base (16) ao dígito de cima — o \(2\) passa a valer \(18\) — e compensamos com \(+1\) na próxima coluna do subtraendo (o \(1\) vira \(2\)). Agora \(18 - 7 = 11\), que em hexadecimal é o dígito \(\mathtt{B}\).
- Próxima coluna: \(5 - 2 = 3\).
Resultado: \(52_{16} - 17_{16} = 3\mathtt{B}_{16}\).
Dica de verificação: \(52_{16} = 82\) e \(17_{16} = 23\); \(82 - 23 = 59\), que em base 16 é \(3 \times 16 + 11 = 3\mathtt{B}_{16}\).
Repare que a conta é a mesma dos dois exemplos anteriores — muda só o valor emprestado, que é sempre a base.
Na base 2, podemos usar o conhecimento já adquirido da “tabuada” para facilitar a subtração.
Exemplo: Subtração na base 2
Passo a passo, da direita para a esquerda:
- \(0 - 1\) não dá. Somamos a base (2) ao topo, que vira \(10_2\), e compensamos \(+1\) na próxima coluna de baixo. \(2 - 1 = 1\).
- Topo \(1\), baixo \(0 + 1 = 1\). \(1 - 1 = 0\), sem compensação.
- Topo \(0\), baixo \(1\). Somamos a base: \(2 - 1 = 1\), e compensamos.
- Topo \(0\), baixo \(1 + 1 = 2\). Somamos a base: \(2 - 2 = 0\), e compensamos.
- Topo \(1\), baixo \(0 + 1 = 1\). \(1 - 1 = 0\).
- Topo \(1\), baixo \(1\). \(1 - 1 = 0\).
Resultado: \(110010_2 - 101101_2 = 101_2\).
Dica de verificação: \(110010_2 = 50\) e \(101101_2 = 45\); \(50 - 45 = 5\), que em binário é \(101_2\).
Algoritmos Formais e Implementação #
Para um cientista da computação, entender a aritmética não é apenas saber fazer a conta no papel, mas entender o algoritmo que pode ser programado. Abaixo, apresentamos a lógica generalizada para qualquer Base \(B\), primeiro em pseudocódigo e depois em Python.
Algoritmo de Soma (Generalizado) #
A lógica central depende de duas operações inteiras: o resto da divisão (%)
determina o dígito que fica, e a divisão inteira (//) determina o “vai-um”.
Para começar, vamos ver em pseudocógido, que é uma forma de escrever algoritmos de maneira independente de linguagem de programação. Talvez facilite a compreensão antes de vermos o código Python.
Pseudocódigo:
FUNÇÃO Somar(Numero_A, Numero_B, BASE):
vai_um = 0
resultado = ""
PARA cada posição i (da direita para a esquerda):
soma_parcial = digito_a + digito_b + vai_um
# O dígito que fica é o resto da divisão pela base
digito_que_fica = soma_parcial MOD BASE
# O "vai-um" é a divisão inteira pela base
vai_um = soma_parcial DIV BASE
ADICIONAR digito_que_fica À ESQUERDA de resultado
SE vai_um > 0: ADICIONAR vai_um À ESQUERDA de resultado
RETORNAR resultadoImplementação em Python:
Para os códigos Python, usaremos uma string auxiliar para mapear dígitos maiores
que 9:
DIGITOS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
DIGITOS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def somar_bases(n1: str, n2: str, base: int) -> str:
# Inverte as strings para facilitar a iteração da direita para esquerda
n1, n2 = n1[::-1].upper(), n2[::-1].upper()
# Iguala o tamanho das strings com zeros à direita (que são à esquerda no número real)
tam_max = max(len(n1), len(n2))
n1 = n1.ljust(tam_max, '0')
n2 = n2.ljust(tam_max, '0')
vai_um = 0
resultado = []
for i in range(tam_max):
# Converte caractere para valor numérico (Ex: 'A' -> 10)
v1 = DIGITOS.index(n1[i])
v2 = DIGITOS.index(n2[i])
soma_parcial = v1 + v2 + vai_um
# Lógica da Base
digito_fica = soma_parcial % base
vai_um = soma_parcial // base
resultado.append(DIGITOS[digito_fica])
if vai_um > 0:
resultado.append(DIGITOS[vai_um])
# Inverte de volta para retornar a string correta
return "".join(resultado[::-1])
# --- Exemplos de Execução (Baseados nos exemplos do artigo) ---
# Base 10: 67 + 84
print(f"Base 10: {somar_bases('67', '84', 10)}")
# Resultado: 151
# Base 9: 67 + 84
print(f"Base 9: {somar_bases('67', '84', 9)}")
# Resultado: 162 (Note que 7+4=11, que é 12 na base 9)
# Base 16: F1A + E09
print(f"Base 16: {somar_bases('F1A', 'E09', 16)}")
# Resultado: 1D23
# Base 2: 10111 + 11011
print(f"Base 2: {somar_bases('10111', '11011', 2)}")
# Resultado: 110010Algoritmo de Subtração (Método Carry Sub) #
Neste método, quando o dígito de cima é menor, somamos a BASE a ele e marcamos
uma compensacao (+1) para ser adicionada ao dígito de baixo na próxima coluna.
Pseudocódigo:
FUNÇÃO Subtrair(Minuendo, Subtraendo, BASE):
compensacao = 0
resultado = ""
PARA cada posição i (da direita para a esquerda):
digito_baixo = Subtraendo[i] + compensacao
digito_cima = Minuendo[i]
SE digito_cima < digito_baixo:
# "Pega emprestado" da base (soma a base ao topo)
digito_cima = digito_cima + BASE
compensacao = 1
SENÃO:
compensacao = 0
diferenca = digito_cima - digito_baixo
ADICIONAR diferenca À ESQUERDA de resultado
RETORNAR resultadoImplementação em Python:
def subtrair_bases(n1: str, n2: str, base: int) -> str:
# Este algoritmo só sabe produzir resultados não negativos. Sem a checagem
# abaixo, subtrair_bases('38', '75', 10) devolveria '63' em silêncio.
# Comparar numerais da mesma base não exige convertê-los: basta olhar o
# comprimento (sem zeros à esquerda) e, em caso de empate, comparar dígito a
# dígito — os símbolos de DIGITOS já estão em ordem crescente.
a = n1.upper().lstrip('0') or '0'
b = n2.upper().lstrip('0') or '0'
if (len(a), a) < (len(b), b):
raise ValueError(f"{n1} < {n2} na base {base}: resultado seria negativo")
n1, n2 = n1[::-1].upper(), n2[::-1].upper()
tam_max = max(len(n1), len(n2))
n1 = n1.ljust(tam_max, '0')
n2 = n2.ljust(tam_max, '0')
compensacao = 0
resultado = []
for i in range(tam_max):
v_cima = DIGITOS.index(n1[i])
v_baixo = DIGITOS.index(n2[i]) + compensacao
if v_cima < v_baixo:
# Aplica a lógica do Carry Sub (soma a base em cima)
v_cima += base
compensacao = 1
else:
compensacao = 0
diferenca = v_cima - v_baixo
resultado.append(DIGITOS[diferenca])
# Remove zeros à esquerda resultantes (ex: 037 -> 37)
return "".join(resultado[::-1]).lstrip('0') or "0"
# --- Exemplos de Execução ---
# Base 10: 75 - 38
print(f"Base 10: {subtrair_bases('75', '38', 10)}")
# Resultado: 37
# Base 8: 52 - 17 (Exemplo do artigo: pegamos emprestado 8)
print(f"Base 8: {subtrair_bases('52', '17', 8)}")
# Resultado: 33 (Pois 2 virou 10 (2+8), 10-7=3. O 1 virou 2, 5-2=3)
# Base 16: 52 - 17
print(f"Base 16: {subtrair_bases('52', '17', 16)}")
# Resultado: 3B (Pois 2 virou 18 (2+16), 18-7=11(B). O 1 virou 2, 5-2=3)
# Base 2: 1101010 - 101101 (Exemplo adaptado)
print(f"Base 2: {subtrair_bases('1101010', '101101', 2)}")
# Resultado: 111101Tabela-Resumo #
| Situação | Regra | Exemplo do artigo |
|---|---|---|
| Soma, coluna a coluna | escreva \(s \bmod b\) e leve \(s \div b\) | \(67_9 + 84_9 = 162_9\) |
| Vai-um com duas parcelas | o transporte nunca passa de 1 | \(1_2 + 1_2 = 10_2\) |
| Vai-um com três parcelas | o transporte pode valer 2 ou mais | \(10100_2 + 11101_2 + 11011_2 = 1001100_2\) |
| Pior caso da soma | dois dígitos máximos na mesma coluna | \(77_8 + 77_8 = 176_8\) |
| Vai-um em cadeia | o transporte atravessa várias colunas | \(2\mathtt{FF}_{16} + 1\mathtt{FE}_{16} = 4\mathtt{FD}_{16}\) |
| Subtração (carry sub) | se o de cima for menor, some a base em cima e \(+1\) na próxima coluna de baixo | \(52_8 - 17_8 = 33_8\) |
| Quanto se empresta | sempre o valor da base | 8 na base 8, 16 na base 16, 2 na base 2 |
| Verificação | converta para decimal e refaça a conta | \(42 - 15 = 27 = 33_8\) |
| Soma em código | digito = soma % base, vai_um = soma // base |
somar_bases('F1A','E09',16) |
| Subtração em código | if v_cima < v_baixo: v_cima += base |
subtrair_bases('52','17',16) |
| Limite do algoritmo | só resultados não negativos | subtrair_bases('38','75',10) levanta ValueError |
Conclusão e Próximos Passos #
Como vimos, a aritmética posicional é consistente: não importa se temos 2 símbolos (binário) ou 16 (hexadecimal), o algoritmo é o mesmo. A única coisa que muda é o valor que dispara o “vai-um” ou o “empréstimo”.
Dominar essas operações no papel é excelente para entender a lógica, mas levanta uma questão importante: será que o hardware do computador realiza subtrações pedindo emprestado bits vizinhos?
Na prática, não — e o motivo talvez surpreenda. Não é que um subtrator seja caro: um subtrator completo custa praticamente o mesmo que um somador completo, porque ambos são feitos das mesmas portas lógicas. O problema é o desperdício.
Vale a pena ver de perto o circuito de que estamos falando. O somador completo é a peça que executa, em silício, exatamente uma coluna da conta que fizemos no papel: ele recebe dois bits e o vai-um que chegou da coluna anterior, e devolve o bit da soma e o vai-um para a coluna seguinte. São cinco portas lógicas, só isso:

Ligando oito dessas peças em fila, com o vai-um de uma entrando na seguinte, temos exatamente a soma de 8 bits que desenhamos mais acima — inclusive a espera em cadeia. E um subtrator completo tem esse mesmo porte: as mesmas cinco portas, ligadas de outro jeito. É aí que está o desperdício.
Manter dois circuitos separados, um para somar e outro para subtrair, gasta área do processador fazendo duas vezes um trabalho quase idêntico — e, pior, obriga o projeto a decidir qual dos dois usar a cada operação.
A saída da computação moderna é elegante: transformar toda subtração em soma, de modo que um único somador dê conta das duas operações. É o conceito de Complemento de Dois e de números com sinal, e é exatamente sobre essa representação de números negativos que falaremos no próximo artigo.
Até lá!