Computadores e Programação 2007–2008 Orlando Oliveira, Helmut Wolters adaptado a partir duma apresentação de Fernando Nogueira, José António Paixão, António José Silva [email protected], [email protected] Computadores e Programação – p.1 Programa • O modelo de von Neumann do computador digital. Arquitectura de um computador moderno. • Representação digital de dados. Códigos binários para representação de inteiros (código de valor absoluto e sinal e código de complementos de 2), reais (vírgula flutuante), caracteres (ASCII, unicode), imagem (RGB, JPEG) e som (CD-AUDIO). • Operações numéricas sobre dados binários. Problemas ligados à imprecisão da representação dos números reais em vírgula flutuante. • Processadores. Funcionamento de um CPU. Representação binária do código executável de um programa. Computadores e Programação – p.2 Programa • Assembladores, compiladores e interpretadores. Linguagens de programação de alto nível e de muito alto nível (VHLL). Sistemas operativos. • Introdução à linguagem de programação Python. • A instrução de atribuição. Aliasing. Noção de ponteiro. • Tipos numéricos: inteiros, inteiros longos, números em vírgula flutuante e complexos. • Sequências (listas, tuplas e sequências de caracteres). Iteração sobre sequências e operações de fatiagem (slicing). Abrangências. Dicionários. • Instruções de controlo de fluxo: if..elif..else, while..else, for..else. Computadores e Programação – p.3 Programa • Funções. Espaço dos nomes e regras de alcance. Mecanismo de passagem de argumentos e devolução de valores. • Programação funcional e imperativa. Funções puras. As ferramentas de programação funcional lambda, map, filter e reduce. Exemplos de pequenos programas em estilo funcional. • Módulos. Ferramentas de introspecção e metaprogramação. • Ficheiros. Formatação. Redirecção dos canais de fluxo de entrada e saída. Computadores e Programação – p.4 Programa • Programação orientada por objectos. Noção de classe e instâncias de classe. Atributos e métodos. Herança, encapsulamento e polimorfismo. Sobrecarga de operadores. Objectos persistentes: módulos pickle e shelve. • Excepções. As instruções raise e try..except..finally. • Recursão. Iteradores e geradores. • Resolução de problemas numéricos de Física e Biomedicina. Computadores e Programação – p.5 Avaliação • 30 % Resolução de problemas Entrega semanalmente por correio electrónico • 30 % Projecto Início de Dezembro, entrega até 1a semana de Janeiro • 40 % Mini testes 31 de Outubro 5 de Dezembro Computadores e Programação – p.6 O modelo de von Neumann • O matemático Johann von Neumann, consultor do projecto Manhattan, envolve-se nos projectos do ENIAC e do EDVAC em Junho de 1944. Inspirado por estes, concebe um modelo téorico para um computador, que é o modelo adoptado até hoje. • O computador é constituído pelas seguintes unidades funcionais: ◦ Memória central ◦ Unidade aritmética e lógica ◦ Unidade de controlo ◦ Unidades de entrada e saída • Hoje em dia o processador engloba a unidade aritmética e lógica e a unidade de controlo. Computadores e Programação – p.7 O modelo de von Neumann Unidade de controlo C C I C Unidade A/L D Unidades de E/S R D R D R ´ Memoria Central Computadores e Programação – p.8 O modelo de von Neumann • O processador não efectua operações directamente sobre a memória (à excepção da transferência de dados). • O processamento é feito em células especiais de memória no interior da UAL denominadas registos. • A tranferência de dados entre a memória central e os dipositivos de entrada e saída pode ser feita passando pelo processador ou através de acesso directo à memória (DMA). Computadores e Programação – p.9 Informação Digital • Os computadores processam informação digital. • Grandeza analógica Varia de forma contínua (ex: temperatura lida num termómetro de Hg). • Grandeza digital Descontínua (existe apenas um número finito de estados). • Elemento mínimo de informação: dígito binário (bit). • bit: 2 estados 0 ou 1. Computadores e Programação – p.10 Informação Digital • Um conjunto de n bits pode tomar 2n configurações distintos, podendo representar 2n objectos ou informações elementares. • Exemplo com 3 bits: Configurações possíveis (8 = 23 ): 000, 001, 010, 011, 100, 101, 110, 111. • Podemos utilizar estas combinações de bits para representar de forma unívoca 8 letras do alfabeto: A B C D 000 001 010 011 E F G H 100 101 110 111 Computadores e Programação – p.11 Codificação/descodificação • Os computadores processam (apenas) informação/dados em formato digital. • Todos os dados têm que ser codificados num formato digital para serem passíveis de tratamento informático. • Para cada tipo de dado tem de se estabelecer um código que permita atribuir uma configuração binária única a cada dado desse tipo → codificação. A operação inversa é a descodificação. • Vamos passar em revista alguns dos códigos actualmente usados para representação digital de vários tipos de dados num computador: ◦ Números inteiros, ◦ Números inteiros relativos ◦ Números reais ◦ (Caracteres) ◦ (Som e imagem) Computadores e Programação – p.12 Codificação de inteiros • A forma mais simples de representar um número inteiro num formato digital corresponde a utilizar a sua representação binária, isto é, na base 2. • O número é representado por n bits an−1 an−2 · · · a0 onde ai = 0, 1 e i = 0, ..., n − 1. • O inteiro correspondente a esta sequência de bits é: an−1 2n−1 + an−2 2n−2 . . . + a0 = n−1 X ai 2i i=0 • Este código designa-se por código binário ponderado. Computadores e Programação – p.13 Codificação de inteiros • O maior número inteiro que é possível representar com um conjunto de n bits é n−1 X 2n = 2n − 1 i=0 • n bits → 2n números inteiros, incluindo o zero: 0, 1, . . ., 2n−1 . Computadores e Programação – p.14 Conversão decimal/binário • A conversão de um número inteiro na base 10 em código binário ponderado é muito fácil. • Exemplo: Conversão do decimal 203 para a base 2. Representando o quociente e o resto da divisão inteira pelos operadores div e mod, temos: 203 div 2 =101; 203 mod 2 = 1 = a0; 101 div 2 = 50; 101 mod 2 = 1 = a1; 50 div 2 = 25; 50 mod 2 = 0 = a2; 25 div 2 = 12; 25 mod 2 = 1 = a3; 12 div 2 = 6; 12 mod 2 = 0 = a4; 6 div 2 = 3; 6 mod 2 = 0 = a5; 3 div 2 = 1; 3 mod 2 = 1 = a6; 1 div 2 = 0; 1 mod 2 = 1 = a7; Então 20310 = 110010112 . Computadores e Programação – p.15 Conversão decimal/binário • A conversão inversa (binário → decimal) é trivial. • Exemplo: 110010112 = 1 × 27 + 1 × 26 + 1 × 23 + 1 × 2 + 1 = 20310 Computadores e Programação – p.16 Notação octal/hexadecimal • É comum utilizar-se a notação hexadecimal, (base 16) para exprimir de forma mais compacta números binários. Cada dígito hexadecimal equivale a 4 dígitos binários. • Noutra notação, denominada octal, o número é representado na base 8, em que cada dígito octal (0 . . . 7) agrupa 3 bits. • Em hexadecimal são utilizados os 16 símbolos 0, 1, 2, . . . , 9, A, B, C, D, E, F. Por exemplo, o número 20010 pode ser escrito como 110010002 , C816 ou 3108 . Computadores e Programação – p.17 Tabela de conversão entre as bases mais usadas Binário Decimal Hexa. 0000 0 0 0001 1 1 0010 2 2 0011 3 3 0100 4 4 0101 5 5 0110 6 6 0111 7 7 Binário Decimal Hexa. 1000 8 8 1001 9 9 1010 10 A 1011 11 B 1100 12 C 1101 13 D 1110 14 E 1111 15 F • A transcrição de um número inteiro na base 10 para base 2 pode ser facilitada, sobretudo quando se trata de números grandes, fazendo primeiro a transcrição para hexadecimal, e utilizando a tabela acima para transcrever cada dígito hexadecimal na correspondente sequência de 4 algarismos binários. Computadores e Programação – p.18 Codificação de números relativos • Existem vários códigos que permitem codificar números inteiros relativos (códigos bipolares). • O código bipolar mais simples é o código de sinal e valor absoluto: ◦ o bit mais significativo representa o sinal ◦ os restantes n − 1 bits o valor absoluto. • Por convenção, o bit de sinal tem o valor 1 quando o número é negativo e o valor 0 quando é positivo. • Por exemplo, numa palavra de 8 bits, os números ±19 têm, neste código, a seguinte representação binária: +1910 = 00010011 −1910 = 10010011 Computadores e Programação – p.19 Codificação de números relativos • Vantagem deste código: simplicidade. • Desvantagens: ◦ podem-se representar apenas 2n − 1 números distintos com n bits e não 2n (o zero tem representação dupla) ◦ a adição de números relativos é problemática. Computadores e Programação – p.20 Código de complementos de 2 • No código de complementos de 2 representam-se os números positivos como no código anterior, e representa-se cada número negativo somando 1 ao complemento do número positivo que lhe corresponde. Um eventual transbordo que ocorra nesta soma é ignorado. • Vejamos como representar o número −19 numa palavra de 8 bits usando este código: +1910 = 00010011 −1910 = 11101100 + 00000001 = 11101101 • Regra prática para converter um número binário no respectivo complemento de 2: copiam-se os dígitos, a começar pelo bit menos significativo até encontrar o primeiro “1”, que também se copia. A partir daí, substituem-se os “0”s por “1”s e vice-versa. Computadores e Programação – p.21 Código de complementos de 2 • Vantagens da representação de complementos de 2: ◦ O zero tem representação única (verifique!). ◦ O bit mais significativo pode ser interpretado como bit de sinal: este bit é zero nos números positivos e 1 nos números negativos. ◦ O bit menos significativo determina sempre se um número é par ou ímpar, o bit é zero nos números pares e 1 nos ímpares. ◦ O número total de números que é possível representar neste código numa palavra de n bits é 2n , correspondendo ao intervalo −2(n−1) , . . . , 2(n−1) − 1. Computadores e Programação – p.22 Representação de números reais • Na base decimal 17.3210 = 1 × 101 + 7 × 100 + 3 × 10−1 + 2 × 10−2 • Do mesmo modo, na base 2 teremos 17.3210 = 1 × 24 + 0 × 23 + 0 × 22 + 0 × 21 + 1 × 20 + + 0 × 2−1 + 1 × 2−2 + 0 × 2−3 + 1 × 2−4 + 0 × 2−5 = + 0 × 2−6 + 0 × 2−7 + 1 × 2−8 + . . . = 10001.01010001 . . .2 • Mas 10001.010100012 = 17.3164062510 6= 17.3210 ! • E 10001.01010001111010112 = 17.319992065429687510 ! • Parece não haver representação binária finita de 17.3210 . . . Computadores e Programação – p.23 Representação em vírgula flutuante (IEEE754) • Os números reais formam um conjunto denso → não é possível representar exactamente um (intervalo) de reais num computador! • Representação em vírgula fixa: número fixo de casas decimais, digamos 6. Basta codificar um inteiro (o número sem a vírgula)! • Não é uma boa escolha → limita a gama dinâmica de valores que se podem representar com um conjunto de n bits. • Utiliza-se a notação em vírgula flutuante, semelhante à notação científica: mmmmmm × 10eeee , ◦ mmmmmm → mantissa ◦ eeee → expoente Computadores e Programação – p.24 Representação em vírgula flutuante (IEEE754) • Por exemplo, o número 0.000341237 pode ser escrito de várias formas: 0.00341237 × 10−1 , 0.0341237 × 10−2 , . . . 3.41237 × 10−4 • A última é a forma canónica normalizada (não tem zeros atrás do ponto decimal). • A representação em vírgula flutuante é efectuada habitualmente em 32, 64 ou 128 bits (precisão simples, dupla, e quádrupla). • Em precisão simples: s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm Computadores e Programação – p.25 Representação em vírgula flutuante (IEEE754) • bit 31 → bit de sinal • bits 30 · · · 23 expoente • bits 22 · · · 0 mantissa • Nota: utiliza-se normalização, pelo que se subentende que o primeiro algarismo da mantissa é diferente de zero. Na base 2 este algarismo só pode ser 1, e portanto não se representa. Assim, usando 23 bits a mantissa tem 24 bits efectivos de precisão! • O expoente é codificado com um offset de 127, ou seja é preciso subtrair 127 ao número inteiro que representa o expoente para obter o seu valor real. Computadores e Programação – p.26 Representação em vírgula flutuante (IEEE754) • Os valores reais do expoente com significado variam entre -127 e 127 (0 a 254 sem offset). Reserva-se o padrão eeeeeeee = 11111111 = 255 para representar os infinitos (s = 0, m = 0, +∞), (s = 1, m = 0, −∞). • Também existem dois “zeros” (s = 0, m = 0, 0+ ) e (s = 1, m = 0, 0− ). • Os padrões com a mantissa 6= 0 e expoente = 255 não representam números, mas códigos de erro (NAN - not a number, por exemplo divisão por zero). P. bits sinal mants. expo. min max alg. sign. S D 32 64 1 1 23 52 8 11 1.2E-38 2.2E-308 3.4E38 1.8E308 6–9 15-17 Computadores e Programação – p.27 Representação em vírgula flutuante (IEEE754) • Numa codificação de 32 bits, não se pode armazenar mais informação do que a permitida pelos 32 bits→ o número de “números reais” com representação distinta neste esquema de codificação é = 232 , tal como para os números inteiros. • A interpretação dos bits é diferente, mas o número de possibilidades distintas de codificação é o mesmo. No caso dos números inteiros, a distribuição é uniforme, mas já o mesmo não se passa com a representação em vírgula flutuante! • Os “números reais” representados neste formato não estão uniformemente distribuídos. Computadores e Programação – p.28 Representação em vírgula flutuante (IEEE754) • De facto, a distribuição é uniforme numa escala logarítmica: ◦ existem tantos números (224 para uma mantissa de 23 bits, ou seja cerca de 8 milhões) entre 2−3 e 2−2 como entre 252 e 253 . • A representação dos números reais em vírgula flutuante não é (em geral) exacta e a aritmética efectuada com esta representação também não! O processo de normalização pode causar sérios erros de arredondamento. • Exemplo: matematicamente 1 + x − 1 = x, mas em aritmética de vírgula flutuante 1 + x − 1 pode resultar num número muito diferente de x. Computadores e Programação – p.29