Física Computacional FSC5705

Propaganda
11/10/12
Página de Evy Salcedo
Física Computacional ­ FSC­5705
Súmula
Aulas
Lista
Conc.
Freq.
Outros
Ensino
Representação de um número pelo computador
Converter decimal para binário
Suponhamos que queremos converter o
numero 100 para binário. O procedimento é
simples, basta ir dividindo por 2 e os restos
dessas divisões dão os bits do número em
binário. Como se mostra na figura ao lado, o
processo é relativamente simples. Dividimos o
número, no caso 100 (dividendo), por 2
(divisor), o resto será o bit menos significativo
0
(representado a potencia 2 ). O quociente ou
resultada, que no caso é 50, será o novo
dividendo, o qual será divido por 2, o resto
dessa operação será o segundo bit menos
1
significativo (representado a potencia 2 ). Esse processo continua até que o último quociente
resulte em zero. Para escrever o número devemos escrever seguindo o sentido indicado pela
zeta, do fim para o inicio, dessa forma o número que foi obtido em nossa conversão é 1100100.
O último passo é colocar o número na base da maquina, por exemplo o número 1100100 é um
número escrito com 7 bits, um computador não pode representar ele pois o tamanho mínimo é o
byte que são 8 bits e representam um char, assim para passar para 8 bits simplesmente
colocamos um zero a mais e dessa forma obtemos: 01100100. Note que se usamos um
unsigned
long
int
para
guardar
o
nosso
número
ele
será
escrito
como:
00000000000000000000000001100100.
Utilizando o programa deste link podemos converter qualquer número para binário ou
hexadecimal. Você pode perceber que os dados binários são escritos ao contrario. Isso se deve a
que em computadores de tipo Intel (arquitetura x86) o padrão dos números é o chamado de
"little endian", diferentemente do outro padrão chamado de "big endian" (a transmissão de dados
através rede - internet - é nesse formato). O little endian se carateriza por colocar o byte menos
significativo no inicio da memoria e o byte mais significativo no fim da memoria.
Como mostrado na figura embaixo, o big endian coloca o byte mais significativo na posição de
memoria mais baixa e o menos significativo.
Representação de inteiros com sinal
Até agora analisamos como é representado um número inteiro dentro da memoria do
computador.
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
1/6
11/10/12
Página de Evy Salcedo
Para se definir como representar os números negativos, foi escolhida a chamada representação
complemento de dois. Utilizando essa representação para se obter o negativo do número
desejado temos que seguir o seguintes passos
Calcule o complemento boolenao de cada bit (ou seja se é zero passa a ser um e viceversa)
Some 1 ao sinal
Além disso se convencionou que o bit mais significativo será zero se o número for positivo, caso
ele seja negativo o número será negativo.
Para entender isso melhor vejamos um exemplo, vamos converter o número
+18
→
00010010
complemento bit a bit
→
11101101
somando 1 em binario
18
para negativo:
00000001
−18
→
11101110
Existe uma expressão matemática que permite converter um dado número binário, levando em
consideração a representação de complemento dois, para a base decimal:
n−2
n−1
A = −2
i
a n−1 + ∑ 2 a i
i=0
Assim, no caso de nosso exemplo:
7
00010010
→
−2
11101110
→
−2
100000000
→
−2
7
7
6
∗ 0 + 2
6
∗ 1 + 2
6
∗ 0 + 2
5
∗ 0 + 2
5
∗ 1 + 2
5
∗ 0 + 2
4
∗ 0 + 2
4
∗ 1 + 2
4
∗ 0 + 2
3
∗ 1 + 2
3
∗ 0 + 2
3
∗ 0 + 2
2
∗ 0 + 2
2
∗ 1 + 2
2
∗ 0 + 2
1
∗ 0 + 2
1
∗ 1 + 2
1
∗ 0 + 2
0
∗ 1 + 2
0
∗ 1 + 2
0
∗ 0 + 2
∗ 0
→
18
∗ 1
→
−18
∗ 1
→
0
Na última linha (primeira coluna) é colocado o resultado da soma dos 18 + (−18) na
representação booleana, e como é de se esperar o resultado foi zero. Observe que sobrou um
um a mais na posição 9, esse número é desconsiderado (chamado de carry).
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
2/6
11/10/12
Página de Evy Salcedo
Na figura acima utilizamos o programa convertDecimalToBinaryAndHex.c para ver a
representação booleana de 18 e −18. Observamos que os resultados coincidem com nossos
cálculos.
Esta explicação permite entender o porque os números com sinal som menos de que aqueles
com sinal, em geral se temos n bits para representar um número, a faixa de números decimais
n−1
n−1
que podemos representar está dada por −2
→ +2
− 1, o menos um se deve a que o
zero é um número positivo, nessa representação, e portanto consome uma possível
representação.
Para finalizar é importante mencionar que está não é a única representação possível para os
números negativos, mas é a representação que apresenta vantagens consideráveis: O zero tem
uma representação única (ficando fácil testar quando um número é zero) e as operações
matemática básicas (soma e resta) ficam simples, simplesmente se lembrando que 0 + 0 = 0,
1 + 0 = 0 + 1 = 1 e 1 + 1 = 10 (observe o 1 que é o carry - vai um).
Representação de ponto Flutuante
Para representar um número de ponto flutuante os computadores utilizam a notação científica ou
seja, os números são representados segundo o formato
Com isso em mente os desenhadores da Intel construíram a primeira unidade de ponto flutuante
(FPU) no microprocessador 8086 para lidar com 3 tipos de números de ponto flutuante diferente,
os números de precisão simples (float) - de 32 bits ou 4 bytes, os números de precisão dupla
(double) - de 64 bits ou 8 bytes, e os números de precisão estendida de 80 bits ou 10 bytes. O
trabalho desenvolvidos por eles (Kahn, Coonan, and Stone) foi tão bom que serviu como base
para o padrão definido pelo IEEE (I-3-E: Institute of Electrical and Electronics Engineers) no
standart 754.
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
3/6
11/10/12
Página de Evy Salcedo
Seguindo a notação científica, se instituiu que os números de precisão simples (float) terão o bit
mais significativo para o sinal (±), os seguintes 8 bits para o expoente e os restantes 23 bits
para o significado (ou mantissa, como era antigamente chamado).
Os números de dupla precisão (double) terão o bit mais significativo para o sinal (±), os
seguintes 11 bits para o expoente e os restantes 52 bits para o significado.
Os números de precisão estendida terão o bit mais significativo para o sinal (±), os seguintes 11
bits para o expoente e os restantes 63 bits para o significado. Esta representação de números
reais foi durante muitos anos o padrão utilizado pelos processadores da Intel (e as outras
companhias que aderiram ao padrão x86 da Intel) para o processamento interno de operações
de ponto flutuante, sem importar se o número era definido como float ou double. Esse cenário
mudou em com a substitução da unidade FPU x87 (devido a que o coprocessador matemático
que acompanhou o Intel 8086, chamado de Intel 8087) pela nova FPU SSE (Streaming SIMD
Extensions) com desenho vetorial (No SSE ou "3DNow! Profissional", o processador ganha a
capacidade de leer 128 bits de forma simultânea, ou 4 bytes, o que corresponde a 4 float. Com
isso ele pode realizar operações matemáticas ou lógicas nesses dados e colocar de volta na
memoria, ou seja, ele pode somar 2 pares de números "simultaneamente". Recentemente foi
introduzido o AVX - Advanced Vector Extensions - estendendo para 256 bits essa capacidade,
podendo ser possível somar 2 pares de doubles).
Converter de real para binário
± a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 b 1 b 2 b 3 … b 23
Quando o número decimal é representado em formato binário podem ser utilizadas duas formas
de representação, a forma normalizada ou a forma denormalizada. Na forma normalizada, que é
a representação mais usada, o bit mais significativo é assumido ser sempre 1, dessa forma todo
±E
número será escrito na forma ±1.b1 b2 b3 … b23 × 2 , onde os b são os 23 bits que são
utilizados para representar a mantissa (ou significado, como é atualmente chamada a mantissa),
E é o expoente definido no 8 bits (a 1 a 2 a 3 … a 8 ). Assim vemos que se assumimos que o bit
mais significativo é 1, nossos 23 bit de significado na verdade representam 24 bit (já que o 1 é
assumido).
O expoente utiliza a representação polarizada. Para o caso de 8 bit no expoente podemos
8
representar 2 − 1 = 255 números e nesse caso a polarização é 255/2 = 127. Assim podemos
representar números desde −127 até 128. Para entender melhor vejamos a tabela seguinte
bits do expoente (a1 a2 a3 … a8 )
representação numérica
−126
(00000000)
= (0)
±(0.b 1 b 2 b 3 … b 23 )
×2
(00000001)
= (1)
±(1.b 1 b 2 b 3 … b 23 )
×2
(00000010)
= (2)
±(1.b 1 b 2 b 3 … b 23 )
×2
(00000011)
= (3)
±(1.b 1 b 2 b 3 … b 23 )
×2
2
2
2
2
10
2
10
−126
2
10
−125
2
10
−124
2
↓
↓
0
(01111111)
= (127)
±(1.b 1 b 2 b 3 … b 23 )
×2
(10000000)
= (128)
±(1.b 1 b 2 b 3 … b 23 )
×2
2
2
10
2
10
1
2
↓
↓
125
(11111100)
= (252)
±(1.b 1 b 2 b 3 … b 23 )
×2
(11111101)
= (253)
±(1.b 1 b 2 b 3 … b 23 )
×2
(11111110)
= (254)
±(1.b 1 b 2 b 3 … b 23 )
×2
(11111111)
= (255)
2
2
2
2
10
2
10
2
10
10
2
±∞
se
126
127
, N aN em outros
casos
b 1 = … b 23
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
4/6
11/10/12
Página de Evy Salcedo
Além de sabermos como se expressa o expoente ±∞ se b1 = … b23 , temos que considerar os
valores associado ao significado ou mantissa. Quando representamos os números inteiros vimos
que a ordem dos bits aumentava de direita para esquerda, isto é o primeiro bit de esquerda para
0
1
2
direita deve ser multiplicado por 2 , o segundo por 2 , o terceiro por 2 , …, o nessimo de
n
2
esquerda para direita deve ser multiplicado por
, logo é somado cada um dos resultados e me
é possível expressar o número binário em decimal. No caso em questão, onde queremos
expressão um número real em binário devemos considerar que o bit esquerda, no campo do
significado ou mantissa, continua a ser o bit mais significativo só que agora o valor atribuído a
cada bit é diferente como se mostra na tabela embaixo
b1
b2
b3
b4
1
1
2
1
=
1
2
1
2
1
=
1
4
1
2
3
=
1
8
2
4
=
b2 3
…
1
16
1
…
2
23
=
1
8388608
Para entender melhor essa representação vejamos um exemplo, vamos representar o número
123.687510 em binário. Primeiro escrevemos a parte inteira do número real em binário, ou seja
123 = 1111011 e agora escrevemos a parte decimal da seguinte forma: dividimos a parte
−1
−2
fracionaria por 2
= 0.5 ,
o resto dessa operação é divida por 2
= 0.25
e assim
sucessivamente até obter zero como resto ou esgotar as 23 possibilidade (
−23
−7
2
= 1.1920928955078125 × 10
. Na figura acima é mostrado o procedimento passo a
passo, para o exemplo acima, mas note que se o número for mudado para 123.687610 o número
de bit (bi ) necessários para representar ele se torna muito grande (provavelmente infinito) ou
seja, não é possível representar exatamente, como pode ser verificado utilizando o programa
converteFracaoParaBinario.c. (Como teste baixe o programa e verá que ele imprime a diferença
na representação e no número, teste para o caso em que o número for 0.1 armazenado em um
−08
float, nesse caso a diferença é de aproximadamente 9.536743164062636 × 10
. Na verdade o
padrão IEEE estabelece que o número deve ser arredondado já seja para cima ou para baixo).
Continuando com o exemplo então a parte
fracionaria é 0.687510 e representada em
binário por pelo numero 0.1011, somando à
representação da parte inteira do número
obtemos que a representação de 123.687510 é
1111011.10112 ,
passando
para
notação
"científica" (com base 2, é claro), o número
binário
pode
ser
escrito
como:
6
1.1110111011 × 2 . Assim, no computador a
mantissa do número será representada
utilizando, a forma normalizada (que suprime o
1 inicial), como 11101110110000000000000 (para o caso de um float). O expoente foi 6 na
representação polarizada é o número 6 + 127 = 13310 , que em binário é 10000101. Juntando
tudo, e colocando o bit 31 igual a 0 pois o número é positivo, obtemos a representação binaria
de 123.687510 em um float de 32 bits como: 0 10000101 11101110110000000000000 , no caso
de um computador da família Intel esse número será representado internamente no formato little
endian, assim obteremos 00000000 01100000 ; 11110111 01000010 (a fim de verificar utilize o
programa convertDecimalToBinaryAndHex.c)
O menor número positivo que podemos representar no formato normalizado é
0
00000001
0000000000000000000000
que equivale aproximadamente ao número
−126
Nmin = (1.0000000000000000000000) × 2
2
−126
= 2
−38
= 1.1754943508222875 × 10
No outro extremos temos o máximo número positivo no formato normalizado que pode ser
representado:
0
11111110
11111111111111111111111
que equivale aproximadamente ao número
127
Nmin = (1.11111111111111111111111) × 2
2
127
= 1.9999998807907104 × 2
38
= 3.4028234663852886 × 10
Infinitos e NaN
Na última linha da representação dos números de ponto flutuante está a definição do padrão
IEEE-745 para tratar alguns casos excepcionais que podem ocorrer exemplo 1/0 = ∞. Para
tratar essa e outras exepções, inicialmente se consideraba atribuir a esse operação o máximo
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
5/6
11/10/12
Página de Evy Salcedo
valor representável, o problema desta abordagem é que o usuario não fica sabendo que seu
programa deu pau, de fato, se você aceita essa convenção então a operação 1/0 − 1/0 = 0 não
fica bem representada. Uma outra alternativa seria simplesmente para o programa e avisar que
se deu um erro de divisão por zero, mas isto também não ajudaria, como exemplo considere um
programa que calcule a resistencia equivalente de 2 o mais resistores em paralelo, se algum dos
resistores for zero aparecerá uma destas exepções, contudo como 1/Req = 1/R1 + 1/R2 ,
vemos que o processo não tem porque parar e sem continuar pois o resultado de
R eq = 0
.
Dessa forma o IEEE introduz um padrão para os bits que representam esse tipo de exepção. A
vatagem desta avordagem é que essa representação pode ser testada de forma a tomar uma
descição quando ela venha ocorrer.
/media/ext4_evy/Ensino/UFSC/Ano2012/IIsemestre/public_html/…/aula111.html
6/6
Download