domingo, dezembro 29, 2013

Sobre o curso de Física

Alguém perguntou-me recentemente sobre o curso de Física e, aproveitando a oportunidade de uma pergunta postada recentemente no Yahoo! Respostas, resolvi escrever um pouco sobre minha visão sobre o curso.

Tenha em mente que eu nunca concluí o curso de Física. Fiz apenas o primeiro ano do curso no milênio passado. Mas acredito que as dicas aqui são válidas e, por favor, corrijam-me onde houver erros.

No curso de Física, há a possibilidade de obter o diploma de bacharel ou de licenciado.

O bacharel em Física é o profissional que trabalhará com pesquisa e desenvolvimento em instituições de pesquisa e universidades. O curso dura cerca de 4 anos.

O profissional de Licenciatura está habilitado a dar Aulas para o ensino fundamental e médio. Normalmente, são acrescentadas matérias de didática e prática de ensino, que eleva o curso para 5 anos. É muito comum o licenciado também ser bacharel em Física.

Quanto a carga horária, a média é de 24h semanais, o que leva a 4 a 5 horas de aula por dia. Entretanto, para cada uma hora gasta em sala de aula, pode levar de uma a duas horas de dedicação fora da sala de aula.

Você não perguntou, mas vou aproveitar e descrever um pouco da minha visão sobre as possibilidades.

Licenciatura: Se optar por dar aulas, recomendo que a faça nas escolas particulares. Infelizmente, o salário no setor público é muito baixo para professores (entre 2.000 e 2.500,00 iniciais) e a lei e regulamentação pública colocou o professor e os profissionais da educação em uma situação digamos, delicada. Basta fazer uma pesquisa na Internet sobre problemas de processo e indisciplina nas salas de aula.

Você já pode trabalhar assim que se formar, mas ter um mestrado e doutorado pode até permitir-lhe salários maiores.

Bacharelado: No bacharelado, fazer mestrado e doutorado é praticamente uma obrigação. Logo, você terá cerca de 5 anos de graduação, 2 para o mestrado e 4 para o doutorado.Hoje já existe uma opção de fazer o doutorado direto, o que acelera seu progresso na carreira.

A "obrigação" do mestrado e doutorado está relacionada ao mercado de trabalho. Praticamente o físico está limitado a pesquisa e desenvolvimento em universidades e instituições específicas de pesquisa. Normalmente, os concursos já solicitam ao menos o mestrado o doutorado.

Como o mestrado e doutorado, há outra opção aberta, que é ministrar aulas no ensino superior. O ensino superior não requer a licenciatura, mas requer profissionais com pós-graduação.

Finalmente, algumas dicas se você resolver fazer o curso de Física:

1) Inglês. O Inglês é imprescindível para as matérias à partir do 2 ano, pois diversas cadeiras nem possuem livros em Português sobre o assunto.

2) Seja autodidata: Parece estranho, mas apesar de haver professores, você precisará aprender a consultar a biblioteca e procurar fontes para aprender, quando estiver "empacado" em algum conceito. É muito importante aprender a procurar e localizar o conhecimento.

3) Manter as notas: Para obter boas bolsas de mestrado e doutorado, seu currículo deve possuir boas notas e não possuir reprovação.

4) Não baixar a guarda no 1º ano:  No primeiro ano os alunos estão em júbilo (empolgados) por iniciar um curso universitários e se esquecem de estudar. Como a dinâmica das aulas é muito diferente do ensino médio, desastres acontecem. Cuidado com 1º ano! Na minha turma, mais da metade foi reprovada em pelo menos  75% (três entre quatro matérias) por este descuido.

5) Aprender a programar: Comumente o Físico precisar fazer cálculos numéricos, e haverá necessidade de aprender um linguagem de programação.

6) Sondar as áreas. Já no primeiro ano, é importante sondar, conhecer as área da Física que você queira se especializar. Entre elas: Física-Matemática, Física teórica, Física aplicada, Meteorologia (em algumas faculdades este é um curso separado), Geofísica, Oceanografia, Bio-física e qualquer outra que eu tenha esquecido e não mencionado aqui.

6) Fazer iniciação científica: Nada tão importante como conhecer uma área, é experimentá-la. Fazer a iniciação é uma oportunidade conhecer a área que você escolheu e nortear sua carreira. Recomendo começar a fazê-la logo no 2º ano.

Nota: Não aconselho fazer no 1º ano. Além de não haver bolsa, você terá que se preocupar

7) Viver como um monge: A menos que você seja "pai-trocinado", você vai ganhar pouco nos primeiros anos, enquanto tiver a bolsa de mestrado e doutorado. Escolha bem o local onde fará o mestrado e, se for possível, tente uma bolsa integral no exterior. Lá, pelo menos, eles dimensionam melhor as bolsas.

8) Relações inter-pessoais 1: Você não deve ser arrogante nem discutir com pessoas desnecessariamente, seja alunos, professores ou mesmo funcionários da instituição. Você não deve puxar o saco, mas defender seu ponto de vista e argumentar com educação é de bom grado.  Como já existem poucas portar na Física, ter atitudes ruins para fechá-las não é muito inteligente.

9) Relações inter-pessoais 2: Não tenha colegas "negativos". Procure ter amizade com colegas que sejam estudiosos e tenham afinidades com você. Pessoas muito negativas não trazem motivação. Evite ou tente persuadir estas pessoa a mudar de atitude.

P.S.: Se por acaso você estiver se referindo ao curso de Educação Física, desculpe-me, mas você não especificou. Senão, tenha em mente que 100% vão achar que você faz Educação Física quando você informa que fazem Física. É um engano comum.

terça-feira, fevereiro 20, 2007

Alguns links para aprender Perl

Documentação: http://perldoc.perl.org/
Livros: http://www.perl.org/books/library.html
Tutorial On-line: http://www.steve.gb.com/perl/index.html

segunda-feira, fevereiro 19, 2007

Perl e Matemática

Quem já codificou algum programa, e acabou escrevendo uma variável ou mesmo um cometário com acento ou mesmo cedilha(ç) ? No mínimo recebeu uma mensagem de erro, e precisou voltar e corrigir todo o texto.

Essa restrições parecem estar com os dias contados. Com o advento do Unicode, várias linguagens e bibliotecas possuem suporte a este padrão. Por exemplo, a linguagem de Pythonprogramação suporta o UTF-8 ( e outros formatos) no código fonte, como comentários e literais para impressão ("strings"). Identificadores suportam apenas o conjunto de caracteres alfa numéricos básicos do ASCII [a-zA-Z0-9] e _.

Já o Perl 5.8.8 chega ao extremo de permitir o uso de caracteres de outros alfabetos como identificadores. Parece frívolo, para a maioria das aplicações, mas não posso deixar de imaginar como seria útil definir uma função Σ e Π ? Veja o exemplo no link

Perl and Unicode, no meu blog de códigos. Entretanto, note que apenas caracteres referentes a alfabetos podem ser utilizados como identificadores. Nada de utilizar símbolos do Zodíaco em variáveis. Perl 6 entretanto, poderá definir operadores utilizando qualquer caracter Unicode.

Blogs: Moderação & Justiça

Recentemente fui alertado sobre o a responsabilidade de um autor de Blog sobre os comentários postados. Um internauta já foi processado (vide o site Consultor Jurídico, Divisão de culpas). Segundo o mesmos site, embora não exista uma lei específica sobre a matéria, a jurisprudência irá estender as mesmas regras aplicadas à imprensa.

Portanto, fique atento. A recomendação é ativar o mecanismo de moderação ou bloquear os comentários.

domingo, novembro 12, 2006

Buscando mecanismos de busca.

Aproveitando que o último post deste blog tratava sobre funções recursivas, vamos ver o mecanismo de busca recursivo!

Não é nada do outro mundo não. Se você usa o Firefox e os mecanismos de busca, já deve ter visitado o site site http://mycroft.mozdev.org/ . Faça uma busca pelo próprio domínio mycroft.mozdev.org.

quarta-feira, novembro 01, 2006

Refatoração de funções recursivas.

Refatoração é uma prática que tem o intuito de modificar a estrutura interna de uma função ou classe, sem alterar se comportamento.

Na semana passada, ao ler tópicos de uma lista sobre linguagem Java, me deparei com uma pergunta sobre stack overflow, causado pela execução de um algoritmo. Tratava-se de um algoritmo de preenchimento de regiões. Partindo-se de um ponto de partida, o algoritmo deveria visitar seus vizinhos, marcando aqueles que possuem cores semelhantes.

Para determinar a semelhança entre duas cores, toma-se a norma Euclidiana da diferença dos vetores de cores. Se esse valor fosse menor que uma dada tolerância, este era julgado semelhante. Os pontos vizinhos aos pontos já visitados também deveriam ser visitados. O Algoritmo para quando não há mais pontos semelhantes.

Segue o pseudo-código do algoritmo recursivo:


visita_ponto(imagem, linha, coluna, cor)
COMECE
SE linha,coluna NÃO PERTENCE A imagem
FAÇA
RETORNO
FIM
ponto <- imagem[linha][coluna]
SE visitado(ponto) É FALSO ENTÃO
FAÇA
SE norma(cor(ponto) - cor) É MENOR QUE TOLERÂNCIA ENTÃO # cor for próxima
FAÇA
visitado(ponto) <- VERDADEIRO
visita_ponto(imagem, linha + 1, coluna)
visita_ponto(imagem, linha - 1, coluna)
visita_ponto(imagem, linha, coluna + 1)
visita_ponto(imagem, linha, coluna - 1)
FIM
FIM
FIM


Note que há 4 pontos de chamada da mesma função. O problema é que este algoritmo estourou a pilha do Java. No algoritmo original, certa de 40 bytes (no mínimo) eram alocados por chamada. Admita esse número é o consumo de byte de uma chamada do método em Java. Para uma imagem de 128x128 pontos (um ícone, por exemplo) poderia chegar a bagatela de 40x128x128 = 65Kbytes consumidos na pilha.. Para uma imagem de 680x480, 11,7 MB !

Claramente, o stack overflow ocorre pelo uso excessivo de memória. A pilha de uma thread em Java é configurada com 2MB de memória, no máximo. A primeira solução é substituir o algoritmo recursivo por um algoritmo iterativo. Com uma pilha explícita, alocada no heap, mais memória pode ser empregada, e sem precisar modificar os parâmetros de chamada da máquina virtual.

No http://www.refactoring.com/catalog/replaceRecursionWithIteration.html há uma descrição sobre esse padrão refatoração. Mas não é apresentado um método geral para obter uma conversão de uma rotina recursiva para outra, com mesma funcionalidade e iterativa.

Entretanto, um método pode ser obtido pela explicitação da pilha. Para tanto, devemos seguir alguns passos para o procedimento:


  1. Criação de pilha explícita.
  2. Criação de um laço ENQUANTO que monitora a condição de retorno da rotina, ou seja, do fim da iteração, ou do que antes era a condição de retorno da chamada mais profunda do algoritmo recursivo.
  3. Criação de uma variável rótulo, que mantém informação do estado, ou do último ponto de onde foi feita uma "chamada". É equivalente a guardar o endereço de retorno da rotina.
  4. Testes para executar o código do ponto onde havia parado a computação. Se a linguagem possuir algum tipo de GOTO, a implementação fica mais fácil.
  5. Analise os parâmetros, para determinar quais são constantes, ou aqueles que modificam com um padrão previsível (como um contador, por exemplo). Eles podem ser retirados da pilha explícita.




Aplicando os princípios acima citados, vamos reescrever o pseudo-código:


visita_ponto2(imagem, linha, coluna, cor)
COMECE
pilha_linha := vetor(0..(linha*coluna)-1)
pilha_coluna := vetor(0..(linha*coluna)-1)
pilha_imagem := vetor(0..(linha*coluna)-1)
pilha_rotulo := vetor(0..(linha*coluna)-1) # ponto de parada
pos_pilha := inteiro



pilha_linha[0] <- linha
pilha_coluna[0] <- coluna
pilha_imagem[0] <- imagem
pilha_rotulo[0] <- 0
pos_pilha <- 1

ENQUANTO pos_pilha FOR MAIOR QUE 0
FAÇA
linha <- pilha_linha[0]
coluna <- pilha_coluna[0].
imagem <- pilha_imagem[0]
# início do antigo algoritmo.
SE linha,coluna NÃO PERTENCE A imagem
FAÇA
pos_pilha <- pos_pilha - 1
CONTINUE
FIM
ponto <- imagem[linha][coluna]
SE visitado(ponto) É FALSO ENTÃO
FAÇA
SE norma(cor(ponto) - cor) É MENOR QUE TOLERÂNCIA ENTÃO # cor for próxima
FAÇA
visitado(ponto) <- VERDADEIRO
SE pilha_rotulo[0] É 0 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 1 # ponto de retorno
pos_pilha <- pos_pilha + 1
pilha_linha[pos_pilha] <- linha + 1
pilha_coluna[pos_pilha] <- coluna
pilha_imagem[pos_pilha] <- imagem
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 1 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 2 # ponto de retorno
pos_pilha <- pos_pilha - 1
pilha_linha[pos_pilha] <- linha - 1
pilha_coluna[pos_pilha] <- coluna
pilha_imagem[pos_pilha] <- imagem
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 2 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 3 # ponto de retorno
pos_pilha <- pos_pilha
pilha_linha[pos_pilha] <- linha
pilha_coluna[pos_pilha] <- coluna + 1
pilha_imagem[pos_pilha] <- imagem
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 3 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 4 # ponto de retorno
pos_pilha <- pos_pilha + 1
pilha_linha[pos_pilha] <- linha
pilha_coluna[pos_pilha] <- coluna - 1
pilha_imagem[pos_pilha] <- imagem
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
FIM
FIM
pos_pilha <- pos_pilha - 1 # Se estamos aqui, temos 4 nós visitados.
FIM
FIM


Note que o código ficou muito maior. A pilha agora é uma variável, que pode ser declarada no heap, na pilha, ou mesmo estaticamente. Analisando ainda mais o pseudo-código resultante, nota-se:


  1. É possível monitorar a posição da pilha e reportar um possível stack overflow.
  2. O argumento imagem é sempre constante. Pode então ser retirado do algoritmo.


No algoritmo original, em Java, haviam cerca de 10 argumentos, sendo que apenas 2 (linha e coluna) precisavam ser armazenados. Admitindo-se que a linha,coluna e o rótulo são variáveis inteiras, de 32 bits, temos um consumo de 12 bytes por iteração.



visita_ponto3(imagem, linha, coluna, cor)
COMECE
pilha_linha := vetor(0..(linha*coluna)-1)
pilha_coluna := vetor(0..(linha*coluna)-1)
pilha_rotulo := vetor(0..(linha*coluna)-1) # ponto de parada
pos_pilha := inteiro

pilha_linha[0] <- linha
pilha_coluna[0] <- coluna
pilha_rotulo[0] <- 0
pos_pilha <- 1

ENQUANTO pos_pilha FOR MAIOR QUE 0
FAÇA
SE pos_pilha FOR IGUAL A linha*coluna ENTÃO
FAÇA
SINALIZAR ESTOURO DE PILHA
FIM

linha <- pilha_linha[0]
coluna <- pilha_coluna[0].
imagem <- pilha_imagem[0]
# início do antigo algoritmo.
SE linha,coluna NÃO PERTENCE A imagem
FAÇA
pos_pilha <- pos_pilha - 1
CONTINUE
FIM
ponto <- imagem[linha][coluna]
SE visitado(ponto) É FALSO ENTÃO
FAÇA
SE norma(cor(ponto) - cor) É MENOR QUE TOLERÂNCIA ENTÃO # cor for próxima
FAÇA
SE pilha_rotulo[0] É 0 ENTÃO
FAÇA
visitado(ponto) <- VERDADEIRO
pilha_rotulo[pos_pilha] <- 1 # ponto de retorno
pos_pilha <- pos_pilha + 1
pilha_linha[pos_pilha] <- linha + 1
pilha_coluna[pos_pilha] <- coluna
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 1 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 2 # ponto de retorno
pos_pilha <- pos_pilha - 1
pilha_linha[pos_pilha] <- linha - 1
pilha_coluna[pos_pilha] <- coluna
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 2 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 3 # ponto de retorno
pos_pilha <- pos_pilha
pilha_linha[pos_pilha] <- linha
pilha_coluna[pos_pilha] <- coluna + 1
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
SE pilha_rotulo[0] É 3 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- 4 # ponto de retorno
pos_pilha <- pos_pilha + 1
pilha_linha[pos_pilha] <- linha
pilha_coluna[pos_pilha] <- coluna - 1
pilha_rotulo[pos_pilha] <- 0
CONTINUE
FIM
FIM
FIM
pos_pilha <- pos_pilha - 1 # Se estamos aqui, temos 4 nós visitados.
FIM
FIM


Evidentemente, a segunda e terceira versão do código é muito maior, devido a repetição. Quanto a isso, podemos modificar o código de iteração, usando uma tabela para calcular as coordenadas do vizinhos a serem visitados.


#tabela auxiliar.
tab := [ +1 0;
-1 0;
0 -1;
0 +1]

visita_ponto4(imagem, linha, coluna, cor)
COMECE
pilha_linha := vetor(0..(linha*coluna)-1)
pilha_coluna := vetor(0..(linha*coluna)-1)
pilha_rotulo := vetor(0..(linha*coluna)-1) # ponto de parada
pos_pilha := inteiro

pilha_linha[0] <- linha
pilha_coluna[0] <- coluna
pilha_rotulo[0] <- 0
pos_pilha <- 1

ENQUANTO pos_pilha FOR MAIOR QUE 0
FAÇA
SE pos_pilha FOR IGUAL A linha*coluna ENTÃO
FAÇA
SINALIZAR ESTOURO DE PILHA
FIM

linha <- pilha_linha[0]
coluna <- pilha_coluna[0].
imagem <- pilha_imagem[0]
# início do antigo algoritmo.
SE linha,coluna NÃO PERTENCE A imagem
FAÇA
pos_pilha <- pos_pilha - 1
CONTINUE
FIM
ponto <- imagem[linha][coluna]
SE visitado(ponto) É FALSO ENTÃO
FAÇA
SE norma(cor(ponto) - cor) É MENOR QUE TOLERÂNCIA ENTÃO # cor for próxima
FAÇA
visitado(ponto) <- VERDADEIRO
SE pilha_rotulo[0] É MENOR QUE 4 ENTÃO
FAÇA
pilha_rotulo[pos_pilha] <- pilha_rotulo[pos_pilha] + 1 # ponto de retorno
pilha_linha[pos_pilha + 1] <- linha + tab[rotulo][0]
pilha_coluna[pos_pilha + 1] <- coluna + tab[rotulo][1]
pilha_rotulo[pos_pilha + 1] <- 0
pos_pilha <- pos_pilha + 1
CONTINUE
FIM
FIM
FIM
pos_pilha <- pos_pilha - 1 # Se estamos aqui, temos 4 nós visitados.
FIM
FIM


Interpretação Geométrica



Vejamos uma imagem, de 5 x 5 posições. Começando-se pelo ponto central, vamos escrever a ordem de descobrimento do algoritmo:

















00 09 10 19 20
01 08 11 18 21
02 07 12 17 22
03 06 13 16 23
04 05 14 15 24


Veja que existem uma profundiade de chamadas: 0 -> 24. Ou seja, tivemos uma pilha com profundidade máxima de 25 chamadas. Em um caso mais geral, o número de chamadas será de linhas x colunas (pior caso).

Esse algoritmo se expande como se fosse uma curva. Seria mais conveniente, entretanto, que ele se espalha-se de acordo com uma fronteira.

Nesse caso, se faz necessário o emprego de uma outra estrutura de dados, diferente da pilha, pois os termos já visitados precisariam ser descartados. Essa estrutura de dados é uma fila.

O tamanho da memória empregada aqui é muito menor. O número máximo de elementos é da ordem do perímetro da tabela, que é 4 x linhas x colunas. no caso de uma tabela quadrada.

Fazendo a conversão final do algoritmo, para que este empregue a fila, temos:


#tabela auxiliar. relativa
tab_rel := [ -1 0;
+2 0;
-1 -1;
0 +2]

visita_ponto5(imagem, linha, coluna, cor)
COMECE
dqueue := nova dqueue[2*(linha + coluna)]

dqueue.inserirFrente(linha, coluna)

ENQUANTO dqueue.vazia() FOR FALSO
FAÇA
tamanho_da_borda <- dqueue.comprimento()
PARA TODA linha, coluna EM dqueue
FAÇA
SE linha,coluna NÃO PERTENCE A imagem
FAÇA
CONTINUE
FIM
ponto <- imagem[linha][coluna]
SE norma(cor(ponto) - cor) ENTÃO
FAÇA
visitado(ponto) <- VERDADEIRO
FIM
FIM

ENQUANTO tamanho_da_borda > 0
FAÇA
tamanho_da_borda <- tamanho_da_borda - 1
linha, coluna <- dqueue.retireTras()
ponto <- imagem[linha][coluna]
SE visitado(ponto) É VERDADEIRO ENTÃO
FAÇA
PARA I := 0..3
FAÇA
linha <- linha + tab[I][0]
coluna <- coluna + tab[I][0]
ponto <- imagem[linha][coluna]
SE visitado(ponto) É FALSO
dqueue.inserirFrente(linha, coluna)
FIM
FIM
FIM
FIM
FIM
FIM


Por fim, vamos fazer um comparação com uma tabela de algoritmos x imagem:











Algoritimo/Dimensões300x200640x4801024x768
recursivo(pilha)2.29MB11.72MB30.00MB
iterativo(pilha)703.12kB3.52MB9.00MB
iterativo(fila)7.81kB17.50kB28.00kB


Conclusões



Um algoritmo recursivo pode ser convertido para um equivalente iterativo, com o emprego de uma pilha explícita.

Com um pouco mais de análise pode-se chegar a uma simplificação da pilha e do código. Nesse exemplo, a complexidade do algoritmo com pilhas era de O(MN) (M=linhas, N=colunas) foi baixado para O(M+N). O método não deve ser empregado como única possibilidade de refatoração do algoritmo.


O resultado é uma melhoria de qualidade o código, sem dúvida. Entretanto, outras análises podem trazer algoritmo ainda mais eficientes.

Marcadores:

domingo, outubro 29, 2006

Perfis falsos e Adão no Orkut

Como é que é possível? Existem perfils falsos que entram aparecem no Orkut e não tem amigos? Eu acho que o Orkut precisa colocar uma regra, se alguém atingir o nível 0 de amigos, então, deveria ser deletado do sistemas.

Outra coisa, será que o Orkut mantém informação do seu pai? Aqui eu chamo de pai o usuário que o convidou para o Orkut. Seria interessante que alguém que adicionasse muitos perfis falsos fosse delatado também.

E falando em Pai, árvores de descendência, quem será o Adão do Orkut?