Módulo 2: Exercícios — Representação de Dados e Aritmética Computacional

Estes três exercícios foram elaborados para que você aplique, de forma progressiva, os conceitos estudados no material do Módulo 2. Leia cada enunciado com atenção, tente resolvê-lo antes de consultar o material e registre seu raciocínio por escrito — mesmo que incompleto. A capacidade de articular o que você ainda não sabe é tão valiosa quanto a de demonstrar o que já domina.


Exercício 1 — Nível Básico

Representações Numéricas e Operações em Complemento de Dois

Ao final do primeiro dia de tutoria do Projeto Integrador, sua equipe percebe que o firmware lê corretamente a temperatura do sensor de ambiente (que retorna um valor de 8 bits com sinal, em complemento de dois, representando graus Celsius) mas o display LCD exibe números sem sentido quando a temperatura é negativa. Após investigar, vocês chegam à conclusão de que a rotina de conversão para exibição está tratando o byte recebido como um inteiro sem sinal, em vez de com sinal.

Para corrigir o problema, você precisa dominar completamente as representações numéricas envolvidas. Resolva as questões a seguir, mostrando todos os passos intermediários.

Parte A — Conversões entre bases

Converta cada um dos valores abaixo para as demais representações indicadas, mostrando o procedimento utilizado em cada conversão:

  • 173_{10}: converta para binário (8 bits) e para hexadecimal.
  • \text{0xA3}: converta para decimal e para binário (8 bits) sem passar pelo decimal como intermediário.
  • 1001\;0110_2: converta para decimal e para hexadecimal.

Parte B — Representação de inteiros negativos em complemento de dois

O sensor de temperatura pode retornar os seguintes valores binários de 8 bits. Para cada um, determine se o número é positivo ou negativo (interpretando como complemento de dois de 8 bits) e calcule o valor decimal correspondente. Mostre o procedimento de cálculo em cada caso.

  • 0111\;1111_2
  • 1000\;0000_2
  • 1111\;0110_2
  • 0000\;0000_2

Parte C — Operação aritmética e verificação de overflow

Considere que o registrador de trabalho W do PIC18F4550 contém o valor 1101\;0011_2, que representa uma temperatura em complemento de dois de 8 bits. O sistema precisa somar +20 a esse valor para aplicar uma correção de calibração.

Realize a soma em binário, mostrando os bits de cada operando e o resultado. Em seguida, determine o valor decimal do resultado em complemento de dois de 8 bits e verifique se ocorreu overflow segundo a regra formal apresentada no material: houve overflow se e somente se os sinais dos dois operandos são iguais mas o sinal do resultado é diferente. Justifique sua resposta.

Parte D — Extensão de sinal

Após corrigir a rotina de conversão, a equipe decide aumentar a precisão do sistema armazenando temperaturas em int16_t em vez de int8_t, para poder representar valores como -200 (representando -20,0 °C em ponto fixo com escala 10). Para isso, é necessário estender o sinal de valores de 8 bits para 16 bits.

Aplique a extensão de sinal correta para os seguintes valores de 8 bits em complemento de dois, obtendo a representação em complemento de dois de 16 bits. Explique por que o procedimento correto é replicar o bit de sinal, e não preencher com zeros.

  • 1111\;1011_2 (representa -5)
  • 0110\;0100_2 (representa +100)

Exercício 2 — Nível Intermediário

Aritmética Segura, Ponto Fixo e Limitações do IEEE 754

O Projeto Integrador evoluiu e agora precisa calcular a média móvel de dez leituras consecutivas de temperatura para filtrar ruídos do sensor. Além disso, o sistema deve exibir a média com uma casa decimal de precisão no display LCD, sem usar float (pois operações de ponto flutuante são lentas no PIC18F4550).

Você também foi encarregado de investigar se seria seguro usar float em uma segunda função que calcula o valor eficaz (RMS) de uma grandeza analógica amostrada pelo ADC. Para isso, precisa compreender profundamente as limitações do IEEE 754.

Parte A — Cálculo de média com ponto fixo

As dez leituras de temperatura obtidas pelo sensor, em int8_t (complemento de dois, °C), foram as seguintes:

23, \; 24, \; -3, \; 22, \; 25, \; 21, \; -2, \; 23, \; 24, \; 22

Utilizando a representação em ponto fixo com escala 10 (conforme apresentada no material: o valor inteiro V representa a temperatura V/10 °C), resolva:

  1. Converta cada leitura para a representação em ponto fixo com escala 10, determinando o valor int16_t correspondente. Verifique se todos os valores cabem em int16_t (faixa: -32.768 a +32.767).

  2. Some os dez valores em ponto fixo. Antes de realizar a soma, determine o valor máximo possível da soma e verifique se ele cabe em int16_t ou se será necessário usar int32_t para evitar overflow durante o cálculo intermediário. Justifique sua resposta com base nas faixas de representação apresentadas no material.

  3. Divida a soma por 10 para obter a média. Qual é o valor decimal (em °C, com uma casa decimal) que esse resultado representa? Mostre como esse valor seria enviado ao display LCD como string, assumindo que você usa a notação “parte inteira, vírgula, parte fracionária”.

  4. Explique, em suas próprias palavras, por que a abordagem em ponto fixo com escala 10 é preferível ao uso de float neste cenário específico do PIC18F4550, considerando tanto a precisão dos resultados quanto o desempenho do processador.

Parte B — Análise de representação IEEE 754

Um colega propõe usar float para armazenar as leituras e calcular a média. Para avaliar se essa proposta é adequada, você precisa analisar a representação IEEE 754 de alguns valores.

  1. Decomponha o número -12,5 em seus três campos IEEE 754 de precisão simples (32 bits): bit de sinal, expoente armazenado (8 bits) e fração (23 bits). Mostre cada passo: determinação do sinal, conversão para binário, normalização, cálculo do expoente com bias de 127 e extração da fração. Ao final, escreva o padrão completo de 32 bits em hexadecimal.

  2. Considere os seguintes padrões de 32 bits em hexadecimal. Para cada um, identifique o tipo de valor que ele representa (número normal positivo ou negativo, número subnormal, zero positivo, zero negativo, infinito positivo, infinito negativo ou NaN), justificando com base nos valores dos campos de expoente e fração:

  • 0x00000000
  • 0xFF800000
  • 0x7F800001
  • 0x80000000
  • 0x00400000
  1. Explique o fenômeno do cancelamento subtrativo descrito no material. Invente um exemplo numérico concreto (com valores específicos) que demonstre como dois valores float próximos podem produzir um resultado com perda significativa de precisão relativa quando subtraídos. Quantifique, em número de bits de fração, a perda de precisão no seu exemplo.

Parte C — Detecção de overflow em aritmética com sinal

Implemente, na forma de pseudocódigo ou fluxograma, o algoritmo de detecção de overflow para a operação int16_t soma_segura(int16_t a, int16_t b). O algoritmo deve:

  • Verificar os sinais de a e b antes da soma.
  • Realizar a soma usando um tipo intermediário mais largo (int32_t) para não perder o resultado real.
  • Aplicar a regra formal de detecção de overflow: verificar se o resultado real está fora da faixa [-32.768,\; +32.767].
  • Retornar tanto o resultado (truncado para int16_t) quanto um indicador de status (OK ou OVERFLOW).

Em seguida, aplique seu algoritmo aos seguintes pares e determine o status de cada operação:

  • a = +30.000, b = +5.000
  • a = -20.000, b = -15.000
  • a = +20.000, b = -15.000

Exercício 3 — Nível Desafiador

Circuitos Aritméticos, Promoção de Tipos e Análise Completa de Sistema

Este exercício integra os temas do Módulo 2 em um cenário que exige raciocínio de múltiplos níveis: da lógica digital ao comportamento do compilador C no PIC18F4550.

Parte A — Projeto de um somador de 4 bits com carry-lookahead

O material descreve que o Ripple Carry Adder sofre de latência proporcional ao número de bits devido à propagação sequencial do carry. O Carry-Lookahead Adder resolve isso calculando todos os carries em paralelo a partir dos sinais de geração (G_i = A_i \cdot B_i) e propagação (P_i = A_i \oplus B_i).

  1. Para um somador de 4 bits com Carry-Lookahead, escreva as equações booleanas completas de C_1, C_2, C_3 e C_4 em termos de G_0, G_1, G_2, G_3, P_0, P_1, P_2, P_3 e C_0 (carry de entrada). Você deve derivá-las a partir das equações recursivas apresentadas no material, expandindo cada carry completamente.

  2. Aplique as equações que você derivou para calcular a soma A = 1011_2 e B = 0110_2 com C_0 = 0. Calcule primeiro os sinais G_i e P_i para cada bit i \in \{0, 1, 2, 3\}, depois os carries C_1 a C_4 usando as equações de lookahead, e finalmente os bits de soma S_i = A_i \oplus B_i \oplus C_i. Verifique o resultado convertendo A, B e S para decimal.

  3. Determine o número máximo de níveis de portas lógicas pelos quais um sinal precisa passar para que C_4 esteja disponível no Carry-Lookahead Adder de 4 bits que você analisou. Compare com o número equivalente de níveis no Ripple Carry Adder de 4 bits (assuma que cada full adder tem 2 níveis de lógica para C_{out}). O que essa comparação revela sobre o trade-off entre velocidade e complexidade de hardware?

Parte B — Análise de comportamento do compilador e armadilhas de tipo

O compilador MPLAB XC8 segue as regras de promoção de tipos do padrão C. O material afirma que operações em tipos menores que int são promovidas para int antes da computação. Considere o seguinte fragmento de código para PIC18F4550 (onde int é 16 bits no XC8):

uint8_t  a = 200;
uint8_t  b = 100;
uint8_t  c = a + b;          /* Linha 1 */
uint16_t d = a + b;          /* Linha 2 */
uint16_t e = (uint16_t)a * b; /* Linha 3 */
int8_t   f = -100;
int8_t   g = -50;
int8_t   h = f + g;          /* Linha 4 */
int16_t  i = (int16_t)f + g; /* Linha 5 */

Para cada linha numerada (1 a 5), responda:

  1. Qual o valor matemático correto da operação?
  2. Em que tipo a operação é efetivamente realizada pelo compilador (após promoção)?
  3. Qual valor é armazenado na variável de destino? Há truncamento ou overflow silencioso?
  4. O resultado armazenado é o esperado? Se não, como o código deveria ser corrigido?

Ao final, escreva um parágrafo explicando por que a diferença entre uint8_t, uint16_t e os tipos intermediários de promoção é especialmente crítica em microcontroladores de 8 bits como o PIC18F4550, comparando com o comportamento em processadores de 32 ou 64 bits onde int teria largura maior.

Parte C — Projeto integrado: conversor numérico robusto

Projete, em nível de especificação completa (sem escrever o código — apenas especifique o comportamento esperado, os casos de borda e a lógica de alto nível), uma função chamada formatar_temperatura destinada ao display LCD do Projeto Integrador. A função deve satisfazer os seguintes requisitos, derivados diretamente dos conceitos do módulo:

  1. Entrada: um valor int16_t representando temperatura em ponto fixo com escala 10 (ou seja, o valor V representa V/10 °C). A faixa válida de temperaturas do sensor é -400 a +1250 (correspondendo a -40,0 °C a +125,0 °C).

  2. Saída: uma string no formato "-XX.X" ou "XXX.X", adequada para exibição direta no LCD Sunstar 2004A (máximo de 6 caracteres incluindo o terminador nulo).

  3. Tratamento de casos especiais: a função deve lidar corretamente com o valor zero (0 = 0,0 °C), com o valor mínimo da faixa (-400 = -40,0 °C) e com o valor máximo (1250 = 125,0 °C).

  4. Detecção de entrada inválida: se o valor estiver fora da faixa [-400, +1250], a função deve indicar erro de forma adequada (você deve especificar como).

Para a sua especificação, descreva:

  1. Como a função extrairá a parte inteira e a parte fracionária do valor em ponto fixo, usando apenas aritmética inteira (divisão por 10 e módulo 10). Preste atenção especial ao tratamento de valores negativos: a parte fracionária exibida deve sempre ser positiva, mesmo quando o valor total é negativo. Por exemplo, -35 (que representa -3,5 °C) deve exibir "-3.5", não "-3.-5". Explique como garantir esse comportamento.

  2. Como a função determinará o número de caracteres necessários para a parte inteira, para evitar zeros à esquerda desnecessários (por exemplo, +5 deve exibir "0.5" ou "0,5", não "000.5").

  3. Qual seria a sequência exata de operações aritméticas e de extração de dígitos para converter o valor -127 (representando -12,7 °C) na string "-12.7", passo a passo.

  4. Identifique ao menos dois casos de borda adicionais que sua especificação deve tratar explicitamente, além dos já mencionados, e descreva o comportamento esperado para cada um.

Dica para o Exercício 3, Parte A: antes de escrever as equações de lookahead, construa a tabela de G_i e P_i para o exemplo numérico. Isso facilita muito a verificação das equações booleanas.

Dica para a Parte C: o tratamento de valores negativos em ponto fixo é a parte mais delicada. Pense bem na diferença entre o sinal do número (que determina se o prefixo "-" é exibido) e as magnitudes das partes inteira e fracionária (que devem sempre ser positivas). Considere usar abs() ou operações de magnitude explícita.

👉 Entregue um arquivo TXT contendo as respostas

👉 Somente 1 entrega por grupo!!!