Questão 7 (Exercício de Programação). Admita:
Sugira um código para truncamento e um código para arredondamento, considerando que o número
seja representado por uma quantidade
de dígitos, com
a)
b)
a)
b)
Passo 1
O enunciado dá os parâmetros do formato de ponto-flutuante:
,
,
,
.
Pede-se: sugerir um código (algoritmo) para realizar
Pede-se: sugerir um código (algoritmo) para realizar
- truncamento, e
- arredondamento,
quando um númeroé representado por dígitos da mantissa, nos dois casos:
a)(ou seja, já cabe na precisão),
b)(ou seja, precisa reduzir para dígitos).
Informações relevantes que vamos usar (tudo extraído do enunciado ou necessário para resolver):
- Base do sistema:
. - Precisão desejada:
dígitos significativos. - Limites de expoente:
(mínimo) e (máximo) — importantes para detectar underflow/overflow se o arredondamento alterar o expoente. - Representação canônica assumida: um número normalizado é representado por sinal
, vetor de dígitos da mantissa com , expoente e
- A variável
é o número atual de dígitos disponíveis na mantissa de .
O objetivo técnico: fornecer pseudocódigo claro e robusto para os dois procedimentos (truncamento e arredondamento), tratando separadamente
e
, incluindo tratamento de carry no arredondamento e verificação de limites de expoente (
).
Passo 2
Entender o que significa cada operação (aula rápida e intuitiva):
Truncamento:
- Significa simplesmente cortar (descartar) todos os dígitos além do
-ésimo, sem alterar os dígitos mantidos. Ex.: em base , com , truncado para dá .
Arredondamento (regra usual “arredondar para o mais próximo”):
- Olha-se o dígito imediatamente após o
-ésimo (ou seja, ). - Se
então mantém-se os primeiros dígitos (igual ao truncamento). - Se
então incrementa-se o -ésimo dígito em 1 (com propagação de carry se necessário). - Se
a regra mais comum é arredondar para par ou simplesmente arredondar para cima (aqui usaremos a regra simples: arredondar para cima quando ). Em , o limiar é .
Efeito de carry no arredondamento:
- Se após incrementar o dígito
ele fica igual a , então esse dígito vira e propagamos 1 para , etc. - Se todos os dígitos até
causarem carry (ex.: incrementando), obtemos uma situação como — normalizamos transformando isso em e incrementamos em 1. Isso pode causar overflow se .
Underflow/Overflow:
- Se o incremento do expoente fizer
reportar overflow (p.ex. representar como ±infinito no sistema). - Se a operação resultasse em expoente
(pouco provável apenas por truncamento, mas pode ocorrer em representações subnormais), teria underflow. Aqui vamos apenas sinalizar se ocorrer.
Passo 3
Caso geral
(não é preciso reduzir):
- Explicação: se o número já tem no máximo
dígitos significativos, tanto truncamento quanto arredondamento deixam os dígitos iguais (podemos opcionalmente preencher zeros até para padronizar a mantissa). - Código (ideia): retornar os dígitos originais (ou os mesmos dígitos com zeros à direita até completar
). - Exemplo simples:
, se com , então resultado será se quisermos dígitos explícitos.
Passo prático (pseudocódigo explicado em palavras):
- Se
então - para truncamento: devolver mantissa
(com zeros até dígitos) e expoente . - para arredondamento: fazer o mesmo (não há dígito
para decidir mudança).
- para truncamento: devolver mantissa
Passo 4
Caso
— algoritmo do truncamento (passo a passo didático e código):
Lógica:
- Mantemos os primeiros
dígitos . - Discardamos
. - O expoente
não muda. - Não há carry a propagar porque não incrementamos nada.
- Verificação simples: depois do truncamento, a mantissa ainda está normalizada (pois
era não nulo e permanece).
Pseudocódigo (estilo Python-like, com variáveis matemáticas em destaque):
Truncamento:
function TRUNCATE(sign, digits, exponent, ,
):
# digits é lista com
len(digits)
if len(digits)
:
return (sign, digits padded with zeros to length , exponent)
else:
new_digits = first entries of digits # keep
return (sign, new_digits, exponent)
Truncamento:
function TRUNCATE(sign, digits, exponent,
# digits é lista
if len(digits)
return (sign, digits padded with zeros to length
else:
new_digits = first
return (sign, new_digits, exponent)
Explicação de cada linha:
- “padded with zeros” significa acrescentar zeros à direita para que a mantissa tenha exatamente
dígitos. - “first
entries” é a operação de cortar.
Passo 5
Caso
— algoritmo do arredondamento (passo a passo didático e código):
Lógica:
- Olhar o dígito seguinte
. - Se
então o resultado é igual ao truncamento. - Se
então incrementamos em 1 e realizamos a propagação de carry para a esquerda até que não haja mais carry ou até atingir . - Se a propagação provoca um overflow nos dígitos (isto é, além de
ainda há carry), então transformamos a mantissa em (com dígitos: seguido de zeros) e fazemos . - Após possível incremento do expoente, verificar limites: se
sinalizar overflow; se sinalizar underflow (se houver redução do expoente, o que normalmente só ocorre em casos especiais).
Pseudocódigo (com detalhes de carry e verificações):
function ROUND(sign, digits, exponent, ,
,
,
):
j = len(digits)
if j
:
# não há dígito extra para decidir arredondamento
return (sign, digits padded with zeros to length , exponent)
# j > t
prefix = first digits of digits # (d1,…,dt)
next_digit = digits[ ] # d_{t+1}, index baseado em 0 em pseudocódigo
if next_digit < floor( ):
return (sign, prefix, exponent) # igual ao truncamento
else:
# devemos incrementar prefix como um inteiro em base beta
i = - 1 # índice do último dígito em prefix (0-based)
carry = 1
while i >= 0 and carry == 1:
prefix[i] = prefix[i] + 1
if prefix[i] == :
prefix[i] = 0
carry = 1
i = i - 1
else:
carry = 0
if carry == 1:
# houve overflow nos dígitos: mantissa vira 1.000… e expoente aumenta
prefix = [1] + [0]*( -1)
exponent = exponent + 1
if exponent > :
signal overflow and return representation inf (segundo convenção)
return (sign, prefix, exponent)
function ROUND(sign, digits, exponent,
j = len(digits)
if j
# não há dígito extra para decidir arredondamento
return (sign, digits padded with zeros to length
# j > t
prefix = first
next_digit = digits[
if next_digit < floor(
return (sign, prefix, exponent) # igual ao truncamento
else:
# devemos incrementar prefix como um inteiro em base beta
i =
carry = 1
while i >= 0 and carry == 1:
prefix[i] = prefix[i] + 1
if prefix[i] ==
prefix[i] = 0
carry = 1
i = i - 1
else:
carry = 0
if carry == 1:
# houve overflow nos dígitos: mantissa vira 1.000… e expoente aumenta
prefix = [1] + [0]*(
exponent = exponent + 1
if exponent >
signal overflow and return representation inf (segundo convenção)
return (sign, prefix, exponent)
Notas didáticas:
- Em
, . Assim, se arredondamos para cima. - O laço while implementa a propagação do carry. Se todos os dígitos se tornarem zero por causa do carry, criamos a mantissa normalizada
e incrementamos .
Passo 6
Exemplos numéricos (para fixar): usando
,
Exemplo A (truncamento simples):
-
. Aqui . - TRUNCATE: mantissa fica
→ com interpretado como (ou padronizando: com três dígitos fracionários? manter consistência: mantissa significa se interpretarmos duas casas fracionárias; atenção: estamos usando o formato então o valor é se os dígitos originais foram — a ideia é cortar após 3 dígitos mantidos).
Exemplo B (arredondamento com carry):
-
. então incrementa de para . Resultado: . - Caso crítico:
com . Prefixo , próximo dígito . Incrementar produz carry até além de , transformando prefixo em e expondo . Portanto o número arredondado fica (e verificar se não excede ).
Resposta
Truncamento (pseudocódigo):
function TRUNCATE(sign, digits, exponent, ,
):
j = len(digits)
if j
:
return (sign, digits + [0]*( -j), exponent)
else:
new_digits = digits[0: ] # keep (d_1,…,d_t)
return (sign, new_digits, exponent)
function TRUNCATE(sign, digits, exponent,
j = len(digits)
if j
return (sign, digits + [0]*(
else:
new_digits = digits[0:
return (sign, new_digits, exponent)
Arredondamento (pseudocódigo):
function ROUND(sign, digits, exponent, ,
,
,
):
j = len(digits)
if j
:
return (sign, digits + [0]( -j), exponent)
prefix = digits[0: ] # (d_1,…,d_t)
next_digit = digits[ ] # d_{t+1}
if next_digit < floor( ):
return (sign, prefix, exponent)
else:
i = - 1
carry = 1
while i >= 0 and carry == 1:
prefix[i] = prefix[i] + 1
if prefix[i] == :
prefix[i] = 0
carry = 1
i = i - 1
else:
carry = 0
if carry == 1:
prefix = [1] + [0]( -1)
exponent = exponent + 1
if exponent > :
signal overflow (represent as ±inf or conforme ao sistema)
return (sign, prefix, exponent)
function ROUND(sign, digits, exponent,
j = len(digits)
if j
return (sign, digits + [0](
prefix = digits[0:
next_digit = digits[
if next_digit < floor(
return (sign, prefix, exponent)
else:
i =
carry = 1
while i >= 0 and carry == 1:
prefix[i] = prefix[i] + 1
if prefix[i] ==
prefix[i] = 0
carry = 1
i = i - 1
else:
carry = 0
if carry == 1:
prefix = [1] + [0](
exponent = exponent + 1
if exponent >
signal overflow (represent as ±inf or conforme ao sistema)
return (sign, prefix, exponent)