Gabarito da Lista 1
Transcrição
Gabarito da Lista 1
Computadores e Programação (MAB-353) Primeira Lista de Exercı́cios Individual v.0 100 pontos Prof. Paulo Aguiar (DCC/IM/UFRJ)- GABARITO Questão 1 Exercı́cio 2.65 do livro. (20 pontos) Tradução do enunciado: Escreva um código para implementar a seguinte função: /* Retorna 1 quando x contém um número ı́mpar de uns; 0 caso contrário. Assuma w=32. */ int odd ones(unsigned x); Sua função deve seguir as regras de codificação ao nı́vel de bit para inteiros (página 120), exceto que você pode assumir que o tipo int tem w = 32 bits. O seu código pode conter um máximo de 12 operações bit a bit aritméticas e lógicas. Solução: Para detetar um número ı́mpar de bits uns em uma palavra de 32 bits, assumindo bi como o valor do bit da posição i, 0 ≤ i ≤ 31, tenho que computar b0 ⊕ b1 · · · ⊕ b31 . Mas para fazer isso em menos de 12 operações, temos que quebrar o valor x de 32 bits em duas partes, digamos x1 e x2 , calcular p16 = x1 ⊕ x2 , bit a bit, reduzindo para 16 bits. Fácil ver que p1 6 = [b31 ⊕ b15 , b30 ⊕ b14 , · · · , b16 ⊕ b0 ]. Repetindo o processo, pode-se obter p8 = [b31 ⊕ b15 ⊕ b23 ⊕ b7 , b30 ⊕ b14 ⊕ b22 ⊕ b6 , · · · , b24 ⊕ b8 ⊕ b16 ⊕ b0 ] p4 = [b31 ⊕ b15 ⊕ b23 ⊕ b7 ⊕ b27 ⊕ b11 ⊕ b19 ⊕ b3 , · · · , b28 ⊕ b12 ⊕ b20 ⊕ b4 ⊕ b24 ⊕ b8 ⊕ b16 ⊕ b0 ] p2 = [b31 ⊕ b15 ⊕ b23 ⊕ b7 ⊕ b27 ⊕ b11 ⊕ b19 ⊕ b3 ⊕ b29 ⊕ b13 ⊕ b21 ⊕ b5 ⊕ b25 ⊕ b9 ⊕ b17 ⊕ b1 , b30 ⊕ b14 ⊕ b22 ⊕ b6 ⊕ b26 ⊕ b10 ⊕ b18 ⊕ b2 ⊕ b28 ⊕ b12 ⊕ b20 ⊕ b4 ⊕ b24 ⊕ b8 ⊕ b16 ⊕ b0 ], e finalmente p1 = b31 ⊕ b15 ⊕ b23 ⊕ b7 ⊕ b27 ⊕ b11 ⊕ b19 ⊕ b3 ⊕ b29 ⊕ b13 ⊕ b21 ⊕ b5 ⊕ b25 ⊕ b9 ⊕ b17 ⊕ b1 ⊕ b30 ⊕ b14 ⊕ b22 ⊕ b6 ⊕ b26 ⊕ b10 ⊕ b18 ⊕ b2 ⊕ b28 ⊕ b12 ⊕ b20 ⊕ b4 ⊕ b24 ⊕ b8 ⊕ b16 ⊕ b0 ], ou seja, p1 é o ou-exclusivo de todos os bits de x e o valor a ser retornado. O código C da rotina é dado abaixo, lembrando que o deslocamento à direita para unsigned é lógico: int odd_ones (unsigned x) { unsigned p16 = (x >> 16) ^ x; /* Xor bits i e i+16 para 0 <= i unsigned p8 = (p16 >> 8) ^ p16; /* Xor bits i and i+8 for 0 <= unsigned p4 = (p8 >> 4) ^ p8; /* Xor bits i and i+4 for 0 <= i unsigned p2 = (p4 >> 2) ^ p4; /* Xor bits i and i+2 for 0 <= i unsigned p1 = (p2 >> 1) ^ p2; /* Xor bits 0 and 1; lixo nos 31 return p1 & 1; /* retorna o valor no LSB apenas, desprezando o 1 < 16; lixo nos 16 bits superiores */ i < 8; lixo nos 24 bits superiores */ < 4; lixo nos 28 bits superiores */ < 2; lixo nos 30 bits superiores */ bits superiores */ lixo */ Questão 2 Exercı́cio 2.66 do livro. (20 pontos) Tradução do enunciado: Escreva um código para implementar a seguinte função: /* Gere uma máscara que indica a posição do 1 mais à esquerda. Assuma w=32. Por exemplo 0XFF00 − > 0x8000, e 0x6600 −− > 0x4000. Se x=0, então retorne 0. */ int lefmost one (unsigned x); Sua função deve seguir as regras de codificação ao nı́vel de bit para inteiros (página 120), exceto que você pode assumir que o tipo int tem w = 32 bits. O seu código pode conter um máximo de 15 operações bit a bit aritméticas e lógicas. Dica: Primeiro transforme x num vetor da forma [0 ... 011 ... 1]. A dica aponta para a solução. Assumindo bi o valor do bit na posição i, ao se fazer x = x|(x >> 1), obtemos x = [b31 |b31 , b31 |b30 , b30 |b29 , b29 |b28 , · · · , b2 |b1 , b1 |b0 ]. Observe que se b31 = 1, então as duas posições superiores do resultado ficariam em 1. Se b31 = 0, então a ocorrência de 1 em b31 |b30 dependerá do valor de b30 , ou seja, as duas posições mais significativas terão 1 a partir do bit mais à esquerda de x em 1. Fazendo em seguida x = x|(x >> 2), obtemos x = [b31 |b31 , b31 |b30 , b31 |b30 |b29 , b31 |b30 |b29 |b28 , b30 |b29 |b28 |b27 , · · · , b4 |b3 |b2 |b1 , b3 |b2 |b1 |b0 ]. As quatro posições mais significativas terão 1 a partir do bit mais à esquerda de x em 1. Fazendo em seguida x = x|(x >> 4), as 8 posições mais significativas terão 1 a partir do bit mais à esquerda de x em 1. Fazendo em seguida x = x|(x >> 8), as 16 posições mais significativas terão 1 a partir do bit mais à esquerda de x em 1. Fazendo em seguida x = x|(x >> 16), as 32 posições terão 1 a partir do bit mais à esquerda de x em 1, e teremos obtido a máscara da dica. Para de fato gerar a resposta pretendida, falta o passo xˆ= (x >> 1), que zera todos os bits da máscara anteriormente obtida, exceto na posição do bit 1 de x mais à esquerda. O código C é dado abaixo, com 12 operações bit a bit: int leftmost_one(unsigned x) { /* Obtém a máscara da dica no formato [0...011...1] */ x |= (x>>1); x |= (x>>2); x |= (x>>4); x |= (x>>8); x |= (x>>16); /* Deixa agora apenas o bit 1 mais à esquerda */ x ^= (x>>1); return x; } Questão 3 Exercı́co 2.69 do livro.(20 pontos) Tradução do enunciado: Escreva o código para uma função com o seguinte protótipo: /* Faça um deslocamento circular à esquerda. Assuma 0 ≤ n < w. * Exemplos quando x = 0x12345678 e w = 32: * n = 4 − > 0x23456781, n = 20 − > 0x67812345 */ unsigned rotatel ef t(unsignedx, intn); 2 Sua funç~ ao deve seguir as regras de codificaç~ ao ao nı́vel de bit para inteiros (página 120). Cuidado para o caso de n=0. Soluç~ ao: O resultado será a composiç~ ao de duas partes: a esquerda e a direita. unsigned rotate_left (unsigned x, int n) { /* Quando n=0, cria máscara com todos os bits em 1; todos em 0, caso contrário. */ int mascara = -!n; /* Lembrar que -1 s~ ao todos os bits em 1 */ /* Desloca n bits à esquerda para posicionar a rotaç~ ao e gerar espaço para os n bits inferiores. */ /* Obtem os w-n bits inferiores na posiç~ ao certa */ unsigned esquerda = x << n; /* Desloca w-n bits à direita para posicionar adequadamente os n bits superiores de x na rotaç~ ao */ /* Desloca o número de bits adequado */ unsigned direita = x >> ((sizeof(unsigned) << 3)-n); /* Se máscara for só de 1s é porque n=0 e retorna x; */ /* Se for só de 0s, retorna a concatenaç~ ao de esquerda e direita */ return (mascara & x) | (mascara & (esquerda|direita));} Questão 4 Exercı́cio 2.71 do livro. (20 pontos) Tradução do enunciado: Você acabou de iniciar trabalhando em uma companhia que está implementando um conjunto de rotinas para operar sobre uma estrutura de dados onde 4 bytes com sinal estão empacotados em um tipo unsignes de 32 bits. Bytes dentro da palavra sÃo numerados de 0 (LSB) a 3 (MSB). Você foi designado para desenvolver uma função para uma máquina operando com complemento a 2 e deslocamentos à direita aritméticos com o seguinte protótipo: /* Declaração de tipo onde 4 bytes são empacotados em um tipo unsigned. */ typedef unsignes packed t; /* Extrair byte da palavra. Retorna um inteiro com sinal. */ int xbyte (packed t word, int bytenum); Isto é, a função extrai o byte designado e estende o sinal para ser representado como um inteiro de 32 bits. O seu antecessor (que foi despedido por incompetência) escreveu o seguinte código: /* Tentativa fracassada de xbyte */ int xbyte (packed_t word, int byteenum) { return (word >> (bytenum << 3)) & 0xFF; A. O que está errado com este código? R: O deslocamento a esquerda equivale a multimplicar por 8. Caso se pretenda extrair um byte qye represente um valor negativo, o deslocamento à direita estará sempre inserindo bits à esquerda dependendo apenas valor do bit 31, o que não é a extensão de sinal desejada. Os 24 bits superiores do resultado deveriam ter o sinal do MSB do byte alvo. B. Dê uma implementação correta da função que usa apenas deslocamentos à direita e à esquerda, junto com uma única subtração. R: A ideia é deslocar o byte alvo até a posição 3 e depois deslocar à direita 24 posições, fazendo a extensão de sinal com o deslocamento aritmético. int xbyte(packed_t word, int bytenum) { int left = word << ((3-bytenum) << 3); /* desloca à esquerda para posicionar corretamente */ /* o byte alvo na posiç~ ao 3 */ return left >> 24; /* desloca byte alvo para a posiç~ ao 0, estendo corretamente o sinal */} 3