Uma variável em double foi convertida para inteiro 16-bit com sinal. Explique o overflow e:
  1. Para x=k V_{h}, determine o maior V_{h} sem overflow para k=120.
  2. Escreva pseudocódigo de um safe_cast_16.

Passo 1

O que o exercício pede e o que foi dado:
  • O enunciado diz que uma variável em tipo ponto flutuante (double) foi convertida para inteiro com sinal de 16 bits.
  • Preciso explicar o que é overflow nesse contexto.
  • Pergunta 1: para x = k\,V_{h} com k=120, determine o maior V_{h} que NÃO causa overflow ao converter para inteiro 16-bit com sinal.
  • Pergunta 2: escrever pseudocódigo de um \text{safe\_cast\_16}.
  • Informações relevantes dadas/implícitas que vou usar: a conversão é para inteiro com sinal de 16 bits (intervalo e comportamento típico de cast precisam ser explicitados).

Passo 2

O que é overflow ao converter de double para inteiro 16-bit com sinal (explicação didática):
  • “Overflow” significa que o valor que você tem em ponto flutuante é maior (ou menor) do que o maior (ou menor) número que pode ser representado no tipo destino. Quando isso acontece, a conversão não consegue representar corretamente o valor.
  • Para inteiro com sinal de 16 bits o intervalo de valores representáveis é obtido assim: existem 2^{16} códigos no total; metade são negativos (incluindo zero no lado positivo ou negativo dependendo da convenção). Os limites padrão são \text{INT16\_MIN} = -2^{15} = -32768
\text{INT16\_MAX} = 2^{15}-1 = 32767
Ou seja, qualquer valor convertido deve ficar dentro de \left[-32768,\,32767\right] para não ocorrer overflow.
  • Observação sobre arredondamento/truncamento: em linguagens C/C++ típicas, ao fazer cast de double para int, o valor é truncado em direção a zero (por exemplo 3{,}9 vira 3, -3{,}9 vira -3). Para segurança absoluta é melhor exigir que o valor esteja dentro do intervalo de inteiros representáveis antes da conversão, porque comportamento fora desse intervalo é indefinido ou implementação-dependente.

Passo 3

Modelagem do problema para x = k\,V_{h}:
  • Queremos garantir que a conversão de x para int16 não transborde, ou seja \text{INT16\_MIN} \le x \le \text{INT16\_MAX}.
  • Substituindo x = k\,V_{h} obtemos a condição \text{INT16\_MIN} \le k\,V_{h} \le \text{INT16\_MAX}.
  • No caso do enunciado k=120. Supondo V_{h} não negativa (geralmente é assim se for amplitude/escala), a restrição relevante é k\,V_{h} \le \text{INT16\_MAX}.
  • Isolando V_{h} obtemos V_{h} \le \frac{\text{INT16\_MAX}}{k}.

Passo 4

Cálculo numérico para k=120:
  • Usando \text{INT16\_MAX}=32767 e k=120, temos V_{h} \le \frac{32767}{120}.
  • Faço a divisão passo a passo: 120 \times 273 = 32760. O resto é 32767-32760=7. Então \frac{32767}{120} = 273 + \frac{7}{120} = 273{,}058333\ldots
  • Portanto o maior V_{h} (valor real) que garante k\,V_{h}\le 32767 é V_{h,\max} = \frac{32767}{120} \approx 273{,}058333\ldots
  • Se V_{h} precisa ser um número inteiro (por exemplo contagem de passos), o maior inteiro que não causa overflow é \left\lfloor\frac{32767}{120}\right\rfloor = 273.

Passo 5

Nota sobre o detalhe de truncamento e alternativa ligeiramente mais permissiva
  • Se a conversão usa truncamento para zero: ao converter um x positivo, qualquer x<32768 truncado para inteiro resultará em \le 32767. Assim, em tese, um valor real V_{h} poderia ser um pouquinho maior até V_{h} < \frac{32768}{120} = 273{,}0666\ldotse ainda, por truncamento, o inteiro obtido seria \le 32767.
  • Contudo, essa condição é frágil (depende de políticas de conversão, de valores infinitos/NaN e do comportamento da plataforma). Por isso, a escolha mais segura e portável é usar V_{h}\le 32767/120 como no Passo 4.

Passo 6

Especificação do que o \text{safe\_cast\_16} deve fazer (didática):
  • Objetivo de \text{safe\_cast\_16}(value): converter um valor em ponto flutuante para inteiro com sinal de 16 bits sem causar overflow ou comportamento indefinido.
  • Decisões de projeto comuns (escolha explicada):
    • Detectar valores especiais: \text{NaN} (not-a-number) e \pm\infty devem ser tratados como erro.
    • Se o valor está fora do intervalo \left[\text{INT16\_MIN},\text{INT16\_MAX}\right], duas opções usuais são:
      1. Sinalizar erro/rejeitar a conversão (mais seguro quando queremos detectar falhas).
      2. Fazer saturação (clamp) para \text{INT16\_MIN} ou \text{INT16\_MAX} — útil em aplicações de áudio/controle que preferem uma resposta limitada em vez de erro.
    • Escolherei um comportamento que retorna um status (sucesso/falha) e o valor convertido; também mostro a variante com saturação.

Passo 7

Pseudocódigo do \text{safe\_cast\_16} (variante que sinaliza erro em overflow)
  • Função que retorna um par (\text{success},\,\text{result}), onde \text{success} é booleano e \text{result} é o inteiro convertido apenas se \text{success}=\text{true}.
  • Pseudocódigo (com constantes em TeX):
    function safe_cast_16(\(value\)):
        constants:
            \(INT16\_MIN = -32768\)
            \(INT16\_MAX = 32767\)
        if isNaN(\(value\)) or isInf(\(value\)):
            return (false, 0)   // conversão inválida
        // opcional: escolher política de arredondamento; aqui usamos truncamento para zero
        \(rounded =\) trunc(\(value\))   // trunc elimina a parte fracionária em direção a zero
        if \(rounded < INT16\_MIN\) or \(rounded > INT16\_MAX\):
            return (false, 0)   // overflow detectado
        return (true, (int16)\(rounded\))
    
  • Explicações rápidas das chamadas usadas:
    • \text{isNaN}(\cdot) verifica se é not-a-number.
    • \text{isInf}(\cdot) verifica infinito positivo/negativo.
    • \text{trunc}(\cdot) remove a parte fracionária em direção a zero.
    • (int16) representa o cast seguro depois da verificação.

Passo 8

Pseudocódigo alternativo com saturação (útil em muitas aplicações)
function safe_cast_16_saturate(\(value\)):
    constants:
        \(INT16\_MIN = -32768\)
        \(INT16\_MAX = 32767\)
    if isNaN(\(value\)):
        return (false, 0)   // ou tratar NaN como 0, conforme necessidade
    if \(value <= INT16\_MIN\):
        return (true, INT16\_MIN)
    if \(value >= INT16\_MAX\):
        return (true, INT16\_MAX)
    // aqui \(value\) está no intervalo representável
    // pode optar por round() ou trunc(); vou usar round-to-nearest
    \(rounded =\) round(\(value\))
    // garantir que o arredondamento não saiu do intervalo (proteção extra)
    if \(rounded < INT16\_MIN\): \(rounded = INT16\_MIN\)
    if \(rounded > INT16\_MAX\): \(rounded = INT16\_MAX\)
    return (true, (int16)\(rounded\))
  • Comentário: esta versão nunca “explode” — sempre retorna um inteiro, mas pode alterar o valor original por saturação.

Resposta

V_{h,\max} = \dfrac{32767}{120} \approx 273{,}058333\ldots (maior valor real sem overflow). Se V_{h} deve ser inteiro: \left\lfloor\dfrac{32767}{120}\right\rfloor = 273.\nfunction safe_cast_16(\(value):\n constants:\n INT16\_MIN = -32768\n INT16\_MAX = 32767\n if isNaN( value) or isInf( value):\n return (false, 0)\n rounded = trunc( value)\n if rounded < INT16\_MIN or rounded > INT16\_MAX:\n return (false, 0)\n return (true, (int16) rounded))