Sistemas de ponto flutuante
Como e quão bem computadores representam números
Vamos lá?
Seria ótimo que todas as contas feitas nos computadores fossem exatas. Infelizmente esse não é o caso. Para entender o por que disto, precisamos entender como número são representados internamente nos computadores e tentar quantificar a qualidade dessa representação. Esse é o assunto dessa aula.
- 1
- 2
- 3
Em um sistema de ponto flutuante, com base 10, capaz de representar 4 dígitos na mantissa e 1 no expoente, quais das alternativas abaixo são corretas?
Em um sistema de ponto flutuante, com base 10, capaz de representar 4 dígitos na mantissa e 1 no expoente, quais dessas outras alternativas são corretas?
Em um sistema de ponto flutuante...
- A. a unidade de arredondamento é o maior erro absoluto possível entre $x$ e $\fl(x).$
- B. o erro relativo no resultado de qualquer operação aritmética é limitado.
- C. $u\approx 10^{-16}$ é o menor número positivo representável possível, em precisão dupla.
- D. Se $x>0$ então $\fl(1+x) > 1.$
- E. Se $0 < x < u,$ onde $u$ é a unidade de arredondamento, então $\fl(x) = 0.$
O computador, com sua memória finita, não é capaz de representar todos os números reais. De fato, não é possível representar nem mesmo um único número irracional, uma vez que não haveria como armazenar os infinitos dígitos que o compõem. No computador apenas alguns números racionais e dentro de um intervalo finito são passíveis de serem armazenados. A representação para esses números é conhecida como representação em ponto flutuante e os parâmetros e propriedades que definem essa representação constituem um sistema de ponto flutuante ou SPF.
Vamos entender como funciona a representação em ponto flutuante através de um exemplo. Suponha que $x=\sqrt{3} =1.73205080757\ldots.$ No computador, o espaço de memória finito permite armazenar apenas alguns desses dígitos, os mais importantes ou significativos deles. O número de ponto flutuante associado a $x$ é $$ \fl(x) = 1.732051,$$ onde $\fl(x)$ é a função que mapeia o número real $x$ no número de ponto flutuante do SPF mais próximo dele, neste exemplo com apenas os 7 dígitos mais significativos preservados. Veja mais alguns exemplos. \begin{align*} \fl(\pi) & = 3.141593 & \fl(43\,209\,622.48) &= 43\,209\,620.00\\ \fl(1/3) & = 0.3333333 & \fl(0.00001223) &= 0.00001223 \end{align*} Quando falamos dos 7 dígitos mais significativos queremos dizer os 7 dígitos da esquerda para a direita, a partir do primeiro dígito não nulo do número. Cuidado para não vá confundir com 7 casas decimais (veja novamente os exemplos acima). Só não está claro ainda de onde vem o termo ponto flutuante. Pois bem, apenas os 7 dígitos significativos são armazenados, o que significa que para $\pi,$ apenas os dígitos $3141593$ serão guardados, enquanto que para $43\,209\,622.48$ apenas os dígitos $4320962$ são guardados. Porém, perceba que para compreender o que esses conjuntos de dígitos significam é necessário guardar também a posição em que o ponto decimal estava. Isso é guardado como um expoente. Ou seja, $\fl(\pi) = 0.3141593 \cdot 10^{1}$ e $\fl(43\,209\,622.48) = 0.4320962\cdot 10^{8}.$ Por uma questão de convenção, o expoente é definido de forma que o fator que multiplica a potência, denominado mantissa, sempre comece com $0.d,$ onde $d$ é um dígito não nulo.
Com base nesses exemplos, um sistema de ponto flutuante $\mathbb{F}(\beta,t,L,U)$ é definido pela escolha de uma base ($\beta$), da quantidade de dígitos significativos $(t)$ preservados na mantissa e o menor e maior expoentes possíveis $(L,U).$ Nos exemplos abaixo, vamos considerar o SPF $\mathbb{F}(10,5,-99,99).$ \begin{align*} \fl(3.14159265) &= 3.1416 = 0.31416 \cdot 10^{1} & (\mbox{mantissa }= 31416, \mbox{expoente} = 1)\\ \fl(299\,792.458) & = 299\,790.00 = 0.29979\cdot 10^{6} & (\mbox{mantissa }= 29979, \mbox{expoente} = 6)\\ \fl(-0.0133748) & = -0.013375 = -0.13375\cdot 10^{-1} & (\mbox{mantissa }= -13375, \mbox{expoente} = -1)\\ \fl(6.318\cdot 10^{120}) & = \infty\; (\mbox{overflow}) & (\mbox{expoente além do máximo possível})\\ \fl(9.23\cdot 10^{-120}) & = 0\; (\mbox{underflow}) & (\mbox{expoente abaixo do mínimo possível}) \end{align*}
Repare que ao determinar o último dígito significativo sempre é preciso inspecionar o dígito seguinte. Caso este seja maior ou igual a $5,$ o número em precisão finita é arredondado para cima, isto é, seu dígito final é acrescido de $1.$ Por exemplo, $\fl(4.2371\mathbf{8}) = 4.237\mathbf{2},$ pois o dígito seguinte ao quinto e último dígito a ser preservado era $8 \ge 5.$
Ainda em $\mathbb{F}(10,5,-99,99),$ como na representação o primeiro dígito da mantissa deve ser sempre não nulo (exceto para o número zero), temos que o menor e o maior números positivos representáveis são, respectivamente, $$ 0.10000\cdot10^{-99} \quad \mbox{e}\quad 0.99999\cdot 10^{99}. $$
A qualidade ou precisão de um sistema de ponto flutuante é definida como o erro no compto das operações aritméticas elementares (soma, subtração, produto e divisão). Não devemos confundir precisão com acurácia, que quantifica o erro no cálculo de uma aproximação para a solução de um problema como um todo. A precisão de um SPF é quantificada através da unidade de arredondamento, definida como o menor número positivo de ponto flutuante $u$ tal que $$ \fl(x \,\square\, y) =(x \, \square\, y)(1+\delta), \quad |\delta| \lt u, $$ onde $\square$ representa $+,$ $-$, $\times$ ou $\div.$ Perceba que $\delta$ representa o erro relativo na operação aritmética. Portanto, a unidade de arredondamento $u$ é o limitante superior para o erro relativo em operações aritméticas no sistema de ponto flutuante. Pare! Reflita sobre essa afirmação, antes de continuar.
Uma forma de determinar a unidade de arrendondamento da máquina é descobrir qual o menor valor para $u,$ representável no SPF, tal que $\fl(1 + u)$ ainda é maior que $1.$ Ou seja, se $0 \lt x \lt u$, então $\fl(1+x) = 1.$ Isso pode dar a impressão errada de que $\fl(x) = 0,$ isto é, que o computador toma valores menores que a unidade de arredondamento como zero. Isso não é verdade. $x$ é tomado como zero apenas quando comparado a 1 em uma soma ou subtração. No exemplo do SPF $\mathbb{F}(10,5,-99,99)$ teríamos que \begin{align*} u & = 5\cdot 10^{-5}, &\mbox{(unidade de arredondamento)}\\ \fl(10^{-6}) & = 10^{-6}, \\ \fl(1 + 10^{-6}) & = 1. \end{align*}
Praticamente todo computador segue o SPF definido no padrão IEEE-754 . Nesse padrão, há duas formas de representar números de ponto flutuante, dependendo do espaço reservado para o armazenamento. Em precisão simples, onde cada número ocupa 4 bytes, o SPF é $\mathbb{F}(2,23,-126,127),$ $u = 2^{-23} \approx 1.19\cdot 10^{-7}$ e o menor número representável é $2^{-149} \approx1.40\cdot 10^{-45}.$ Em precisão dupla, onde cada número ocupa 8 bytes, o SPF é $\mathbb{F}(2,52,-1022,1023),$ $u=2^{-52} \approx 2.22\cdot 10^{-16}$ e o menor número representável é $2^{-1074} \approx 4.94\cdot 10^{-324}.$
A unidade de arredondamento pode ser conferida no Octave com o comando eps
. No Octave, todas as variáveis reais são armazenadas em precisão dupla, a menos que explicitamente inicializadas em precisão simples com o comando single
.
Na próxima aula veremos como a precisão de um SPF afeta o resultado de contas quando mais de uma operação for efetuada.
Observações adicionais
Nesta aula usamos como exemplo sistemas de precisão finita em base 10 apenas para facilitar a apresentação dos conceitos. Computadores e outros dispositivos digitais utilizam a base 2. Isto tem algumas implicações não tão óbvias. Em nossos exemplos com base decimal, os números apresentados representam exatamente os valores que estariam armazenados no sistema de ponto flutuante. Entretanto, quando a base binária é utilizada, é necessário um passo de conversão de base para apresentar o resultado, uma vez que nós, humanos, preferimos ver os números na base decimal. Essa conversão entre bases também ocorre quando inicializamos uma variável no computador. Por exemplo, o código a = 0.2
significa que o número decimal $0.2$ será convertido para o número binário mais próximo possível e depois atribuído à variável a
.
Dito isto, não devemos confundir a exibição do valor de uma variável com o que de fato está armazenado nela. Por exemplo, considere o bloco de código executado no Octave
a = sqrt(2); b = single(sqrt(2)); format native-bit a, b a = 1011001111011100111111100110011001111001000001010110111111111100 b = 11001111001000001010110111111100 format short a, b a = 1.4142 b = 1.4142 format long a, b a = 1.414213562373095 b = 1.4142135
Apenas quando escolhemos o formato native-bit
estamos vendo os valores exatos das variáveis a
e b
, armazenados no computador. Porém essa exibição é, no mínimo, inconveniente. O usual é utilizar outro formato de exibição. A exibição padrão do Octave é conseguida com format short
. Perceba que neste formato as variáveis a
e b
parecem ter o mesmo valor, visto que apenas 5 dígitos significativos estão sendo exibidos. Usando o format long
, podemos ver que a
é de fato diferente de b
.
A intenção aqui não é que você saiba tudo sobre representação em ponto flutuante ou, mais ainda, sobre questões intrínsecas à implementação de um sistema de ponto flutuante. Entretanto, você precisa estar ciente de que os números que você vê no computador, quando exibe uma variável, não são exatamente os número que estão armazenados, por conta das conversões de base.
Referências
O texto de Steve Hollasch sobre o padrão IEEE-754 é muito bom e didático. Recomendo aos interessados no assunto lerem. A revisão feita em 2019 no padrão IEEE-754 está aqui.
IEEE Standard for Floating-Point Arithmetic, in IEEE Std 754-2019 (Revision of IEEE 754-2008), pp.1-84, 22 July 2019, doi: 10.1109/IEEESTD.2019.8766229.
Michael L. Overton. Numerical Computing with IEEE Floating Point Arithmetic. SIAM, 2001.
Para os exercícios abaixo, considere o SPF $\mathbb{F}(10,5,-99,99).$
1. Qual a distância entre os dois menores números representáveis no SPF? Qual a distância entre os dois maiores números representáveis no SPF?
$10^{-104}$ e $10^{94}.$
2. Estime a unidade de arredondamento de seu computador, calculadora científica e calculadora do celular. Qual dos seus dispositivos tem a melhor precisão? Para isso utilize o algoritmo abaixo.
- u $\leftarrow$ 1
- enquanto (1+u) > 1, repita:
- u $\leftarrow$ u/2
- u $\leftarrow$ 2u
Por que a redução no valor da variável u
é feita dividindo-o por 2? Se, ao invés disto, u
fosse multiplicado por um fator diferente, como 0.8, por exemplo, isso faria diferença? Faça experimentos, conjecturas. Discuta.
3. Determine o resultado das operações abaixo e qual o erro relativo esperado em cada uma delas, quando realizadas no sistema de ponto flutuante.
- $a = 4.2226,$ $b= 0.0003811$, $c = a+b.$
- $x = 12.82,$ $y = 0.4114$, $w = xy.$
- $v = \pi^2.$
- $a = 25.67,$ $b=0.003285$, $c = 0.003297$, $x = a-b-c$ e $y = a-(b+c).$
(a) $\fl(a+b) = 4.2222$ com erro relativo de $4.5\cdot 10^{-6}.$ (b) $\fl(xy) = 5.2741$ com erro relativo de $9.1\cdot 10^{-6}.$ (c) $\fl(\pi^2)=9.8696$ com erro relativo de $4.5\cdot 10^{-7}.$ (d) $\fl(x) = 25.667$ com erro relativo de $1.4\cdot 10^{-4}$ e $\fl(y)=25.663$ com erro relativo de $1.6\cdot 10^{-5}.$