Análise da aritmética em ponto flutuante;
Normatização;
Erros.
A aritmética em ponto flutuante é uma representação numérica amplamente utilizada em computação e ciência da computação para lidar com números reais. Nesse sistema, os números são representados por uma mantissa (ou significante) e um expoente, permitindo a representação de um vasto conjunto de valores. Essa abordagem é especialmente útil em situações em que os números podem variar em magnitude, pois permite uma maior precisão em uma faixa ampla de valores numéricos.
Um dos padrões mais comuns para a aritmética em ponto flutuante é o padrão IEEE 754, que foi introduzido em 1985 e tem sido amplamente adotado pela indústria de computação. Esse padrão define formatos para representação binária de números em ponto flutuante de precisão simples (32 bits) e dupla precisão (64 bits), entre outros.
No entanto, é importante destacar que a aritmética em ponto flutuante não é isenta de problemas. Devido às limitações da representação finita em binário, certos números racionais não podem ser exatamente representados em ponto flutuante, levando a erros de arredondamento. Além disso, operações aritméticas que envolvem números em ponto flutuante também podem levar a perda de precisão e acúmulo de erros, especialmente em cálculos iterativos ou que envolvam números com magnitudes muito diferentes.
A normatização é uma abordagem fundamental para minimizar esses erros em cálculos em ponto flutuante. Ela consiste em representar os números de tal forma que o bit mais significativo da mantissa seja sempre 1, eliminando a necessidade de armazenar esse bit e, assim, aumentando a precisão da representação. Além disso, a normatização permite distinguir valores especiais, como zero, infinito e NaN (Not a Number), que podem surgir em cálculos envolvendo números em ponto flutuante.
Nesse contexto, a análise da aritmética em ponto flutuante refere-se ao estudo dos erros associados a operações aritméticas realizadas em números representados dessa maneira. Compreender esses erros e suas propriedades é essencial para garantir a confiabilidade e a precisão dos resultados obtidos em aplicações computacionais, especialmente em áreas sensíveis, como engenharia, ciências e finanças.
Este texto tem como objetivo fornecer uma introdução aos conceitos básicos da aritmética em ponto flutuante, explorando a normatização como uma ferramenta para mitigar erros e destacando a importância da análise desses erros em cálculos numéricos. A compreensão desses fundamentos é essencial para desenvolver algoritmos robustos e garantir que as aplicações computacionais forneçam resultados precisos e confiáveis.
Bons estudos!
Um número qualquer pode ser representado por qualquer base, sendo a mais usual no dia a dia a base decimal (10). Além dessa, outras bases muito utilizadas são a binária (2), amplamente empregada em sistemas digitais, a base octal (8) e a hexadecimal (16). Neste material, será dada maior ênfase às bases decimal e binária.
Nas tabelas 1 e 2 alguns dos valores nas bases mais conhecidas.
Um número qualquer N pode ser descrito pelo polinômio a seguir:
Um número representado através de determinada base pode ser representado em outra base. No entanto, a mudança de base pode gerar erros, uma vez que um determinado número pode ter representação exata em uma base e não possuir representação exata em outra base. A seguir, são apresentados os métodos para conversão de uma base qualquer β para a base decimal, assim como da base decimal para uma base β.
Para esta conversão, basta aplicar o polinômio do item 1.1., substituindo o valor de β e dos coeficientes conhecidos.
Exemplo 1 de mudança de base: Converter o número binário 11011 para decimal.
O número na base decimal é 27(10).
Exemplo 2 de mudança de base: converter o número binário 10110000 para decimal.
O número na base decimal é 176(10).
Outros exemplos:
a) (11011)2 = 1 x 24 + 1 x 23 + 0 x 22 + 1 x 21 + 1 x 20 = (27)10
b) (10,011)2 = 1 x 21 + 0 x 20 + 0 x 2–1 + 1 x 2–2 + 1 x 2–3 = (2,375)10
Observe que os números após a vírgula da base recebem o expoente negativo decrescente.
c) (0430)8 = 0 x 83 + 4 x 82 + 3 x 81 + 0 x 80 = (280)10
Observe que a base agora é Octa, então a base = 8
d) (3AF)16 = 3 x 162 + 10 x 161 + 15 x 160 = (943)10
Observe que a base agora é Hexadecimal, então a base = 16
A letra “A” tem valor de 10 e a letra “F” igual a 15.
Para realizar a mudança da base decimal para uma base β, é mais conveniente adotar procedimentos diferenciados para a parte inteira e para a parte fracionária. Dessa forma, para a parte inteira, basta realizar a divisão inteira do número N por β, até que o quociente seja maior que zero e menor que β. O resultado na nova base será obtido a partir do quociente seguido dos restos em ordem inversa, como no exemplo a seguir:
Assim o número (26)10 = (11010)2, e, para verificar, basta utilizar o polinômio para transformar novamente em decimal. Vamos verificar.
Já para a parte fracionária, adota-se outro método. Multiplica-se a parte fracionária do número original pela base. A nova representação é obtida a partir do resultado inteiro das multiplicações, como apresentado a seguir:
Observa-se que, nesse exemplo, a representação na base binária não é exata, pois o resultado da parte fracionária no último cálculo realizado ainda não foi nulo.
Outro exemplo transforma em decimal o número (0,625)10.
A solução para transformar decimal fracionário em binário é multiplicarmos apenas parte fracionária por 2 sucessivas vezes até a parte fracionária ser igual a zero ou o número repetir uma sequência. A parte inteira sempre será 0 ou 1.
Como exercício, faremos o caminho inverso colocando na forma decimal.
Em muitos casos, temos números com parte inteira e fracionária, ou seja, misto na forma decimal para transformar em binário. Então, devemos aplicar os dois processos em separado.
Exemplo: transforme o número (37,375)10 em binário.
Para fazer isso, primeiro vamos transformar a parte inteira, ou seja, o 37.
Assim, na parte inteira temos (100101)2, mas ainda falta a parte fracionária. Tomando apenas esta, faremos como no exemplo anterior.
Um número inteiro N geralmente é armazenado e tratado em uma máquina digital como uma sequência de n bits, ou seja:
N = dn–1dn–2 … d1d0
Com essa representação, N pode representar qualquer valor inteiro de zero até 2n −1, ou ainda 2n valores. No entanto, se for necessário atribuir um sinal a esse número, podem ser empregados mais de um método, conforme visto a seguir.
Os computadores lidam com números positivos e números negativos, sendo necessário encontrar uma representação para números com sinal negativo.
Sinal e amplitude/magnitude (S+M)
Complemento para 1
Complemento para 2
Notação em excesso (ou biased)
Consiste na utilização de um dos bits para representação do sinal, sendo geralmente o bit mais significativo (mais à esquerda). Supondo um número representado por 32 bits, tem-se:
Essa forma apresenta duas possibilidades para representação do zero (+0 e − 0). Podem ser representados 2n − 1 valores na faixa de −(2n–1 − 1) até +(2n–1 − 1).
Neste caso, o primeiro bit representa um termo aditivo −(2n–1 − 1) e o restante dos bits representa um inteiro não negativo, conforme representado a seguir:
A seguir, são apresentados dois exemplos de representação utilizando o complemento de um:
a) (01001101)2 = 1 x 26 + 0 x 25 + 0 x 24 + 1 x 23 + 1 x 22 + 0 x 21 + 1 x 20 − 0 x (27 − 1) =
(01001101)2 = 1 x 26 + 1 x 23 + 1 x 22 + 1 x 20 − 0 x (27 − 1) = (77)10
O primeiro zero à esquerda é para indicar que o número é positivo.
b) (10110010)2 = 1 x 25 + 1 x 24 + 1 x 21 − 1 x (27 − 1) = (−77)10
(10110010)2 = 1 x 25 + 1 x 24 + 1 x 21 − 1 x (27 − 1) = (−77)10
Com base nesses exemplos, percebe-se que a troca de sinal é obtida através da inversão de cada bit de representação do número. A faixa de valores é igual à do caso anterior.
Neste caso, o primeiro bit representa um termo aditivo −(2n–1) e o restante dos bits representa um inteiro não negativo, conforme representado a seguir:
Ao contrário das representações anteriores, o zero possui uma única representação (000 … 000)2 e podem ser representados 2n valores diferentes na faixa entre −2n–1 até 2n–1 − 1. O exemplo a seguir mostra os mesmos valores do exemplo anterior nessa forma de representação:
a) (01001101)2 = 1 ∙ 26 + 1 ∙ 23 + 1 ∙ 22 + 1 ∙ 20 − 0 ∙ (27) = (77)10
b) (10110011)2 = 1 ∙ 25 + 1 ∙ 24 + 1 ∙ 21 + 1 ∙ 20 − 1 ∙ (27) = (−77)10
Nesse exemplo, percebe-se que o valor negativo pode ser obtido através do número resultante da inversão de cada bit (complemento de um) somado a uma unidade.
Esse método de representação é o mais utilizado atualmente por máquinas digitais.
É uma forma de representação no qual a precisão é fixa e finita. Considerando um número N como a representação de dois números inteiros P e Q, tem-se:
N = P, Q
A representação de N possuirá n = p + q + 1 bits, sendo p o número de bits de P e q o número de bits de Q. N ainda pode ser representado como N(p, q). Abaixo, são apresentadas formas semelhantes para representação utilizando o complemento de dois:
A seguir, são apresentados exemplos de números de 8 bits com notação de ponto fixo onde foi utilizado o complemento de dois para representação da parte inteira.
a) N(5,2)2 = 01101101
N = ((1101101)2 − 0 x 27) ∙ 2–2 = (27,25)10
Ou...
N = ((11011)2 − 0 x (25)) + (0,01)2
N = (27 − 0) + (0,25) = (27,25)10
b) N(5,2)2 = 10010011
N = ((0010011)2 − 1 ∙ 27) ∙ 2–2 = (−27,25)10
Ou...
N = ((00100)2 − 1 ∙ (25)) + (0,11)2
N = (4 − 32) + (0,75) = (−27,25)10
c) N(3,4)2 = 01101101
N = ((1101101)2 − 0 ∙ 27) ∙ 2–4 = (6,8125)10
Ou...
N = ((110)2 − 0 ∙ (23)) + (0,1101)2
N = (6 − 0) + (0,8125) = (6,8125)10
Dessa forma, podem ser representados valores fracionários no intervalo de −2p até (2p − 2–q) em intervalos de 2–q.
Se em alguma operação o resultado for menor em módulo que 2–q, diz-se que houve um erro de underflow. Já se o resultado for menor que −2p ou maior que (2p − 2–q), diz-se que houve um erro de overflow.
A notação de ponto fixo apresenta algumas características indesejáveis, por exemplo, se forem atribuídos muitos dígitos à parte fracionária, o valor máximo representável se torna pequeno. Por outro lado, com poucos dígitos destinados à parte fracionária, o problema será com valores muito pequenos.
A notação de ponto flutuante representa uma solução para esse problema. Nesse caso, alguns bits são designados como expoentes de um número “principal” (matissa). A seguir, é representado um número x com essa notação:
Onde:
β é a base numérica;
di são números inteiros contidos no intervalo 0 ≤ di < β; i = 1, 2, … , t;
d1 ≠ 0;
e é o expoente de β, contido no intervalo e1 ≤ e ≤ e2;
e1 e e2 são os limites inferior e posterior do expoente, respectivamente;
t é o número de dígitos significativos do sistema de representação ou precisão da máquina.
Observação: o número zero é representado como 0,00 … 0 ∙ βe.
O sistema de ponto flutuante F(β, t, e1, e2) é definido como o conjunto de números que inclui o zero e os pontos flutuantes em base β com t dígitos de precisão e expoente entre e1 e e2.
Cabe salientar que nesse sistema de numeração, ao contrário dos anteriores, o espaçamento não é igual entre os números representados. Por exemplo, considerando a representação no formato F(10,1, −1,1), tem-se:
Uma propriedade importante dos números representados por pontos flutuantes diz respeito às propriedades algébricas, sendo diferente dos números reais, racionais ou inteiros, por exemplo:
x ⊕ y ≠ x + y x ⊗
y ≠ x × y
(x ⊕ y) ⊕ z ≠ x ⊕ (y ⊕ z)
x ⊗ (y ⊕ z) ≠ (x ⊗ y) ⊕ (x ⊗ z)
Onde ⊕ e ⊗ representam a soma e a multiplicação em ponto flutuante, respectivamente.
Como exemplo prático, considerando x = 0,10 ∙ 10–3 e y = z = 0,10 ∙ 105, com elementos de um conjunto F(10, 2, −10, 10), tem-se que:
a) x ⊕ (y ⊖ z) = 0,10 ∙ 10–3
b) (x ⊕ y) ⊖ z = 0,00 ∙ 100
Quando se utiliza uma solução numérica, através do emprego de algoritmos numéricos, para obter a solução de um problema real geralmente essa solução não será exata.
Simplificação do modelo matemático;
Erro nos dados de entrada;
Truncamento (por exemplo, substituição de um processo infinito por um finito);
Erro de arredondamento em aritmética de ponto flutuante.
A seguir, serão abordados alguns tipos de erros de interesse em métodos numéricos:
Erro de arredondamento: é um erro global resultante da aplicação de um método numérico.
Arredondamento para baixo ou por falta (∇Y);
Arredondamento para cima ou por excesso (ΔY);
Arredondamento para o número de máquina mais próximo (0Y).
Erro de truncamento: é proveniente de processos que deveriam ser infinitos ou muito grandes para determinação de um valor. Por razões práticas, esses processos são truncados, ou seja, o cálculo é interrompido quando uma determinada precisão é atingida;
Erro relativo: é definido como o módulo do erro absoluto dividido pelo valor aproximado:
Precisão: é dada pelo número de dígitos na mantissa;
Exatidão: é uma medida de quanto próxima uma aproximação está do seu valor exato;
Épsilon da máquina: dá uma ideia da exatidão da máquina. É o menor número de ponto flutuante tal que 1 + s > 1. Abaixo, é apresentado o código fonte em C de um exemplo de software para determinação do épsilon:
É um parâmetro alternativo ao cálculo do erro absoluto ou relativo, pois, para o cálculo deles, é necessário conhecer o valor exato (o que nem sempre é possível):
No segundo caso, tem-se o DIGSE de xk+1 em relação a xk (interação anterior), sendo:
É o padrão recomendado pelos institutos ANSI (American National Standard Institute) e IEEE (Institute of Electrical and Electronic Engineers) para aritmética binária de ponto flutuante.
As normas desse padrão se referem ao armazenamento, métodos de arredondamento, ocorrência de underflow e overflow, e a realização das operações aritméticas básicas.
De acordo com esse padrão, um número X é dado por:
Esse padrão também faz uso de expoente de deslocamento (𝛅), que tem por objetivo eliminar o sinal do expoente.
O formato padrão para números de ponto flutuante é:
Número de bits e precisão:
a) Se 0 < expoente < 2e − 1, então o bit mais significativo é 1 e o número é dito normalizado;
b) Expoente = 0 e Mantissa ≠ 0, o número é não normalizado;
c) Expoente = 0 e Mantissa = 0, o número é ±0, dependendo do bit de sinal
d) Expoente = 2e − 1 e Mantissa = 0, o número é ±∞, dependendo do bit de sinal;
e) Expoente = 2e − 1 e Mantissa ≠ 0, o resultado é “NaN” (não é um número).
CAMPOS FILHO, F. F. Algoritmos Numéricos. 2. ed. Belo Horizonte: LTC, 2007.
GUIDI, L. F. Notas da disciplina Cálculo Numérico. Porto Alegre: UFRGS, 2014.
Coordenação e Revisão Pedagógica: Claudiane Ramos Furtado
Design Instrucional: Gabriela Rossa
Diagramação: Marcelo Ferreira
Ilustrações: Rogério Lopes
Revisão ortográfica: Ane Arduim