Aritmética de Ponto Flutuante Formato Padrão IEEE 32 bits, Sinal, Expoente e Mantissa, Normalização, Conversão, Unidade de Ponto Flutuante Intel (FPU), Registradores e Instruções associados à FPU Orlando Figueiredo, Rio Claro, Maio de 2006
Números Reais e Computação Números reais são difíceis de representar computacionalmente Podem ser muito extensos Podem ser infinitos Dízimas periódicas Números irracionais É inevitável truncá-los
Números Reais e Computação Desde os primórdios da computação duas abordagem prevaleceram Ponto fixo O separador da parte inteira e da parte fracionária ( ponto nos EUA, vírgula no Brasil) permanece numa mesma casa Ponto flutuante Similar à notação científica O separador varia de casa, conforme o expoente da potência associada 7,02 x 10 2 70,2 x 10 1 0,702 x 10 3 (na centena) (na dezena) (no milhar)
O Formato de Ponto Flutuante Em geral, a base da potência é 2 Três partes: Sinal Expoente Mantissa Exemplo: (101,11 x 10 1101 ) 2 Expoente: 1101 Mantissa: 101,11
Os Formatos do Padrão IEEE Short Real : 32 bits Sinal: 1 bit Expoente: 8 bits Mantissa: 23 bits Long Real : 64 bits Sinal: 1 bit Expoente: 11 bits Mantissa: 52 bits 31 30 23 22 0 1 11111111 11111111111111111111111
Números Binários Fracionários A mantissa é um número binário fracionário O valor de uma casa é metade do valor da casa vizinha à esquerda Esquematicamente,... 8 4 2 1 ½ ¼ 1/8 1/16 1/32 1/64 1/128 2 3 2 2 2 1 2 0 2-1 2-2 2-3 2-4 2-5 2-6 2-7
Números Binários Fracionários Quanto vale 0,1 binário em decimal? R: Metade de 1,0 (= ½) Quanto vale 0,01 binário em decimal? R: Metade de 0,1 (= ¼) Quanto vale 0,11 binário em decimal? R: 0,11 = 0,1 + 0,01 = ½ + ¼ = ¾ Quanto vale 11,1011? R: 2 + 1 + ½ + 0/4 + 1/8 + 1/16 = 3,6875
Expoente O expoente no Padrão IEEE é deslocado de +127 unidades Expoente Ajustado Em binário +5 132 10000100-10 117 01110101 +128 255 11111111-127 0 00000000
Normalização da Mantissa O separador deve ficar imediatamente após o primeiro algarismo significativo Valor Binário Normalizado Expoente 1101,101 1,101101 3 0,00101 1,01-3 1,0001 1,0001 0 10000011,0 1,0000011 7
Empacotamento Final A mantissa é sempre normalizada, logo o bit mais significativo é sempre 1 e, por isso, não precisa ser armazenado Valor Expoente Sinal, Expoente, Mantissa -1,11 127 1 01111111 11000000000000000000000 +1101,101 130 0 10000010 10110100000000000000000-0,00101 124 1 01111100 01000000000000000000000 Exercícios: -100111,0 +0,0000001101011
Dízimas Periódicas Binárias Como fica 1/5 em codificação binária: R: 0,001100110011001100110011001100110011...
Unidade de Ponto Flutuante As operações aritméticas sobre números representados em ponto flutuante são muito onerosas Foi preciso implementá-las por hardware para melhorar o desempenho geral dos computadores Originalmente, esse hardware era chamado coprocessador aritmético e era vendido separadamente 8087 (para o 8086),..., 80387 (para o 386) Posteriormente, ele foi incorporado em definitivo ao processador principal e passou a ser chamado de FPU Isso aconteceu a partir do 486
Registradores da FPU 8 registradores de 80 bits São organizados como uma pilha circular O topo da pilha é o ST(0), ou ST Os demais são ST(1), ST(2),..., ST(7) Há outros registradores de propósito geral
Instruções Todas começam com F de floating Exemplos: FADD FLD FST FMUL FINIT FSUBR FDIV FDIVR FADDP etc
Instruções de Movimentação de Dados FLD src LD é um mnemônico para LoaD (carregar) Escreve um valor no topo da pilha FPU O valor está em src, que deve ser obrigatoriamente uma posição de memória Não valem registradores da CPU ou constantes É como se fosse um push para a pilha da FPU
Instruções de Movimentação de Dados FST dest ST é um mnemônico para STore (armazenar) Lê o valor no topo da pilha FPU O valor é copiado para dest, que deve ser obrigatoriamente uma posição de memória Não valem registradores da CPU ou constantes Não apaga o valor no topo da pilha, por isso, não funciona como um pop
Instruções Aritméticas FADD Adição FSUB Subtração FMUL Multiplicação FDIV Divisão
Instruções Aritméticas Sem Operandos A forma mais simples de funcionamento de uma instrução aritmética não envolve operandos Ex: fadd Nesse caso, a operação é feita sobre os dois registradores que estão no topo da pilha, ST(0) e ST(1) Tudo se passa como se os dois fossem retirados da pilha para a realização da operação e o resultado fosse colocado na pilha ao final ST(1) é o destino e ST(0), a fonte
Instruções Aritméticas Sem Operandos ST(0) 4.0 ST(7) 4.0 ST(1) 3.0 ST(0) -1.0 ST(2) 0.6 fsub ST(1) 0.6 ST(3) 0.0 ST(2) 0.0...... ST(0) e ST(1) são removidos da pilha. 0.6 passa a ser o ST(0). Faz-se a conta 3.0-4.0, que resulta em -1.0. O resultado é colocado na pilha e passa a ser o novo ST(0). A pilha é circular. Abaixo de ST(0) está ST(1) e assim sucessivamente. Abaixo de ST(7), está ST(o). À medida que ST(0) avança ou recua, todo o conjunto vai junto.
Instruções Aritméticas Sem Operandos Lembra a utilização de uma calculadora RPN Para calcular (1+7) x 6, digita-se: 1 7 + 6 * ou 6 1 7 + * Ao lado, programa para calcular a área de um triângulo.data dois REAL4 2.0 base REAL4? ;a ser lida alt REAL4? ;idem.code ;Após a entrada de dados: fld base fld alt fmul fld dois fdiv
Instruções Aritméticas Com Um Operando As instruções aritméticas podem ser utilizadas com um operando que corresponde a uma posição da memória Nesse caso, a operação é realizada entre o operando e o ST(0), sendo ele o destino.data dois REAL4 2.0 base REAL4? ;a ser lida alt REAL4? ;idem.code ;Após a entrada de dados: fld base mul alt ;ST<- ST * alt fdiv dois ;ST<- ST / 2
Operações Aritméticas Com Dois Operandos Um dos operandos deve ser obrigatoriamente o ST (=ST(0)) Exemplos: fadd st, st(3) fmul st(2),st
Invertendo a Ordem da Subtração e da Divisão FSUBR O R é de reversa Sem operandos: calcula ST - ST(1) Com um operando: calcula operando ST Com dois operandos: calcula op2 op1 FDIVR Sem operandos: calcula ST / ST(1) Com um operando: calcula operando / ST Com dois operandos: calcula op2 / op1
Trabalhando com Operandos Inteiros Todas as instruções mostradas anteriormente requerem que os operandos que estejam na memória estejam no formato de ponto flutuante É possível trabalhar com variáveis inteiras A conversão é feita automaticamente Se o dado na memória é levado para a FPU durante a operação, converte-se o dado de inteiro para ponto flutuante Se o dado é levado da FPU para a memória, converte-se o dado de ponto flutuante para inteiro
Trabalhando com Operadores Inteiros Denotam-se as operações com operandos inteiros adicionando-se um I depois do F que inicia o mnemônico da operação Exemplos: FILD FIADD FISUBR
Extra POP Existe a opção de se apagar o resultado da operação da pilha imediamente após a operação Isso é conhecido como extra POP Denota-se o extra POP adicionando-se a letra P no final do mnemônico Exemplos: FADDP FSTP FIDIVRP A instrução FSTP é, portanto, similar a um POP da pilha
Carregando Constantes Existem instruções especiais para carregar constantes muito usadas fldz fld1 fldpi fldl2t Põe +0,0 na pilha da FPU Põe +1,0 na pilha da FPU Põe π na pilha da FPU Põe log 2 10 na pilha da FPU fldl2e fldlg2 fldln2 Põe log 2 e na pilha da FPU Põe log 10 2 na pilha da FPU Põe log e 2 na pilha da FPU
Mais Instruções finit Inicializa a FPU fchs Inverte o sinal de ST fcom Comparação Resultado nos flags C0, C1 e C2 da FPU
Programa Exemplo Volume da Esfera.data quat REAL4 4 tres REAL4 3 raio REAL4 34.5 vol REAL4?.code main PROC finit fld raio fmul raio fmul raio fmul quat fdiv 3 fstp vol exit main ENDP
Referências KNUTH, DONALD E. The Art Of Computing Programming. V.2, p.198-213 Apresenta os algoritmos para adição (subtração), normalização e multiplicação (divisão) IRVINE, KIP. 4.ed. Capítulo 17, no CD. DANDAMUDI, SIVARANA. Introduction to Assembly Language Programming. 2.ed. Springer, 2005. Capítulo 17. Apresentação disponível no site do autor; discute os registradores de controle e status