Aritmética computacional
Contents
2. Aritmética computacional#
Computadores representam números inteiros de maneira exata [Recorte 9: Aritmética exata e números racionais]. Entretanto, números reais possuem apenas representações aproximadas e em quantidades finitas. A aritmética computacional comumente opera com números inteiros e com os chamados números em ponto flutuante.
O interesse da aritmética computacional resume-se em dois pontos principais: i) a representação de números no formato de máquina (binário) e ii) a construção de algoritmos que realizam as operações fundamentais (adição, subtração, multiplicação e divisão). Em linhas gerais, métodos numéricos resultam de algoritmos sofisticados que utilizam essas quatro operações.
Atualmente, o padrão IEEE 754 [Recorte 3: Padrão de Ponto Flutuante IEEE 754] é o mais amplamente seguido pelos fabricantes de processadores modernos. O documento orienta sobre como números em ponto flutuante devem ser representados, operados e comportar-se em qualquer arquitetura, seja de 16, 32, 64 ou mesmo 128 bits. A última atualização do padrão, cujo ano de origem é 1985, ocorreu em 2019 [IEEE 754-2019].
2.1. Unidade Lógica e Aritmética#
A Unidade Lógica e Aritmética (ULA) é a parte do hardware computacional conectada à unidade central de processamento (CPU) que realiza as operações aritméticas e lógicas sobre os dados processados (Fig. 2.1). A ULA é um componente eletrônico que funciona segundo a lógica dos cicuitos digitais, ou seja, interpretando operações em lógica Booleana (and
, or
, not
).
Há muito mais por trás das operações fundamentais executadas pelos computadores. Em Python, por exemplo, há casos de aproximações que chegam a ser curiosos. Isto ocorre devido ao erro inerente da representação numérica, principalmente quando os números são fracionários.

Fig. 2.1 Ilustração de um chip de computador destacando as interconexões responsáveis por operações lógicas, aritméticas e troca de informação com a unidade de controle.#
2.2. Casos curiosos#
A aritmética de ponto flutuante possui situações inusitadas e respostas estranhas que podem levar-nos a duvidar se estamos realizando operações corretamente. Abaixo, mostramos alguns casos curiosos que ocorrem devido à representação finita de números pelo computador. Outras indagações sobre ponto flutuante são respondidas em [Números em ponto flutuante e seus problemas].
A fração \(1/3 \approx 0.3333\ldots\) é uma dízima. O seu triplo é?
1/3
0.3333333333333333
1/3 + 1/3 + 1/3
1.0
A soma \(0.3 + 0.3 + 0.3\) difere de \(0.9\).
0.3 + 0.3 + 0.3
0.8999999999999999
\(1/10 + 1/10 + 1/10 \neq 3/10\)
1/10 + 1/10 + 1/10 == 3/10
False
Multiplicação por fracionários
# note a variabilidade de dígitos após o ponto
for x in [0.3, 0.33, 0.333, 0.3333, 0.33333, 0.333333, 0.3333333, 0.333333333]:
print(f'3*{x}'.ljust(13,' '),'=', 3*x, sep=' ')
3*0.3 = 0.8999999999999999
3*0.33 = 0.99
3*0.333 = 0.9990000000000001
3*0.3333 = 0.9999
3*0.33333 = 0.99999
3*0.333333 = 0.999999
3*0.3333333 = 0.9999998999999999
3*0.333333333 = 0.999999999
2.3. A finitude explicada#
Os casos acima possuem uma razão comum: a capacidade finita dos computadores para representar números fracionários. Vamos analisar de modo breve o caso da fração 1/10 sem nos aprofundar em detalhes.
Em um computador de arquitetura 64 bits que segue o padrão IEEE 754, a melhor aproximação para 1/10 é um número com 55 dígitos decimais.
# imprime número com 55 dígitos
print(format(0.1,'.55f'))
0.1000000000000000055511151231257827021181583404541015625
Notemos que tentar aumentar os dígitos não produzirá significância:
# imprime número com 60 dígitos
print(format(0.1,'.60f'))
0.100000000000000005551115123125782702118158340454101562500000
# imprime número com 80 dígitos
print(format(0.1,'.80f'))
0.10000000000000000555111512312578270211815834045410156250000000000000000000000000
Portanto, quando somamos 1/10 + 1/10 + 1/10 vemos um número diferente de 3/10.
# imprime número com 55 dígitos
print(format(0.1 + 0.1 + 0.1,'.55f'))
0.3000000000000000444089209850062616169452667236328125000
2.4. Notação científica#
Números em ponto flutuante são a versão computacional da notação científica. Escrevemos um número decimal em notação científica da seguinte forma:
com a fração (ou mantissa) \(f\) determinando a precisão e o expoente \(e\) a ordem de grandeza. Pontos flutuantes admitem \(f\) na forma normalizada, isto é, menor do que 1. A tabela abaixo mostra alguns exemplos de como usamos essas notações.
Número decimal |
Notação científica |
Repr. ponto flutuante |
---|---|---|
\(2.65\) |
\(2.65 \times 10^0\) |
\(0.265 \times 10^1\) |
\(0.0000012\) |
\(1.2 \times 10^{-6}\) |
\(0.12 \times 10^{-5}\) |
\(4532\) |
\(4.532 \times 10^{3}\) |
\(0.4532 \times 10^{4}\) |
Em termos de código, a notação científica em base 10 pode ser realizada da seguinte forma:
2.65e0, 1.2e-6, 0.4532e4, 1e1
(2.65, 1.2e-06, 4532.0, 10.0)
2.5. Conversão numérica entre sistemas#
Nesta seção são dados exemplos de como converter números entre os sistemas mais comuns: binário, decimal e hexadecimal.
# (100)_2 -> base 10
c = int('100',base=2)
print(c)
# representação
print(1*2**2 + 0*2**1 + 0*2**0)
# (4)_10 -> base 2
# obs: note que '0b' indica que o número é binário
c = bin(4)
print(c)
4
4
0b100
# (222)_8
c = int('222',base=8)
print(c)
# representação
print(2*8**2 + 2*8**1 + 2*8**0)
# (146)_10 -> base 8
c = oct(146)
# obs: note que '0o' indica que o número é octal
print(c)
146
146
0o222
# (2AE4)_16
c = int('2ae4',base=16)
print(c)
# representação
# obs: A = 10; E = 14
print(2*16**3 + 10*16**2 + 14*16**1 + 4*166**0)
# (146)_10 -> base 8
c = oct(146)
# obs: note que '0o' indica que o número é octal
print(c)
10980
10980
0o222
2.6. Máquina binária#
O código abaixo é um protótipo para implementação de uma máquina binária. Uma versão muito mais robusta e melhor implementada pode ser vista aqui: https://vnicius.github.io/numbiosis/conversor/index.html.
"""
Converte inteiro para binário
por divisões sucessvvvas.
! Confronte com a função residente 'bin()'
"""
def int2bin(N):
b = [] # lista auxiliar
# divisões sucessivas
while N >= 2:
b.append(N % 2)
N = N//2
b.append(N)
b.reverse()
b = [str(i) for i in b] # converte para string
s = ''
s = s.join(b)
return s # retorna string
"""
Converte parte fracionária para binário
por multiplicações sucessivas.
"""
def frac2bin(Q):
count = 0 # contador (limite manual posto em 10!)
b = [] # lista auxiliar
# multiplicações sucessivas
Q *= 2
while Q > 0 and count <= 10:
if Q > 1:
Q = Q-1
b.append(1)
else:
b.append(0)
Q *= 2
count += 1
b = [str(i) for i in b] # converte para string
s = ''
s = s.join(b)
return s # retorna string
def convert(app,btn):
print(btn)
# Função principal
def main():
# Pré-criação da interface com usuário
# todo: tratamento de exceção no tipo de entrada
# contagem de casas decimais no caso de dízimas
print('*** MÁQUINA BINÁRIA ***')
# N = input('Selecione a parte inteira:\n')
# Q = input('Selecione a parte fracionária:\n')
# print('Seu número é: ' + int2bin( int(N) ) + '.' + frac2bin( float(Q) ) + '.')
# print('*** ***')
if __name__ == "__main__":
main()
*** MÁQUINA BINÁRIA ***
2.7. Visualizando um sistema de ponto flutuante#
2.7.1. A reta “perfurada”#
Em vez de operar sobre o conjunto dos números reais (conjunto \(\mathbb{R}\)), a matemática computacional está definida no domínio \(\mathbb{F}\), o conjunto dos números em ponto flutuante representáveis pela máquina. Vejamos um exemplo.
Considerando o sistema de ponto flutuante \(\mathbb{F}(2,3,-1,2)\), determinemos todos os seus números representáveis.
Como a base é \(2\), os dígitos possíveis são \(0\) e \(1\) com mantissas:
\(0.100\)
\(0.101\)
\(0.110\)
\(0.111\)
Para cada expoente no conjunto \(e=\{-1,0,1,2\}\), obteremos 16 números positivos, a saber:
\((0.100 \times 2^{-1})_{2} = (0.01)_2 = 0.2^0 + 0.2^{-1} + 1.2^{-2} = 1/4\)
\((0.100 \times 2^{0})_{2} = (0.1)_2 = 0.2^0 + 1.2^{-1} = 1/2\)
\((0.100 \times 2^{1})_{2} = (1.0)_2 = 1.2^0 + 0.2^{-1} = 1\)
\((0.100 \times 2^{2})_{2} = (10.0)_2 = 1.2^1 + 0.2^{1} + 0.2^{-1} = 2\)
\((0.101 \times 2^{-1})_{2} = (0.0101)_2 = 0.2^0 + 0.2^{-1} + 1.2^{-2} + 0.2^{-3} + 1.2^{-4}= 5/16\)
\((0.101 \times 2^{0})_{2} = (0.101)_2 = 0.2^0 + 1.2^{-1} + 0.2^{-2} + 1.2^{-3} = 5/8\)
\((0.101 \times 2^{1})_{2} = (1.01)_2 = 1.2^0 + 0.2^{-1} + 1.2^{-2} = 1\)
\((0.101 \times 2^{2})_{2} = (10.1)_2 = 1.2^1 + 0.2^{1} + 0.2^{-1} = 2\)
(…)
Fazendo as contas para os números restantes, obtemos a seguinte tabela:
m |
0.100 |
0.101 |
0.110 |
0.111 |
|
---|---|---|---|---|---|
e |
|||||
-1 |
1/4 |
5/16 |
3/8 |
7/16 |
|
0 |
1/2 |
5/8 |
3/4 |
7/8 |
|
1 |
1 |
5/4 |
3/2 |
7/4 |
|
2 |
2 |
5/2 |
3 |
7/2 |
Na reta real, esses valores ficariam dispostos da seguinte forma:

Isto é, \(\mathbb{F}\) é uma reta “perfurada”, para a qual apenas 16 números positivos, 16 simétricos destes e mais o 0 são representáveis. Logo, o conjunto contém apenas 33 elementos.
2.8. Simulador de \(\mathbb{F}\)#
O código abaixa gera uma reta perfurada para o sistema computacional de interesse.
import numpy as np
import matplotlib.pyplot as plt
def simulacao_F(b,t,L,U):
x = []
epsm = b**(1-t) # epsilon de máquina
M = np.arange(1.,b-epsm,epsm)
E = 1
for e in range(0,U+1):
x = np.concatenate([x,M*E])
E *= b
E = b**(-1)
y = []
for e in range(-1,L-1,-1):
y = np.concatenate([y,M*E])
E /= b
yy = np.asarray(y)
xx = np.asarray(x)
x = np.concatenate([yy,np.array([0.]),xx])
return x
Y = simulacao_F(2,4,-3,5)
X = np.zeros(Y.shape)
# plotagem
fig, ax = subplots(figsize=(8,1),constrained_layout=True)
ax.scatter(Y,X,marker='o',color='g');
ax.get_yaxis().set_visible(False)

2.9. Limites de máquina para ponto flutuante#
Em Python, podemos utilizar diferentes sistemas de ponto flutuante. Cada um possui suas particularidades. Os mais comuns são:
float16
(meia precisão): ideal para aplicações onde a velocidade e o uso de memória são críticos, como em inferências de aprendizado profundo em dispositivos com recursos limitados.float32
(precisão simples): comumente usado em jogos, gráficos, e muitas aplicações de aprendizado de máquina devido ao bom equilíbrio entre precisão e eficiência.float64
(precisão dupla; alias parafloat
): essencial para simulações científicas, finanças e outras áreas onde a precisão é crucial e a memória não é preocupação.
O numpy
suporta todos os três na maioria dos computadores de hoje (Tabela 2.1).
Atributo |
|
|
|
---|---|---|---|
Tamanho |
16 bits (2 bytes) |
32 bits (4 bytes) |
64 bits (8 bytes) |
Precisão |
Baixa |
Moderada |
Alta |
Intervalo de Valores |
\(\approx 5.96 \times 10^{-8}\) a \(6.55 \times 10^{4} \) |
\(\approx 1.18 \times 10^{-38} \) a \(3.4 \times 10^{38} \) |
\(\approx 2.23 \times 10^{-308} \) a \(1.8 \times 10^{308} \) |
Bits de Sinal |
1 |
1 |
1 |
Bits de Expoente |
5 |
8 |
11 |
Bits de Mantissa |
10 |
23 |
52 |
Uso de Memória |
Muito baixo |
Moderado |
Alto |
Aplicações |
Aprendizado profundo em dispositivos de recursos limitados |
Gráficos de computador, simulações científicas, aprendizado de máquina |
Cálculos científicos, engenharia, finanças de alta precisão |
Exemplo de Valores |
\(3.140625\) para representar aproximadamente \(\pi\) |
\(3.1415927\) para representar aproximadamente \(\pi\) |
\(3.141592653589793\) para representar aproximadamente \(\pi\) |
Vantagens |
Usa menos memória e é mais rápido em termos de computação. Ideal para aplicações onde a memória é restrita e a precisão pode ser sacrificada. |
Oferece um bom equilíbrio entre precisão e uso de memória. Amplamente utilizado em gráficos e aprendizado de máquina. |
Alta precisão e amplo intervalo dinâmico. Ideal para cálculos científicos e de engenharia onde a precisão é crucial. |
Desvantagens |
Precisão muito limitada, o que pode levar a erros significativos em cálculos complexos. |
Pode não ser suficientemente preciso para cálculos científicos muito precisos. |
Usa mais memória e pode ser mais lento em termos de computação comparado com float16 e float32. |
A seguinte função imprime os valores dos principais atributos de numpy.finfo
que nos ajudam a entender melhor os limites de máquina em Python para esses sistemas de ponto flutuante.
import numpy as np
def print_attribute(dtype: str, attrib: str) -> None:
"""
Imprime informações de atributo para os sistemas de ponto flutuante \
de 16, 32 e 64 bits operados pelo numpy
Atributos relevantes:
- eps: menor valor x, tal que 1.0 + x > 1.0 (epsilon de máquina)
- max: maior número finito que pode ser representado pelo tipo de dado de ponto flutuante.
- min: menor número finito negativo que pode ser representado pelo tipo de dado de ponto flutuante.
- tiny: menor número positivo normalizado que pode ser representado.
- nexp: número de bits no expoente
- nmant: número de bits na mantissa
"""
# checagem de sistema permitido
assert dtype in ['float16', 'float32', 'float64'], 'Sistema não permitido!'
# impressão
print(f'{attrib}:')
exec(f'print(np.finfo(np.{dtype}).{attrib})')
# # função para calculo do epsilon: erro relativo
# def eps_mach(func=float):
# eps = func(1)
# while func(1) + func(eps) != func(1):
# epsf = eps
# eps = func(eps) / func(2)
# return epsf
A partir daí, podemos verificar os valores para cada sistema individualmente:
print('--- float16 \n')
for attrib in ['eps', 'max', 'min', 'tiny', 'nexp', 'nmant']:
print_attribute('float16', attrib)
print('\n--- float32 \n')
for attrib in ['eps', 'max', 'min', 'tiny', 'nexp', 'nmant']:
print_attribute('float32', attrib)
print('\n--- float64 (float) \n')
for attrib in ['eps', 'max', 'min', 'tiny', 'nexp', 'nmant']:
print_attribute('float64', attrib)
--- float16
eps:
0.000977
max:
65500.0
min:
-65500.0
tiny:
6.104e-05
nexp:
5
nmant:
10
--- float32
eps:
1.1920929e-07
max:
3.4028235e+38
min:
-3.4028235e+38
tiny:
1.1754944e-38
nexp:
8
nmant:
23
--- float64 (float)
eps:
2.220446049250313e-16
max:
1.7976931348623157e+308
min:
-1.7976931348623157e+308
tiny:
2.2250738585072014e-308
nexp:
11
nmant:
52
2.9.1. O épsilon de máquina#
A unidade de arredondamedssdnto, \(\epsilon_M\), comumente chamada de “épsilon de máquina”, é definida como o menor número do sistema computacional tal que
Esta inequação também pode ser lida da seguinte forma: \(\epsilon_M\) é a diferença entre a unidade e o próximo número mais próximo dela representável pela máquina.
Para entender isto, vamos usar um sistema hipotético de 8 bits, no qual cada número é representado por uma sequencia de até 8 dígitos binários. Em um sistema de 8 bits, uma “palavra” (termo da Arquitetura Computacional) armazena um número real da seguinte forma:
o primeiro bit é reservado para o sinal do número
os próximos 3 bits são reservados para o expoente (com bias)
os últimos 4 bits são reservados para a mantissa.
Neste sistema, a unidade \((1)_{10}\) é representada em forma binária por: \(00110000\).
O próximo número de máquina neste sistema seria \(00110001\), que equivale a \((1.0625)_{10}\).
Portanto, para este sistema \(\epsilon_M = (1.0625)_{10} - (1)_{10} = 0.0625\).
Explicando um pouco mais…
Para 8 bits, o bias é o quociente inteiro resultante da divisão de \((2^3 - 1)/2 = 3\). Então, usando a expressão de ponto flutuante
temos que
\(c = 0 \times 2^2 + 1 \times 2^1 + 1 \times 2^0 = 3\) (esquerda para a direita, correspondendo às posições 2,3 e 4). Como o número é positivo, \(s = 0\). A mantissa corresponde às 4 últimas caixas, que são zero, i.e. \(f = 0\).
Por fim, \(x = (-1)^0 \, 2^{(3-3)} \, (1+0) = 1\) e a representação de 8 bits de 1 é \(00110000\).
Para \(\epsilon_M\), note que o próximo número tem uma contribuição de \(2^{-4} = 0.0625\). Ou seja, a mantissa decresce para a direita \(2^{-1}, 2^{-2}, 2^{-3}, 2^{-4}\). O ponto “decimal” (radix) fica implícito e o expoente cresce para a esquerda, \(2^0, 2^1\), e \(2^2\).
Em seguida, o próximo número representável (depois de \(1.0625\)) teria uma contribuição de \(2^{-4} + 2^{-3} = 0.1875\), sendo, pois, \(1.1875\). Evidentemente, \(1.1875 - 1.0625 = 0.125\), mas \(\epsilon_M < 0.125\). Isto mostra que a unidade de arredondamento não equivale a uma “distância” no sentido dos números reais como se vê na representação de reta perfurada.
2.9.2. Sensibilidade#
O efeito de \(\epsilon_M\) em cálculos pode ser mostrado na figura abaixo. Quando subtraímos 1 de valores de \(\epsilon\) cada vez menores, a subtração no denominador da fração
começa a se aproximar de zero por cancelamento subtrativo e o valor de \(f\) torna-se cada vez mais instável até cair a “zero”.

2.10. Valores especiais#
O padrão IEEE 754 traz alguns valores especiais para representar cadeias de bits especiais. São eles:
NaN (not a number): representa um valor que é um erro.
Inf (infinity): representa o infinito (em ambos os sentidos, positivo e negativo).
A partir desses valores especiais, operáveis pelo módulo numpy com numpy.nan
e numpy.inf
, respectivamente, podemos imitar operações matemáticas “equivalentes”. Primeiramente, façamos:
from numpy import nan, inf
2.10.1. Operações especiais#
\(n \div \pm \infty \to \pm 0, n \in \mathbb{F}\)
2.1/inf, -4/inf, 5.2/-inf, 6/-inf
(0.0, -0.0, -0.0, -0.0)
\(\pm \infty \times \pm \infty \to \pm \infty\)
inf*inf, inf*(-inf), -inf*inf, (-inf)*(-inf)
(inf, -inf, -inf, inf)
\(n \div \pm 0 \to \ \ !, n \in \mathbb{F}^{*}\)
1/0, -2/0, 3/(-0), 4/(-0)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In [24], line 1
----> 1 1/0, -2/0, 3/(-0), 4/(-0)
ZeroDivisionError: division by zero
\(n \times \pm \infty \to \pm \infty, n \in \mathbb{F}\)
1*inf, -2*inf, 3.1112*(-inf), -111*(-inf)
\(\pm \infty \pm \infty \to \pm \infty \vee \text{nan}\)
inf + inf, inf - inf, - inf + inf, -inf - inf
\(\pm 0 \div \pm 0 \to \ \ !\)
0/-0
\(\pm \infty \div \pm \infty \to \text{nan}\)
inf/inf, inf/-inf, -inf/inf, -inf/-inf
\(\pm \infty \times 0 \to \text{nan}\)
inf*0, -inf*0
\(\text{nan} \neq \text{nan}\)
nan == nan, nan != nan
2.11. Exemplos#
2.11.1. Sistema de 16 bits#
Comporta faixa de binários de \(0000000000000000\) a \(1111111111111111\)
Limite superior: \((1 \times 2^{14}) + (1 \times 2^{13}) + \ldots + (1 \times 2^1) + (1 \times 2^0) = 32767\)
Uma vez que \(+0 = 0000000000000000\), \(-0 = 1000000000000000\) é um negativo a mais
Intervalo de inteiros representáveis: \([-32768,32767]\)
2.11.2. Limites de underflow e overflow#
Para o sistema \(\mathbb{F}(10,3,-5,5)\), vejamos os seguintes casos:
2.11.2.1. Caso I: número representável x número não representável#
\(x = 235.89 = 0.23589 \times 10^3\) (5 dígitos na mantissa)
\(0.235 \times 10^3\) e \(0.236 \times 10^3\) são representáveis
\(0.23589 \times 10^3\) não é representável (perda de dígitos significativos)
2.11.2.2. Caso II: número não representável por causa de underflow#
\(x = 0.654 \times 10^{-7}\) (expoente rompeu o limite \(L=-5\))
2.11.2.3. Caso III: número não representável por causa de overflow#
\(x = 0.923 \times 10^{12}\) (expoente rompeu o limite \(U=5\))
Considere \(\mathbb{F}(2,3,-1,2)\). Represente os seguintes números, dados na base \(10\), neste sistema de ponto flutuante normalizado.
a) \(x = 0.25\)
b) \(x = 3.5\)
c) \(x = 0.125\)
d) \(x = 4\)
e) \(x = 0.3\)
2.11.2.4. Solução#
Devemos ter \(x = \pm 0.d_1d_2d_3 \times 2^e\), com \(d_1 =1\), \(d_2 \in \left\{0, 1\right\}\), \(d_3 \in \left\{0, 1\right\}\) e \(e \in \left\{-1, 0, 1, 2 \right\}\).
a) \(x = 0.25\)
Note que, \((0.25)_{10} = (0.01)_2 = 0.1 \times 2^{-1}\), i.e. \(d_1 = 1\) e \( e = -1\). Logo, a representação de \(x\) neste sistema de ponto flutuante é: \(x = + \,0.100 \times 2^{-1}\).
b) \( x = 3.5\)
Aqui: \((3.5)_{10} = (11.1)_2 = 0.111 \times 2^{2}\), i.e. \(d_1 = 1\) e \(e = 2\). Como \(2_{10} = (10)_2\), a representação de \(x\) neste sistema de ponto flutuante é: \(x = + \, 0.111 \times 2^{10}\).
c) \(x = 0.125\)
Aqui: \((0.125)_{10} = (0.001)_2 = 0.1 \times 2^{-2}\) , i.e, \(d_1 = 1\) e \(e = -2\). Como \(e < L = -1\), temos underflow (não representável).
d) \(x = 4\)
Note que, \((4)_{10} = (100)_2 = 0.1\times 2^{3}\), i.e \(d_1 = 1\) e \(e = 3\). Como \(e > U = 2\), temos overflow (não representável).
e) \(x = 0.3\)
Note que, \((0.3)_{10} = (0.0\,1001\,1001\dots)_2 =(0.1001\,1001\dots)\times 2^{-1}\), i.e. \(d_1 = 1\) e \(e = {-1}\). Como devemos ter apenas 3 dígitos, este número não é representável neste sistema de ponto flutuante.
Se truncarmos em 3 dígitos, então temos uma aproximação para \(x\) dada por $\(0.100 \times 2^{-1} =(0.0100)_2 = \\ 0\times \frac{1}{2} + 1\times \frac{1}{4} + 0 \times \frac{1}{8}+ 0 \times \frac{1}{16} + 0 \times \frac{1}{32} = \\ (0.25)_{10} \ne (0.3)_{10}.\)$
2.11.3. Maior e menor número representável#
Considerando o mesmo sistema de ponto flutuante do exemplo anterior, determinar:
a) O menor número real positivo representável neste sistema
b) O maior número real positivo representável neste sistema
2.11.3.1. Solução#
O menor número real positivo representável neste sistema é
O maior número real positivo representável neste sistema é $\(x_{max} = 0.111\times 2^2 = (11.1)_{2} = 1\times 2^1 + 1 \times 2^0 + 1\times \frac{1}{2} =(3.5)_{10}.\)$
Lembre que no Exemplo 1.4, c), com \(x = (0.125)_{10}\), e no Exemplo 1.4 d), com \( x = 4_{10}\), tivemos situações de underflow e overflow, respectivamente.
Já no Exemplo anterior, e), com \(x = (0.3)_{10}\), tivemos truncamento/aproximação.
2.11.4. Números representáveis#
Determinar todos os números reais que são representáveis exatamente no sistema \(\mathbb{F}(2,3,-1,2)\).
2.11.4.1. Solução#
Como \( t = 3 \), as possíveis mantissas não nulas são: \( (0.100)_2, (0.101)_2, (0.110)_2 \) e \((0.111)_2 \). Como \(L=−1\) e \(U=2\), os possíveis expoentes são: \(−1 0,1\) e \(2\). Assim, os números positivos com representação exata são:
Portanto, temos apenas 33 números reais representáveis exatamente neste sistema. Todos os acima e os negativos, i.e.: