Sistemas de Computação
      Mestr. Integr.
      Engª Informática, 1º ano
      2015/2016
      Docente 
      responsável: A.J.Proença
Autoavaliação
 
Representação de informação 
Última Modificação: 03 Mar 2016
| 
         
          | 
        
         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)