Sistemas de Computação
Lic.
Engª Informática, 1º ano
2013/2014
Docente
responsável: A.J.Proença
Autoavaliação
Representação de informação
Última Modificação: 28 Mar 2014
|
A |
R |
B |
E |
---|---|---|---|---|
Conhecimentos e competências específicas de Sistemas de Computação |
||||
- Identificar formas de
representação binária de informação num computador (textual, numérica,
audiovisual ou de comandos de um processador), e |
Ö - |
Ö Ö |
Ö Ö |
Ö Ö |
- Analisar ficheiros de documentos (c/ texto) e distinguir entre formatos proprietários de formatos baseados em texto anotado |
- | Ö | Ö | Ö |
- Reconhecer os sistemas de numeração binário e hexadecimal e aplicar técnicas de conversão entre sistemas |
Ö | Ö | Ö | Ö |
- Explicar a representação
de números inteiros e reais (norma IEEE 754), visualizar a sua
representação em binário, em ambiente laboratorial Unix/Linux & IA-32, |
Ö - - |
Ö Ö - |
Ö Ö Ö |
Ö Ö Ö |
A1.
Resolva os seguintes problemas.
a) Mostrando os cálculos que efetuar, converta para hexadecimal o valor 0.26075*103
b) Um registo de 16 bits contém o conjunto de bits correspondente ao valor 0xD8. Mostre o valor que está lá guardado, em decimal, conforme o registo contém um valor inteiro sem sinal, ou o registo contém um valor inteiro (codificado em complemento para 2). Justifique os resultados apresentados.
c) Efetuando o menor nº
possível de operações, represente na base 3 os seguintes valores: 11, 33, 99
Nota (para R): veja se consegue com apenas 2 divisões, explicitando o raciocínio seguido.
d) Uma variável em C declarada
como unsigned short int
(16 bits) é inicializada com um valor que corresponde à dimensão da memória
cache no início dos processadores IA-32 com cache interna (i.e., 40K). Mostre, em hexadecimal, qual o valor que é guardado em memória.
Notas (para R): (i) tente resolver o problema sem efetuar qualquer
divisão aritmética, mostrando os passos que seguir; e resolva adicionalmente o
seguinte: (ii) repita o exercício para o dobro desse valor (80K), e (iii) repita
o exercício mas considerando agora que a variável foi declarada como
float, e efectuando o menor
nº possível de operações..
A2.
Um "cardeal" de LEI tentava
explicar a um colega seu como é que estava organizada a página desta UC na Web.
Analise, com espírito crítico e usando os seus conhecimentos, a afirmação do
"cardeal", conforme anotada no caderno do seu colega:
"A página web da UC SC é um ficheiro HTML com logotipos,
textos formatados, datas e ...
Tudo isto está guardado num único ficheiro num PC:
- os textos são carateres alfanuméricos codificados em ASCII 7-bits;
- a formatação
dos textos são comandos específicos que estão codificados em binário conforme o instruction set
do Pentium;
- os logotipos são imagens JPEG;
- as datas, como são valores inteiros, estão codificados e guardadas no PC em
complemento para 2"
A3.
A gama de valores representáveis
(na base decimal) num registo do Pentium está no intervalo:
a)
[-2^31, +2^31[ , sempre que o
registo contiver o valor de uma variável numérica que foi declarada num programa
em C; comente esta afirmação.
Nota: a questão colocada nesta alínea tem uma subtileza para uma classificação
R, ou mesmo B. Para uma classificação de apenas A, leia a
sua reformulação na resolução (sugestão aos estudantes que pretendem mais que
A: tentem encontrar essa "subtileza" antes de saltarem para a resolução).
b) [0, +2^32] se o registo for o IP/PC; comente esta afirmação.
c) [0, 9999] se o valor estiver representado como uma string de caracteres alfanuméricos em ASCII; comente esta afirmação.
d)
[-2^128,
+2^128] se for
o conteúdo de um registo de vírgula flutuante de 32 bits; comente esta afirmação.
Nota: a resolução correta desta alínea apenas é exigida para a classificação
R.
R1.
Durante a execução do seguinte
fragmento de código C, compilado para um processador compatível com IA-32, o
espaço
de memória
atribuído às variáveis locais
fval,ival,sval,tamp
estende-se contiguamente, no sentido dos endereços crescentes, com início em
0xBFFFDA0
.
A sequência de valores
00 50 89 43 , expresso em
formato hexadecimal, refere-se ao conteúdo dessas primeiras quatro células de
memória.
char
tamp[3]="AJP"; // ‘A’ = 65 em decimal //
short int sval;
int ival;
float fval;
.....
.....
fval = ??? //
valor especificado no enunciado //
ival = (int) fval;
sval = (short int) -fval; // notar o sinal menos //
a) Apresente o valor em decimal atribuído a cada uma das variáveis fval, ival, sval .
b) Considerando que o valor ASCII do caracter ´A´ é 65 (decimal), represente, em hexadecimal, no espaço de memória reservado, a variável tamp .
c) Represente, em hexadecimal, todas as variáveis declaradas, no fragmento de código, com a indicação precisa dos endereços ocupados na memória.
Nota (para classificação B): se repetisse a resolução da alínea anterior para um computador big endian, que diferenças iria encontrar?
R2.
Numa aula de laboratório de SC, os grupos estavam a analisar o comportamento
do processador na execução de um programa em C; mais concretamente, estavam a
visualizar os conteúdos dos registos (em hexadecimal) após terem interrompido a
execução a meio.
De repente, um grupo comenta: "Olha! Que coincidência! Os registos
%esp
(stack
pointer, i.e., o apontador para o topo da pilha em memória) e
%eax
(um outro que foi usado para representar uma das variáveis inteiras do
programa) têm o mesmo valor, e portanto representam o mesmo valor decimal!"
E comenta um outro grupo: "E conosco também acontece o mesmo!!"
O docente vai ver ambos os terminais e confirma que os valores visualizados em
cada monitor são o mesmo, embora sejam diferentes de um grupo para o outro. E
comenta: "É verdade que esses 2 registos têm o mesmo conteúdo em binário! Mas um
dos grupos fez uma afirmação correta, e o outro não!"
a) Encontre uma explicação
válida para a posição do docente.
Nota: se esta questão não
contivesse a alínea b), seria para uma classificação B.
b) Suponha que o 1º grupo via nos registos que tinham o mesmo conteúdo o valor 0x800c14, enquanto o segundo grupo tinha 0xfffffffe. Calcule e indique o valor, em decimal, armazenado em cada um dos registos, nos 2 grupos.
B1.
Imagine que está a desenvolver software (em C) para controlo de um equipamento
industrial (que requer bastante precisão numérica nas coordenadas). Esse
software, depois de devidamente testado num PC, vai ser portado para um outro
processador (um microcontrolador) que ficará embebido no equipamento. Contudo,
esse processador não suporta o formato de precisão dupla conforme especificado
na norma IEEE 754, pelo que todas as variáveis que tenham sido declaradas como
double
serão representadas apenas com 32 bits, no formato de precisão simples dessa
mesma norma.
Considere os seguintes valores, resultados intermediários de operações com
variáveis que declarou como sendo do tipo
double.
Mostre como serão representadas no processador/memória
do sistema embebido. Comente os resultados obtidos.
Nota: os valores apresentados nas alíneas seguintes estão em hexadecimal, e foram obtidos com ferramentas de debugging, enquanto o software era testado num Pentium.
a) 0x 48 A9 01 00 80 C5 00 00
b) 0x 34 09 01 00 80 00 00 00
c) 0x B7 41 90 10 80 00 C0 00
a) Mostrando os cálculos que efetuar, converta para hexadecimal o valor 0.26075*103
Sugestão de resolução
Na conversão de um número em decimal para
hexadecimal, é possível optar por uma de 2 alternativas (ambas correctas):
- divisões/multiplicações sucessivas por 16 (método directo), ou
- converter primeiro para binário (evitando, se possível, a realização de
divisões/multiplicações por 2) e depois, sem operações, associar os bits em
grupos de 4, para a esquerda/direita do ponto decimal, e atribuir a cada grupo
de 4 bits o correspondente valor hexadecimal.
Este pb tem, contudo, uma mui ligeira
complexidade adicional: o valor fornecido na base 10 é apresentado, não sob a
forma de um nº contendo uma parte inteira e uma parte fraccionária (como se viu
nas sessões teórico-práticas), mas sim com a chamada notação científica (uma
parte fraccionária que multiplica por uma potência de 10).
Quando confrontados com uma questão deste tipo, certos estudantes ficam confusos
e, por vezes, atacam logo com a resolução do pb sem pensar bem no assunto, i.e.,
assumem que este valor é constituído por 2 partes
- a parte fraccionária 0.26075, e
- o expoente 3,
convertem cada um desses números em separado para a nova base, e apresentam o
resultado como sendo o produto da parte fraccionária (na nova base) pela nova
base elevada ao expoente (convertido para a nova base).
ISTO É UM DISPARATE!
Podem comprová-lo experimentando fazer uma
conversão de um nº pequeno e simples - como por ex., o valor 5 escrito na forma
0.5*101 - e analisando criticamente o resultado dessa conversão:
- pelo método disparatado daria 0.12*21; como a
multiplicação de um nº pela sua base corresponde a deslocar o ponto decimal 1
casa para a direita, o resultado final desta multiplicação daria o valor 12.
Acha que 5 no sistema decimal é igual a 1 no sistema binário?
Assim, antes de fazermos qq operação de conversão de bases, temos primeiro de passar este valor da notação científica para a outra notação; neste caso pegar no valor fornecido, fazer a multiplicação lá especificada pela potência da base 10, para se obter o valor 260.75. E é este o valor que irá ser convertido para hexadecimal.
Neste caso concreto (e na maioria dos casos) é mais simples passar primeiro para binário e depois para hexadecimal.
Se ainda não resolveu este pb, tente agora fazê-lo antes de espreitar pelo resto da resolução...
Vamos então à conversão, por partes:
- parte inteira: 260 ; vamos evitar as divisões sucessivas, e tentar encontrar as potências de 2 que, somadas, perfazem esse valor; sabendo a tabuada de cor, recordamos que a potência de 2 mais próxima de 260 e <260 é 256 (=28); para 260 faltam 4, que é outra potência de 2 (=22); então 260 = 28 + 22 , ou seja, 260=1000001002 ;
- parte fraccionária: 0.75 ; vamos evitar as multiplicações sucessivas, e tentar encontrar as potências negativas de 2 que, somadas, perfazem esse valor; este caso é demasiado simples: 0.75=0.5+0.25 = 1/2 + 1/22 , ou seja 0.75=0.112 ;
Temos então que 260.75 = 100000100.112
.
Para passar para hexadecimal é só agrupar em conjuntos de 4 bits, a contar do ponto decimal,
para a esquerda e direita, acrescentando os zeros que forem precisos e que não
alteram o valor: 0001 0000 0100.11002 .
Então, 260.75 = 0x104.C ou 104.C16 .
b) Um registo de 16 bits contém o conjunto de bits correspondente ao valor 0xD8. Mostre o valor que está lá guardado, em decimal, conforme o registo contém um valor inteiro sem sinal, ou o registo contém um valor inteiro (codificado em complemento para 2). Justifique os resultados apresentados.
Sugestão de resolução
O valor 0xD8 em binário é 1101 10002 .
Alguns pensarão que, como o bit mais à esquerda é 1, este valor em complemento para 2 representa um valor negativo. Será?
Pense e responda antes de continuar!
Atenção ao enunciado: esse valor está num registo de 16 bits; logo o que lá se encontra é o valor binário 0000 0000 1101 10002 .
E agora, para codificar em complemento para 2, o que se faz? Como é "complemento para 2", temos de trocar todos os bits e somar 1, verdade?
Pense e responda antes de continuar!
DISPARATE!!
Este valor em complemento para 2 representa um valor positivo, que vale em decimal tanto quanto um valor sem sinal!
Portanto, quer o registo contenha um valor inteiro sem sinal, ou um valor inteiro representado em complemento para 2, o valor em decimal é o mesmo e vem dado por 27+26+24+23 = 216 .
c) Efectuando o menor nº
possível de operações, represente na base 3 os seguintes valores: 11, 33, 99
Nota (para R): veja se consegue com apenas 2 divisões, explicitando o raciocínio seguido.
Sugestão de resolução
Comecemos pelo 1º nº, o 11; na 1ª divisão pela nova base (3) daria quociente 3 e resto 2 (que será o 1º algarismo à esquerda do ponto decimal, no sistema de numeração de base 3); dividindo agora o quociente (3) novamente pela base (3) teríamos 0 de resto (o 2º algarismo à esq do ponto decimal) e 1 de quociente (o 3º e último algarismo).
Mas, será que precisávamos de fazer estas 2
divisões por 3? Neste caso tão simples, não dá para ver que 11 = 32+2,
ou seja, 11 = 1*32+2*30
?
Assim, neste caso, 11 = 1023 .
E agora 33: não será fácil de constatar que 33=11*3 , e que 99=11*9=11*32 ?
Se ainda não resolveu este pb,
tente agora fazê-lo antes de espreitar pela resolução...
Ainda não conseguiu?
E não se lembra do que leu na resolução de a) ? Que a multiplicação de um nº
pela sua base correspondia a deslocar o ponto decimal de uma casa para a
direita? E no caso de um inteiro (sem ponto decimal, embora se possa
subentendê-lo onde deveria estar), multiplicar pela sua base corresponde a
deslocar todo o nº uma casa para a esquerda, acrescentando um zero à direita do
nº.
Tente outra vez...
Resolução:
33 = 11*3 = (1*32+2*30)*31 = 1*33+2*31 = 10203
99 = 11*32 = (1*32+2*30)*32
= 1*34+2*32 = 102003 ou
99 = 33*3 = (1*33+2*31)*31 = 1*34+2*32
= 102003
d) Uma variável em C declarada
como unsigned short int
(16 bits) é inicializada com um valor que corresponde à dimensão da memória
cache no início dos processadores IA-32 com cache interna (i.e., 40K). Mostre,
em hexadecimal, qual o valor que é guardado em memória.
Notas (para R): (i) tente resolver o problema sem efetuar qualquer
divisão aritmética, mostrando os passos que seguir; e resolva adicionalmente o
seguinte: (ii) repita o exercício para o dobro desse valor (80K), e (iii) repita
o exercício mas considerando agora que a variável foi declarada como
float, e efetuando o menor
nº possível de operações..
Sugestão de resolução:
Recorde a tabuada das potências de 2... O nº 40
não lhe diz nada?
Se não, então calcule 40*1024 e depois faça as sucessivas divisões por 2, aproveitando os restos
das divisões.
Se prefere antes usar a cabeça, então...
40K = (32+8)*1K = (25+23)*210 = 215+213
= 1010 0000 0000 00002 = 0xA000
.
Para representar o dobro desse valor, isso
corresponderia a multiplicar pela base (2), ou seja, deslocar o nº uma casa para a
esquerda, acrescentando um zero à direita; mas, como em binário com 16 bits (sem
sinal) o bit mais à esquerda neste caso é diferente de zero, se o deslocarmos um
bit à esquerda vamos perdê-lo.
Esta variável, da maneira como foi declarada em C, não pode usar mais de 16
bits.
Logo, não é possível representar 80K com 16 bits, pois ultrapassa a capacidade
máxima de representação de nºs com 16 bits (máx 216-1, ou seja,
64K-1).
Mas... se se pretende representá-lo em vírgula
flutuante, então temos que preparar a expressão que nos calcula os 80K e
adaptá-la à expressão que nos dá o valor em decimal de um nº em vírgula
flutuante, precisão simples, no IEEE 754:
V = (-1)S * 1.F * 2 E-127
=
V = 2 * 40K = 2 * (32+8) * 1K = 2 *
(25+23) * 210 = (25+23) * 211
= 10 10002 * 211 = 1.012 * 216 =
(-1)0 * 1.012 * 2 E-127
Daqui se tira que:
S = 0
F = 010..02 (23 bits no total)
E = 127+16 = 143 = 27+23+22+21+20
= 1000 11112
Donde, em hexadecimal, o valor que será guardado
em memória virá dado por (os bits do expoente estão sublinhados)
0100 0111 1010 0000 0000 0000 0000 00002 =
0x47A00000
Sugestão de resolução
Vamos analisar o pb, relembrar alguns conceitos para compreender o enunciado, e refletir sobre a sua resolução; assim:
Julgo que com esta informação já não é preciso dizer mais nada. Falta apenas construir a resposta em Português simples e claro, eventualmente reutilizando algum deste texto..
a) [-2^31, +2^31[ , sempre que o registo contiver o valor de uma variável numérica que foi declarada num programa em C; comente esta afirmação.
Nota: a questão colocada nesta alínea tem uma subtileza para uma classificação R, ou mesmo B. Para uma classificação de apenas A, leia a sua reformulação na resolução (sugestão aos estudantes que pretendem mais que A: tentem encontrar essa "subtileza" antes de saltarem para a resolução).
Sugestão de resolução
Se não descobriu a "subtileza", eis a questão reformulada:
a) [-2^31, +2^31[ , sempre que o registo contiver o valor de uma variável numérica que foi declarada como int num programa em C; comente esta afirmação.
O Pentium é um processador característico da família IA-32; como tal, as variáveis do tipo
int são representadas em complemento para 2, com 32 bits. A gama de valores inteiros (negativos e positivos) representáveis em binário, com n bits, é de 2n; em complemento para 2, há apenas uma representação do zero, sendo possível representar mais um valor inteiro negativo que positivo.Então, com 32 bits, a gama de valores representáveis no Pentium é [-2^31, +2^31[, conforme indicado no enunciado.
Voltando agora à questão original.
Na questão inicial não se especificava a maneira como a variável numérica tinha
sido especificada: poderia ter sido como
int,
short int,
unsigned int,
unsigned short int,
ou até como float
ou double
.
De todas estas formas de especificar, apenas uma especificação do tipo
int
poderia produzir o resultado indicado no enunciado; em todos os outros casos, o
intervalo de valores seria distinto.
Sugestão adicional aos pretendentes de uma boa
classificação: indique os intervalos para os 5 restantes tipos acima referidos.
O resultado está no fim da alínea seguinte.
a)
(...)
b)
[0, +2^32]
se o registo for o IP/PC; comente esta afirmação.
Sugestão de resolução
O registo Instruction Pointer (tradicionalmente conhecido como Program
Counter) contém o apontador para a localização em memória da próxima
instrução (em linguagem máquina) a ser executada pelo processador.
Sendo um endereço de memória, representa um valor inteiro sem sinal.
A gama de valores representáveis em binário, com n bits, é de
2n; vai de zero a
2n-1, inclusive.
Então, com 32 bits, a gama de endereços de
memória representáveis em registo num Pentium é
[0, +2^32[, e não o intervalo indicado no
enunciado.
E agora a resolução à questão adicional colocada na sugestão
de resolução da alínea anterior:
-
short int,
[-2^15, +2^15[
- unsigned
int,
[-0, +2^32[
- unsigned
short int,
[0, +2^16[
- float,
]-2^128, +2^128[
- double,
]-2^1024, +2^1024[
.
a)
(...)
b)
(...)
c) [0, 9999] se o valor
estiver representado como uma string de caracteres alfanuméricos em ASCII;
comente esta afirmação.
Sugestão de resolução
Se pretendemos representar um nº como uma string de
caracteres alfanuméricos em ASCII, então cada algarismo será codificado como um
carater ASCII, não necessitando de ocupar mais que uma célula de memória
(8-bits).
Como cada registo do Pentium tem 32 bits, é possível escrever num registo todo o
conteúdo de uma string de 4 elementos, i.e., é possível guardar num
registo um nº codificado com 4 caracteres alfanuméricos, e como tal estando no
intervalo '0000' a '9999'.
Assim, o intervalo de valores especificado no enunciado está
de acordo com este raciocínio.
a)
(...)
b)
(...)
c)
(...)
Sugestão de resolução
A representação de valores em vírgula flutuante no Pentium
segue a norma IEEE 754; se se usarem apenas 32 bits, então segue a parte da
norma referente à precisão simples.
A norma contempla a representação de valores normalizados, valores
não-normalizados (os muito próximos de zero), e alguns casos especiais
(incluindo o zero e os infinitamente grandes, quer positivos quer negativos).
Como se pretende a gama de valores representáveis, desde o muito grande
negativo, até ao muito grande positivo, esta gama é integralmente definida
apenas pelos valores normalizados. E o valor decimal de um nº representado em
binário normalizado, segundo o IEEE 754 vem dado por
V = (-1)S * 1.F * 2 E-127
Então pretende-se o maior valor de F e de E para os valores de S=0 e S=1; isto corresponde a F=1..12 (23 bits) e E=1111 11102 (para ser normalizado tem de ser diferente de tudo uns), i.e., E=254.
A gama de valores encontra-se então entre
-1.111111111111111111111112*2127
e +1.111111111111111111111112*2127
, incluindo estes 2 valores extremos.
Os valores logo a seguir a estes, mas já fora do intervalo de valores
representáveis, seriam -2*2127
e +2*2127 ,
o que corresponde a representarmos a gama de valores como estando no intervalo
]-2^128, +2^128
char
tamp[3]="AJP"; // ‘A’ = 65 em decimal //
short int sval;
int ival;
float fval;
.....
.....
fval = ??? // valor especificado no enunciado //
ival = (int) fval;
sval = (short int) -fval; // notar o sinal menos //
a) Apresente o valor em decimal atribuído a cada uma das variáveis fval, ival, sval .
Sugestão de resolução
De acordo com o enunciado, a variável fval é uma variável declarada como sendo de vírgula flutuante, de precisão simples (32 bits, norma IEEE 754, como acontece em computadores compatíveis com o IA-32); e essa variável está em memória, ocupando as 4 células (32 bits = 4*8) que se seguem a 0xBFFFDA0 . O conteúdo dessas 4 células é tb indicado no enunciado: "00 50 89 43 , expresso em formato hexadecimal"; se nos lembrarmos que o IA-32 é little endian, sabemos que na 1ª célula se encontra o byte menos significativo, e na última estará o mais significativo.
Então, o conteúdo da variável
fval representado em hexadecimal e binário,
de acordo com a norma IEEE, é, respectivamente
(os bits do expoente estão sublinhados),
0x43895000 e 0100 0011
1000 1001 0101 0000 0000 00002
S = 0 (valor positivo)
E = 1000 01112
=> normalizado, logo em notação excesso
127 ; subtraindo 127 para se saber quanto vale o expoente: subtrai-se 128
(remove-se o 1 à esquerda) e soma-se 1; dá 10002
= 8
F = 0.0001 0010 1012
Sabendo que o valor em decimal de um nº em vírgula flutuante,
normalizado, precisão simples, representado pela norma IEEE 754, é calculado
pela expressão
V = (-1)S * 1.F * 2 E-127
então
fval = (-1)0 * 1.0001
0010 1012 * 2 8 =
1 0001 0010.1012 =
256+16+2+1/2+1/8 = 274.625
De acordo com o fragmento de código C
disponibilizado,
ival é o resultado da conversão de um valor
em vírgula flutuante (fval)
para um valor inteiro (codificado em complemento para 2), através da truncatura da parte decimal; neste caso
concreto,
ival =
(int) 274.625
= 274
Também de acordo com o fragmento de código C
disponibilizado,
sval é o resultado da conversão de um valor
em vírgula flutuante (-fval)
para um valor inteiro (codificado em complemento para 2), "curto" (16 bits),
através da truncatura da parte decimal; neste caso concreto,
sval =
(short int
Durante a execução do sequinte fragmento de código C, compilado para um processador compatível com IA-32, o espaço de memória atribuído às variáveis locais fval,ival,sval,tamp estende-se contiguamente, no sentido dos endereços crescentes, com início em 0xBFFFDA0 .
char
tamp[3]="AJP"; // ‘A’ = 65 em decimal //
short int sval;
int ival;
float fval;
.....
.....
fval = ??? // valor especificado no enunciado //
ival = (int) fval;
sval = (short int) -fval; // notar o sinal menos //
a)
(...)
b) Considerando que o valor
ASCII do caracter ´A´ é 65 (decimal), represente, em hexadecimal, no espaço de
memória reservado, a variável
tamp
.
Sugestão de resolução
A tabela ASCII codifica as letras do alfabeto com códigos
adjacentes e crescendo com a ordem alfabética; assim, se 'A' é codificado por
65, 'J' deverá ser codificado por 74, e 'P' por 80.
Por outro lado, numa string (que é representada normalmente por um vector
de caracteres), o conjunto de caracteres que lhe são assim atribuídos são colocados
nos primeiros elementos do vector, e se esses não encherem a totalidade do
vector, então são atribuídos caracteres null (ASCII '0', ou como
normalmente se designa em C, '\0') aos restantes
elementos do vector (string).
Assim, o vector
tamp[3], que tem
reservado na memória espaço para 4 elementos de 1 byte, contém os
seguintes valores em hexadecimal (resultantes da codificação directa dos valores
em decimal acima referidos, 65, 74, 80 e 0): 41 4A 50 00.
Durante a execução do sequinte fragmento de código C, compilado para um processador compatível com IA-32, o espaço de memória atribuído às variáveis locais fval,ival,sval,tamp estende-se contiguamente, no sentido dos endereços crescentes, com início em 0xBFFFDA0 .
char
tamp[3]="AJP"; // ‘A’ = 65 em decimal //
short int sval;
int ival;
float fval;
.....
.....
fval = ??? // valor especificado no enunciado //
ival = (int) fval;
sval = (short int) -fval; // notar o sinal menos //
a)
(...)
b) (...)
c) Represente, em hexadecimal,
todas as variáveis declaradas, no fragmento de código, com a indicação precisa
dos endereços ocupados na memória.
Sugestão de resolução
São 4 as variáveis declaradas neste fragmento de código C:
fval,ival,sval,tamp.
O valor em decimal das primeiras 3 variáveis foi calculado em a); falta agora recuperar/calcular
os seus valores em hexadecimal:
-
fval
está no texto do enunciado;
-
ival
é a representação em binário/hexadecimal, complemento para 2, de '274': 0000 0000
0000 0000 0000 0001 0001 00102 <=> 0x112
-
sval
é a representação em binário/hexadecimal, complemento para 2, com 16 bits,
de '-274':
1111 1110 1110 11102
<=> 0xFEEE
O valor em hexadecimal da 4ª variável foi calculado na alínea anterior.
Localização das variáveis: fval (ocupando 4 células) em 0xBFFFDA0 ; ival (4 células) em 0xBFFFDA4 ; sval (2 células) em 0xBFFFDA8 ; tamp (4 células) em 0xBFFFDAA .
Resumindo, sem esquecer que o IA-32 é little endian:
0x 0B FF FD A0 :
00
"
A1
:
50
" A2
:
89
" A3
:
43
0x 0B FF FD A4
:
12
" A5
:
01
" A6
:
00
" A7
:
00
0x 0B FF FD A8
:
EE
" A9
:
FE
0x 0B FF FD AA :
41
" AB
:
4A
" AC
:
50
" AD
:
00
E se estivéssemos a analisar um computador big endian, em vez de um
baseado no Pentium?
A diferença está apenas na maneira como uma quantidade
escalar, não estruturada - e cuja dimensão em nº de bits é superior à de uma célula de
memória - é armazenada nessas células. E o pb do big versus little
endian apenas se coloca neste caso.
No nosso exercício, temos 3 variáveis escalares e uma estruturada (uma string,
representada como um array), cujos elementos são carateres (e portanto
requerendo cada apenas 8 bits, a dimensão de uma célula). Apenas as variáveis
escalares irão ser afetadas por esta questão.
Então, aqueles 14 bytes ficariam assim armazenados em memória, a partir do
endereço inicial
0x 0B FF FD
a) Encontre uma explicação
válida para a posição do docente.
Nota: se esta questão não contivesse a alínea b), seria para uma classificação
B
Sugestão de resolução
Vamos analisar cuidadosamente a afirmação do docente: (i) ele confirma a veracidade dos dados visualizados no monitor, i.e., que os registos
%esp e %eax têm a mesma representação em hexadecimal/binário, em cada um dos grupos que fez a afirmação (i.e., a 1ª parte da afirmação deles está correcta: "têm o mesmo valor" ); mas (ii) ele contesta a afirmação de um dos grupos, e só poderá estar a referir-se à 2ª parte da afirmação: "e portanto representam o mesmo valor decimal!"A questão resume-se a: em que situações é que a mesma codificação de 2 números (em binário/hexadecimal) pode não representar o mesmo valor no sistema de numeração decimal?
Pense um pouco antes de continuar!
Resposta: se esses números representarem tipos de dados
inteiros distintos, e algo mais...
Neste caso em particular, sabe-se que um dos valores é um inteiro sem sinal
(mais concretamente, um endereço de memória, que é o valor do apontador para a
stack); se o outro registo
"foi usado para representar
uma das variáveis inteiras do programa", é muito provável que essa variável
tenha sido declarada como
int, logo um inteiro
com sinal.
Então, a 2ª questão que se pode colocar é a seguinte: em que situação é que a
representação binária de um inteiro sem sinal é diferente da de um inteiro em
complemento para 2? Apenas na representação de nºs negativos em complemento para
2! Se o nº for positivo e puder ser representado na notação em complemento para
2, então essa representação é igual à conversão directa de um nº decimal (sem
sinal) num nº binário/hexadecimal.
Completando a resposta começada em cima: se esses números representarem tipos de
dados inteiros distintos, e se não forem ambos positivos.
b) Suponha que o 1º grupo
via nos registos que tinham o mesmo conteúdo o valor
0x800c14,
enquanto o segundo grupo tinha
0xfffffffe.
Calcule e indique o valor, em decimal, armazenado em cada um dos registos, nos 2
grupos.
Sugestão de resolução
1º grupo
Passando
0x800c14
para binário com 32 bits: 0000 0000 1000 0000 0000 1100 0001 01002
; representa um valor positivo
(a variável inteira em
%eax) ou um valor sem
sinal
(o apontador para o topo da stack), e ambos valem o
mesmo:
223 + 211 + 210 + 24
+ 22
2º grupo
Passando
0xfffffffe
para binário com 32 bits: 1111 1111 1111 1111 1111 1111 1111 11102
; representa um valor negativo pequeno (o que estará em
%eax), ou um valor muito grande se for considerado sem
sinal (o apontador para o topo da stack),
e valem:
- em
%eax : calculando o complemento para 2, este conjunto de
bits vale (-102)
ou (
Nota: os valores apresentados nas alíneas seguintes estão em hexadecimal, e foram obtidos com ferramentas de debugging, enquanto o software era testado num Pentium.
a) 0x 48 A9 01 00 80 C5 00 00
Sugestão de resolução
Há uma decisão de fundo a tomar antes de atacar este pb:
(i) vamos 1º identificar os limites de representação de nºs normalizados e
desnormalizados (intervalo de valores e resolução) para cada um dos formatos
(precisão simples/dupla) e depois analisar cada um dos valores propostos, ou
(ii) começamos de imediato a tentar calcular o valor decimal de cada um destes
dados e tentamos convertê-los depois para o novo formato.
A 1ª abordagem dá-nos uma melhor perspetiva do que está em causa, mas exige mais trabalho no início; contudo, como esta questão tem 3 conjuntos de valores, este acréscimo de trabalho inicial é depois "amortizado" em cada uma das alíneas consequentes. Vamos pois seguir esta abordagem.
Um outro aspeto a analisar é tentar identificar, antes de qq outra atividade, que tipo de pb's poderão surgir quando tentamos converter um valor de um formato em FP para outro que utiliza menos bits, pois coloca-nos em melhor posição para uma análise crítica dos resultados que formos obtendo ao longo da resolução. Vamos ver o quero dizer com isto.
O que distingue estes 2 formatos é essencialmente o nº de bits
usado para representar o expoente (8 e 11) e a mantissa (23 e 52).
Implicações:
- expoente: quanto maior o nº de bits usado no expoente maior é a
gama de valores que é possível representar, quer no eixo positivo, quer no
negativo; isto terá como consequência que (i) valores muito grandes (em modo
absoluto) em precisão dupla poderão não ter representação em precisão simples (overflow
positivo ou negativo, que de acordo com a norma IEEE será codificado como sendo
±
Vamos então identificar os limites de
representação de nºs normalizados e desnormalizados:
- precisão simples, caminhando de – ¥
até + ¥
(em caso de dúvida, consultar a resolução da alínea d) de
A3)
]-2^128,
-2^-126] ]-2^-126,
-2^-149]
[2^-149,
2^-126[
[2^-126,
2^128[
- - precisão dupla, caminhando de –
¥ até +
¥ (à semelhança
da precisão simples, o expoente usa a notação excesso 2n-1-1, i.e.,
1023)
]-2^1024,
-2^-1022] ]-2^-1022,
-2^-1074]
[2^-1074,
2^-1022[
[2^-1022,
2^1024[
Olhando para estes intervalos, já são
mais claras a afirmações feitas anteriormente sobre as implicações do nº
diferente de bits para representar o expoente; apenas alguns exemplos:
- qq nº em precisão dupla normalizado
³2128 e
<21024 é overflow
positivo quando convertido para precisão simples;
- qq nº em precisão dupla normalizado
³2-149 e
<2-126 é representado
como desnormalizado quando convertido para precisão simples;
- qq nº em precisão dupla normalizado
³2-1074 e
<2-149 é underflow
positivo quando convertido para precisão simples;
- qq nº em precisão dupla desnormalizado é underflow (positivo ou
negativo) quando convertido para precisão simples.
E agora vamos ver o caso concreto desta
alínea (os bits do expoente estão
sublinhados):
0x 48
A9 01 00 80 C5 00 00 =
0100 1000 1010 1001 0000 0001 0000 0000 1000
0000 1100 0101 0000 0000 0000 00002
S = 0 (positivo)
E = 100 1000 10102 (=> normalizado)
= 1024+128+8+2 = (1024+138)
F = 1001 0000 0001 0000 0000 1000 0000 1100
0101 0000 0000 0000 00002
Donde,
V = (-1)S * 1.F * 2 E–1023
= = (-1)0 * 1.F * 2
(1024+138) –1023 = 1.F * 2139 =>
=> não é possível representá-lo em precisão simples por estar fora da gama de
valores representáveis (overflow positivo); vai ter de ser codificado
como sendo +
¥
Resultado:
0111 1111 1000 0000 0000 0000 0000 00002
= 0x 7F 80 00 00
Imagine que está a desenvolver software (em C) para controlo de um equipamento industrial (que requer bastente precisão numérica nas coordenadas). Esse software, depois de devidamente testado num PC, vai ser portado para um outro processador (um microcontrolador) que ficará embebido no equipamento. Contudo, esse processador não suporta o formato de precisão dupla conforme especificado na norma IEEE 754, pelo que todas as variáveis que tenham sido declaradas como double serão representadas apenas com 32 bits, no formato de precisão simples dessa mesma norma.
Nota: os valores apresentados nas alíneas seguintes estão em hexadecimal, e foram obtidos com ferramentas de debugging, enquanto o software era testado num Pentium.
a)
(...)
b) 0x 34 09 01 00 80 00 00 00
Sugestão de resolução
Após todos os considerandos da alínea anterior
0x 34
09 01 00 80 00 00 00 =
0011 0100 0000 1001 0000 0001 0000 0000 1000
0000 0000 0000 0000 0000 0000 00002
S = 0 (positivo)
E = 011 0100 00002 (=> normalizado) = 512+256+64 = 832
F = 1001 0000 0001 0000 0000 1000 0000 0000
0000 0000 0000 0000 00002
Donde,
V = (-1)S * 1.F * 2 E–1023 = = (-1)0 * 1.F * 2
832–1023 = 1.F * 2–191 =>
=> não é possível representá-lo em precisão simples por estar fora da gama de
valores representáveis (underflow positivo); vai ter de ser codificado
como sendo +0
Resultado:
0000 0000 0000 0000 0000 0000 0000 00002
= 0x0
Imagine que está a desenvolver software (em C) para controlo de um equipamento industrial (que requer bastente precisão numérica nas coordenadas). Esse software, depois de devidamente testado num PC, vai ser portado para um outro processador (um microcontrolador) que ficará embebido no equipamento. Contudo, esse processador não suporta o formato de precisão dupla conforme especificado na norma IEEE 754, pelo que todas as variáveis que tenham sido declaradas como double serão representadas apenas com 32 bits, no formato de precisão simples dessa mesma norma.
Nota: os valores apresentados nas alíneas seguintes estão em hexadecimal, e foram obtidos com ferramentas de debugging, enquanto o software era testado num Pentium.
a)
(...)
b)
(...)
c) 0x B7 41 90 10 80 00 C0 00
Sugestão de resolução
Após todos os considerandos da alínea a)
0x B7
41 90 10 80 00 C0 00 =
1011 0111 0100 0001 1001 0000 0001 0000 1000
0000 0000 0000 0000 1100 0000 00002
S = 1 (negativo)
E = 011 0111 01002 (=> normalizado) = 512+256+64+32+16+4 = 884
F = 0001 1001 0000 0001 0000 1000 0000 0000
0000 0000 1100 0000 00002
Donde,
V = (-1)S * 1.F * 2 E–1023 = = (-1)1 * 1.F * 2
884–1023 = 1.0001 1001 0000 0001 0000 1000 0000 0000 0000 0000 112
* 2–139 =>
=> representável em precisão simples, mas como valor desnormalizado.
Então, vai ser preciso modificar a expressão acima
apresentada, para que ela fique semelhante à expressão que nos dá o valor de um
nº desnormalizado em precisão simples:
V = (-1)S * 0.F * 2 –126
= –1.0001 1001 0000 0001 0000 1000 0000 0000 0000 0000 112 * 2–139
=
= –0.0000 0000 0000 1000 1100 1000 0010
0001 0000 0000 0000 0001
12 * 213 * 2–139 =
(como só existem 23 bits na mantissa em precisão simples, vão-se perder dígitos
significativos
Resultado:
1000 0000 0000 0000 0000 0100 0110 01002
= 0x 80 00 04 64 (com perda de dígitos
significativos)