quarta-feira, 27 de janeiro de 2010

Emulando computadores antigos com o MESS

Quem é mais "antigo" na informática deve lembrar dos primeiros computadores pessoais comercializados no Brasil. Nos anos 80 já existia no mercado uma boa variedade de computadores domésticos, entre eles o Commodore 64, Amiga, CP-400 (Color Computer 2), TK-85 (ZX-81), MSX etc.

Naquela época era comum o computador usar como mídia de armazenamento uma simples fita cassete. Muitos também usavam cartuchos próprios e alguns já possuíam como opção os disquetes flexíveis. E o monitor era a televisão.

Hoje podemos reviver aquela época em nosso computador atual utilizando softwares chamados emuladores. Um emulador tem o propósito de recriar as funções originais do hardware. Um software executado em um emulador apresenta-se exatamente como se estivesse sendo executado no hardware original.

Um dos melhores e mais completos emuladores atualmente é o MESS. Seu nome é um acrônimo para "Multi Emulator Super System". O MESS é capaz de reproduzir sistemas de computadores e consoles em um PC. Atualmente possui capacidade para emular mais de 250 sistemas das últimas cinco décadas. O propósito primário do MESS é preservar a história dos computadores e consoles. O MESS é baseado no MAME, um emulador de jogos arcade.

O MESS emula o hardware destes sistemas e muitas vezes utiliza imagens da ROM para carregar programas e jogos. A ROM é equivalente a BIOS dos computadores atuais e graças aos hobistas o conteúdo de quase todas as ROMs de antigamente foram convertidas para arquivos imagem e podem ser encontradas pela Internet. Assim da mesma forma acontece com os softwares, onde antigamente eram armazenados em mídias que hoje em dia estão fora de linha, entretanto foram transferidos para os sistemas atuais e geralmente também na forma de arquivos imagem.

Podem ser encontradas versões do MESS para os sistemas Windows, Linux e Mac, inclusive os fontes para quem queira editar e compilar seu código. O MESS é um software gratuito porém vale salientar que as imagens das ROMs e dos softwares antigos na maioria das vezes não são.

O MESS possui uma interface bastante completa. É possível configurar os dispositivos de entrada para simularem os antigos dispositivos. As unidades de armazenamento funcionam como unidades virtuais, o sistema emulado vai interpretar o arquivo imagem como uma mídia real em um hardware. É possível montar imagens de disquetes, cartuchos, fitas cassetes etc.

Para quem usa Linux, provavelmente nos repositórios da distro tenha disponível o pacote contendo o MESS, na distro Fedora está no pacote sdlmess. Qualquer coisa no site oficial do MESS (http://www.mess.org/) é possível fazer o download para qualquer sistema.


Mostrando e alterando os MAC times dos arquivos no Linux

Os Mac times são partes dos metadados do sistema de arquivos onde são registrados certos eventos, ocorridos mais recentemente, relacionados a um arquivo. Os eventos são geralmente descritos como "modification" (a data em que o arquivo foi modificado), "access" (a data em que o arquivo foi lido) e "metadata change" (a data em que as permissões do arquivo foram alteradas). São estes termos "mtime", "atime" e "ctime" que derivam para o acrônimo MAC.

Estes são os eventos tradicionais no sistema de arquivos do Unix, onde o "ctime" é tido como a mudança nos metadados, para as permissões. Os sistemas Windows são os únicos sistemas que usam o "ctime" para significar data de criação do arquivo, diferentemente do adotado em sistemas Unix. Entretanto, o sistema de arquivos NTFS possui além dos eventos de modificação, acesso e criação, também possui o evento "Entry Modified", que registra a data de uma alteração na tabela MFT relacionada ao arquivo. A MFT é uma tabela localizada no início do sistema de arquivos na qual são armazenadas informações como datas, nomes, tamanho e localização dos arquivos. Estes quatro eventos são comumente abreviados como valores "MACE".

O comando stat, do pacote coreutils, é capaz de mostrar o status de um arquivo. Veja um exemplo de uma saída do comando stat. As três últimas linhas são as que trazem os MAC times:

$ stat .bash_history

File: `.bash_history'
Size: 50427 Blocks: 112 IO Block: 4096 arquivo comum
Device: 803h/2051d Inode: 2269552 Links: 1
Access: (0600/-rw-------) Uid: ( 500/ usuario) Gid: ( 500/ grupo)
Access: 2010-01-27 13:43:14.000000000 -0200
Modify: 2010-01-27 08:03:35.000000000 -0200
Change: 2010-01-27 08:03:35.000000000 -0200


O comando touch, também do pacote coreutils, é capaz de alterar a data dos eventos. Seguindo a sintaxe "touch [OPÇÃO] ARQUIVO" usa-se a opção "-a" para alterar a data de acesso e a opção "-m" para alterar a data de modificação. Para especificar a data pode-se usar em conjunto a opção "-t CCYYMMDDhhmm.ss". O comando touch não é capaz de alterar o evento "ctime".

Com as informações dos MAC times é possível, por exemplo, um aplicativo elaborar uma linha do tempo, com os acessos e modificações, dos arquivos contidos em uma unidade de armazenamento.

terça-feira, 26 de janeiro de 2010

Problema dos círculos tangentes

Originárias do Japão no período feudal, as gravuras com figuras geométricas conhecidas como sangaku, ou tabuletas matemáticas, ainda podem ser encontradas discretamente penduradas na entrada dos templos ou dos santuários.

O conteúdo e a forma dos sangaku tratam quase sempre de enunciados de problemas, propostos por um indivíduo, com ou sem a solução. Eles são relativamente sucintos e inspirados em composições geométricas complexas, nas quais quadrados, círculos e elipses se posicionam lado a lado ou se cruzam harmoniosamente proporcionando um belo efeito visual.

Um problema clássico da matemática japonesa que se encontra em muitos manuais e tabuletas matemáticas é apresentado neste artigo. O problema relaciona três círculos tangentes:


Três círculos C1, C2 e C3, com raios r1, r2 e r3, estão mutuamente tangentes um aos outros dois e numa linha paralela ao eixo x, como na figura acima. O centro do círculo C1 está na posição 0 do eixo. Como calcular a posição em x dos centros dos círculos C2 e C3 e o raio r3 sabendo apenas os raios r1 e r2?

A posição em x do centro do círculo C2 é dada pela distância horizontal entre os centros de C1 e C2 na resolução da equação


para x2, obtemos


A posição e o raio de C3 pode ser encontrado nas resoluções das equações



para x3 e r3, obtemos



A última equação pode ser escrita na forma


Este problema, encontrado em um templo japonês, é do ano de 1824. Os pares (x,r) de cada círculo nada mais são do que as coordenadas dos centros num plano cartesiano.

Liderança do Linux entre os 500 supercomputadores

Dentre os 500 sistemas de computadores mais poderosos conhecidos no mundo, classificados e detalhados pelo projeto TOP500, o sistema operacional Linux é utilizado em 89,2 %. Veja na tabela e no gráfico abaixo a tremenda superioridade que existe entre o Linux e os outros sistemas operacionais:

Sistema Operacional        Contagem      Percentual
Linux 446 89,2 %
Windows 5 1,0 %
Unix 25 5,0 %
BSD 1 0,2 %
Misto 23 4,6 %
Total 500 100,0 %


Talvez, como a maioria dos supercomputadores estão localizados em centros de pesquisa e em universidades, a escolha do sistema operacional deve seguir, além dos quesitos de desempenho e estabilidade, o baixo custo. O Linux tem estes três quesitos ao mesmo tempo.

segunda-feira, 25 de janeiro de 2010

Algoritmo para resolução do Sudoku

Os programas de computador podem empregar diferentes métodos de resolução para o quebra-cabeça Sudoku, o método mais comum é o de retorno à um estado anterior já analisado, uma forma sistematizada de tentativa e erro pela qual soluções parciais são propostas e à medida que se revelam erradas o algoritmo retorna e as corrige.

O algoritmo básico funciona com o programa inserindo o número 1 na primeira casa vazia. Se a escolha é compatível com os números já presentes no Sudoku, o programa segue para a próxima casa vazia e insere outro 1. Quando há um conflito, o algoritmo apaga o 1 que acabou de inserir e escreve 2 ou, se essa opção for inválida, 3 ou o próximo algarismo possível. Depois de chegar ao algarismo possível, passa para a próxima casa e recomeça com o número 1. Se o número que precisa ser alterado é o 9, que é o valor máximo no Sudoku padrão, o programa retorna e aumenta o número na casa anterior em uma unidade, que é onde está o penúltimo número inserido. A seguir, avança novamente até haver novo conflito. É comum o programa retroceder várias vezes antes de avançar.

Em um programa bem escrito, esse método explora amplamente todas as hipóteses e termina por encontrar uma solução, se ela existir. Caso haja múltiplas soluções, o que ocorreria para um Sudoku não-válido, o programa encontra todas.

Esta técnica de recuo pode ser codificada em algoritmos bastante pequenos. Abaixo é apresentado um algoritmo em linguagem C que utiliza essa técnica. A função "resolve" percorre todas as células da matriz tentando inserir os números de 1 a 9 em cada. Cada número é testado pela função "verifica" antes que seja inserido na célula atual. O teste é simples, verifica se já não existe o número na linha, coluna e região. A função "resolve" é chamada recursivamente para as células seguintes a fim de confirmar o número tentado na célula atual. Isso tudo é feito para cada célula da matriz. Quando terminado, o programa imprime a solução na tela.

#include <stdio.h>

int grade[9][9] = {{8,3,0,0,0,5,6,9,0},
                   {0,0,6,0,8,0,0,0,2},
                   {0,0,0,6,0,0,0,0,5},
                   {6,0,0,0,0,3,0,0,0},
                   {3,0,5,0,0,0,9,0,6},
                   {0,0,0,9,0,0,0,0,7},
                   {4,0,0,0,0,2,0,0,0},
                   {5,0,0,0,4,0,1,0,0},
                   {0,8,7,1,0,0,0,4,9}};

void imprime() {

  static int solucoes = 0;
  int l, c;

  printf("      Solucao: %d\n", ++solucoes);
  for (l = 0; l < 9; l++) {
    for (c = 0; c < 9; c++) {
      printf(" %d", grade[l][c]);
      if (c % 3 == 2) printf("  ");
    }
    printf("\n");
    if (l % 3 == 2) printf("\n");
  }

}

int verifica(int lin, int col, int n) {

  int l, c, lr, cr;

  if (grade[lin][col] == n) return 1;
  if (grade[lin][col] != 0) return 0;
  for (c = 0; c < 9; c++)
    if (grade[lin][c] == n) return 0;
  for (l = 0; l < 9; l++)
    if (grade[l][col] == n) return 0;
  lr = lin / 3;
  cr = col / 3;
  for (l = lr * 3; l < (lr + 1) * 3; l++)
    for (c = cr * 3; c < (cr + 1) * 3; c++)
      if (grade[l][c] == n) return 0;

  return 1;

}

void resolve(int lin, int col) {

  int n, t;

  if (lin == 9)
    imprime();
  else
    for (n = 1; n <= 9; n++)
      if (verifica(lin, col, n)) {
        t = grade[lin][col];
        grade[lin][col] = n;
        if (col == 8)
          resolve(lin + 1, 0);
        else
          resolve(lin, col + 1);
        grade[lin][col] = t;
      }

}

int main() {

  resolve(0,0);
  return 0;

}

sábado, 23 de janeiro de 2010

Problema de Lógica: Duas perguntas aos honestos e mentirosos

Atenção, resposta logo após o problema!

Um turista está em férias por um país onde cada pessoa é classificada como trabalhador, capitalista ou estudante. Os trabalhadores são honestos e só falam a verdade. Os capitalistas, ao contrário, são desonestos e mentem sempre. Os estudantes às vezes são honestos, mas podem agir de forma desonesta também. Chegou a hora do almoço e o turista se encontra em uma encruzilhada à procura de um restaurante. Nesta encruzilhada há duas estradas: uma para um restaurante e a outra para um abismo. Ali, há um trabalhador, um capitalista e um estudante. Apenas olhando para aqueles nativos não é possível ao turista identificá-los. Portanto ele não sabe quem é honesto ou mentiroso. Como o turista descobre o caminho para o restaurante fazendo apenas duas perguntas? Cada pergunta deve ser dirigida a uma única pessoa que se encontra na encruzilhada.






RESPOSTA






Primeiro pergunta-se a um dos três indivíduos "qual o caminho para o restaurante que cada um dos outros dois indicaria?". Se a pergunta for feita para o estudante ele saberá dizer claramente a resposta do trabalhador e a do capitalista. Se a pergunta for feita para o trabalhador ou para o capitalista, ele saberá dizer a resposta de um indivíduo mas não saberá dizer a resposta do outro, que é o estudante. Neste primeiro passo o turista descobre quem é o estudante. A segunda pergunta, que deve ser feita a um dos dois que não seja o estudante, será "qual o caminho para o restaurante que o outro indivíduo indicaria?". Neste caso o outro indivíduo citado na pergunta não pode ser o estudante, pois não se sabe a resposta. Seja qual for o indivíduo inquirido, a resposta indica sempre o caminho errado. Se perguntasse ao trabalhador, a resposta indicaria o caminho errado pois o capitalista não indica o caminho certo. Se perguntasse ao capitalista, a resposta indicaria o caminho errado pois o trabalhador indica o caminho correto.

sexta-feira, 22 de janeiro de 2010

Probabilidades

O simples experimento de lançar um dado possui um resultado que não pode ser previsto, não podemos saber com antecedência o número obtido, apenas sabemos que os possíveis resultados são 1, 2, 3, 4, 5 e 6. Este tipo de experimento é chamado aleatório. Na teoria das probabilidades, estudamos os experimentos aleatórios equiprováveis, onde qualquer resultado pode ocorrer com a mesma chance.

No estudo da teoria das probabilidades temos dois elementos, o espaço amostral e o evento. Espaço amostral é o conjunto universo de todos os resultados possíveis de um experimento aleatório equiprovável. O número de elementos desse conjunto é indicado por n(U). Evento é qualquer subconjunto do espaço amostral U. O número de elementos desse subconjunto é indicado por n(A).

Assim, no lançamento de um dado, por exemplo, o evento "obter um número maior ou igual a 4" é dado por A={4,5,6}, subconjunto de U={1,2,3,4,5,6}.

Quando A é igual à U, o evento é certo. Quando A é igual à conjunto vazio, o evento é impossível. Quando A união com 'A é igual à U, e, A intersecção com 'A é igual a conjunto vazio, os eventos A e 'A são complementares.

Se, num experimento aleatório equiprovável, o número de elementos do espaço amostral U é n(U) e o número de elementos do evento A é n(A), então a probabilidade de que ocorra o evento A é dada pelo número real P(A), tal que P(A) = n(A)/n(U). Portanto, a probabilidade de um evento é dada pelo quociente da divisão do número de casos favoráveis pelo número de casos possíveis.

A probabilidade de um evento é sempre um número entre 0 (probabilidade do evento impossível) e 1 (probabilidade do evento certo). Se A é igual a conjunto vazio então n(A) = 0 e portanto P(A) = 0. Se A é igual a U então n(A) = n(U) e P(A) = 1. Se A está contido em U então 0 <= n(A) <= n(U) e 0 <= P(A) <= 1. Se A e 'A são eventos complementares então n(A) + n('A) = n(U) e P(A) + P('A) = 1.

Se A e B são 2 eventos de um espaço amostral U, sabemos que n(A união com B) é igual a n(A) + n(B) - n(A intersecção com B) e portanto P(A união com B) = P(A) + P(B) - P(A intersecção com B). Se A intersecção com B é igual a conjunto vazio, os eventos são mutuamente exclusivos, isto é, P(A intersecção com B) = 0, daí P(A união com B) = P(A) + P(B).

A probabilidade do produto é dada por um princípio análogo ao princípio fundamental da contagem, quando os eventos A e B são independentes. Se um evento A tem probabilidade p e, em seguida, ocorre o evento B de probabilidade q, então a probabilidade de que ocorram os eventos A e B na ordem indicada é p x q, pois P(A intersecção com B) = P(A) x P(B). Esta regra pode ser generalizada para mais de dois eventos com suas respectivas probabilidades.