<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-6306509703738480474</atom:id><lastBuildDate>Thu, 11 Mar 2010 16:04:54 +0000</lastBuildDate><title>Brain Dump</title><description>O que está passando pela cabeça do Ricbit no momento.</description><link>http://www.ricbit.com/</link><managingEditor>noreply@blogger.com (Ricardo Bittencourt)</managingEditor><generator>Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-44272255538823634</guid><pubDate>Sun, 07 Mar 2010 03:00:00 +0000</pubDate><atom:updated>2010-03-07T09:16:04.967-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mágica</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>math</category><title>Mais mágicas com calculadoras</title><description>Quando eu era criança, a mágica que eu mais gostava era aquela onde o ilusionista serra a assistente ao meio. Acho que a graça era tentar entender como ele fazia aquilo, levei um tempão para &lt;a href="http://en.wikipedia.org/wiki/Sawing_a_woman_in_half"&gt;descobrir o truque&lt;/a&gt;. Usando uma calculadora também temos um truque parecido, mas ao invés de serrar uma assistente, vamos cortar um número em dois!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/ricbit_magico2-763948.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/ricbit_magico2-763908.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Para começar essa mágica, peça para a criança digitar o número mágico 142857 na calculadora:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_06-710954.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://www.ricbit.com/uploaded_images/calc_06-710939.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Agora peça para que ela multiplique esse número por dois:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_05-742456.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="72" src="http://www.ricbit.com/uploaded_images/calc_05-742440.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Olha só! Você cortou o número ao meio e juntou as partes ao contrário, 14-2857 virou 2857-14!&lt;br /&gt;&lt;br /&gt;Agora peça para ela digitar novamente o número mágico e multiplicar por três:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_04-789818.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="72" src="http://www.ricbit.com/uploaded_images/calc_04-789803.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Ahá! Novamente você cortou o número ao meio, 1-42857 virou 42857-1.&lt;br /&gt;&lt;br /&gt;Você pode continuar a mágica a partir daqui, esse truque funciona com todos os múltiplos até 6:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;142857 * 1 = 142857&lt;/div&gt;&lt;div style="text-align: center;"&gt;142857 * 2 = 285714&lt;/div&gt;&lt;div style="text-align: center;"&gt;142857 * 3 = 428571&lt;/div&gt;&lt;div style="text-align: center;"&gt;142857 * 4 = 571428&lt;/div&gt;&lt;div style="text-align: center;"&gt;142857 * 5 = 714285&lt;/div&gt;&lt;div style="text-align: center;"&gt;142857 * 6 = 857142&lt;/div&gt;&lt;br /&gt;Aparentemente, a parte díficil desse truque é memorizar o número mágico. Quando você está cercado de crianças barulhentas, não é fácil lembrar 142857! Mas, felizmente, você não precisa decorar o número. É só lembrar que ele é a dizíma periódica de 1/7, e você pode usar a própria calculadora para calcular a dízima:&lt;br /&gt;&lt;br /&gt;1/7 = 0.142857142857142857...&lt;br /&gt;&lt;br /&gt;A pergunta natural é: tem outras dízimas com essa propriedade, ou o 142857 é especial? Espantosamente, existem sim outros números. Eles tem até nome: são os &lt;b&gt;números cíclicos&lt;/b&gt;. Para achar esses outros números, vale a pena entender porque o 1/7 funciona, e para isso é só observar o comportamento da dízima no algoritmo de divisão longa:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/conta_lousa-780571.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="193" src="http://www.ricbit.com/uploaded_images/conta_lousa-780568.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Você começa dividindo o número 1, e sempre que o resto é menor que 7, coloca um zero atrás e continua. Note que, quando você divide por 7, só tem sete restos possíveis: 0, 1, 2, 3, 4, 5 e 6. Se o resto for zero em algum momento, a divisão acaba e o resultado é exato. Mas se em algum momento o resto repetir, ou seja, for igual a algum resto que já apareceu antes, então você tem uma dízima.&lt;br /&gt;&lt;br /&gt;Os números cíclicos são formados por divisões de período máximo. Como você nunca pode ter um zero de resto, então no caso da dízima de 7, o maior período possível seria seis (felizmente é o caso). Você começa com o resto 1, e quando chega no 1 de novo começa a repetir, como no diagrama abaixo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/conta_lousa3-793797.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="194" src="http://www.ricbit.com/uploaded_images/conta_lousa3-793794.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Veja como agora dá pra entender porque os números cíclicos funcionam:&amp;nbsp;142857 é a dízima de 1/7. Se a gente multiplicar 1/7 por dois, teremos 2/7, e a dízima tem que ser o dobro também. Mas se você olhar no diagrama, multiplicar por dois é a mesma coisa que começar a percorrer o diagrama a partir do 2, ao invés de começar no 1. Mas não importa de onde você começa, a seqüência será sempre a mesma, e daí o resultado vai ser uma rotação da dízima original!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/conta_lousa2-744538.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="194" src="http://www.ricbit.com/uploaded_images/conta_lousa2-744535.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Sabendo que os números cíclicos são as dízimas de período máximo, já dá pra começar a procurar propriedades desses números. Quais números, além do 7, geram dízimas de período máximo?&lt;br /&gt;&lt;br /&gt;A primeira coisa que a gente nota é que esses números precisam ser primos. O raciocínio é relativamente simples. Vamos chamar esse número que procuramos de k, e fazer a divisão longa de 1 por k. Os restos da divisão longa formam uma recorrência, onde o primeiro termo é 1, e para os seguintes você coloca um zero no final e acha o resto da divisão por k:&lt;br /&gt;&lt;br /&gt;R[0] = 1&lt;br /&gt;R[n] = 10*R[n-1] (mod k)&lt;br /&gt;&lt;br /&gt;Essa recorrência dá pra resolver de cabeça:&lt;br /&gt;&lt;br /&gt;R[n] = 10&lt;sup&gt;n&lt;/sup&gt; (mod k)&lt;br /&gt;&lt;br /&gt;Para termos uma dízima de período máximo, o resto precisa ser 1 novamente quando n=k-1, ou seja:&lt;br /&gt;&lt;br /&gt;R[k-1] = 10&lt;sup&gt;k-1&lt;/sup&gt; = 1 (mod k)&lt;br /&gt;&lt;br /&gt;Agora, do &lt;a href="http://en.wikipedia.org/wiki/Euler's_theorem"&gt;teorema de Euler-Fermat&lt;/a&gt;, nós sabemos que:&lt;br /&gt;&lt;br /&gt;10&lt;sup&gt;φ(k)&lt;/sup&gt; = 1 (mod k)&lt;br /&gt;&lt;br /&gt;Onde φ(k) é a &lt;a href="http://en.wikipedia.org/wiki/Euler's_totient_function"&gt;função totiente&lt;/a&gt;. Ora, nós sabemos que, quando k é composto, o totiente é sempre menor que k-1, então k não pode ser composto, e portanto é primo.&lt;br /&gt;&lt;br /&gt;Certo, então k precisa ser primo, mas qualquer primo serve? Nope. Tem alguns primos que não funcionam, como por exemplo onze. No caso do 11, é verdade que 10&lt;sup&gt;10&lt;/sup&gt; deixa resto 1, mas logo 10&lt;sup&gt;2&lt;/sup&gt; já tem resto 1 também, então a dízima é muito mais curta que gostaríamos.&lt;br /&gt;&lt;br /&gt;Na verdade, o segredo desses primos que funcionam é que... hum... ninguém sabe qual o segredo. Esse é um &lt;a href="http://mathworld.wolfram.com/FullReptendPrime.html"&gt;problema em aberto&lt;/a&gt;. Na verdade, a coisa é tão feia que ninguém sabe nem mesmo se esses primos são finitos ou infinitos. O melhor que podemos fazer é um script que ache os primeiros deles:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/cyclic.py"&gt;Script em python que acha os primeiros números cíclicos&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Depois do sete, o primeiro primo que funciona é o 17, e o número cíclico associado é&amp;nbsp;0588235294117647. Note que esse é um caso onde o zero à esquerda faz diferença! Se a sua calculadora tiver um visor bem grande, dá pra divertir uma criança por um tempão com esse número :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-44272255538823634?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2010/03/mais-magicas-com-calculadoras.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-8285510843962864816</guid><pubDate>Wed, 03 Mar 2010 01:27:00 +0000</pubDate><atom:updated>2010-03-03T00:22:22.616-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mágica</category><category domain='http://www.blogger.com/atom/ns#'>math</category><title>Mágicas com calculadoras</title><description>Tem um diálogo que sempre acontece quando vou visitar algum amigo que tenha filho pequeno. Eu sou apresentado pelo amigo como "o Ricbit, aquele amigo que &lt;i&gt;gosta de Matemática&lt;/i&gt;". Aí a criança, espantada, responde "mas como assiiiiiim ele gosta de Matemática?!". E o amigo responde "ah, mas matemática com o tio Ricbit é divertida. Mostra pra ele, Ricbit!". E aí eu, que nem cheguei direito, já estou com a batata quente na mão!&lt;br /&gt;&lt;br /&gt;Felizmente, eu já descobri alguns truques pra lidar com situações assim. Se a criança ainda está na fase de achar que matemática é aritmética, então uma abordagem que funciona bem é pedir uma calculadora emprestada,e falar que você vai usá-la pra fazer &lt;i&gt;mágicas&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/ricbit_magico-721213.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="237" src="http://www.ricbit.com/uploaded_images/ricbit_magico-721179.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Uma das mágicas clássicas funciona assim:&lt;br /&gt;&lt;br /&gt;1. Primeiro você pede pra criança digitar 13837, que é um número &lt;i&gt;mágico&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_01-717197.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://www.ricbit.com/uploaded_images/calc_01-717181.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;2. Depois, você pergunta quantos anos tem o pai dela, e fala pra ela multiplicar aquele número mágico pela idade do pai. Digamos que o pai tem 42 anos, então o resultado será 581154.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_02-730240.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://www.ricbit.com/uploaded_images/calc_02-730223.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;3. Por fim, você fala pra criança multiplicar esse número que está no visor por outro número &lt;i&gt;mágico&lt;/i&gt;, 73.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/calc_03-746179.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="http://www.ricbit.com/uploaded_images/calc_03-746165.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Surpresa! O resultado é 42424242, a idade do pai repetida até encher o visor da calculadora! Crianças adoram isso, eu imagino que o motivo é uma variação da &lt;a href="http://en.wikipedia.org/wiki/Clarke's_three_laws"&gt;Lei de Clarke&lt;/a&gt;. A criança não entende porque isso aconteceu, e qualquer conta suficientemente incompreensível é indistinguível de magia. (Pensando bem, isso funciona com estudantes de engenharia também).&lt;br /&gt;&lt;br /&gt;O truque funciona com qualquer valor de idade, é claro. O motivo é simples: se você multiplicar os dois números mágicos, 13837*73 resulta em 1010101. Qualquer número de dois dígitos fica replicado quatro vezes quando você multiplica por 1010101. O ilusionismo do truque é que o par de números mágicos obfusca esse valor.&lt;br /&gt;&lt;br /&gt;A pergunta natural nesse caso é: dá pra fazer a mágica com cinco repetições? Seis? Quantas eu quiser?&lt;br /&gt;&lt;br /&gt;Isso só é possível se o número 101...01 não for primo. Sendo composto, você sempre pode separar os fatores em dois números mágicos. Vamos fazer um teste rápido. Para duas repetições não dá, 101 é primo. Para três repetições temos 259 e 39, para cinco temos 372731 e 271. Usando o &lt;a href="http://www.wolframalpha.com/"&gt;Wolfram Alpha&lt;/a&gt;, dá pra checar manualmente que acima de duas repetições todos os números parecem compostos. Mas dá pra provar isso?&lt;br /&gt;&lt;br /&gt;Eu achei que esse seria um problema complexo, mas acabou sendo mais fácil do que eu esperava! A prova pode ser feita só com matemática elementar. Suponha que o número que queremos fatorar gera n repetições, então ele pode ser escrito como a soma de uma progressão geométrica finita:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=\sum_{k%3D0}^{n-1}%20100^k%3D\frac{100^n-1}{100-1}%3D\frac{100^n-1}{99}" /&gt;&lt;br /&gt;&lt;br /&gt;Se você notar que 100&lt;sup&gt;n&lt;/sup&gt; é o mesmo que 10&lt;sup&gt;2n&lt;/sup&gt;, então dá pra fatorar o numerador como diferença de quadrados:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=\frac{100^n-1}{99}%3D\frac{10^{2n}-1}{99}%3D\frac{(10^n%2B1)(10^n-1)}{99}" /&gt;&lt;br /&gt;&lt;br /&gt;Agora é só notar que, para n&amp;gt;2, os dois termos do numerador são bem maiores que 99, então nenhum deles simplifica completamente. Daí, o valor final sempre vai ter pelo menos dois fatores, o que completa a demonstração.&lt;br /&gt;&lt;br /&gt;Ainda tem um monte de mágicas que podem ser feitas com calculadoras, mas essas ficam para posts futuros :)&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(Obrigado ao Jacques Brancher e ao Fábio Moreira pelas idéias.)&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-8285510843962864816?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2010/03/magicas-com-calculadoras.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-1258845451433215472</guid><pubDate>Sun, 07 Feb 2010 18:16:00 +0000</pubDate><atom:updated>2010-02-07T15:16:49.168-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>sistemas formais</category><category domain='http://www.blogger.com/atom/ns#'>strange loop</category><category domain='http://www.blogger.com/atom/ns#'>pair programming</category><category domain='http://www.blogger.com/atom/ns#'>tdd</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>metaprogramming</category><category domain='http://www.blogger.com/atom/ns#'>assembly</category><title>Single-Person Pair Programming</title><description>Dia desses me perguntaram no &lt;a href="http://twitter.com/ricbit"&gt;twitter&lt;/a&gt; o que eu achava de &lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;Pair programming&lt;/a&gt;. Não apenas eu gosto, como sou entusiasta! Pair programming tem um monte de vantagens, sendo que a principal delas é que o programa será escrito com dois pares de olhos. E como nos lembra a &lt;strike&gt;Lei do Beholder&lt;/strike&gt;&amp;nbsp;Lei de Linus:&amp;nbsp;&lt;i&gt;dados olhos suficientes, todos os bugs são fáceis&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/monstros-736960.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/monstros-736932.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Minha técnica predileta de pair programming é o &lt;i&gt;Ping-Pong Pair Programming&lt;/i&gt;, que eu aprendi com o &lt;a href="http://misko.hevery.com/"&gt;Miško&lt;/a&gt;. A idéia é mesclar as idéias do pair programming com o &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;test-driven development&lt;/a&gt;. Você começa colocando dois teclados no computador, aí um parceiro escreve um teste, e o outro escreve o código que faz aquele teste passar. A vantagem desse método é que funciona mesmo se um dos programadores for preguiçoso, e, de fato, funciona até melhor assim!&lt;br /&gt;&lt;br /&gt;Por exemplo, vamos supor que Alice e Bob querem escrever um programa bem simples: uma função que incrementa um número. Digamos que a assinatura dessa função será int increment(int value). Alice escreve um teste que valida essa função:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;void teste1() {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;assertEquals(2, increment(1));&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Um teste bem razoável. Se entrar um, tem que sair dois. Agora Bob vai escrever o código que faz esse teste passar:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;int increment(int value) {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;return 2;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;FAIL? O Bob é um cara preguiçoso, então ele escreveu um código que sempre retorna dois. Isso faz o teste passar, mas não era isso que a Alice tinha em mente!&lt;br /&gt;&lt;br /&gt;Surpreendentemente, essa é a vantagem do ping-pong. Suponha que esse teste fosse o único teste que o código tinha. Agora digamos que alguém, anos depois, foi &lt;a href="http://en.wikipedia.org/wiki/Code_refactoring"&gt;refatorar&lt;/a&gt; o código, mas fez uma bobagem no processo e agora a função que incrementa um número está retornando sempre 2. Nesse caso, o teste não vai detectar o erro!&lt;br /&gt;&lt;br /&gt;A conclusão é que o teste inicial não era robusto o suficiente. Pra melhorar isso, Alice escreve um segundo teste:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;void teste2() {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;assertEquals(3, increment(2));&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Agora o código original do Bob não funciona, e ele precisa refatorar pra criar um código que passe os dois testes:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;int increment(int value) {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;if (value == 1)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 2;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;else&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 3;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;E agora, FAIL? Não há dúvidas de que o conjunto com dois testes é mais robusto que apenas o primeiro teste, mas esse processo não parece prático. Afinal, os dois poderiam ficar no ping-pong até exaurir todos os valores do int, o que levaria um bocado de tempo.&lt;br /&gt;&lt;br /&gt;Mas isso não acontece! Como sabemos, o Bob é preguiçoso. Na verdade, ele é tão preguiçoso, que atingiu o nível supremo da preguiça: a meta-preguiça. O Bob sabe que se ele continuar nesse ping-pong, ele vai ficar trabalhando até depois das seis, e ele quer ir pra casa ver a novela. Se a Alice escrever testes o suficiente, ela vai acabar &lt;i&gt;forçando&lt;/i&gt; o Bob a escrever o código correto, porque é o código mais simples que resolve o problema.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;void teste3() {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;assertEquals(4, increment(3));&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;int increment(int value) {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;return value + 1;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Agora sim! O resultado final é duplamente bom, nós temos um conjunto de testes robustos, e um código que é o mais simples possível (o que é sempre uma vantagem, esse código é o mais fácil de entender, tem o menor custo de manutenção, etc.)&lt;br /&gt;&lt;br /&gt;Esse método me fascinou por dois motivos. Primeiro, ele é uma aplicação da&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Occam's_razor"&gt;Navalha de Occam&lt;/a&gt; em software: você parte de uma série de observações e deduz a teoria mais simples que modela o sistema. Segundo,&amp;nbsp;o método é um indicativo de que é possível fazer um conjunto de testes que &lt;i&gt;define&lt;/i&gt; a operação em questão.&lt;br /&gt;&lt;br /&gt;Juntando as duas observações, a pergunta natural que faz é: pra que eu preciso do Bob? Eu poderia construir uma máquina que, dado um conjunto de testes, encontre o programa mais simples que os satisfaçam. Se a máquina conseguir jogar o ping-pong de maneira ótima, então acabamos de inventar o Single-Person Pair Programming!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/ping-pong-766413.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/ping-pong-766386.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Antes de tentar resolver esse problema, precisamos escolher alguma definição para "programa mais simples". Por exemplo, vamos escolher que o programa mais simples é o menor programa que resolve o problema. Uma maneira de achar esse programa é fazer um brute force: basta testar todos os programas possíveis!&lt;br /&gt;&lt;br /&gt;Isso é fácil de visualizar em assembly. O conjunto de opcodes do processador é limitado, então a quantidade de programas em assembly com um único opcode é finito. Eu testo todos eles pra ver se algum satisfaz os testes: se algum passar, ele é a solução, senão, eu repito o procedimento com todos os programas de tamanho dois, e assim por diante. Esse algoritmo garantidamente acha o menor programa que satisfaz os testes.&lt;br /&gt;&lt;br /&gt;Um problema teórico com essa abordagem é que ela está sujeita ao problema da parada de Turing. Eventualmente, algum desses programas que você está testando pode entrar num loop infinito e você não tem como detectar isso. Uma solução é sair pela tangente: a maioria dos problemas da vida real podem ser resolvidos com modelos computacionais mais fracos que a máquina de Turing. Em assembly, nós poderíamos proibir os saltos pra trás, o que resolve essa limitação.&lt;br /&gt;&lt;br /&gt;Essa técnica para achar o programa mínimo se chama &lt;a href="http://en.wikipedia.org/wiki/Superoptimization"&gt;Superotimização&lt;/a&gt;, e hoje em dia há vários papers sobre o assunto. Em 2003 eu escrevi um superotimizador para assembly Z80, então foi fácil adaptá-lo para fazer Single-person Pair Programming.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/singleppp.c"&gt;Single-person Pair Programming escrito em C&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Vamos testar. Se eu tenho um único teste, 1-&amp;gt;2, o programa acha três soluções mínimas, sendo uma delas ADD&amp;nbsp;A,A. É claro, com esse único teste, ele não sabe se estamos somando um ou multiplicando por dois. Colocando dois testes, 1-&amp;gt;2 e 2-&amp;gt;3, ele já converge para a solução única INC&amp;nbsp;A.&lt;br /&gt;&lt;br /&gt;Complicando: e se quisermos um incremento módulo 8 (ou seja, a=(a+1)%8)? Podemos definir isso com os testes 1-&amp;gt;2, 2-&amp;gt;3 e 7-&amp;gt;0. Colocando essa suite no programa, temos o resultado abaixo:&lt;br /&gt;&lt;br /&gt;INC A&lt;br /&gt;AND 7&lt;br /&gt;&lt;br /&gt;Ou seja, o Single-person Pair Programming funciona direitinho!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bônus!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;O vencedor do Ricbit Jam #1 foi o &lt;b&gt;Davi Costa&lt;/b&gt;, parabéns! Por uma questão de logística que envolve a China eu ainda não tive como compilar os resultados, mas fiquem de olho lá no meu twitter que em breve eu farei uma página com soluções e comentários.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-1258845451433215472?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2010/02/single-person-pair-programming.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-806756697191745963</guid><pubDate>Sun, 17 Jan 2010 22:32:00 +0000</pubDate><atom:updated>2010-01-17T21:55:03.535-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>ricbit jam</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>complexidade</category><title>Tatuagens em cadeia</title><description>Uma classe de artistas que eu admiro muito são os tatuadores, e por um motivo simples: eles não podem errar. Um desenhista pode usar borracha, um arte-finalista pode cobrir o erro com tinta branca, um artista digital pode apertar control-Z, mas o tatuador não pode fazer nada disso. Um escultor, se erra, tem a opção de jogar fora o bloco de pedra e começar de novo, mas o tatuador nem essa opção tem.&lt;br /&gt;&lt;br /&gt;Exatamente por isso, tem um tatuador que eu conheço que se recusa a tatuar nomes de namorados. Tatuagens são permanentes, mas namoros são efêmeros: imagine namorar alguém que tem uma tatuagem com o nome do ex? Nesse caso, uma solução prática é reciclar a tatuagem e namorar alguém que tenha o mesmo nome do seu ex. Não é elegante, mas funciona.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/tatuagem-727747.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="283" src="http://www.ricbit.com/uploaded_images/tatuagem-727697.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Isso leva a conclusões curiosas. Veja o meu caso, por exemplo. Se eu tatuar ILA e minha esposa tatuar RICARDO, aparentemente ela estaria levando vantagem. É muito mais fácil arrumar outro Ricardo que arrumar outra Ila. Por outro lado, eu não precisaria procurar apenas Ilas, eu poderia arranjar uma Priscila ou uma Camila, bastando adicionar mais letras na tatuagem!&lt;br /&gt;&lt;br /&gt;Isso naturalmente leva à pergunta: qual é o máximo de namoradas que um Serial Tatuator pode ter?  Por exemplo, uma pessoa poderia ir de Ana para Iana e depois Fabiana. Será que dá pra achar uma cadeia de tatuagens de tamanho quatro? Cinco? Hora de fazer uma simulação!&lt;br /&gt;&lt;br /&gt;Antes de começar, precisamos de um corpus de nomes. O jeito mais fácil de conseguir o corpus é escrevendo um crawler para um desses sites com nomes de bebês. Uma busca rápida e eu achei o &lt;a href="http://www.babyhold.com/"&gt;Babyhold&lt;/a&gt;, que tem a vantagem de separar os nomes por sexo. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/crawl_names.py"&gt;&lt;i&gt;Script python para fazer crawling de nomes de meninas&lt;/i&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;O script retornou mais de 7100 nomes de meninas. Agora é só fazer um outro script que calcule a máxima cadeia de nomes. Como a quantidade de nomes não é tão grande assim, um algoritmo cúbico bobo dá conta do recado:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/name_chain.py"&gt;&lt;i&gt;Script python para achar cadeias máximas&lt;/i&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;O script acabou achando várias soluções de tamanho seis, mas sem dúvida a seqüência mais curiosa foi a abaixo :)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/mulheres_li-784991.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="167" src="http://www.ricbit.com/uploaded_images/mulheres_li-784959.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;Li -&amp;gt; Lin -&amp;gt; Elin -&amp;gt; Elina -&amp;gt; Angelina -&amp;gt; Angelina Jolie&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Bônus!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Embora o algoritmo cúbico funcione bem para 7100 nomes, certamente há como otimizá-lo. Ao invés de fazer uma solução mais rápida, dessa vez eu vou abrir para os leitores enviarem suas soluções! Clicando no link abaixo você vai para o primeiro &lt;i&gt;Ricbit Jam&lt;/i&gt;, feito com a engine do spoj. Ganha quem enviar a solução mais rápida nos próximos quinze dias. Não tem prêmio, mas o vencedor terá seu nome divulgado no próximo post :)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/ricbitjam1/"&gt;Ricbit Jam #1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Não adianta tentar mandar o programa em python acima, ele não acha todas as soluções e vai dar TLE no servidor do spoj. Mas você pode usar como base pra fazer a sua solução.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-806756697191745963?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2010/01/tatuagens-em-cadeia.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>29</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-8361784126950886319</guid><pubDate>Sat, 02 Jan 2010 03:45:00 +0000</pubDate><atom:updated>2010-01-02T01:35:09.761-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>física</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>história da ciência</category><title>Newton e os universos paralelos</title><description>&lt;a href="http://www.blogger.com/"&gt;&lt;/a&gt;&lt;span id="goog_1262398529649"&gt;&lt;/span&gt;&lt;span id="goog_1262398529650"&gt;&lt;/span&gt;Neste último Natal fomos passar o feriado no sítio. Não precisei de muito tempo pra notar que eu não funciono muito bem nesse ambiente. Além de ser alérgico a quase todos os insetos, eu tinha apenas uma pequena noção de coisas básicas de quem vive por lá (como andar a cavalo, por exemplo).&amp;nbsp;Isso nem me chateia, porque em compensação eu tenho outras habilidades que o pessoal do sítio não tem, como saber usar o &lt;a href="http://www.google.com/sky/skymap.html"&gt;Google Sky Map&lt;/a&gt; pra identificar as estrelas no céu.&lt;br /&gt;&lt;br /&gt;Enquanto eu descansava numa rede, eu comecei a pensar como seria um universo paralelo onde o Ricbit é um matuto que entende tudo da vida no campo. Mas o pensamento não durou muito. Que coisa batida isso, se for pra imaginar um universo paralelo, vamos imaginar um mais original!&lt;br /&gt;&lt;br /&gt;Sempre que pensamos em universo paralelos, tendemos a imaginar um muito semelhante ao nosso, onde apenas alguns detalhes mudam. E se imaginássemos um universo tão diferente que até as leis físicas são distintas da nossa? Por exemplo, como seriam as órbitas planetárias num universo onde a Lei da Gravidade não variasse com o quadrado da distância, mas sim com alguma outra expressão qualquer?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/rede_sitio-776204.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="315" src="http://www.ricbit.com/uploaded_images/rede_sitio-776197.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Esse exemplo é bacana por causa da sua importância histórica. Vamos voltar para o tempo do &lt;a href="http://en.wikipedia.org/wiki/Isaac_Newton"&gt;Isaac Newton&lt;/a&gt;, que o Asimov considerava o maior de todos os cientistas. É inegável que o Newton era um gênio, mas o que nem todo mundo sabe é que ele era briguento, vingativo, e costumava cometer o maior pecado que um cientista pode fazer: não citar as fontes.&lt;br /&gt;&lt;br /&gt;Isso aconteceu com a Lei da Gravidade. Naquela época ainda não existiam as listas de discussão, então os cientistas conversavam por cartas escritas à mão. Certa vez, Newton recebeu uma carta do &lt;a href="http://en.wikipedia.org/wiki/Robert_Hooke"&gt;Robert Hooke&lt;/a&gt;, aquele que hoje é conhecido pela &lt;a href="http://en.wikipedia.org/wiki/Hooke's_Law"&gt;lei da molas&lt;/a&gt;. Nessa carta, Hooke dizia que suspeitava da existência de uma força da gravidade, que seria central (dependendo apenas da distância), e provavelmente proporcional ao inverso do quadrado da distância. Na carta ele ainda dizia que não sabia como provar essa suspeita.&lt;br /&gt;&lt;br /&gt;Hoje em dia a razão para o Hooke não saber provar é clara. Pra conseguir provar, você precisa saber Cálculo, que o Newton já tinha inventado, mas ainda não tinha contado pra ninguém. Se o Newton fosse gente boa, ele teria respondido algo do tipo "eu sei provar, chega mais e vamos resolver juntos". Ao invés disso, ele ficou na miúda, e anos depois publicou o Principia Mathematica, onde ele usava o Cálculo para mostrar que a tal força central inversamente quadrática implica em órbitas que são seções cônicas.&lt;br /&gt;&lt;br /&gt;O Hooke, compreensivelmente, ficou puto, e foi reclamar com o editor do livro, o &lt;a href="http://en.wikipedia.org/wiki/Edmond_Halley"&gt;Halley&lt;/a&gt; (o cientista, não o cometa). Depois de muito bate-boca, o Halley convenceu o Newton a colocar um prefácio onde ele dizia que a lei da gravidade tinha sido sugerida informalmente pelo Hooke, mas sem demonstração. Numa carta posterior ao Hooke, Newton ainda diria "&lt;i&gt;se enxerguei mais longe, foi porque estava sobre o ombro de gigantes&lt;/i&gt;". Não era humildade, era trollagem. Conta-se que Hooke era baixinho e corcunda.&lt;br /&gt;&lt;br /&gt;Mas o Newton não parou por aí. Certa vez, ele ficou como responsável pela mudança de prédio da Royal Society. Entre os quadros que precisavam ser mudados, estavam os retratos de todos os membros do grupo. Por uma coincidência não-explicada, o quadro do Hooke foi o único que se perdeu no caminho. Hoje em dia, ninguém sabe como era o rosto do Hooke, esse quadro perdido era o único retrato dele.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/royal_society-746652.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="124" src="http://www.ricbit.com/uploaded_images/royal_society-746604.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Nada disso teria acontecido se o Hooke soubesse Cálculo. E nós, para calcularmos nossas órbitas em universos paralelos, vamos fazer exatamente as contas que o Hooke desconhecia! Se você também não sabe cálculo, pule a caixa azul e vá direto pro resultado.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #f0f0ff; border: 1px dashed black; clear: both; padding: 10px;"&gt;Consideremos um sistema com duas massas pontuais no vácuo. As contas em coordenadas cartesianas são meio chatas, então vamos usar coordenadas polares, centradas numa das massas. Nesse tipo de conta, o normal é usar um sistema de versores &lt;b&gt;r&lt;/b&gt; e &lt;b&gt;θ&lt;/b&gt; que giram junto com o planeta, mas a engenharia me deixou vícios difíceis de largar, então eu vou usar exponenciais complexas. A posição do planeta é a seguinte:&lt;br /&gt;&lt;br /&gt;&lt;img alt="p=re^{j\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=p%3Dre%5E%7Bj%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Note que r e θ na verdade são r(t) e θ(t), eu vou omitir o tempo pra não poluir as equações. A aceleração da partícula é a segunda derivada:&lt;br /&gt;&lt;br /&gt;&lt;img alt="p'=r'e^{ j\theta}+rj\theta'e^{j\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=p'%3Dr'e%5E%7B%20j%5Ctheta%7D%2Brj%5Ctheta'e%5E%7Bj%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="p''=r''e^{j\theta} +r'j\theta'e^{j\theta}+r'j\theta'e^{j\theta}+rj \theta''e^{j\theta}+rj^{2}\theta'^{2} e^{j\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=p''%3Dr''e%5E%7Bj%5Ctheta%7D%20%2Br'j%5Ctheta'e%5E%7Bj%5Ctheta%7D%2Br'j%5Ctheta'e%5E%7Bj%5Ctheta%7D%2Brj%20%5Ctheta''e%5E%7Bj%5Ctheta%7D%2Brj%5E%7B2%7D%5Ctheta'%5E%7B2%7D%20e%5E%7Bj%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Agrupando os termos e lembrando que j&lt;sup&gt;2&lt;/sup&gt; = -1, temos:&lt;br /&gt;&lt;br /&gt;&lt;img alt="p''=(r''-r\theta'^{2})e^{j\theta}+(2r'\theta'+r\theta'')je^{j\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=p''%3D(r''-r%5Ctheta'%5E%7B2%7D)e%5E%7Bj%5Ctheta%7D%2B(2r'%5Ctheta'%2Br%5Ctheta'')je%5E%7Bj%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Até aqui tudo genérico. Vamos impor agora que a força seja central. Nesse caso, a componente transversal vale zero. Note que, com uma pequena manipulação algébrica, dá pra isolar uma derivada:&lt;br /&gt;&lt;br /&gt;&lt;img alt="2r'\theta'+r\theta''=\frac{1}{r}(2rr'\theta'+r^{2}\theta'')=\frac{1}{r}\frac{d}{dt}(r^{2}\theta')=0" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=2r'%5Ctheta'%2Br%5Ctheta''%3D%5Cfrac%7B1%7D%7Br%7D(2rr'%5Ctheta'%2Br%5E%7B2%7D%5Ctheta'')%3D%5Cfrac%7B1%7D%7Br%7D%5Cfrac%7Bd%7D%7Bdt%7D(r%5E%7B2%7D%5Ctheta')%3D0" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Aqui temos duas soluções. A primeira é sem graça, 1/r=0 se as duas massas estiverem infinitamente distantes, aí naturalmente a força transversal é zero. O segundo caso é mais legal:&lt;br /&gt;&lt;br /&gt;&lt;img alt="\frac{d}{dt}(r^{2}\theta')=0 \Rightarrow r^{2}\theta'=k" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Cfrac%7Bd%7D%7Bdt%7D(r%5E%7B2%7D%5Ctheta')%3D0%20%5CRightarrow%20r%5E%7B2%7D%5Ctheta'%3Dk" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Se a derivada é zero, então a integral é uma constante. Se você lembrar que r&lt;sup&gt;2&lt;/sup&gt;θ é o dobro da área de um setor circular, então o que essa fórmula diz é que a taxa de variação da área de um setor é constante, ou seja, para um dado intervalo de tempo, ele percorre sempre a mesma área. Ora, essa é a segunda lei de Kepler! Pelo que concluímos, ela funciona pra qualquer força central, não só pra gravidade.&lt;br /&gt;&lt;br /&gt;Vamos lidar com a componente radial agora. As massas são todas constantes, então vale que F=ma. Além disso, vamos introduzir uma variável u pra facilitar as contas:&lt;br /&gt;&lt;br /&gt;&lt;img alt="\frac{F}{m}=r''-r\theta'^{2}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Cfrac%7BF%7D%7Bm%7D%3Dr''-r%5Ctheta'%5E%7B2%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="r=\frac{1}{u}\Rightarrow u=\frac{1}{r}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=r%3D%5Cfrac%7B1%7D%7Bu%7D%5CRightarrow%20u%3D%5Cfrac%7B1%7D%7Br%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Nós podemos isolar o tempo e deixar o raio em função do ângulo, usando uma mudança de váriaveis com a regra da cadeia.&lt;br /&gt;&lt;br /&gt;&lt;img alt="r^{2} \theta'=k \Rightarrow \frac{d\theta}{dt}=\frac{k}{r^{2}}=ku^{2}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=r%5E%7B2%7D%20%5Ctheta'%3Dk%20%5CRightarrow%20%5Cfrac%7Bd%5Ctheta%7D%7Bdt%7D%3D%5Cfrac%7Bk%7D%7Br%5E%7B2%7D%7D%3Dku%5E%7B2%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="r'=\frac{dr}{dt}=\frac{dr}{d\theta}\frac{d\theta}{dt}=\frac{d}{d\theta}(\frac{1}{u})ku^{2} =-\frac{1}{u^{2}}\frac{du}{d\theta}ku^{2}=-k\frac{du}{d\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=r'%3D%5Cfrac%7Bdr%7D%7Bdt%7D%3D%5Cfrac%7Bdr%7D%7Bd%5Ctheta%7D%5Cfrac%7Bd%5Ctheta%7D%7Bdt%7D%3D%5Cfrac%7Bd%7D%7Bd%5Ctheta%7D(%5Cfrac%7B1%7D%7Bu%7D)ku%5E%7B2%7D%20%3D-%5Cfrac%7B1%7D%7Bu%5E%7B2%7D%7D%5Cfrac%7Bdu%7D%7Bd%5Ctheta%7Dku%5E%7B2%7D%3D-k%5Cfrac%7Bdu%7D%7Bd%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="r''=\frac{dr'}{dt}=\frac{dr'}{d\theta}\frac{d\theta}{dt}=\frac{d}{d\theta}(-k\frac{du}{d\theta})ku^{2}=-k^{2}u^{2}\frac{d^{2}u}{d\theta^{2}}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=r''%3D%5Cfrac%7Bdr'%7D%7Bdt%7D%3D%5Cfrac%7Bdr'%7D%7Bd%5Ctheta%7D%5Cfrac%7Bd%5Ctheta%7D%7Bdt%7D%3D%5Cfrac%7Bd%7D%7Bd%5Ctheta%7D(-k%5Cfrac%7Bdu%7D%7Bd%5Ctheta%7D)ku%5E%7B2%7D%3D-k%5E%7B2%7Du%5E%7B2%7D%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Agora é só substituir na equação original:&lt;br /&gt;&lt;br /&gt;&lt;img alt="\frac{F}{m}=r''-r(\frac{d\theta}{dt})^{2}=-k^{2}u^{2}\frac{d^{2}u}{d\theta^{2}}-\frac{1}{u}(ku^{2})^{2}=-k^{2}u^{2}(\frac{d^{2}u}{d\theta^{2}}+u)" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Cfrac%7BF%7D%7Bm%7D%3Dr''-r(%5Cfrac%7Bd%5Ctheta%7D%7Bdt%7D)%5E%7B2%7D%3D-k%5E%7B2%7Du%5E%7B2%7D%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D-%5Cfrac%7B1%7D%7Bu%7D(ku%5E%7B2%7D)%5E%7B2%7D%3D-k%5E%7B2%7Du%5E%7B2%7D(%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D%2Bu)" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="-\frac{F}{mk^{2}u^{2}}=\frac{d^{2}u}{d\theta^{2}}+u" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=-%5Cfrac%7BF%7D%7Bmk%5E%7B2%7Du%5E%7B2%7D%7D%3D%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D%2Bu" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Pronto! Esta é a equação geral das órbitas com força central. Para conferir se está certo, vamos colocar uma força inversamente quadrática. Note que as forças precisam ser negativas, pois, na nossa orientação, forças atrativas são negativas. Aliás, como eu não estou interessado em unidades, vou escolher constantes que cancelem.&lt;br /&gt;&lt;br /&gt;&lt;img alt="F=-\frac{mk^{2}}{r^{2}}=-mk^{2}u^{2}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=F%3D-%5Cfrac%7Bmk%5E%7B2%7D%7D%7Br%5E%7B2%7D%7D%3D-mk%5E%7B2%7Du%5E%7B2%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="1=\frac{d^{2}u}{d\theta^{2}}+u" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=1%3D%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D%2Bu" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Para resolver a equação diferencial, somamos a solução particular com as homogêneas. Uma particular é fácil, u=1. A homogênea todo mundo sabe de cabeça, é cos(θ) (vezes uma constante que depende das condições de contorno). Afinal, é a mesma solução do sistema massa-mola, do oscilador LC, e assim por diante.&lt;br /&gt;&lt;br /&gt;&lt;img alt="u=1+e.cos(\theta) \Rightarrow r=\frac{1}{1+e.cos(\theta)" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=u%3D1%2Be.cos(%5Ctheta)%20%5CRightarrow%20r%3D%5Cfrac%7B1%7D%7B1%2Be.cos(%5Ctheta)" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Ahá! Esta é equação da seção cônica em coordenadas polares. Dependendo do valor de e, a órbita pode ser circular (e=0, como Vênus, aproximadamente), elíptica (e&amp;lt;1, como a Terra), parabólica ou hiperbólica (e=1 ou e&amp;gt;1, como os cometas).&lt;br /&gt;&lt;br /&gt;Vamos tentar outro tipo de força, por exemplo, uma inversamente cúbica. Nesse caso:&lt;br /&gt;&lt;br /&gt;&lt;img alt="F=-\frac{mk^{2}}{r^{3}}=-mk^{2}u^{3}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=F%3D-%5Cfrac%7Bmk%5E%7B2%7D%7D%7Br%5E%7B3%7D%7D%3D-mk%5E%7B2%7Du%5E%7B3%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;img alt="u=\frac{d^{2}u}{d\theta^{2}}+u \Rightarrow \frac{d^{2}u}{d\theta^{2}} =0 \Rightarrow u=\theta \Rightarrow r=\frac{1}{\theta}" class="ee_img tr_noresize" eeimg="1" src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=u%3D%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D%2Bu%20%5CRightarrow%20%5Cfrac%7Bd%5E%7B2%7Du%7D%7Bd%5Ctheta%5E%7B2%7D%7D%20%3D0%20%5CRightarrow%20u%3D%5Ctheta%20%5CRightarrow%20r%3D%5Cfrac%7B1%7D%7B%5Ctheta%7D" style="vertical-align: middle;" /&gt;&lt;br /&gt;&lt;br /&gt;Ou seja, a órbita agora é uma espiral.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Agora que temos a equação geral, podemos colocar a força que quisermos, e analisar a órbita resultante. O problema é que muitas fórmulas geram equações que não tem solução analítica, então eu fiz um scriptzinho em python pra resolver numericamente mesmo. Abaixo o script e os resultados para várias funções:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/orbit.py"&gt;Script em python para resolver órbitas em universos paralelos&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px; margin-top: 10px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/orbit-740350.gif" style="clear: both; float: left;" /&gt;Para uma força &lt;b&gt;inversamente quadrática&lt;/b&gt;, a órbita é circular, como esperado pela Lei da Gravidade.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px; margin-top: 10px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/orbit-797050.gif" style="clear: both; float: left;" /&gt;Já uma força &lt;b&gt;inversamente cúbica&lt;/b&gt; gera uma espiral. Essa força é fraquinha demais pra manter uma órbita, e o planeta vai aos poucos se afastando.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px; margin-top: 10px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/orbit-734776.gif" style="clear: both; float: left;" /&gt;Uma força &lt;b&gt;inversamente linear&lt;/b&gt; demora para estabilizar, mas acaba fazendo uma órbita circular também.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px; margin-top: 10px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/orbit-793860.gif" style="clear: both; float: left;" /&gt;E uma força &lt;b&gt;constante&lt;/b&gt;, independente da distância? Ela também termina numa órbita circular, o que pra mim faz sentido. O planeta se move até o ponto onde a força constante é igual à centrípeta.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px; margin-top: 10px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/orbit-758036.gif" style="clear: both; float: left;" /&gt;Agora vamos sacanear e colocar uma força &lt;b&gt;senoidal&lt;/b&gt; só pra ver o que acontece. Ele não diverge, mas faz uma órbita muito doida. Provavelmente é um atrator estranho.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-8361784126950886319?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2010/01/newton-e-os-universos-paralelos_02.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>27</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-4729670866888402172</guid><pubDate>Sun, 15 Nov 2009 22:19:00 +0000</pubDate><atom:updated>2009-11-15T22:12:37.527-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>sistemas formais</category><category domain='http://www.blogger.com/atom/ns#'>lógica</category><title>A Lei de Ricbit</title><description>Já faz quinze anos que eu assino mailing lists, e uma coisa sempre foi constante em todo esse tempo: as &lt;a href="http://en.wikipedia.org/wiki/Flaming_(Internet)"&gt;flamewars&lt;/a&gt;. Aparentemente, listas na internet têm o poder de enfurecer os participantes e transformá-los em monstros incontroláveis. Ironicamente, essas brigas pela internet são tão previsíveis, que podemos até extrair padrões delas, como a &lt;a href="http://en.wikipedia.org/wiki/Godwin's_Law"&gt;Lei de Godwin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Dia desses eu fiz uma observação sobre a natureza dessas brigas que os meus amigos apelidaram de &lt;i&gt;Lei de Ricbit&lt;/i&gt;. A premissa é simples: as flamewars acontecem em qualquer lista de discussão, mesmo em listas sobre matemática e computação, onde supostamente os leitores são agentes racionais. Como isso pode ocorrer? Será que uma briga poderia acontecer mesmo se o Spock e o Data se encontrassem no &lt;a href="http://wave.google.com/help/wave/about.html"&gt;Google Wave&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/briga-789004.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="257" src="http://www.ricbit.com/uploaded_images/briga-789000.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Data&lt;/b&gt;: Fiz uma medição surpreendente! Usando os sensores da Enterprise, eu medi os ângulos entre três estrelas distantes, e o resultado é que a soma dos ângulos do triângulo formado pelas estrelas não dá 180 graus!&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Fascinante, mas temo que você tenha cometido um erro. Obviamente a soma dos ângulos de um triângulo é sempre 180 graus. Usando a lógica, eu posso &lt;i&gt;provar&lt;/i&gt; que isso é sempre é verdade. Basta considerar uma reta paralela à base do triângulo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/triangulo-738445.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="160" src="http://www.ricbit.com/uploaded_images/triangulo-738400.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Como você pode ver, os ângulos α e α' são &lt;a href="http://pt.wikipedia.org/wiki/Retas_paralelas"&gt;alternos internos&lt;/a&gt;, e portanto iguais. O mesmo acontece com β e β', logo, a soma dos três ângulos é um ângulo raso.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Data&lt;/b&gt;: Como você sabe, andróides não cometem erros de medida. Os ângulos não somaram 180 graus por culpa da &lt;a href="http://en.wikipedia.org/wiki/General_relativity"&gt;teoria da relatividade geral&lt;/a&gt;. Objetos tão massivos quanto as estrelas em questão deformam o espaço, o que explica a minha medida. Eu esperava mais dos vulcanos, certamente não se pode questionar os dados experimentais.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Eu não estava questionando a medida, estava questionando a conclusão. O que você mediu não era um triângulo de verdade, mas sim um outro tipo de figura geométrica de três vértices. Triângulos precisam necessariamente somar 180 graus: se não somarem, não são triângulos. Eu esperava mais dos andróides, certamente não se pode questionar a lógica.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_ricbit-754218.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_ricbit-754213.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Ricbit&lt;/b&gt;: Vocês dois vão ficar discutindo pra sempre, sem concluir nada, e eu vou mostrar o porquê. Muita gente acha que somente a lógica pode levar à verdade, mas isso não é inteiramente correto. A lógica, por si só, pode apenas produzir &lt;a href="http://en.wikipedia.org/wiki/Tautology_(logic)"&gt;obviedades&lt;/a&gt;. A função real da lógica não é &lt;i&gt;produzir&lt;/i&gt; verdades, mas sim &lt;i&gt;transformar&lt;/i&gt; verdades. Para usar a lógica na prática, você precisa de verdades básicas, os &lt;a href="http://en.wikipedia.org/wiki/Axiom"&gt;axiomas&lt;/a&gt;, e a partir deles você deriva as verdades mais complexas.&lt;br /&gt;&lt;br /&gt;Cada conjunto de axiomas determina um sistema formal. E é por isso que vocês nunca vão concordar, os dois estão partindo de axiomas diferentes! O Spock, ao dizer que alternos internos são iguais, assumiu implicitamente o &lt;a href="http://en.wikipedia.org/wiki/Parallel_postulate"&gt;Postulado das Paralelas&lt;/a&gt; do Euclides. Já o Data, ao dizer que o espaço é curvo, assumiu a negação do Postulado das Paralelas, gerando assim uma &lt;a href="http://en.wikipedia.org/wiki/Non-Euclidean_geometry"&gt;geometria não-Euclideana&lt;/a&gt;. Como os axiomas são diferentes, vocês dois vão discordar sempre, mesmo que usem a lógica perfeitamente.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Obviamente, eu sabia disso.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Data&lt;/b&gt;: Eu também.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_ricbit-754218.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_ricbit-754213.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Ricbit&lt;/b&gt;: Se sabiam, porque continuaram a discussão?&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;, &lt;b&gt;Data&lt;/b&gt;: ...&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_ricbit-754218.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_ricbit-754213.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Ricbit&lt;/b&gt;: Olha, que tal esquecer tudo isso? Vamos jogar uma partida de Guitar Hero que é mais divertido.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Excelente! Eu fico com a guitarra, prefiro os instrumentos de corda.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Data&lt;/b&gt;: Onde que o Guitar Hero é instrumento de corda? Não tem corda nenhuma lá, só botão.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Ora, quando eu clico no botão ele faz som de instrumento de corda.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_data-760077.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_data-760072.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Data&lt;/b&gt;: Mas você não está excitando nenhuma corda, está só apertando um botão! Não tem como dizer que a guitarra do Guitar Hero é um instrumento de corda só porque ela produz som de corda.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_spock-788900.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_spock-788895.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Spock&lt;/b&gt;: Se for assim, então o piano também não é um instrumento de corda, afinal, você aciona teclas, e não cordas.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/avatar_ricbit-754218.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/avatar_ricbit-754213.jpg" /&gt;&lt;/a&gt;&lt;b&gt;Ricbit&lt;/b&gt;: (facepalm)&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: 1px dotted #a0a0a0; clear: both; height: 1px;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/rockband-783753.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="322" src="http://www.ricbit.com/uploaded_images/rockband-783748.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Uma mesma proposição P pode ser verdadeira ou falsa, dependendo do sistema de axiomas que você adota. Mas como decidir qual sistema formal é o correto? A resposta é que você não &lt;i&gt;decide&lt;/i&gt; qual é o correto, você &lt;i&gt;escolhe&lt;/i&gt; qual é o correto. O único requisito de um sistema formal é que ele seja internamente consistente, fora isso, você escolhe o que for mais útil na ocasião.&lt;br /&gt;&lt;br /&gt;O que vale para sistemas formais também funciona informalmente, mas ao invés de axiomas você tem definições. Qual a definição correta de "instrumento de corda"? É o que produz som de corda, ou é aquele onde você excita uma corda diretamente? Novamente, não existe um correto: você escolhe um deles e arca com as conseqüências da sua definição (se você achar que Guitar Hero não é instrumento de corda, então o piano também não vai ser).&lt;br /&gt;&lt;br /&gt;Dito isso, agora já podemos enunciar a Lei de Ricbit, em sua forma original:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lei de Ricbit&lt;/b&gt;: &lt;i&gt;Se dois interlocutores discordam de uma definição, então eles vão discutir pra sempre, sem nunca concordar&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;E como usar a Lei de Ricbit na prática? Fique de olho em definições conflitantes, que usualmente são implícitas. Por exemplo, um sinal claro de definição conflitante é a expressão "de verdade". FPGA não é hardware livre &lt;i&gt;de verdade&lt;/i&gt;, como o Arduino. Java não é orientada a objeto &lt;i&gt;de verdade&lt;/i&gt;, como Smalltalk. Quando a pessoa usa "de verdade", está te dizendo que a definição dele é diferente da sua, e aí é inútil prosseguir.&amp;nbsp;E qual definição é a certa, a sua ou a dele? Tanto faz: desde que você seja consistente, pode adotar qualquer uma como verdadeira.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-4729670866888402172?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/11/lei-de-ricbit.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>54</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-1312191282791960276</guid><pubDate>Mon, 09 Nov 2009 03:50:00 +0000</pubDate><atom:updated>2009-11-09T00:50:09.753-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>processamento de imagens</category><category domain='http://www.blogger.com/atom/ns#'>nsfw</category><category domain='http://www.blogger.com/atom/ns#'>licenças</category><category domain='http://www.blogger.com/atom/ns#'>história da ciência</category><title>Lena e iLena</title><description>Existem algumas imagens que são icônicas. São tão conhecidas, que só com uma descrição simples você já sabe de qual imagem eu estou falando. O rosto do Che Guevara, a Marilyn com a saia levantada, o chinesinho parando os tanques: todos conhecem essas imagens.&lt;br /&gt;&lt;br /&gt;Agora, se você for um estudioso do &lt;a href="http://en.wikipedia.org/wiki/Digital_image_processing"&gt;processamento digital de imagens&lt;/a&gt;, as suas imagens icônicas são outras. Para poder comparar algoritmos, nós usamos uma série de &lt;a href="http://en.wikipedia.org/wiki/Standard_test_image"&gt;imagens padronizadas&lt;/a&gt;, como o &lt;a href="http://sipi.usc.edu/database/database.cgi?volume=misc&amp;amp;image=11#top"&gt;mandrill&lt;/a&gt; e as &lt;a href="http://sipi.usc.edu/database/database.cgi?volume=misc&amp;amp;image=15#top"&gt;pimentas&lt;/a&gt;. Mas, dessas imagens, nenhuma é tão conhecida como a &lt;a href="http://en.wikipedia.org/wiki/Lenna"&gt;Lena&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/lena-713374.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://www.ricbit.com/uploaded_images/lena-713372.jpg" width="200" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;i&gt;Lena&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Há quem diga que a imagem da Lena ficou tão famosa entre os cientistas por ser uma imagem complexa o suficiente pra testar qualquer algoritmo: ela tem freqüências baixas e altas, texturas complexas, faixa dinâmica larga. A minha teoria é mais prosaica: se você vai ter que ficar olhando pra mesma imagem por meses, uma mulher bonita é melhor que um babuíno de nariz vermelho :)&lt;br /&gt;&lt;br /&gt;Mas a imagem da Lena tem um segredo que nem todos conhecem. Quando eu descobri a origem da imagem, fiquei doido pra conseguir uma cópia original da fonte de onde essa imagem saiu. E depois de anos procurando, finalmente consegui:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Ricbit_Lena-731231.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="220" src="http://www.ricbit.com/uploaded_images/Ricbit_Lena_metade-750955.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Clique na imagem pra ver a versão completa, NSFW&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Sim, a imagem usada por cientistas do mundo todo, na verdade, é um centerfold da Playboy!&lt;br /&gt;&lt;br /&gt;Essa edição é a Playboy americana de novembro de 1972. Eu corajosamente a comprei no ebay, mesmo com os avisos que diziam "warning: pages may be sticky". Foi um ótimo negócio, o vendedor me vendeu uma Playboy usada, e eu comprei um pedaço da história da computação :)&lt;br /&gt;&lt;br /&gt;A origem da imagem é curiosa. Conta-se que o pesquisador tinha um paper pra entregar no dia seguinte, e precisava de uma imagem com urgência. Ele acabou digitalizando a primeira revista que achou em sua mesa, a edição da Playboy com a Lena, que, curiosamente, também foi a &lt;a href="http://www.playboy.com/worldofplayboy/faq/what.html"&gt;edição mais vendida&lt;/a&gt; da história da revista. Ele não contou pra ninguém a origem da imagem, e por anos muitos usaram a imagem sem conhecer a história dela.&lt;br /&gt;&lt;br /&gt;Isso acabou gerando um problema quando a Playboy descobriu que uma das suas imagens estava sendo copiada indiscriminadamente por aí. Inicialmente, ela tentou impedir o uso da imagem, mas depois acabou descobrindo que era boa propaganda, e hoje em dia a diretoria da revista faz vista grossa para o assunto.&lt;br /&gt;&lt;br /&gt;Por outro lado, como a imagem ainda tem copyright, nunca se sabe se um dia a diretoria não vai mudar de idéia e vetar novamente o uso. Se você precisa de uma nova imagem de teste, agora tem uma nova solução! A &lt;a href="http://www.ilafox.com/"&gt;minha esposa&lt;/a&gt; (ilustradora, modelo e atriz), fez um remake da imagem da Lena, e disponibilizou com a licença &lt;a href="http://creativecommons.org/licenses/by-sa/2.5/br/"&gt;Creative Commons Attribution-Share Alike&lt;/a&gt;. E se você usar a imagem em algum paper, eu ainda posso fazer um peer review na faixa pra você.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Ila-Lena-rosto_extended_web2-747350.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://www.ricbit.com/uploaded_images/Ila-Lena-rosto_extended_web2-747287.jpg" width="200" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;i&gt;iLena&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Obviamente, a versão original dessa imagem só eu tenho :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-1312191282791960276?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/11/lena-e-ilena.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-6918349246033307426</guid><pubDate>Fri, 06 Nov 2009 02:38:00 +0000</pubDate><atom:updated>2009-11-05T23:46:45.689-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>retro</category><category domain='http://www.blogger.com/atom/ns#'>emulação</category><category domain='http://www.blogger.com/atom/ns#'>história da ciência</category><title>Top 5 emuladores</title><description>Dia desses, um amigo me perguntou se eu conseguiria fazer uma lista com os meus cinco emuladores prediletos. Esse é o tipo de pergunta que, normalmente, é difícil de responder. Eu já escrevi um monte de emuladores, já conversei com inúmeros autores, e era de se esperar que fosse muito díficil criar uma lista assim. Afinal, sempre que você faz um top five, precisa deixar muita coisa bacana de fora, especialmente se você conhece bastante o assunto.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/emuladores-744118.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="236" src="http://www.ricbit.com/uploaded_images/emuladores-744074.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Porém, surpreendentemente, fazer a lista foi fácil! Tem cinco emuladores que se destacam, pela enorme influência que tiveram em tudo que se seguiu. Em ordem cronológica reversa:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;VMware (2001)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/logo_vmware-(1)-779388.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="75" src="http://www.ricbit.com/uploaded_images/logo_vmware-(1)-779375.jpg" width="200" /&gt;&lt;/a&gt;No fim da década de 90, quando se falava em emuladores, imediamente as pessoas pensavam em videogames. O &lt;a href="http://en.wikipedia.org/wiki/VMware"&gt;VMware&lt;/a&gt; trouxe de volta os emuladores ao mundo corporativo. As aplicações são inúmeras: desenvolvedores, por exemplo, podem programar no Linux, e testar a aplicação num Windows emulado. Em datacenters o impacto é ainda maior. Usando a versão ESX, os administradores de datacenter podem usar uma mesma imagem em todos os servidores, mesmo que eles sejam heterogêneos; e dá até pra trocar uma imagem de um servidor para outro enquanto ela está rodando, com downtime mínimo.&lt;br /&gt;&lt;br /&gt;O truque do VMware pra conseguir desempenho é que a &lt;a href="http://en.wikipedia.org/wiki/Platform_virtualization"&gt;virtualização&lt;/a&gt; dele tenta evitar a emulação tanto quanto possível. Em algumas situações, como código rodando em user space, o VMware roda o código diretamente na CPU. Ele só usa emulação nos trechos críticos, como código rodando em kernel space, ou código acessando periféricos que foram virtualizados.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;bleem (1999)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/logo_bleem-732137.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="143" src="http://www.ricbit.com/uploaded_images/logo_bleem-732124.jpg" width="200" /&gt;&lt;/a&gt;Se o VMware mudou a percepção que o povo da época tinha dos emuladores, o &lt;a href="http://en.wikipedia.org/wiki/Bleem!"&gt;bleem&lt;/a&gt; foi igualmente importante, ao mudar a percepção do underground para o mainstream. Até então, emuladores de videogame eram um produto de nicho, conhecidos só por alguns poucos viciados em internet. O bleem, que na época era o melhor emulador de Playstation, levou os emuladores para as lojas. Hoje nós temos um mercado construído em cima da emulação de jogos, como prova o sucesso do Virtual Console no Wii, e quem começou esse mercado foi o bleem.&lt;br /&gt;&lt;br /&gt;Mas pra mim o bleem tem um significado mais especial. Naquela época em que fazíamos emuladores, ninguém tinha muita certeza se nós estávamos dentro da legalidade ou não. Quando o bleem começou a bombar, a Sony processou os criadores do bleem, e depois de uma ferrenha briga judicial, o &lt;a href="http://www.theregister.co.uk/1999/04/12/bleem_beats_sony/"&gt;bleem saiu vitorioso&lt;/a&gt;. Eu passei a dormir mais tranquilo depois disso :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;O emulador de 8080 do Paul Allen (1975)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/logo_altair-756733.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="143" src="http://www.ricbit.com/uploaded_images/logo_altair-756719.jpg" width="200" /&gt;&lt;/a&gt;O Bill Gates sempre foi bom de blefe. Quando ele descobriu que a &lt;a href="http://en.wikipedia.org/wiki/Micro_Instrumentation_and_Telemetry_Systems"&gt;MITS&lt;/a&gt; estava fazendo o &lt;a href="http://en.wikipedia.org/wiki/Altair_8800"&gt;Altair 8800&lt;/a&gt;, ele entrou em contato com os fabricantes para oferecer um interpretador BASIC. Os fabricantes se empolgaram e marcaram uma reunião pra fazer uma demonstração. O problema é que não havia demo, foi tudo um blefe do Bill! Com a reunião marcada, ele e o sócio Paul Allen tiveram que correr pra preparar um demo a tempo. O blefe era tão vazio, que eles nem tinham um Altair pra poder programar.&lt;br /&gt;&lt;br /&gt;Como criar um interpretador para o Altair, sem ter um Altair? A solução que eles encontraram foi a emulação. Enquanto o Bill Gates escrevia o interpretador, o Paul Allen escreveu um emulador de 8080, a CPU usada no Altair. Como eles também não tinham computador pra rodar o emulador, testavam o software deles no &lt;a href="http://en.wikipedia.org/wiki/PDP-10"&gt;PDP-10&lt;/a&gt; da Harvard, a faculdade onde estudavam. No final, eles acabaram a tempo, e criaram a Microsoft para vender aquele interpretador. Poucos emuladores podem ser tão influentes assim :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;IBM System/360 (1964)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/logo_IBM-782193.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="143" src="http://www.ricbit.com/uploaded_images/logo_IBM-782176.jpg" width="200" /&gt;&lt;/a&gt;Tem muitas coisas que são naturais para nós, mas que eram o ápice da inovação no passado. Upgrades, por exemplo. Hoje em dia, se o seu programa está rodando muito lento, você pode comprar um computador mais novo e o programa rodará mais rápido. Mas antigamente isso não era verdade: se você comprasse um computador novo, iria precisar de um software novo também. Não existia portabilidade.&lt;br /&gt;&lt;br /&gt;A IBM mudou isso com o &lt;a href="http://en.wikipedia.org/wiki/IBM_System/360"&gt;IBM System/360&lt;/a&gt;, uma família de computadores projetada com a compatibilidade em mente. Você poderia comprar um System/360 pequeno, e se precisasse de mais processamento, era só comprar um modelo maior, rodando o mesmo software. E se não bastasse isso, a IBM ainda garantia compatibilidade com modelos anteriores ao System/360! O segredo, é claro, era emulação: a IBM criou emuladores de seus sistemas mais antigos e populares. Não por acaso, o System/360 foi o computador mais vendido de sua época.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A máquina universal de Turing (1936)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/uploaded_images/logo_turing-701108.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="143" src="http://www.ricbit.com/uploaded_images/logo_turing-701094.jpg" width="200" /&gt;&lt;/a&gt;No começo do século XX, os matemáticos estavam procurando a solução do &lt;a href="http://en.wikipedia.org/wiki/Entscheidungsproblem"&gt;Entscheidungsproblem&lt;/a&gt;: existe um processo capaz de decidir se uma expressão matemática é verdadeira ou não? Na época ainda não existia o conceito de algoritmo, o Turing teve que partir do zero. Ele construiu um modelo computacional, a &lt;a href="http://en.wikipedia.org/wiki/Turing_machine"&gt;máquina de Turing&lt;/a&gt;, e a usou pra chegar na decepcionante conclusão de que o tal algoritmo de decisão não existe. Por outro lado, ele concluiu que, para todos os algoritmos que existem, também existe uma máquina de Turing capaz de executá-lo (essa é a &lt;a href="http://en.wikipedia.org/wiki/Church-Turing_thesis"&gt;tese de Church-Turing&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Mas o Turing foi além. Baseado no trabalho do &lt;a href="http://en.wikipedia.org/wiki/Kurt_G%C3%B6del"&gt;Gödel&lt;/a&gt;, ele concebeu uma máquina de Turing mais poderosa, que era capaz de rodar qualquer algoritmo que outra máquina de Turing conseguisse. O truque, como vocês devem ter deduzido, é usar emulação. As &lt;a href="http://en.wikipedia.org/wiki/Universal_Turing_machine"&gt;máquinas universais de Turing&lt;/a&gt;&amp;nbsp;não apenas são o modelo matemático que permite a existência de emuladores, como também de toda a computação.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-6918349246033307426?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/11/top-5-emuladores.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-5947193456794483895</guid><pubDate>Tue, 03 Nov 2009 03:34:00 +0000</pubDate><atom:updated>2009-11-12T20:43:00.658-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>fpga</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>hardware</category><category domain='http://www.blogger.com/atom/ns#'>vhdl</category><title>Ataque Cilônio!</title><description>No último post, nós vimos como funciona uma FPGA. Agora é hora de aprender a usá-la na prática, e o melhor jeito é fazendo um pequeno projetinho. Como exemplo de projetinho, eu pensei que poderíamos construir um Cilônio a partir do zero:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/cilonio-782170.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="275" src="http://www.ricbit.com/uploaded_images/cilonio-782165.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Para começar a desenvolver para FPGAs, a primeira coisa de que você precisa é, obviamente, uma FPGA. Se você for o tipo de ninja que consegue soldar &lt;a href="http://en.wikipedia.org/wiki/Surface-mount_technology"&gt;SMD&lt;/a&gt; na mão, pode fazer sua própria placa de desenvolvimento. Eu, como sou inepto com ferro de solda, optei por comprar um kit de desenvolvimento na &lt;a href="http://www.digilentinc.com/"&gt;Digilent&lt;/a&gt;. O kit que escolhi foi o &lt;a href="http://www.digilentinc.com/Products/Detail.cfm?Prod=S3EBOARD"&gt;S3EBOARD&lt;/a&gt;, que tem o menor custo/benefício:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/S3E-top-400-729068.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="280" src="http://www.ricbit.com/uploaded_images/S3E-top-400-729066.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Essa placa custa 150 dólares. Se você comprar do Brasil, somando o frete e impostos, pode ficar meio salgado, mas no final vale a pena. Uma FPGA sozinha não serve pra muita coisa, a coisa só fica divertida quando você a usa pra controlar algum dispositivo. E essa placa da Digilent tem todos os dispositivos que você precisa! Ela tem RAM, conector VGA, PS/2 pra teclado, serial pra mouse, conector Ethernet, DACs pra fazer saída de som, enfim, com ela você pode fazer um computador completo.&lt;br /&gt;&lt;br /&gt;Em especial, no cantinho da placa tem uma série de 8 LEDs. Com isso, já podemos escolher por onde vamos começar a fazer o nosso Cilônio. Já que temos LEDs enfileirados, vamos começar pelo visor!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/cilonio_gif-763473.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/cilonio_gif-763472.gif" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Já temos uma placa com a FPGA, precisamos agora de um compilador para programá-la. Eu uso o &lt;a href="http://www.xilinx.com/tools/webpack.htm"&gt;Xilinx ISE Webpack&lt;/a&gt;, que é free (as in beer), e disponível para Windows e Linux. Compiladores de FPGA são análogos aos compiladores de software, até mesmo na idéia de compilar em etapas. Um compilador típico de C tem estágios de pré-processamento, compilação, otimização e linking. Um compilador para FPGA possui as seguintes etapas:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Síntese&lt;/b&gt;: Tudo começa com a sua descrição do projeto, feita em alguma linguagem de descrição de hardware. Para começar o processo, o compilador traduz essa linguagem para uma representação&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Register_transfer_level"&gt;RTL&lt;/a&gt;, que é basicamente um sistema de equações booleanas. Essas equações são então simplificadas, de modo a eliminar redundâncias e deixar o circuito final mais rápido.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; margin: 0px; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Diagrama-799273.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/Diagrama-799251.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;b&gt;&lt;span style="font-style: italic; font-weight: normal;"&gt;Circuito original, e circuito após otimização&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-style: italic; font-weight: normal;"&gt;&lt;/span&gt;Mapeamento tecnológico&lt;/b&gt;: Mesmo que o otimizador tenha chegado nas equações booleanas mínimas, elas ainda não podem ser usadas na FPGA. Nós sabemos que a FPGA é formada de blocos lógicos (os CLBs), então precisamos de um processo para mapear as equações nos CLBs. Note que a etapa de síntese não depende da arquitetura, mas na etapa de map o compilador precisa saber o modelo exato da FPGA sendo usada, já que cada FPGA tem um tipo de CLB diferente.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Diagrama2-768085.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://www.ricbit.com/uploaded_images/Diagrama2-768056.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Mapeamento tecnológico, cada CLB tem um AND e um OR&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Place and Route&lt;/b&gt;: Depois de feito o mapeamento tecnológico, o compilador sabe &lt;i&gt;quantas&lt;/i&gt; CLBs ele precisa, e &lt;i&gt;como&lt;/i&gt; preencher cada uma delas. Mas ele ainda não escolheu &lt;i&gt;quais&lt;/i&gt; CLBs serão usadas. Apesar das CLBs serem todas iguais, se você utilizar CLBs muito distantes entre si, o tempo que o sinal leva de uma a outra pode influir na velocidade do seu circuito. Na etapa de &lt;a href="http://en.wikipedia.org/wiki/Place_and_route"&gt;place and route&lt;/a&gt;, o compilador escolhe a melhor disposição de CLBs para o seu design.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Diagrama3-731356.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://www.ricbit.com/uploaded_images/Diagrama3-731325.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Antes e depois do place and route&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Geração da bitstream&lt;/b&gt;: Por fim, o compilador gera uma bitstream que é usada pra programar a FPGA, usualmente através de uma interface&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/JTAG"&gt;JTAG&lt;/a&gt;. A partir desse ponto, sua FPGA está programada e pronta pra rodar :)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Diagrama5-772398.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="171" src="http://www.ricbit.com/uploaded_images/Diagrama5-772367.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Agora precisamos escolher a linguagem que vamos usar. O Xilinx Webpack suporta &lt;a href="http://en.wikipedia.org/wiki/VHDL"&gt;VHDL&lt;/a&gt; e &lt;a href="http://en.wikipedia.org/wiki/Verilog"&gt;Verilog&lt;/a&gt;. Escolher uma das duas é como escolher vi ou emacs, existem fãs dos dois lados, mas na prática são quase equivalentes. Em geral, para quem está começando, eu recomendo não pensar muito e escolher aquela que seus amigos usam (assim você tem pra quem perguntar quando tiver dúvidas). Eu acabei escolhendo usar VHDL.&lt;br /&gt;&lt;br /&gt;A origem da linguagem VHDL é curiosa. O departamento de defesa americano fazia muitos contratos de fabricação de chips, mas a documentação que vinha de cada fabricante era diferente. Eles então bolaram um padrão, o VHDL, que no começo era simplesmente um jeito de documentar circuitos. Em um certo ponto, notaram que a documentação era precisa o suficiente pra permitir simulação, e da simulação partiram para a síntese.&lt;br /&gt;&lt;br /&gt;Mas vamos ao nosso projeto. A primeira parte de um design em VHDL, assim como em faríamos em software, são os imports:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/01-728233.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/01-728231.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;O motivo de incluir essas bibliotecas é que sem elas não podemos usar bits em hardware. Bits em software são simples, eles podem ser 0 ou 1. Já em hardware, temos muito mais opções. Além do "0" (pino ligado no GND) e do "1" (pino ligado no Vcc), também temos o "Z" (pino não conectado), "H" (pino ligado no Vcc através de um pull-up), e assim por diante. Em VHDL, bits de hardware são chamados de &lt;a href="http://en.wikipedia.org/wiki/IEEE_1164"&gt;std_logic&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/Diagrama-770646.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="74" src="http://www.ricbit.com/uploaded_images/Diagrama-770627.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Alguns estados do std_logic&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Em seguida nós precisamos definir a entidade que vamos fazer. Uma entidade em VHDL é como uma interface em Java, ela define como seu código interage com o mundo. Em hardware, isso é equivalente a definir quem serão os pinos de entrada e saída do seu design. No nosso projeto, nós precisamos de duas entradas: um clock e um botão de liga-desliga; e oito saídas: uma para cada LED.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/02-799158.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/02-799156.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Agora vamos definir a implementação da interface, que em VHDL é o &lt;i&gt;behaviour&lt;/i&gt;. No nosso projeto, vamos usar um clock de 50MHz, rápido demais para fazer a animação dos LEDs. Precisamos então dividir essa freqüência, pra isso vamos usar um contador que reseta a cada 5 milhões de ciclos. Cada vez que o contador resetar, nós incrementamos um estado da nossa máquina de estados, e, por fim, vamos associar cada estado a uma combinação de LEDs acesos e apagados.&lt;br /&gt;&lt;br /&gt;Se fosse software, precisaríamos de três variáveis pra implementar esse algoritmo. Em hardware, não usamos variáveis, mas sim &lt;a href="http://en.wikipedia.org/wiki/Hardware_register"&gt;registradores&lt;/a&gt;. Uma parte curiosa do VHDL é que você não define os registradores diretamente; ao invés disso, você define os sinais e ele infere quais registradores você precisa. Como você deve imaginar, num projeto grande isso é fonte de inúmeros bugs! Felizmente, nesse projetinho não vamos ter esse problema.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/03-701685.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/03-701685.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Note que ao especificar um registrador, você precisa falar o tamanho dele. Nosso contador de clocks, por exemplo, vai de 0 a 5 milhões, e portanto cabe num registro de 23 bits. Vamos aproveitar e implementar esse contador. A diferença mais importante de hardware e software é que no hardware você tem paralelismo real, não é time-sharing e nem tem limite no número de cores. Em VHDL, cada unidade que roda em paralelo é um processo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/04-721761.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/04-721760.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Na primeira linha de cada processo você define quem são as entradas (nesse caso, o clock e o valor anterior do contador). O primeiro if checa se aconteceu uma mudança no clock que o levou para o estado 1 (ou seja, o código dentro do if só roda em uma &lt;a href="http://en.wikipedia.org/wiki/Clock_edge"&gt;borda de subida&lt;/a&gt;). O resto é como em software, se chegar a 5M, volte a zero, senão incremente.&lt;br /&gt;&lt;br /&gt;O processo seguinte faz o mesmo com o contador do estado atual:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/05-773237.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/05-773237.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;O contador de estado incrementa na borda de subida, mas só quando o contador de clock é zero. Além disso, nós também zeramos o estado quando a chave SW0 está desligada (implementando assim um botão que liga e desliga).&lt;br /&gt;&lt;br /&gt;Agora precisamos associar cada estado a uma combinação de LEDs (o que, em hardware, chamamos de &lt;a href="http://en.wikipedia.org/wiki/Multiplexer"&gt;demultiplexação&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/06-707760.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/06-707760.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Note que além de definir todos os estados possível, ainda temos um else extra. Precisamos sempre lembrar que, em hardware, bits não são apenas 0 ou 1! Se o estado cair em algum dos outros valores, como Z ou H, precisamos do else extra para cuidar dele.&lt;br /&gt;&lt;br /&gt;Por fim, precisamos ligar o demultiplexador nos pinos de saída. Ligações simples de sinais nem precisam de um processo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.ricbit.com/uploaded_images/07-755393.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.ricbit.com/uploaded_images/07-755392.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Agora o VHDL está pronto, mas ainda falta um detalhe para acabar o projeto. O VHDL cuida de tudo que vai acontecer &lt;i&gt;dentro&lt;/i&gt; da FPGA, mas ainda precisamos cuidar do que está &lt;i&gt;fora&lt;/i&gt; dela. Pra isso, precisamos de um constraint file, que vai indicar em quais pinos da FPGA estão ligados nossos periféricos (os LEDs, o clock, etc). Esses valores nós pegamos diretamente do manual do kit da Digilent. Nossos arquivos ficaram assim, então:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/visor.vhd"&gt;Visor cilônio em VHDL&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/visor.ucf"&gt;Visor cilônio (constraint file, no formato UCF)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Com tudo pronto, só precisamos compilar e fazer o upload para a FPGA :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/llEH8lXPSMU&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/llEH8lXPSMU&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Agora temos o visor pronto! Só falta terminar o resto do Cilônio, que fica como exercício para o leitor :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-5947193456794483895?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/11/ataque-cilonio.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>32</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-3102690428216630133</guid><pubDate>Wed, 14 Oct 2009 00:02:00 +0000</pubDate><atom:updated>2009-11-01T15:30:18.108-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>fpga</category><category domain='http://www.blogger.com/atom/ns#'>hardware</category><title>Stallman e o hardware livre</title><description>Hoje em dia, é difícil achar quem trabalhe com computação e não saiba quem é o &lt;a href="http://en.wikipedia.org/wiki/Richard_Stallman"&gt;Richard Stallman&lt;/a&gt;. A primeira vez que vi o nome dele foi lendo os &lt;a href="http://www.google.com/codesearch/p?hl=en&amp;amp;sa=N&amp;amp;cd=1&amp;amp;ct=rc#kzAPNCXfwtc/bison-2.3/src/parse-gram.c&amp;amp;q=parse-gram.c%20richard%20stallman"&gt;sources do bison&lt;/a&gt;, e não demorou muito pra descobrir que ele era o cabeça por trás de vários softwares que eu usava, como o &lt;a href="http://en.wikipedia.org/wiki/GNU_Compiler_Collection"&gt;gcc&lt;/a&gt; e o &lt;a href="http://en.wikipedia.org/wiki/Emacs"&gt;emacs&lt;/a&gt;. E não apenas isso, ele também foi o criador do conceito de &lt;a href="http://en.wikipedia.org/wiki/Free_software"&gt;software livre&lt;/a&gt; e do &lt;a href="http://en.wikipedia.org/wiki/GNU_Project"&gt;projeto GNU&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mas mesmo com todo o seu talento, o Stallman não escapa de ser uma espécie de Michael Jackson da computação. Embora seja inegável que ele é um gênio que influenciou toda uma indústria, também não há como negar que ele não é exatamente um modelo de conduta. Na verdade, conta-se que pessoalmente ele é &lt;a href="http://stulzer.net/blog/2008/03/18/a-terrivel-semana-que-richard-stallman-ficou-na-minha-casa/"&gt;bastante desagradável&lt;/a&gt;, e sua higiene pessoal é de deixar o Cascão com inveja.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/file-754544.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/file-754509.jpg" style="border: 0; cursor: pointer; display: block; height: 313px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Além disso, de vez em quando o Stallman também vacila. Por exemplo, em 1999 perguntaram pra ele se algum dia seria possível ter hardware livre, assim como havia o software livre. Ele respondeu com &lt;a href="http://features.linuxtoday.com/news_story.php3?ltsn=1999-06-22-005-05-NW-LF"&gt;um artigo sobre o assunto&lt;/a&gt;, sendo que em um dado ponto ele escreve que "&lt;i&gt;você não pode baixar hardware pela net, e nós não temos copiadores automáticos para hardware (talvez quando tivermos nanotecnologia)&lt;/i&gt;".  &lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O vacilo do Stallman é que você não precisa de nanotecnologia, desde 1985 já existe uma tecnologia que permite o surgimento do hardware livre: a &lt;a href="http://en.wikipedia.org/wiki/Field-programmable_gate_array"&gt;FPGA&lt;/a&gt;. &lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A FPGA é um chip reprogramável. Ela sai da fábrica vazia, mas você pode reprogramá-la pra virar, por exemplo, uma CPU. Se você mudar de idéia, pode reprogramá-la mais uma vez, e ela vira uma memória. Ou um processador de vídeo, ou um controlador de rede, o que der na telha!&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pra entender como isso é possível, vamos voltar lá pra linha de produção. Chips são feitos em um substrato de silício apelidado de &lt;a href="http://en.wikipedia.org/wiki/Wafer_(electronics)"&gt;bolacha&lt;/a&gt;. O mapa com os circuitos que compõem o chip é impresso sobre a bolacha com um processo químico parecido com a revelação de filmes fotográficos. A parte importante é notar que esse processo é uma espécie de carimbo: você faz centenas de cópias iguais do circuito sobre a bolacha, e, depois de carimbado, não dá mais pra mudar o que foi impresso.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/waffle-736913.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/waffle-736911.jpg" style="cursor: pointer; display: block; height: 300px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Bolacha (wafer)&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mas se o circuito é carimbado e não pode ser mudado, como podemos reprogramar o hardware? Há pelo menos duas maneiras de fazer isso. Para exemplificar, vamos imaginar que queremos implementar uma função booleana qualquer, como a função abaixo:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/circuit1-768298.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/circuit1-768291.jpg" style="border: 0; cursor: pointer; display: block; height: 113px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;S = ((not A and B) or (A and not B)) and C&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Esse é um &lt;a href="http://en.wikipedia.org/wiki/Combinational_logic"&gt;circuito combinatório&lt;/a&gt; simples, então podemos levantar a &lt;a href="http://en.wikipedia.org/wiki/Truth_table"&gt;tabela da verdade&lt;/a&gt; dele:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/tabela-787801.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/tabela-787798.jpg" style="border: 0; cursor: pointer; display: block; height: 200px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 176px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;Agora fica clara qual é a sacada, basta interpretar esse circuito como se fosse uma memória! No caso, a tripla ABC é como se fosse um bus de endereçamento para oito posições de memória, onde cada palavra tem um único bit: a saída S. Memórias reprogramáveis nós sabemos fazer, certo? Nosso circuito reprogramável pode ser implementado como uma simples memória RAM.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A segunda maneira é lembrando que existem portas lógicas que exibem &lt;a href="http://www.allaboutcircuits.com/vol_4/chpt_3/9.html"&gt;universalidade&lt;/a&gt;. Aquela mesma equação booleana pode ser implementada usando apenas portas NAND:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/circuit2-721715.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/circuit2-721712.jpg" style="border: 0; cursor: pointer; display: block; height: 102px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Novamente, a idéia se apresenta. Podemos carimbar na bolacha um monte de portas NAND, e, para reprogramar basta mudar a conexão entre elas (por exemplo, usando uma RAM que funcionaria como se fosse um array de ponteiros).&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As FPGAs utilizam uma mescla dos dois métodos. Elas são formadas de uma série de elementos repetidos, chamados CLB (configurable logic block). No modelo que eu uso em casa, cada CLB é formado de quatro slices, e esse aqui é o conteúdo de um terço de cada slice:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/slice-781549.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/slice-781543.png" style="border: 0; cursor: pointer; display: block; height: 212px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Parte de um slice da Spartan 3E&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Os slices são levemente mais complicados que uma porta NAND, mas isso permite que você consiga aproveitar melhor a arquitetura. Às vezes, dá pra colocar um bom pedaço de lógica em um único slice. Além disso, se você prestar atenção no slice, tem um bloco chamado LUT (look-up table), que é essencialmente aquela RAMzinha do primeiro método.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Para completar, no canto direito tem um &lt;a href="http://en.wikipedia.org/wiki/Flip-flop_(electronics)"&gt;flip-flop&lt;/a&gt; tipo D. Até agora, estávamos falando apenas de circuitos combinatórios, mas FPGAs podem usar esses flip-flops para fazer &lt;a href="http://en.wikipedia.org/wiki/Sequential_logic"&gt;circuitos sequenciais&lt;/a&gt; também. Alguns modelos de FPGA vão além, e possuem até mesmo &lt;a href="http://en.wikipedia.org/wiki/Digital-to-analog_converter"&gt;DACs&lt;/a&gt; e &lt;a href="http://en.wikipedia.org/wiki/Phase-locked_loop"&gt;PLLs&lt;/a&gt; que podem ser usados para sintetizar circuitos analógicos.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.ricbit.com/uploaded_images/file-757409.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"&gt;&lt;img alt="" border="0" src="http://www.ricbit.com/uploaded_images/file-757403.jpg" style="border: 0; cursor: pointer; float: right; height: 200px; margin-bottom: 10px; margin-left: 10px; margin-right: 0px; margin-top: 0px; width: 182px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;A FPGA também tem uma outra vantagem, que pra mim é fundamental. Embora eu adore eletrônica, sou muito ruim para soldar componentes (nunca aprendi como fazer isso tendo só dois braços). Mas as FPGAs não são programadas com soldas, ao invés disso, elas são &lt;a href="http://en.wikipedia.org/wiki/Hardware_description_language"&gt;programadas com descrições em texto&lt;/a&gt;, muito parecidas com as linguagens de programação. Após finalizar a descrição, que é uma espécie de código-fonte do hardware, você usa um compilador e faz upload para a placa, sem precisar de estanho e nem de ferro de solda.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;E melhor, essas descrições em texto podem ser compartilhadas como qualquer arquivo texto. Aplique nelas uma licença apropriada, e temos então o hardware livre que queríamos! Hoje em dia, existem até repositórios de hardware livre, como o &lt;a href="http://opencores.com/projects"&gt;Open Cores&lt;/a&gt;, de onde você pode baixar de tudo, desde clones do Z80 até aceleradores de H264.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Se você ainda não conhecia FPGAs, deve estar bem curioso pra saber como você pode brincar com isso. No próximo post eu vou fazer um pequeno tutorial de como criar um circuito do zero, então fique ligado no blog :)&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-3102690428216630133?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/07/stallman-e-o-hardware-livre.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>18</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-6619825040542849187</guid><pubDate>Sat, 04 Jul 2009 19:17:00 +0000</pubDate><atom:updated>2009-07-04T20:34:31.612-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>história da ciência</category><title>A cidade da ciência</title><description>Leitores atentos devem ter notado que o intervalo entre os dois últimos posts foi maior que o normal. Mas foi por um bom motivo: eu estava casando! Foi uma correria; entre cartórios, mudança e lua de mel, nem eu tive tempo de escrever, e nem minha esposa de desenhar as ilustrações. Mas valeu a pena, é claro :)&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/correria-788932.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/correria-788910.jpg" alt="" style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 187px;" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Para começar a lua de mel, nenhuma cidade poderia ser tão apropriada como Paris. Para o casal, Paris é a cidade dos amantes. Para a minha esposa, Paris é a cidade dos artistas. Mas para mim, Paris é especial por ser a cidade da ciência.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;De fato, desde a revolução francesa, os parisienses se orgulham em manter os ideais do &lt;a href="http://en.wikipedia.org/wiki/Age_of_Enlightenment"&gt;Iluminismo&lt;/a&gt; (sendo essa uma das possíveis origens de um famoso epíteto de Paris: a cidade-luz). O &lt;a href="http://en.wikipedia.org/wiki/La%C3%AFcit%C3%A9"&gt;laicismo&lt;/a&gt; é presente logo no primeiro item da constituição francesa, e a cultura científica permeia a cidade até nos nomes das ruas (você pode morar na &lt;a href="http://maps.google.com.br/maps/ms?ie=UTF8&amp;amp;split=0&amp;amp;gl=br&amp;amp;ei=DcpGSsGGEtCEtwfisrCMCg&amp;amp;hl=pt-BR&amp;amp;t=h&amp;amp;msa=0&amp;amp;msid=108977304071474234392.00046d5eb3a1f33e9afd9&amp;amp;ll=48.870657,2.298524&amp;amp;spn=0.010981,0.021865&amp;amp;z=16"&gt;esquina da Rua Kepler com a Rua Galileu&lt;/a&gt;, pertinho da Rua Newton e da Rua Euler). E isso sem contar que a cidade possui um enorme museu de ciências, o &lt;a href="http://www.cite-sciences.fr/english/index.php"&gt;Citè des Sciences et de l'Industrie&lt;/a&gt;.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mas o principal motivo mesmo para eu considerar Paris como a cidade da ciência data de 1889, ano em que foi terminado o maior monumento à ciência já construído: a Torre Eiffel!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TijAN4NNGkA/SkcGVKLFM9I/AAAAAAAAllA/mmG9cPIng20/s1600-h/torre+eiffel+%282%29.jpg"&gt;&lt;img src="http://3.bp.blogspot.com/_TijAN4NNGkA/SkcGVKLFM9I/AAAAAAAAllA/mmG9cPIng20/s400/torre+eiffel+%282%29.jpg" alt="" id="BLOGGER_PHOTO_ID_5352253642730976210" style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 324px; height: 400px;" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;A Torre Eiffel foi construída para a Exposição Universal que comemorava o centenário da Revolução Francesa, e ela era uma celebração ao triunfo da tecnologia: em sua época, era o mais alto monumento criado pelo homem; e permaneceu assim por 40 anos, até ser desbancada pelo Chrysler Building.&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;A torre também era o estado da arte da engenharia do século XIX. O seu criador, Gustave Eiffel, usou em seu projeto métodos geométricos para minimizar o efeito do vento, e &lt;a href="http://www.sciencedaily.com/releases/2005/01/050106111209.htm"&gt;só recentemente&lt;/a&gt; conseguiram resolver de forma analítica a equação que define a curva de seu perfil, uma exponencial. A solução geométrica de Eiffel era tão precisa, que mesmo sob ventos fortes, o topo da torre desloca apenas 13cm (como comparação, é menos do que o topo desloca por dilatação: se o sol bate de um lado da torre enquanto o outro está na sombra, a torre desloca 18cm).&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Mas das homenagens à ciência na torre, a minha preferida é uma mais sutil, que muitos daqueles que a visitam passam sem perceber. Logo abaixo do primeiro andar, estão gravados em relevo os nomes de 72 cientistas franceses:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TijAN4NNGkA/SkgQuanz0BI/AAAAAAAAln8/8hS7Xm7iSEo/s1600-h/400px-Eiffel_names_highlight.jpg"&gt;&lt;img src="http://3.bp.blogspot.com/_TijAN4NNGkA/SkgQuanz0BI/AAAAAAAAln8/8hS7Xm7iSEo/s400/400px-Eiffel_names_highlight.jpg" alt="" id="BLOGGER_PHOTO_ID_5352546546736156690" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 399px; height: 267px;" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Poinsot, Foucault, Delaunay&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Na primeira vez que vi, reconheci de imediato vários nomes, como Lavoisier, Ampère, Laplace. Mas muitos outros eu não identifiquei, e resolvi matar a curiosidade online. Qual não foi a minha surpresa ao descobrir que alguns eram tão obscuros que &lt;a href="http://en.wikipedia.org/wiki/The_72_names_on_the_Eiffel_Tower"&gt;nem a wikipedia&lt;/a&gt; os conhecia!&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Sendo assim, resolvi arregaçar as mangas e procurar quem eram os 72 cientistas homenageados pelo Eiffel. Abaixo, a lista completa de cientistas e alguns de seus feitos, separados pelo lado da torre em que aparecem:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt; &lt;/i&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TijAN4NNGkA/Sk-iYoy_AhI/AAAAAAAAmPg/EY3xC7KuIMI/s1600-h/trocadero.jpg"&gt;&lt;img src="http://3.bp.blogspot.com/_TijAN4NNGkA/Sk-iYoy_AhI/AAAAAAAAmPg/EY3xC7KuIMI/s400/trocadero.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5354677026118631954" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 131px; " /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Lado do Trocadero&lt;/i&gt;&lt;/div&gt; &lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Seguin&lt;/b&gt;: Inventor da &lt;a href="http://en.wikipedia.org/wiki/Suspension_bridge"&gt;ponte pênsil&lt;/a&gt; moderna.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Lalande&lt;/b&gt;: Astrônomo que nomeou a &lt;a href="http://en.wikipedia.org/wiki/Felis_%28constellation%29"&gt;constelação do Gato&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Tresca&lt;/b&gt;: Criou a primeira barra de platina que serviu de referência de comprimento do &lt;a href="http://en.wikipedia.org/wiki/Metric_system"&gt;sistema métrico&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Poncelet&lt;/b&gt;: Co-autor do &lt;a href="http://en.wikipedia.org/wiki/Poncelet-Steiner_theorem"&gt;teorema de Poncelet-Steiner&lt;/a&gt; da geometria.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Bresse&lt;/b&gt;: Pioneiro dos &lt;a href="http://www.infibeam.com/Books/info/Jacques-Antoine-Charles-Bresse/Water-Wheels-or-Hydraulic-Motors/1410207110.html"&gt;motores hidráulicos&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Lagrange&lt;/b&gt;: Responsável pelo &lt;a href="http://en.wikipedia.org/wiki/Lagrangian"&gt;Lagrangiano&lt;/a&gt; da física, pelos &lt;a href="http://en.wikipedia.org/wiki/Lagrangian_point"&gt;Pontos Lagragianos&lt;/a&gt; da astronomia e pelos &lt;a href="http://en.wikipedia.org/wiki/Lagrange_polynomial"&gt;polinômios de Lagrange&lt;/a&gt; da álgebra.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Bélanger&lt;/b&gt;: Criador da &lt;a href="http://en.wikipedia.org/wiki/Hydraulic_jump"&gt;equação de Bélanger&lt;/a&gt; para o ressalto hidráulico.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Cuvier&lt;/b&gt;: Paleontólogo, foi o primeiro a provar que elefantes indianos, africanos e mamutes &lt;a href="http://en.wikipedia.org/wiki/Georges_Cuvier"&gt;são espécies diferentes&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Laplace&lt;/b&gt;: Criador das &lt;a href="http://en.wikipedia.org/wiki/Laplace_transform"&gt;transformadas de Laplace&lt;/a&gt; usadas no cálculo de transientes elétricos.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Dulong&lt;/b&gt;: Co-autor da &lt;a href="http://en.wikipedia.org/wiki/Law_of_Dulong_and_Petit"&gt;lei de Dulong-Petit&lt;/a&gt; da termodinâmica.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Chasles&lt;/b&gt;: Autor dos &lt;a href="http://en.wikipedia.org/wiki/Chasles%27_theorem"&gt;teoremas de Chasles&lt;/a&gt; em geometria e física.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Lavoisier&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Law_of_conservation_of_mass"&gt;lei da conservação da massa&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Ampère&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Amp%C3%A8re%27s_circuital_law"&gt;lei de Ampère&lt;/a&gt; do eletromagnetismo.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Chevreul&lt;/b&gt;: Inventor da &lt;a href="http://en.wikipedia.org/wiki/Margarine"&gt;margarina&lt;/a&gt;, afinal, culinária é química aplicada.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Flachat&lt;/b&gt;: Engenheiro responsável pelo terminal de &lt;a href="http://en.wikipedia.org/wiki/Gare_Saint-Lazare"&gt;Gare Saint-Lazare&lt;/a&gt;, em Paris.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Navier&lt;/b&gt;: Co-autor das &lt;a href="http://en.wikipedia.org/wiki/Navier-Stokes_equations"&gt;equações de Navier-Stokes&lt;/a&gt; da mecânica dos fluidos.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Legendre&lt;/b&gt;: Criador do &lt;a href="http://en.wikipedia.org/wiki/Legendre_symbol"&gt;símbolo de Legendre&lt;/a&gt; usado na teoria dos números.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Chaptal&lt;/b&gt;: Criador da &lt;a href="http://www.diariodovinho.com/2009/03/chaptalizacao-o-milagre-do-alcool-favor.html"&gt;chaptalização&lt;/a&gt;, técnica para aumentar o teor alcóolico do vinho.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt; &lt;/i&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_TijAN4NNGkA/Sk-iK201EQI/AAAAAAAAmPY/J9RtKOon15o/s1600-h/rio.jpg"&gt;&lt;img src="http://2.bp.blogspot.com/_TijAN4NNGkA/Sk-iK201EQI/AAAAAAAAmPY/J9RtKOon15o/s400/rio.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5354676789366296834" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 131px; " /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Lado da ponte de Grenelle&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Jamin&lt;/b&gt;: Criador do &lt;a href="http://en.wikipedia.org/wiki/Jamin_interferometer"&gt;interferômetro de Jamin&lt;/a&gt; usado na análise de gases.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Gay-Lussac&lt;/b&gt;: Autor das &lt;a href="http://en.wikipedia.org/wiki/Gay-Lussac's_law"&gt;leis de Gay-Lussac&lt;/a&gt; da termodinâmica.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Fizeau&lt;/b&gt;: Criou o primeiro aparato capaz de &lt;a href="http://en.wikipedia.org/wiki/Fizeau-Foucault_apparatus"&gt;medir a velocidade da luz&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Schneider&lt;/b&gt;: Construiu a &lt;a href="http://www.britannica.com/EBchecked/topic/527844/Eugene-Schneider"&gt;primeira locomotiva a vapor&lt;/a&gt; da França.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Le Chatelier&lt;/b&gt;: Autor do &lt;a href="http://pt.wikipedia.org/wiki/Princ%C3%ADpio_de_Le_Ch%C3%A2telier"&gt;princípio de Le Chatelier&lt;/a&gt; nas reações químicas em equilíbrio.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Berthier&lt;/b&gt;: Descobridor da &lt;a href="http://en.wikipedia.org/wiki/Bauxite"&gt;bauxita&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Barral&lt;/b&gt;: Pioneiro na extração da &lt;a href="http://en.wikipedia.org/wiki/Nicotine"&gt;nicotina&lt;/a&gt; a partir da folha de tabaco.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;De Dion&lt;/b&gt;: Criador do primeiro &lt;a href="http://fr.wikipedia.org/wiki/Hangar_Y"&gt;hangar para dirigíveis&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Goüin&lt;/b&gt;: Introduziu as pontes de &lt;a href="http://pt.wikipedia.org/wiki/Rebite"&gt;chapas rebitadas&lt;/a&gt; na França.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Jousselin&lt;/b&gt;: Projetista do &lt;a href="http://fr.wikipedia.org/wiki/Canal_lat%C3%A9ral_%C3%A0_la_Loire"&gt;canal do rio Loire&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Broca&lt;/b&gt;: Anatomista que estudou a &lt;a href="http://en.wikipedia.org/wiki/Broca's_area"&gt;região de Broca&lt;/a&gt; no cérebro humano.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Becquerel&lt;/b&gt;: Ganhador do Nobel como descobridor da &lt;a href="http://en.wikipedia.org/wiki/Radioactivity"&gt;radiatividade&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Coriolis&lt;/b&gt;: Descobridor do &lt;a href="http://en.wikipedia.org/wiki/Coriolis_force"&gt;efeito Coriolis&lt;/a&gt; em rotações.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Cail&lt;/b&gt;: Engenheiro responsável pelo impressionante &lt;a href="http://en.wikipedia.org/wiki/Fades_viaduct"&gt;viaduto de Fades&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Triger&lt;/b&gt;: Criador do &lt;a href="http://dictionary.reference.com/browse/triger+process?qsrc=2446"&gt;processo de Triger&lt;/a&gt; para cavar fundações de pontes.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Giffard&lt;/b&gt;: Inventor do primeiro &lt;a href="http://en.wikipedia.org/wiki/Airship"&gt;dirigível a vapor&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Perrier&lt;/b&gt;: Um dos primeiros a fotografar o &lt;a href="http://pt.wikipedia.org/wiki/Tr%C3%A2nsito_de_V%C3%AAnus"&gt;trânsito de Vênus&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Sturm&lt;/b&gt;: Conhecido pelas &lt;a href="http://mathworld.wolfram.com/SturmFunction.html"&gt;funções de Sturm&lt;/a&gt; da álgebra.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt; &lt;/i&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_TijAN4NNGkA/Sk-ip7K9AeI/AAAAAAAAmPo/_OedJYKkLSs/s1600-h/campo+de+marte.jpg"&gt;&lt;img src="http://2.bp.blogspot.com/_TijAN4NNGkA/Sk-ip7K9AeI/AAAAAAAAmPo/_OedJYKkLSs/s400/campo+de+marte.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5354677323108778466" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 131px; " /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Lado do Campo de Marte&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Cauchy&lt;/b&gt;: Co-autor da &lt;a href="http://en.wikipedia.org/wiki/Cauchy%E2%80%93Schwarz_inequality"&gt;desigualdade de Cauchy-Schwarz&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Belgrand&lt;/b&gt;: Projetista do &lt;a href="http://en.wikipedia.org/wiki/Sanitary_sewer"&gt;sistema de esgotos&lt;/a&gt; de Paris.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Regnault&lt;/b&gt;: Estudioso dos gases, em sua homenagem a &lt;a href="http://en.wikipedia.org/wiki/Ideal_gas_constant"&gt;constante dos gases ideais&lt;/a&gt; recebeu a letra R.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Fresnel&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Fresnel_equations"&gt;lei de Fresnel&lt;/a&gt; para refração de ondas.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;De Prony&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Prony_equation"&gt;equação de Prony&lt;/a&gt; para perda de carga hidráulica.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Vicat&lt;/b&gt;: Inventor do &lt;a href="http://en.wikipedia.org/wiki/Cement"&gt;cimento&lt;/a&gt; moderno.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Ebelmen&lt;/b&gt;: Descobridor do &lt;a href="http://en.wikipedia.org/wiki/Carbon_cycle"&gt;ciclo geoquímico do carbono&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Coulomb&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Coulomb's_law"&gt;lei de Coulomb&lt;/a&gt; para cargas elétricas.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Poinsot&lt;/b&gt;: Inventor do &lt;a href="http://en.wikipedia.org/wiki/Poinsot's_construction"&gt;elipsóide de Poinsot&lt;/a&gt; na mecânica de corpo rígido.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Foucault&lt;/b&gt;: Descobridor das &lt;a href="http://en.wikipedia.org/wiki/Eddy_current"&gt;correntes de Foucault&lt;/a&gt; do eletromagnetismo.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Delaunay&lt;/b&gt;: Estudou o &lt;a href="http://en.wikipedia.org/wiki/Earth-Moon-Sun_system"&gt;problema dos três corpos&lt;/a&gt; aplicado ao sistema Sol-Terra-Lua.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Morin&lt;/b&gt;: Modelou a &lt;a href="http://pt.wikipedia.org/wiki/Atrito"&gt;força de atrito estático&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Haüy&lt;/b&gt;: Autor da &lt;a href="http://www.minsocam.org/msa/collectors_corner/arc/hauyviii.htm"&gt;lei de Haüy&lt;/a&gt; da cristalografia.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Combes&lt;/b&gt;: Estudioso do problema da &lt;a href="http://en.wikipedia.org/wiki/Underground_mine_ventilation"&gt;ventilação em minas&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Thénard&lt;/b&gt;: Descobridor da &lt;a href="http://en.wikipedia.org/wiki/Hydrogen_peroxide"&gt;água oxigenada&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Arago&lt;/b&gt;: Realizou o &lt;a href="http://www.metacafe.com/watch/1394811/bend_light_around_coin_arago_spot/"&gt;experimento de Arago&lt;/a&gt;, que comprova a natureza ondulatória da luz.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Poisson&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Poisson_distribution"&gt;distribuição de Poisson&lt;/a&gt; na estatística.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Monge&lt;/b&gt;: Autor do &lt;a href="http://en.wikipedia.org/wiki/Monge's_theorem"&gt;teorema de Monge&lt;/a&gt; da geometria. &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt; &lt;/i&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_TijAN4NNGkA/Sk-i-ws2yqI/AAAAAAAAmPw/HgVZ6X0ZzaM/s1600-h/rio2.jpg"&gt;&lt;img src="http://3.bp.blogspot.com/_TijAN4NNGkA/Sk-i-ws2yqI/AAAAAAAAmPw/HgVZ6X0ZzaM/s400/rio2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5354677681075440290" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 131px; " /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Lado da Sacre Coeur&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Petiet&lt;/b&gt;: Criador de &lt;a href="http://www.dself.dsl.pipex.com/MUSEUM/LOCOLOCO/petiet/frexp.htm"&gt;locomotivas&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Daguerre&lt;/b&gt;: Inventor do &lt;a href="http://en.wikipedia.org/wiki/Daguerreotype"&gt;daguerreótipo&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Wurtz&lt;/b&gt;: Criador da &lt;a href="http://en.wikipedia.org/wiki/Wurtz_reaction"&gt;reação de Wurtz&lt;/a&gt; da química.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Le Verrier&lt;/b&gt;: Um dos descobridores do &lt;a href="http://en.wikipedia.org/wiki/Discovery_of_Neptune"&gt;planeta Netuno&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Perdonnet&lt;/b&gt;: Construiu as &lt;a href="http://books.google.com.br/books?id=6gwDAAAAYAAJ&amp;amp;pg=RA1-PA154&amp;amp;lpg=RA1-PA154&amp;amp;dq=Albert+Auguste+Perdonnet&amp;amp;source=bl&amp;amp;ots=q36CpcqSyW&amp;amp;sig=cofLUTrsCrjX77EkkE5UwOD75Vs&amp;amp;hl=pt-BR&amp;amp;ei=mqFOSo_XI9OetgfY58iqBA&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;ct=result&amp;amp;resnum=3"&gt;primeiras ferrovias da França&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Delambre&lt;/b&gt;: Mediu o comprimento de um meridiano, definindo assim &lt;a href="http://en.wikipedia.org/wiki/Metre"&gt;o metro&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Malus&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Malus'_law"&gt;lei de Malus&lt;/a&gt; na polarização da luz.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Breguet&lt;/b&gt;: Inventor do &lt;a href="http://museu.fis.uc.pt/145.htm"&gt;telégrafo de Breguet&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Polonceau&lt;/b&gt;: Criador da estrutura conhecida como &lt;a href="http://www.istructe.org/Filesystem/getfile.asp?SubDir=History%20of%20Structural%20Engineering%20Study%20Group%5C2008%20-%202009%20Meeting%20Notices%5C&amp;amp;FName=Flyer%20-%20Joint%20Meeting%20on%208%20April%20-%20Polonceau%20roof%20and%20its%20analysis.pdf&amp;amp;CID=207"&gt;teto de Polonceau&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Dumas&lt;/b&gt;: Descobriu que o &lt;a href="http://en.wikipedia.org/wiki/Kidney"&gt;rim remove uréia do sangue&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Clapeyron&lt;/b&gt;: Autor da &lt;a href="http://en.wikipedia.org/wiki/Clausius-Clapeyron_relation"&gt;equação de Clapeyron&lt;/a&gt; para transição de fase da matéria.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Borda&lt;/b&gt;: Criador do sistema de &lt;a href="http://en.wikipedia.org/wiki/Borda_count"&gt;votação de Borda&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Fourier&lt;/b&gt;: Inventor das &lt;a href="http://en.wikipedia.org/wiki/Fourier_series"&gt;séries de Fourier&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Bichat&lt;/b&gt;: Pai da histologia, o primeiro a reconhecer que &lt;a href="http://en.wikipedia.org/wiki/Biological_tissue"&gt;órgãos são feitos de tecidos&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Sauvage&lt;/b&gt;: Criou os primeiros &lt;a href="http://en.wikipedia.org/wiki/Geologic_map"&gt;mapas geológicos&lt;/a&gt; da França.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Pelouze&lt;/b&gt;: Primeiro a calcular a &lt;a href="http://pt.wikipedia.org/wiki/Ars%C3%AAnio"&gt;massa atômica do Arsênio&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Carnot&lt;/b&gt;: Autor do &lt;a href="http://en.wikipedia.org/wiki/Carnot's_theorem"&gt;teorema de Carnot&lt;/a&gt; da geometria.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Lamé&lt;/b&gt;: Criador da análise por &lt;a href="http://en.wikipedia.org/wiki/Lam%C3%A9_function"&gt;harmônicas elípticas&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;A lista é bem heterogênea. Ela parte de alicerces da ciência como Lagrange e Laplace, e passa por heróis locais que devem ser uma espécie de &lt;a href="http://pt.wikipedia.org/wiki/Santos_Dumont"&gt;Santos-Dumont&lt;/a&gt; à francesa: famosos em seu país, mas nem tanto longe dele. Por fim, há os realmente obscuros. Desse último grupo, eu notei que todos deram aula na &lt;a href="http://en.wikipedia.org/wiki/%C3%89cole_polytechnique"&gt;École Polytechnique&lt;/a&gt;, o que indica que o Eiffel deve ter colocado esses nomes para &lt;strike&gt;puxar o saco&lt;/strike&gt; fazer uma homenagem a seus professores.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;Visitar a torre Eiffel é uma experiência incrível, mas não foi a melhor parte da lua de mel. Uma descrição da melhor parte da lua de mel fugiria do escopo desse blog :)&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt; &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_TijAN4NNGkA/Sk-oyDgHhWI/AAAAAAAAmP4/Q0NCrlrc3Lo/s1600-h/Paris_casal.JPG"&gt;&lt;img src="http://1.bp.blogspot.com/_TijAN4NNGkA/Sk-oyDgHhWI/AAAAAAAAmP4/Q0NCrlrc3Lo/s400/Paris_casal.JPG" border="0" alt="" id="BLOGGER_PHOTO_ID_5354684059853751650" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 400px; height: 308px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-6619825040542849187?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/07/cidade-da-ciencia.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_TijAN4NNGkA/SkcGVKLFM9I/AAAAAAAAllA/mmG9cPIng20/s72-c/torre+eiffel+%282%29.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>17</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-1542785324065742865</guid><pubDate>Mon, 22 Jun 2009 14:21:00 +0000</pubDate><atom:updated>2009-06-22T12:16:12.107-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>óptica</category><category domain='http://www.blogger.com/atom/ns#'>ciências cognitivas</category><category domain='http://www.blogger.com/atom/ns#'>cores</category><title>As batalhas do magenta</title><description>&lt;div style="text-align: left;"&gt;Convencer as pessoas de que o magenta existe foi uma batalha, mas certamente não a única batalha pela qual a cor passou. O magenta é uma cor mais sofrida que o &lt;a href="http://www.scribd.com/doc/7320400/Ziraldo-FlictsIlustrado"&gt;flicts&lt;/a&gt;; na verdade a própria origem do magenta foi em uma batalha!&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/magenta-795298.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/magenta-795295.jpg" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 237px; border: 0" /&gt;&lt;/a&gt;&lt;div&gt;Originalmente, a cor #FF00FF era chamada de fúcsia, em homenagem a &lt;a href="http://en.wikipedia.org/wiki/Fuchsia"&gt;uma singela florzinha&lt;/a&gt; que tem essa cor. Mas em 1859 houve &lt;a href="http://en.wikipedia.org/wiki/Battle_of_Magenta"&gt;uma sangrenta batalha&lt;/a&gt; entre franceses e austríacos, tão intensa que pintou o chão de sangue. Essa batalha aconteceu na cidade italiana de Magenta, e desde então aquele tom da cor de sangue ficou conhecido como magenta.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A batalha mais recente do magenta é contra outra injustiça cometida pelo povo que não conhece física. Dessa vez a abobrinha veio de um designer coreano, que bolou uma &lt;a href="http://www.tuvie.com/color-picker-by-jinsun-park"&gt;caneta-scanner especial para desenhistas&lt;/a&gt;. Se você quiser pintar uma maçã com a aparência similar a uma maçã real, basta usar a ponta-scanner da caneta para capturar o tom RGB exato da fruta, e na outra ponta a caneta mistura as proporções exatas de tintas (vermelhas, verdes e azuis) que reproduzem aquele tom. A idéia da caneta até é legal, mas do jeito que foi bolada, não funciona.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/color-picker4-741667.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/color-picker4-741665.jpg" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 312px; height: 400px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;O problema da caneta, é claro, são as tintas. Para entender por que elas são um problema, precisamos relembrar a definição de cor do Kandel: "Cor é uma experiência subjetiva relacionada à composição espectral da luz que atinge o olho". Ou seja, segundo essa definição, a única coisa que pode ter cor é luz. Como tinta não é luz, logo tinta não pode ter cor.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;A maneira correta de caracterizar uma tinta é através da sua &lt;a href="http://en.wikipedia.org/wiki/Reflectance"&gt;refletância&lt;/a&gt;, ou seja, a relação entre luz absorvida e refletida para um dado comprimento de onda. A cor da tinta não depende apenas de suas características intrínsecas, mas também da luz que incide sobre ela.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Você pode fazer um experimento simples para verificar isso. Primeiro pegue dois pedaços de pano, branco e vermelho, e um lightsaber bicolor, azul e vermelho (se você não tem um lightsaber bicolor, eis uma boa desculpa pra comprar um!). Veja agora como a cor do tecido depende da luz incidente:&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/ok-Ssombra-754812.JPG"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/ok-Ssombra-754460.JPG" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 240px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Luz ambiente (branca)&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/red-787955.JPG"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/red-787508.JPG" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 240px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Luz vermelha&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/blue-786403.JPG"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/blue-786034.JPG" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 240px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Luz azul&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Agora dá pra ver claramente: o tecido "branco" na verdade reflete toda a luz que chega, então ele só é branco quando a luz é branca. Se a luz for vermelha, o tecido fica vermelho, se a luz for azul, o tecido fica azul.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Já o tecido "vermelho", na verdade, absorve todos os comprimentos de onda, menos o vermelho. Tanto faz se a luz é branca ou vermelha, o resultado é o mesmo: só o vermelho é refletido. Já quando a luz é azul, sem componente vermelho nenhum, o resultado é que ele fica com aparência praticamente preta, pois não tem nada pra refletir. O diagrama abaixo mostra o que aconteceu:&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/grafico-758062.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/grafico-758060.jpg" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 245px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Agora fica claro porque a escolha de cores do designer coreano é falha. As tintas que ele escolheu (vermelho, verde e azul) não podem ser misturadas! Vejamos: uma tinta vermelha, na verdade, absorve o verde e azul, refletindo só o vermelho. Uma tinta verde, na verdade, absorve o vermelho e o azul, refletindo só o verde. Se você misturar o vermelho com o verde, a tinta resultante vai absorver o vermelho, o azul e o verde, ou seja, não vai refletir nada. Uma mistura de tintas vermelhas e verdes, em proporções iguais, dá uma tinta preta.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Quem já trocou cartuchos de impressora jato de tinta sabe qual a solução para esse problema. Basta escolher outras cores: amarelo, ciano... e magenta! Essas sim são tintas que podem ser misturadas. Confira: uma tinta magenta, na verdade, absorve o verde. Uma tinta ciano, na verdade, absorve o vermelho. Se você misturar magenta com ciano, o resultado absorve o verde e o vermelho, ou seja, só sobra azul. Tinta magenta com tinta ciano dá tinta azul.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/cores-759041.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/cores-759034.jpg" border="0" alt="" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 167px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Essas tríades de cores são chamadas de &lt;a href="http://en.wikipedia.org/wiki/Primary_color"&gt;cores primárias&lt;/a&gt;. Vermelho, verde e azul são as cores primárias aditivas, aquelas que você usa com emissores de luz, como lâmpadas e LEDs. Ciano, magenta e amarelo são as cores primárias subtrativas, aquelas que você usa com tintas.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/Professora-724502.jpg"&gt;&lt;img src="http://www.ricbit.com/uploaded_images/Professora-724491.jpg" border="0" alt="" style="float: right; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 10px; cursor: pointer; width: 200px; height: 193px; " /&gt;&lt;/a&gt;&lt;div style="text-align: left;"&gt;Por fim, isso nos leva a mais uma batalha do magenta. &lt;i&gt;"Peraí, minha professora na escolinha disse que as cores primárias são vermelho, azul e amarelo"&lt;/i&gt;! Hum, foi mal, mas a sua professora te ensinou errado (deve ter sido a mesma professora que ensinava que se a órbita da Terra era elíptica, então o inverno é quando a Terra está mais longe do Sol). Ela não sabia diferenciar magenta de vermelho, nem ciano de azul.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Uma dúvida mais sutil é &lt;i&gt;"Ah, mas eu misturava vermelho, azul e amarelo, e conseguia fazer todas as cores"&lt;/i&gt;! Sim, sim, essas cores formam uma base no espaço das cores subtrativas, o problema é que não é uma base ortogonal. Se você fizesse uma impressora com essas cores, um dos tubinhos de tinta iria acabar mais rápido. Por isso também que impressoras tem um quarto tubo com tinta preta: para escurecer um tom é mais barato adicionar preto que misturar tinta dos três outros tubos.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Conclusão da história toda: não subestime o magenta! Apesar de ser sistematicamente ignorada, é uma cor com muitas utilidades :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-1542785324065742865?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/06/as-batalhas-do-magenta.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>17</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-5368577896187957115</guid><pubDate>Wed, 04 Mar 2009 01:00:00 +0000</pubDate><atom:updated>2009-03-03T11:40:05.766-02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>javascript</category><category domain='http://www.blogger.com/atom/ns#'>java</category><category domain='http://www.blogger.com/atom/ns#'>gwt</category><category domain='http://www.blogger.com/atom/ns#'>msx</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>ciências cognitivas</category><category domain='http://www.blogger.com/atom/ns#'>cores</category><title>O olhar do macaco</title><description>RicBit e um povo da Engenharia vão até o prédio da psicologia se encontrar com um biólogo europeu. Por trás dessa aglomeração interdisciplinar, uma tese sobre a origem da humanidade, baseada na análise do olhar dos macacos. E tudo isso culminando com a conclusão do dilema: afinal, magenta é ou não uma cor? Suspense, emoção e integrais os aguardam no resto desse post!&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/barney-795544.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 160px;" src="http://www.ricbit.com/uploaded_images/barney-795542.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;No post anterior eu expliquei o que era o magenta, então agora é hora de ver o que é uma cor. O &lt;a href="http://en.wikipedia.org/wiki/Eric_Kandel"&gt;Kandel&lt;/a&gt; diz que cor é "uma experiência subjetiva relacionada à composição espectral da luz que atinge o olho", mas isso é uma simplificação. Pra ter uma experiência cromática você não precisa de luz, e nem de olho.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;Certamente você já ouviu que as pessoas que levam porrada ficam "vendo estrelas". Não é só uma expressão, isso acontece de verdade. O que ocorre é que os mesmos &lt;a href="http://en.wikipedia.org/wiki/Cone_cell"&gt;cones&lt;/a&gt; da retina que convertem luz em sinais elétricos também são sensíveis a pressão. Então, se você apertar o sensor (por exemplo, com uma paulada bem dada), você vai gerar o mesmo impulso elétrico que teria sido gerado se você estivesse olhando para uma fonte luminosa. Daí, a sensação é de ver estrelas, mesmo que você esteja sem nenhuma luz, no completo escuro.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/hippie-724979.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 188px; height: 200px;" src="http://www.ricbit.com/uploaded_images/hippie-724969.jpg" alt="" border="0" /&gt;&lt;/a&gt;Certo, então podemos usar os olhos mesmo sem luz. Mas nem os olhos são realmente necessários. Os sinais elétricos que vão dos cones até o &lt;a href="http://en.wikipedia.org/wiki/Visual_cortex"&gt;córtex visual primário&lt;/a&gt; podem ser injetados diretamente com eletrodos: nesse caso você tem a experiência da cor sem precisar da retina. Ou então você pode injetar uma droga psicoativa como o LSD, que altera o equilíbrio químico do cérebro, causando uma experência cromática mais intensa que colocar uma camiseta branca e um monte de roupas coloridas dentro da máquina de lavar.&lt;br /&gt;&lt;br /&gt;Mas esses são efeitos colaterais. Na maior parte do tempo, você vai mesmo enxergar cor como sendo uma conseqüência do espectro eletromagnético. Curiosamente, tudo que eu posso afirmar é que a cor é uma &lt;span style="font-style: italic;"&gt;conseqüência&lt;/span&gt;: eu não posso dizer, por exemplo, que a cor é uma função do espectro, porque ela falha em satisfazer a definição de função: você pode ter duas cores para um mesmo espectro, e dois espectros para a mesma cor. O primeiro caso pode ser visto facilmente na imagem abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/msx_final-702514.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 264px;" src="http://www.ricbit.com/uploaded_images/msx_final-702276.jpg" alt="" border="0" /&gt;&lt;/a&gt;Os dois MSX produzem a sensação de duas cores diferentes, mas na verdade são o mesmo espectro (pode conferir no Photoshop)! A explicaçao é que o cérebro tem uma etapa diferencial após a captura do espectro pelos cones, então um espectro isolado pode produzir duas percepções diferentes, dependendo do que está em volta.&lt;br /&gt;&lt;br /&gt;O segundo caso é mais chatinho. Eu poderia mostrar aqui dois espectros diferentes, falar que eles geram a mesma cor, e pedir pra vocês acreditarem em mim; mas resolvi fazer melhor que isso: criei um editor de espectro online! Para usar, basta desenhar um espectro com o mouse em cima da caixa bege, logo abaixo vai aparecer qual a cor que o seu olho enxergaria se estivesse vendo esse espectro. Veja como existem um monte de maneiras diferentes de fazer o amarelo. Você consegue fazer o magenta?&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;iframe src="http://www.ricbit.com/code/spectrum/Spectrum.html" width="470" frameborder="0" height="220"&gt;&lt;/iframe&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/spectrum_source.zip"&gt;&lt;span style="font-style: italic;"&gt;Source do editor de espectros online&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Eu escrevi o editor usando &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;, a abscissa é o comprimento de onda (de 430nm até 650nm), a ordenada é a intensidade luminosa (em escala log), e as funções de transferência eu peguei no site do &lt;a href="http://cvision.ucsd.edu/"&gt;Colour and Vision Research Lab&lt;/a&gt; da Universidade da Califórnia em San Diego. Se você estiver lendo esse post por RSS, pode ser que o seu leitor faça sanitização de javascript e o applet não apareça; nesse caso é só ver o post original no &lt;a href="http://www.ricbit.com/"&gt;www.ricbit.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Ok, agora nós sabemos que uma cor pode ser gerada por vários espectros diferentes. Por que isso acontece? A resposta é que o nosso sistema visual joga fora a maior parte da informação que entra, e para explicar os detalhes temos que entender como funcionam os cones.&lt;br /&gt;&lt;br /&gt;Um cone é uma coisinha bem burrinha. A saída dele é binária: manda impulso elétrico ou não manda impulso elétrico; e o disparo é totalmente aleatório. Mas apesar ser aleatório, não é ruído puro, porque a probabilidade de disparo pode ser controlada através da luz que entra no sensor. Algumas freqüências fazem ele disparar com mais facilidade, e se você aumentar a intensidade da luz ele também aumenta a probabilidade.&lt;br /&gt;&lt;br /&gt;No fim do processo, o cérebro vai interpretar esse trem de pulsos e gerar um único valor, que é uma espécie de média ponderada da luz que atingiu o cone. De outra maneira, é como se o cérebro calculasse o &lt;a href="http://en.wikipedia.org/wiki/Inner_product_space"&gt;produto interno&lt;/a&gt; da função de transferência do cone com o espectro da luz incidente (lembrando que produto interno de distribuições é definido como a integral do produto das distribuições; e, de fato, no source do meu editor de espectro tem um método que faz exatamente isso). Em resumo, um cone gera um valor escalar a partir da entrada.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/macaco-%281%29-729112.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 169px;" src="http://www.ricbit.com/uploaded_images/macaco-%281%29-729109.jpg" alt="" border="0" /&gt;&lt;/a&gt;Mas com um cone sozinho nós não conseguiríamos ver cores. Humanos normais possuem três deles, e na verdade é aí que entra a história do macaco. O tal biólogo europeu tinha notado que o olhar dos macacos americanos era diferente do olhar dos macacos africanos: os primeiros tinham só dois cones, enquanto que os segundos tinham três cones. Isso serve de evidência de que a espécie humana surgiu na África, e não na América (já que os macacos de lá tem o mesmo número de cones que a gente).&lt;br /&gt;&lt;br /&gt;A quantidade de cones define quão rica é sua experiência cromática. Alguns humanos nascem com apenas dois cones: são os daltônicos, que enxergam menos cores que os humanos normais. Segundo a wikipedia, entre as mulheres existe um grau significativo de &lt;a href="http://en.wikipedia.org/wiki/Tetrachromacy"&gt;tetracromia&lt;/a&gt; também, o que faz algum sentido pra mim (isso explicaria aquelas mulheres chatas que falam: "você não limpou direito, olha uma mancha aqui", e você olha, olha e não vê mancha alguma; vai ver ela era tetracromática e a mancha era de uma cor que você não enxerga).&lt;br /&gt;&lt;br /&gt;A resposta dos três cones de um humano normal é a abaixo, nós os chamamos  S, M, L (baseado nos comprimentos de onda que eles cobrem, small, medium e large).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/os_cones-759529.png"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 287px; height: 217px;" src="http://www.ricbit.com/uploaded_images/os_cones-759526.png" alt="" border="0" /&gt;&lt;/a&gt;Vamos juntar tudo agora. Um cone retorna um valor escalar, e nós temos três deles. Se podemos formar uma tripla ordenada de escalares com a saída dos cones, então na verdade eles definem um &lt;a href="http://en.wikipedia.org/wiki/Vector_space"&gt;espaço vetorial&lt;/a&gt; de dimensão três. Uma cor, então, é simplesmente um vetor desse espaço.&lt;br /&gt;&lt;br /&gt;Ora, todo espaço vetorial admite uma base. Como o espaço tem dimensão três, você pode escolher três vetores quaisquer pra formar essa base, desde que sejam linearmente independentes. O mais comum é escolher o vermelho, o verde e o azul, porque essas são as cores que você percebe quando estimulamos os nossos cones de maneira independente. Isso dá origem ao sistema &lt;a href="http://en.wikipedia.org/wiki/RGB_color_model"&gt;RGB&lt;/a&gt; que todo mundo conhece.&lt;br /&gt;&lt;br /&gt;Você pode aplicar uma transformação linear qualquer nessa base pra gerar outras, como por exemplo, o &lt;a href="http://en.wikipedia.org/wiki/YIQ"&gt;YIQ&lt;/a&gt; usado em transmissão NTSC, ou o YJK usado nos chips de vídeo do MSX2+. Alguns sistemas de cores são não-lineares, como o &lt;a href="http://en.wikipedia.org/wiki/YCbCr"&gt;YCbCr&lt;/a&gt; da compressão MPEG. Um sistema não-linear muito usado por artistas é o &lt;a href="http://en.wikipedia.org/wiki/HSV_color_space"&gt;HSV&lt;/a&gt;, que deforma o cubo RGB em um cilindro, onde o raio é a saturação, a altura é o brilho, e o ângulo é o tom da cor.&lt;br /&gt;&lt;br /&gt;O sistema HSV pode ser realizado fisicamente se você tiver disponível um laser de freqüência variável e uma lâmpada de cor branca. Se você mudar a freqüência do laser, muda o tom da cor; se mudar a intensidade da lâmpada, mantendo a intensidade do laser fixa, você muda a saturação; e se mudar a intensidade dos dois ao mesmo tempo, muda o brilho. Por exemplo, eu poderia gerar um tom de rosa com um laser vermelho e com branco não muito forte. Um screenshot do editor de espectro gerando esse rosa é assim:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/rosa-794280.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 179px;" src="http://www.ricbit.com/uploaded_images/rosa-794277.png" alt="" border="0" /&gt;&lt;/a&gt;E agora chegamos ao ponto crucial do problema: como você gera o magenta com esse método? A resposta é: você não gera! Não dá pra fazer o magenta assim, porque um único laser não consegue estimular o cone do vermelho e o cone do azul sem estimular junto o cone do verde.&lt;br /&gt;&lt;br /&gt;Isso é evidência de que o magenta não é uma cor? Claro que não, é só uma evidência de que esse método específico de gerar cores não é capaz de percorrer todo o espaço vetorial, e algumas cores ficam de fora.&lt;br /&gt;&lt;br /&gt;A moral da história é que pra trabalhar com cognição você precisa ter um time interdisciplinar. Se o seu time não tiver alguém de exatas pra interpretar a álgebra linear do seu problema, você corre o risco de escrever bobagens como "magenta não é uma cor".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/delorean-749727.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 254px;" src="http://www.ricbit.com/uploaded_images/delorean-749724.jpg" alt="" border="0" /&gt;&lt;/a&gt;No próximo post, a conclusão da série do magenta, com as batalhas que a coitada da cor passou!&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-5368577896187957115?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/02/o-olhar-do-macaco.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>16</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-210275384373209749</guid><pubDate>Sat, 21 Feb 2009 00:21:00 +0000</pubDate><atom:updated>2009-02-21T01:57:35.196-02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>ciências cognitivas</category><category domain='http://www.blogger.com/atom/ns#'>cores</category><title>There Is No Magenta (mesmo?)</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/coher2-776967.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 227px; height: 320px;" src="http://www.ricbit.com/uploaded_images/coher2-776964.jpg" alt="" border="0" /&gt;&lt;/a&gt;O último meme que circula na &lt;a href="http://search.twitter.com/search?q=magenta+color"&gt;twitosfera&lt;/a&gt; é debater se Magenta, afinal de contas, é uma cor ou não. A origem da dúvida é um artigo intitulado "&lt;a href="http://www.biotele.com/magenta.html"&gt;Magenta ain't a colour&lt;/a&gt;", que afirma que não, magenta não é uma cor, ou pelo menos não uma cor de verdade.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mas e aí? Enfim, o magenta é ou não uma cor? Bem, depende de como você define, e tem duas definições nessa afirmação. A primeira é "o que é uma cor?", mas também tem uma segunda, mais sutil e igualmente não trivial: "o que é magenta?".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pra podermos discutir o que é o tal do magenta, eu proponho um &lt;a href="http://www.merriam-webster.com/dictionary/gedankenexperiment"&gt;gedankenexperiment&lt;/a&gt; famoso. Suponha que você tenha nascido com problema no sistema visual, e tudo que as pessoas enxergam como verde você veja como laranja, e vice-versa. Seus pais nunca fizeram nenhum exame em você, então simplesmente apontavam pro Hulk e ensinavam: tá vendo, o Hulk é verde.&lt;br /&gt;&lt;br /&gt;Esse experimento foi proposto pelo &lt;a href="http://en.wikipedia.org/wiki/John_Locke"&gt;John Locke&lt;/a&gt;, e até hoje filósofos e estudiosos da cognição o usam pra &lt;a href="http://plato.stanford.edu/entries/qualia-inverted/"&gt;discutir sobre o qualia&lt;/a&gt;. Independente disso,  uma observação mais simples é que não importa em qual estado sensorial o menino esteja, ele vai chamar o Hulk de verde porque é assim que seus pais o ensinaram. O nome das cores não está ligado apenas às percepções sensoriais: cores são construtos &lt;span class="Apple-style-span" style="font-style: italic;"&gt;culturais&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/hulk-771379.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 356px;" src="http://www.ricbit.com/uploaded_images/hulk-771377.jpg" alt="" border="0" /&gt;&lt;/a&gt;Por exemplo, se eu tivesse nascido no japão feudal, meus pais me ensinariam que a cor verde chama &lt;a href="http://en.wikipedia.org/wiki/Ao_%28color%29"&gt;Aoi&lt;/a&gt; (青い), nome dado para a cor da maçã que não está madura. Mas essa cor Aoi também é a cor do céu e a cor da água. Então,  pros japoneses antigos verde e azul eram a mesma cor?&lt;br /&gt;&lt;br /&gt;Incrivelmente, sim! Pra eles o verde e o azul eram apenas tons diferentes de Aoi, da mesma maneira que nós temos azul claro e azul escuro. Com o tempo eles criaram uma outra palavra, Midori (緑), pra falar especificamente do conjunto "Aoi que não é azul". E quando querem falar do azul propriamente dito, hoje em dia eles falam Burú (ブルー), copiado do inglês Blue.&lt;br /&gt;&lt;br /&gt;Isso ocorre em todas as culturas. Pra gente, o azul é uma coisa só, mas um americano pode dizer que Blue é só o azul escuro, e aquilo que a gente chama de azul claro na verdade é Cyan.&lt;br /&gt;&lt;br /&gt;Por isso, quando eu li o título do artigo, minha primeira dúvida foi: mas de qual magenta ela está falando? O que ela chama de magenta é o mesmo que eu chamo de púrpura? Ou é roxo? Violeta? É a cor da calça do Hulk?&lt;br /&gt;&lt;br /&gt;Ler o artigo original não ajuda, pois lá ela afirma que magenta é a mesma coisa que pink, e aqui na minha cultura isso são coisas diferentes: magenta é a cor no meio do azul e do vermelho, rosa é o vermelho &lt;a href="http://en.wikipedia.org/wiki/Colorfulness"&gt;desaturado&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A moral da história é que se você quer afirmar alguma propriedade a respeito de uma cor, não chame a cor pelo nome pois depende de &lt;a href="http://en.wikipedia.org/wiki/Locale"&gt;locale&lt;/a&gt;. Ao invés disso, é melhor usar uma descrição quantitativa.&lt;br /&gt;&lt;br /&gt;No fim das contas, o que autora queria dizer mesmo é que #FF00FF não é uma cor de verdade, e isso eu vou mostrar no próximo post que é falso também :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PS: Aparentemente eu não tinha cumprido a promessa de dois posts por mês, mas isso é porque eu tive que viajar para a Índia, e os posts acabaram indo para um blog novo só sobre a viagem. Se você quiser ler as bizarras aventuras do Ricbit na Índia, basta visitar o &lt;a href="http://ricbit-india.blogspot.com/"&gt;India Broadcast&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-210275384373209749?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/02/there-is-no-magenta-mesmo.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-1549203179547376502</guid><pubDate>Mon, 05 Jan 2009 02:23:00 +0000</pubDate><atom:updated>2009-01-05T02:45:46.629-02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>computação gráfica</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>desenho</category><category domain='http://www.blogger.com/atom/ns#'>math</category><title>O Teorema de Capullo</title><description>Quando eu era criança, tinham duas coisas que eu fazia bem: programar e desenhar. Em um certo ponto da vida eu decidi conscientemente deixar de lado o desenho pra focar na programação, mas não antes de tentar um emprego como desenhista :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/bitbaby-701167.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 192px;" src="http://www.ricbit.com/uploaded_images/bitbaby-700776.jpg" alt="" border="0" /&gt;&lt;/a&gt;Isso foi quando eu tinha onze anos. Eu morava ao lado do estúdio do &lt;a href="http://pt.wikipedia.org/wiki/Ely_Barbosa"&gt;Ely Barbosa&lt;/a&gt;, que na década de 80 tinha &lt;a href="http://www.elybarbosa.com.br/html/personagens.htm"&gt;vários personagens bizarros&lt;/a&gt;, incluindo um coelho que viajava numa escova de dentes voadora gigante. Na cara de pau eu fui lá e me ofereci pra desenhar os gibis deles. Incrivelmente, eles não falaram "se manda guri", mas fizeram de fato um teste pra ver se eu desenhava o suficiente. (Que eu acabei bombando. Tinha só onze anos poxa.)&lt;br /&gt;&lt;br /&gt;Mas mesmo tendo optado pela programação, eu nunca deixei de lado esse lado artístico. Não por acaso, meus primeiros empregos foram todos com computação gráfica. E, embora há muito eu não desenhe, adoro comprar livros e revistas com técnicas de desenho, para o caso de algum dia dar vontade de desenhar de novo.&lt;br /&gt;&lt;br /&gt;Uma das revistas que tenho aqui é a primeira edição da &lt;a href="http://www.wizarduniverse.com/"&gt;Wizard&lt;/a&gt; brasileira, onde publicaram na íntegra todo o curso de desenho do &lt;a href="http://en.wikipedia.org/wiki/Greg_Capullo"&gt;Greg Capullo&lt;/a&gt; (desenhista do Spawn), uma série muito boa chamada Curso de Impacto (no original Krash Course, tem digitalizado na web se você souber onde procurar). No capítulo sobre perspectiva, eu aprendi um truque muito bom com ele, que na falta de nome melhor eu chamo de &lt;span style="font-weight: bold;"&gt;Teorema de Capullo&lt;/span&gt;:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Se você tiver vários personagens de mesma altura em uma cena, mesmo que eles não estejam na mesma profundidade, sempre haverá uma parte do corpo deles que estará alinhada.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sabendo usar a regra acima, fica super fácil desenhar cenas complexas com perspectiva correta. Pra ver experimentalmente como isso é verdade, eu fiz um programinha em &lt;a href="http://pyopengl.sourceforge.net/"&gt;pyOpenGL&lt;/a&gt; que desenha vários Ricbits em posições aleatórias, usando as regras acima:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/sshot-757128.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://www.ricbit.com/uploaded_images/sshot-757124.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="font-style: italic;" href="http://www.ricbit.com/code/capullo.py"&gt;Script em python que desenha a cena acima&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note como o teorema de Capullo é verdadeiro: apesar de estarem em distâncias diferentes, todos os Ricbits estão alinhados na altura da cintura. Naturalmente, a primeira coisa em que pensei quando vi o teorema foi: dá pra demonstrar? A resposta é: sim, dá, e é surpreendentemente simples!&lt;br /&gt;&lt;br /&gt;Vamos assumir que o observador está a uma altura h do solo, e que o plano de projeção está na coordenada z=1 (sem perda de generalidade). Vamos projetar um ponto P qualquer nesse plano de projeção, cujas coordenadas são Px, Py, Pz, e a intersecção com o plano vai ser em Sx, Sy. O que nós queremos provar é que existe um Sy tal que, para qualquer Pz dado, sempre é possível escolher um Py, independente de Pz, que projeta nesse Sy. Virando a figura de lado ela fica assim:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/diagrama-745137.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 298px; height: 223px;" src="http://www.ricbit.com/uploaded_images/diagrama-745135.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-style: italic;"&gt;(Thanks to Bani/Inkscape pelo diagrama)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Por semelhança de triângulos, nós tiramos que (Py-h)/Pz = Sy/1, logo Sy=(Py-h)/Pz. Agora é imediato, basta escolher Py=h que Sy sempre será zero, independente de Pz, QED.&lt;br /&gt;&lt;br /&gt;A parte bacana de entender matematicamente o que acontece é que você pode extrapolar suas conclusões. Como a escolha de Py depende do h, isso significa que o ponto exato onde as figuras se encontram depende da altura do observador. Subindo o observador no script ficamos com uma figura como a abaixo, note como agora os Ricbits estão alinhados na altura do pescoço:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/sshot-748988.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://www.ricbit.com/uploaded_images/sshot-748986.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Um dia eu ainda volto a desenhar, mas enquanto isso programação e matemática são divertidas demais :)&lt;br /&gt;&lt;br /&gt;PS: Minha resolução de ano novo é atualizar o blog pelo menos duas vezes por mês, então, se eu atrasar, me cobre!&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-1549203179547376502?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2009/01/o-teorema-de-capullo.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-1509499269513455363</guid><pubDate>Sun, 26 Oct 2008 00:07:00 +0000</pubDate><atom:updated>2008-10-26T12:51:30.722-02:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>retro</category><category domain='http://www.blogger.com/atom/ns#'>rickroll</category><category domain='http://www.blogger.com/atom/ns#'>msx</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>processamento de sinais</category><category domain='http://www.blogger.com/atom/ns#'>assembly</category><category domain='http://www.blogger.com/atom/ns#'>compressão</category><title>Dez anos de MUST</title><description>É díficil achar alguém na faixa dos 30 anos que trabalhe com computadores e não conheça o &lt;a href="http://en.wikipedia.org/wiki/MSX"&gt;MSX&lt;/a&gt;, um computador pessoal de 8 bits que fez um sucesso enorme por aqui. No seu auge, entre 85 e 91, estima-se que mais de 400 mil máquinas tenham sido vendidas no Brasil.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/Diploma-728027.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/Diploma-728022.jpg" alt="" border="0" /&gt;&lt;/a&gt;Mas embora esse período tenha sido o auge em número de usuários, não foi o ápice na parte técnica. Os mais avançados softwares brasileiros de MSX foram feitos no período de 1996 a 2004, e há dois motivos pra isso. O primeiro é que esse foi o início da internet comercial, então muitos dos manuais e datasheets que antes eram raros, passaram a ser difundidos livremente pelas listas de discussão. O segundo é que essa também foi a época em que começaram a se formar os primeiros engenheiros que cresceram com o MSX na infância, e toda essa criançada estava sedenta pra usar os novos conhecimentos na sua velha maquininha.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Eu mesmo fiz um monte de brincadeiras nessa época, talvez a mais conhecida tenha sido o meu emulador &lt;a href="http://en.wikipedia.org/wiki/BrMSX"&gt;BrMSX&lt;/a&gt;. Mas agora, em 2008, um outro software que fiz completa dez anos, e nada mais apropriado que comemorar com um detalhado &lt;span style="font-style: italic;"&gt;making of&lt;/span&gt;. Apresento a vocês o &lt;span style="font-weight: bold;"&gt;Music Station&lt;/span&gt;, ou como também era carinhosamente conhecido, o &lt;span style="font-weight: bold;"&gt;MUST&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;center&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/gLMmfraJK4c&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;embed src="http://www.youtube.com/v/gLMmfraJK4c&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Vamos voltar uma década no tempo: em 1998, a internet crescia, nasciam os primeiros grandes portais nacionais, e começava a surgir uma prática que hoje em dia é extremamente comum: o compartilhamento de músicas em mp3. Primeiro por FTP e IRC, depois pelo Napster e Audiogalaxy, em pouco tempo os arquivos mp3 estavam por toda a parte.&lt;br /&gt;&lt;br /&gt;Naturalmente, quem ainda brincava com o MSX também queria entrar na onda. Mais de uma vez me perguntaram "Ricardo, você não pode fazer um programinha pra tocar mp3 no MSX?". Qualquer criatura com um mínimo de bom senso iria perguntar "pra quê?". Mas bom senso nunca foi o meu forte :)&lt;br /&gt;&lt;br /&gt;Eu já sabia de antemão que mp3 no MSX não era viável, o coitado do Z80 não iria dar conta. Mas a essa altura eu já sabia evitar um erro muito comum em desenvolvedores, o de prestar atenção no que o usuário &lt;span style="font-style: italic;"&gt;pede&lt;/span&gt;, ao invés de focar no usuário &lt;span style="font-style: italic;"&gt;quer&lt;/span&gt;. Sure, eles estavam pedindo mp3, mas o que eles queriam mesmo era só tocar música no MSX. Se fosse um outro formato qualquer não faria diferença. Como eu tinha acabado de cursar &lt;a href="http://www.lcs.poli.usp.br/~phillip/ptc5005.html"&gt;Processamento Digital de Sinais&lt;/a&gt; na Poli (com o saudoso prof. &lt;a href="http://www.lcs.poli.usp.br/maxgerken/"&gt;Max Gerken&lt;/a&gt;), achei que poderia encarar a construção de uma solução customizada pro MSX.&lt;br /&gt;&lt;br /&gt;Hora de calibrar os objetivos: eu decidi fazer um player que tivesse a melhor qualidade possível pro MSX, que rodasse em qualquer modelo de MSX, incluindo os nacionais, e que conseguisse espremer pelo menos um minuto de música em uma &lt;a href="http://www.inova.unicamp.br/inventabrasil/megaram.htm"&gt;MegaRAM&lt;/a&gt; de 256kb, o modelo mais comum. O primeiro passo, portanto, é ver se o MSX dá conta de tocar um sample com qualidade aceitável.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/file-782163.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 195px; height: 200px;" src="http://www.ricbit.com/uploaded_images/file-782155.jpg" alt="" border="0" /&gt;&lt;/a&gt;O MSX usa como gerador de som o chip &lt;a href="http://en.wikipedia.org/wiki/AY-3-8910"&gt;AY-3-8910&lt;/a&gt; (popularmente PSG), que é basicamente um gerador de &lt;a href="http://en.wikipedia.org/wiki/Square_wave"&gt;ondas quadradas&lt;/a&gt;. Pra tocar um &lt;a href="http://en.wikipedia.org/wiki/A440"&gt;Lá central&lt;/a&gt;, você especifica a freqüência de 440Hz, acerta o volume apropriado, e se diverte com o barulhinho que ele produz. Se você for um mago do &lt;a href="http://en.wikipedia.org/wiki/Chiptune"&gt;chiptune&lt;/a&gt;, dá pra fazer &lt;a href="http://www.youtube.com/watch?v=Z5UabrI6GFM"&gt;músicas bem legais&lt;/a&gt; com o PSG, mas definitivamente ele não foi feito pra reprodução de áudio digital. Para conseguir isso, nós temos entender como o chip funciona por dentro.&lt;br /&gt;&lt;br /&gt;Internamente, o gerador de ondas quadradas é só um contador digital, que alterna o estado de um &lt;a href="http://en.wikipedia.org/wiki/AY-3-8910"&gt;flip-flop&lt;/a&gt; depois do término de meio período. O chip tem três geradores que você pode ligar ou desligar de maneira independente através de um mixer. Quem tem experiência com &lt;a href="http://en.wikipedia.org/wiki/Transistor-transistor_logic"&gt;chips TTL&lt;/a&gt; sabe que sinais desligados usualmente não são interpretados como nível lógico zero, mas sim como nível lógico um.&lt;br /&gt;&lt;br /&gt;Pro nosso ouvido tanto faz, um sinal constante é silêncio sempre, independente dele estar em zero volts ou em cinco volts, mas o segredo da coisa é que o controle de volume é uma etapa analógica feita &lt;span style="font-style: italic;"&gt;depois&lt;/span&gt; do mixer. Por isso, se você desligar o gerador através do mixer, e mudar bem rapidamente o controle de volume, você pode improvisar qualquer &lt;a href="http://en.wikipedia.org/wiki/Waveform"&gt;forma de onda&lt;/a&gt; que quiser! Como o PSG tem 16 volumes possíveis, isso significa que o MSX pode emular um &lt;a href="http://en.wikipedia.org/wiki/Pulse-code_modulation"&gt;PCM&lt;/a&gt; de 4 bits, mesmo sem ter sido projetado pra isso.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/quantz-746639.png"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 200px;" src="http://www.ricbit.com/uploaded_images/quantz-746637.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-style: italic;"&gt;Quando o sinal está em nível lógico um, basta variar o volume!&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Agora basta ligar esse PCM num timer de alta resolução e pronto. Quer dizer, exceto pelo fato do MSX não ter um timer de alta resolução. O melhor que ele tem é um timer que dispara no início do &lt;a href="http://en.wikipedia.org/wiki/How_Television_Works"&gt;retraço vertical&lt;/a&gt;, a 60Hz, que é uma freqüência baixa demais pra gente. Nesse caso, o jeito é apelar pra &lt;strike&gt;gambiarra&lt;/strike&gt; criatividade :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Como o Z80 do MSX não tem cache, nem prefetching, nem nenhuma dessas firulas de processadores modernos, os &lt;a href="http://en.wikipedia.org/wiki/Opcode"&gt;opcodes&lt;/a&gt; sempre levam o mesmo tempo pra rodar. Assim, você pode criar um pseudo-timer simplesmente contando quantos ciclos de clock seu programa leva pra executar. Se nós precisássemos de uma rotina que lesse um byte da memória, mandasse pro PSG, e levasse exatamente 50 clocks pra rodar, uma possibilidade seria:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;LD A,(HL)      ; 8 clocks&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;LD A,(HL)      ; 8 clocks&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;INC HL         ; 7 clocks&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;OUT (0A1h),A   ; 12 clocks&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;NOP            ; 5 clocks&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;NOP            &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;; 5 clocks&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;NOP&lt;span class="Apple-style-span"  style="font-family:Georgia;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;            &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;; 5 clocks&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;Pra fazer um timer assim, além de programar em assembly, você ainda precisa resolver um &lt;a href="http://en.wikipedia.org/wiki/Subset_sum_problem"&gt;subset sum&lt;/a&gt; dos opcodes, o que é extremamente divertido (eu assumo que se você está lendo até aqui, deve achar essas coisas divertidas também :). Note como é importante fazer o padding correto, além de colocar 3 NOPs, eu também repliquei o carregemento da memória, só pra fazer a conta bater certinho nos 50 clocks.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Agora que temos um jeito de reproduzir o som, precisamos escolher a sampling rate. Pra conseguir o objetivo de 1 minuto em 256kb, o áudio certamente terá que ser comprimido. Então a &lt;a href="http://en.wikipedia.org/wiki/Sampling_rate"&gt;sampling rate&lt;/a&gt; precisa ser baixa o suficiente pra poder suportar a descompressão em real time entre cada amostra, e alta o suficiente pra não perder muita qualidade de som. Eu escolhi 11kHz; como o clock do MSX é 3.57MHz, isso dá um total de 324 clocks por amostra. Não é muito, mas alguma compressão dá pra fazer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Vamos calcular a compressão agora. Pra colocar 60 segundos a 11kHz em 256kb, nós precisamos de, no máximo, 256k*8/60/11k = 3.1 bits por amostra. Nosso sinal original tem 4 bits por amostra, então realmente a compressão é necessária. O Z80 não tem fôlego pra implementar transformadas, então não podemos usar nada de &lt;a href="http://en.wikipedia.org/wiki/Discrete_cosine_transform"&gt;DCT&lt;/a&gt;, e nem mesmo &lt;a href="http://en.wikipedia.org/wiki/Haar_wavelet"&gt;Haar&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O jeito é modelar alguma coisa bem simples mesmo, tipo um código de tamanho variável como o código de &lt;a href="http://en.wikipedia.org/wiki/Huffman_coding"&gt;Huffman&lt;/a&gt;. Esse tipo de código funciona tanto melhor quanto menos uniforme for o seu histograma. Pegando uma &lt;a href="http://www.youtube.com/watch?v=Jdk0AejE7IA&amp;amp;feature=related"&gt;música típica&lt;/a&gt; como teste, chegamos em uma &lt;a href="http://en.wikipedia.org/wiki/Information_entropy"&gt;entropia&lt;/a&gt; de 2.6 bits; mas, por outro lado, a &lt;a href="http://en.wikipedia.org/wiki/Finite_difference"&gt;primeira diferença&lt;/a&gt; tem entropia ainda menor, apenas 2 bits! &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/histogram-778802.png"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 269px;" src="http://www.ricbit.com/uploaded_images/histogram-778784.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Vamos codificar a diferença então. Com apenas 324 clocks não dá pra implementar todo o Huffman, mas tem uma maneira de simplificar, que é usando &lt;a href="http://en.wikipedia.org/wiki/Lossy_compression"&gt;compressão com perdas&lt;/a&gt;. Como 99.3% das diferenças estão na faixa de -3 a 3, eu posso saturar nesses valores pra deixar o código mais simples. O código que utilizei foi o abaixo:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; 3 1111&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; 2 1110&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; 1 01&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; 0 00&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-1 10&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-2 1101&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-3 1100&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No final a implementação desse código ficou menor do que eu esperava, apenas 169 clocks. Isso significava que eu tinha 198 clocks sobrando, com a cpu parada. Eu poderia ter aprimorado o codec com uma compressão mais eficiente, mas pensei que seria mais divertido, ao invés disso, usar esses clocks sobrando pra adicionar animações. Nesses clocks sobrando eu acabei colocando um osciloscópio com a forma de onda tocada, um banner animado na parte inferior, e no cantinho ainda sobrou cpu pra colocar um pingüim dançando!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/DS14A_0001-773904.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 200px; height: 150px;" src="http://www.ricbit.com/uploaded_images/DS14A_0001-773900.png" alt="" border="0" /&gt;&lt;/a&gt;Nesse ponto tudo que faltava era uma tela de abertura. Como no final o programa acabou ficando uma experiência multimídia, eu resolvi que ele seria uma homenagem à série Disc Station da &lt;a href="http://en.wikipedia.org/wiki/COMPILE"&gt;Compile&lt;/a&gt;, que primava por seus excelentes &lt;a href="http://en.wikipedia.org/wiki/Demo_%28computer_programming%29"&gt;demos&lt;/a&gt;. Eu chamei então o meu programinha de Music Station, e como os Disc Station originais sempre começavam com uma menina bonitinha, eu pedi ao &lt;a href="http://raultabajara.com/"&gt;meu irmão&lt;/a&gt; que desenhasse uma pingüinha no mesmo estilo. O desenho original que ele fez foi o abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/MUST-715349.PNG"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/MUST-715346.PNG" alt="" border="0" /&gt;&lt;/a&gt;Adaptar desenhos no MSX é tão complicado quanto adaptar código, a resolução é de apenas 256x192 e ainda tem o problema do &lt;a href="http://en.wikipedia.org/wiki/Attribute_clash"&gt;color clash&lt;/a&gt; (cada bloco de 8x1 pixels pode ter no máximo duas cores). O pingüim tomando sol no canto da imagem teve que sumir, eu não tinha resolução pra isso. Já na pingüinha, eu tive que usar traços bem grossos no contorno, pra minimizar o clash, mas mesmo assim ainda sobraram algumas partes borradas. A solução foi usar &lt;a href="http://en.wikipedia.org/wiki/Sprite_%28computer_graphics%29"&gt;sprites&lt;/a&gt; pra cobrir esse borramento.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/7errors-722193.png"&gt;&lt;img style="border: 0pt none ; margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 154px;" src="http://www.ricbit.com/uploaded_images/7errors-722191.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-style: italic;"&gt;Consegue achar as diferenças?&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Por fim, bastou criar um logo, inspirado no logo original do Disc Station, e o MUST estava finalmente pronto! Pra quem quiser brincar com ele, abaixo tem uma versão em .dsk que pode ser carregada em emuladores, como o &lt;a href="http://www.bluemsx.com/"&gt;blueMSX&lt;/a&gt; ou o &lt;a href="http://openmsx.sourceforge.net/"&gt;openMSX&lt;/a&gt;, e também o código fonte original.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/rickroll.zip"&gt;Imagem de disco para rodar em emuladores&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/must.zip"&gt;Código fonte original do Music Station, em assembly Z80&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/aniversario-718603.jpg"&gt;&lt;img style="border: 0pt none ; margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 186px; height: 200px;" src="http://www.ricbit.com/uploaded_images/aniversario-718599.jpg" alt="" border="0" /&gt;&lt;/a&gt;Na época, a comunidade MSX adorou o MUST. Como eu esperava, o pessoal começou a &lt;a href="http://www.file-hunter.com/music/must.html"&gt;compartilhar músicas convertidas&lt;/a&gt;, do mesmo jeito que o povo do PC compartilhava mp3; e como eu publiquei a engine do MUST em &lt;a href="http://www.gnu.org/copyleft/gpl.html"&gt;GPL&lt;/a&gt;, um monte de gente reaproveitou o código, sendo que a engine foi usada &lt;a href="http://www.msxpro.com/msxrio2002_by_jose_luis.html"&gt;até em joguinhos&lt;/a&gt;. Eu até animei a fazer uma versão com vídeo também, mas isso já é outra história, pra outra ocasião :)&lt;br /&gt;&lt;br /&gt;Parabéns pelos dez anos, Music Station!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Agradecimentos à Ila, ao Acidx e ao Sturaro por ajudar na arqueologia digital :)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-1509499269513455363?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/10/dez-anos-de-must.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>14</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-5043087687640293284</guid><pubDate>Sun, 05 Oct 2008 01:40:00 +0000</pubDate><atom:updated>2008-10-05T12:46:03.656-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>processamento de imagens</category><category domain='http://www.blogger.com/atom/ns#'>pil</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>livros</category><title>O Desentortador</title><description>Eu confesso que fiquei apreensivo quando soube que teria que passar vários meses na Califórnia. Afinal, &lt;a href="http://en.wikipedia.org/wiki/Mountain_View,_California"&gt;Mountain View&lt;/a&gt; não é nenhuma &lt;a href="http://en.wikipedia.org/wiki/San_Francisco,_California"&gt;San Francisco&lt;/a&gt;, eu tinha medo de morrer de tédio enquanto estivesse lá. Mas, felizmente, meu medo esvaiu-se quando eu descobri &lt;a href="http://www.bookbuyers.com/"&gt;O Sebo&lt;/a&gt;!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/IMG_0075-756800.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/IMG_0075-756787.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;O Sebo é um lugar lindo e maravilhoso onde você pode comprar &lt;a href="http://en.wikipedia.org/wiki/The_Diamond_Age"&gt;The Diamond Age&lt;/a&gt; por apenas 50 cents, e inúmeros outros livros por preços tão baixos quanto esse. Na foto acima, você pode ver uma pequena porção do paraíso, mostrando apenas a parte de sci-fi, e apenas os autores das letras D até L. Sim, O Sebo é um lugar gigante e com diversão garantida pra várias semanas.&lt;br /&gt;&lt;br /&gt;Depois de encher a mochila com livros, eu tive vontade de tirar uma foto deles pra mandar pros amigos. Foi então que eu tive um problema. Eu estava tentando tirar a foto à noite, e se eu colocasse a câmera exatamente sobre o livro, o flash estourava, e tudo que saía na foto era um grande borrão branco. Sem flash também não funcionava, ficava escuro demais pra câmera conseguir estabilizar a imagem.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/ricbit_01-711497.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/ricbit_01-711493.jpg" alt="" border="0" /&gt;&lt;/a&gt;Eu resolvi esse problema inclinando a câmera em relação ao plano do livro. Isso certamente resolve o problema do flash, mas em compensação o livro fica torto na foto. Uma solução simples seria simplesmente esperar amanhecer e tirar a foto do livro com a luz do dia. Mas é claro que optei por uma alternativa mais bizarra :) Resolvi escrever um software que desentortasse a foto do livro automaticamente!&lt;br /&gt;&lt;br /&gt;Pra isso, vamos começar com a foto original do livro torto:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/shaolin-778375.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/shaolin-778149.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Pra começar o desentortamento, a primeira coisa que precisamos descobrir é onde estão as bordas do livro, que vão definir como vai ser a rotação que iremos fazer. Achar as bordas é fácil, basta identificar a fronteira entre livro e não-livro. Para isso, eu usei um algoritmo simples de &lt;a href="http://en.wikipedia.org/wiki/Region_growing"&gt;crescimento de região&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/border-723904.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/border-723903.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Não ficou a coisa mais perfeita do mundo: está cheio de ruído em volta, e o algoritmo ainda vazou pra dentro do livro (a mesa era marrom, da mesma cor do urso na capa, e ele se perdeu com isso).&lt;br /&gt;&lt;br /&gt;A boa notícia é que nenhuma dessas coisas importa! O que eu quero achar são as bordas, que tem uma direção preferencial bem determinada. Se eu utilizar a &lt;a href="http://en.wikipedia.org/wiki/Hough_transform"&gt;transformada de Hough&lt;/a&gt;, tanto o ruído quanto o vazamento devem sumir, e de fato é o que acontece. Essa é a transformada da imagem acima:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/hough-761161.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/hough-761158.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;A transformada de Hough leva retas em pontos, então as quatro retas que formam a borda do livro viram quatro pontos bem brilhantes na transformada. É simples agora usar um &lt;a href="http://en.wikipedia.org/wiki/Thresholding_%28image_processing%29"&gt;threshold&lt;/a&gt; pra identificar esses pontos, e aplicar a transformada inversa pra achar as retas na imagem original:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/detected-743504.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/detected-743502.jpg" alt="" border="0" /&gt;&lt;/a&gt;Nessa imagem eu tracei linhas vermelhas nas retas identificadas pela transformada. Estamos quase lá, mas um problema da transformada de Hough é que ela acha retas, e não segmentos de retas. O que me interessa na verdade são os vértices do livro, então eu preciso achar as intersecções entre essas retas.&lt;br /&gt;&lt;br /&gt;O detalhe é que quatro retas em posição geral determinam seis pontos, e não quatro. No caso da imagem acima, por exemplo, as retas verticais se encontram no &lt;a href="http://en.wikipedia.org/wiki/Vanishing_point"&gt;ponto de fuga&lt;/a&gt;, bem acima do livro. A solução que eu usei foi adotar uma &lt;strike&gt;gambiarra&lt;/strike&gt; heurística de considerar apenas os quatro pontos mais próximos do centro da imagem original. Além disso, também é legal converter os pontos pra coordenadas polares em relação ao centro da imagem, assim podemos ordená-los pelo ângulo.&lt;br /&gt;&lt;br /&gt;Tendo os quatro vértices, agora é só aplicar uma &lt;a href="http://en.wikipedia.org/wiki/Affine_transformation"&gt;transformação afim&lt;/a&gt; na imagem que a leve pra um retângulo e o trabalho está terminado né? Quem dera hehe. Se você fizer isso, a imagem fica com uma deformação não-linear: achatada na parte de cima, e esticada na parte de baixo.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/affine-705705.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/affine-705702.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Na década de 90, todo guri metido a programador fazia sua própria engine 3D pra imitar o Doom e o Quake; quem passou por essa época reconhece na hora a origem da deformação. O que está acontecendo é um problema de &lt;a href="http://en.wikipedia.org/wiki/Texture_mapping"&gt;inverse perspective-correct texture mapping&lt;/a&gt;. A perspectiva introduz um fator do tipo 1/z na sua textura, e você precisa compensar isso quando for mapear na imagem. Vamos fazer a correção de perspectiva então:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/final-705442.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/final-705439.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/ricbit_02-781558.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/ricbit_02-781552.jpg" alt="" border="0" /&gt;&lt;/a&gt;Yatta! Finalmente temos a imagem final, desentortada como queríamos :) Na verdade, nós desentortamos a imagem em um único eixo, dá pra ver claramente que além do &lt;a href="http://www.grc.nasa.gov/WWW/K-12/airplane/pitch.html"&gt;pitch&lt;/a&gt; essa imagem também precisava de correção no &lt;a href="http://www.grc.nasa.gov/WWW/K-12/airplane/roll.html"&gt;roll&lt;/a&gt;, mas isso fica como exercício pro leitor.&lt;br /&gt;&lt;br /&gt;Eu implementei todos os passos descritos acima em python, usando a biblioteca &lt;a href="http://www.pythonware.com/products/pil/"&gt;PIL&lt;/a&gt;. Ele roda rapidinho, uns 3s por imagem apenas. O source é o abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/cover.py"&gt;Source do desentortador em python&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Se alguém quiser reaproveitar o código pra fazer alguma coisa útil com ele (hehe), sinta-se à vontade. Salvo indicação em contrário, todos os programas desse blog são disponibilizados sob a Licença Crowley (Do what you want shall be the whole of the License).&lt;br /&gt;&lt;br /&gt;PS: Ah sim, como vocês repararam, a partir de agora o blog vai ter desenhos também! Eu gostaria de dizer que se funcionou pro &lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt;, deve funcionar pra mim também; mas a verdade é que a &lt;a href="http://www.editoraaleph.com.br/"&gt;Aleph&lt;/a&gt; já fazia a mesma coisa lá na década de 80 :)&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-5043087687640293284?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/10/o-desentortador.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>19</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-6573808229981643940</guid><pubDate>Mon, 28 Jul 2008 08:48:00 +0000</pubDate><atom:updated>2008-07-28T06:25:30.232-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>processamento de imagens</category><category domain='http://www.blogger.com/atom/ns#'>computação paralela</category><category domain='http://www.blogger.com/atom/ns#'>xkcd</category><category domain='http://www.blogger.com/atom/ns#'>computação gráfica</category><title>MapReduce is running</title><description>&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/bones.jpg" alt="" border="0" /&gt;Quando eu era estagiário na década de 90, um dos meus primeiros projetos envolvia &lt;a href="http://en.wikipedia.org/wiki/Parallel_computing"&gt;computação paralela&lt;/a&gt;. O projeto &lt;a href="http://www.nlm.nih.gov/research/visible/visible_human.html"&gt;Visible Human&lt;/a&gt; tinha acabado de fatiar os primeiros espécimes, e nosso grupo estava doidinho pra fazer &lt;a href="http://en.wikipedia.org/wiki/Ray_tracing_%28graphics%29"&gt;ray-tracing&lt;/a&gt; do volume de dados. Mas o volume de dados era grande demais pros padrões da época, e única saída foi importar uma &lt;a href="http://en.wikipedia.org/wiki/Meiko_Scientific"&gt;Meiko&lt;/a&gt; com dez processadores, pra dar conta do trabalho.&lt;br /&gt;&lt;br /&gt;(Meiko, aliás, que tem uma história curiosa. Apesar de ter dez processadores, só conseguíamos rodar processos em nove deles, tinha um que não funcionava de jeito nenhum. Depois de muitas ligações pro suporte, resolvemos desmontar a máquina pra ver se tinha alguma coisa errada no hardware, e, surpresa, entre o pente de memória e o conector na motherboard tinha um mosquito preso. Sim, aquela cpu tinha um bug :)&lt;br /&gt;&lt;br /&gt;Mas programar diretamente a comunicação entre os processadores, com &lt;a href="http://en.wikipedia.org/wiki/Parallel_Virtual_Machine"&gt;PVM&lt;/a&gt; ou &lt;a href="http://en.wikipedia.org/wiki/Message_Passing_Interface"&gt;MPI&lt;/a&gt;, é trabalho demais. A nossa solução foi escrever uma camada intermediária que abstraía a parte de comunicação e fazia o paralelismo de modo implícito. Nossa biblioteca era customizada pra &lt;a href="http://en.wikipedia.org/wiki/Volume_rendering"&gt;visualização volumétrica&lt;/a&gt; paralela, mas hoje em dia a mesma abordagem é feita de maneira mais genérica, por pacotes como o &lt;a href="http://en.wikipedia.org/wiki/Hadoop"&gt;Hadoop&lt;/a&gt; e o &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;MapReduce&lt;/a&gt;, sendo que esse último eu uso bastante hoje em dia.&lt;br /&gt;&lt;br /&gt;Mas, mesmo paralelizando o processamento, o melhor que uma abordagem dessas consegue é um ganho linear no número de processadores. Se o tamanho do seu volume de dados precisa daqueles &lt;a href="http://en.wikipedia.org/wiki/SI_prefix"&gt;prefixos que vêm depois do giga&lt;/a&gt;, então até o MapReduce pode demorar um pouco pra rodar. Nesse fim de semana eu encontrei o &lt;a href="http://xkcd.com/"&gt;Randall Munroe&lt;/a&gt;, e pedi pra ele ilustrar como é um MapReduce na prática :)&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/mapreduce.jpg" alt="" border="0" /&gt;&lt;br /&gt;Eu também aproveitei pra filmar o Randall enquanto ele desenhava esse sketch. Como o estilo dele é, hum, minimalista, isso o torna o único cartunista que eu conheço que consegue ser mais rápido que o &lt;a href="http://en.wikipedia.org/wiki/Sergio_Aragon%C3%A9s"&gt;Aragonés&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/mf8eMV2vVNw&amp;amp;hl=en&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;embed src="http://www.youtube.com/v/mf8eMV2vVNw&amp;amp;hl=en&amp;amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-6573808229981643940?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/07/mapeduce-is-running.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-7770571111477333421</guid><pubDate>Sun, 20 Jul 2008 04:17:00 +0000</pubDate><atom:updated>2008-07-20T20:42:55.292-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>puzzle</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>cpp</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>livros</category><title>Eu podia estar roubando</title><description>É isso. Eu podia estar roubando, eu podia estar matando, mas estou aqui escrevendo no blog. Reclamações sobre a periodicidade do blog devem ser enviadas diretamente à &lt;a href="http://www.rockstargames.com/IV/"&gt;Rockstar&lt;/a&gt; :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/barao_owl-793943.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/barao_owl-793934.jpg" alt="" border="0" /&gt;&lt;/a&gt;Ao falar de GTA, sempre tem &lt;a href="http://g1.globo.com/Noticias/Tecnologia/0,,MUL600921-6174,00.html"&gt;quem o associe ao terrorismo islâmico&lt;/a&gt;. Mas pra mim, o que incomoda mais é a associação imediata do islã com o terrorismo, em oposição à sociedade ocidental civilizada. Na verdade, já houve um período onde acontecia o oposto, enquanto a &lt;a href="http://en.wikipedia.org/wiki/Islamic_mathematics"&gt;ciência florescia na cultura islâmica&lt;/a&gt;, os cristãos saqueavam e destruíam em nome da fé (mas na época chamavam isso de &lt;a href="http://en.wikipedia.org/wiki/Crusade"&gt;cruzadas&lt;/a&gt;, ao invés de terrorismo).&lt;br /&gt;&lt;br /&gt;Foi nessa época em que viveu Al-Khwarizm (cujo nome deu origem às palavras algarismo e algoritmo), nessa época em que Bhaskara escreveu &lt;a href="http://en.wikipedia.org/wiki/Lilavati"&gt;Lilavati&lt;/a&gt; e resolveu a equação de segundo grau, e também nesse período é que surgiram as primeiras demonstrações por indução finita. Mas a influência mais direta que a matemática islâmica teve em mim foi, sem dúvida, através das obras do Júlio César de Mello e Souza, que escrevia com o pseudônimo de &lt;a href="http://pt.wikipedia.org/wiki/Malba_Tahan"&gt;Malba Tahan&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/homem_que_calculava-728804.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/homem_que_calculava-728802.jpg" alt="" border="0" /&gt;&lt;/a&gt;Malba Tahan se inspirava na cultura islâmica pra escrever seus livros de divulgação científica, sendo que o mais famoso deles é o &lt;a href="http://pt.wikipedia.org/wiki/O_Homem_que_Calculava"&gt;Homem Que Calculava&lt;/a&gt;. Num &lt;a href="http://www.ricbit.com/2008/06/um-cientista-em-minha-vida.html"&gt;post anterior&lt;/a&gt; eu tinha dito que o cálculo do Pi com método de monte carlo tinha sido o segundo puzzle que levei mais tempo pra resolver; pois o primeiro puzzle foi justamente tirado de um dos capítulos do livro: como escrever qualquer número usando apenas quatro quatros. No livro, Malba Tahan mostra as soluções até o 10, que são mais ou menos assim:&lt;br /&gt;&lt;br /&gt;0 = 44 - 44&lt;br /&gt;1 = 44 / 44&lt;br /&gt;2 = 4/4 + 4/4&lt;br /&gt;3 = (4 + 4 + 4) / 4&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Eu tinha só dez anos quando li pela primeira vez, e consegui estender a seqüência até o 20. O posfácio do livro dizia que era possível escrever até o 100, mas eu levei mais de uma década até ver a solução completa!&lt;br /&gt;&lt;br /&gt;Depois dos 20 primeiros, eu só consegui fazer algum progresso significativo quando estava no colégio técnico. Eu notei que o problema ficava mais simples se eu reduzisse o número de quatros, montando primeiro todas as soluções com um quatro, depois todas com dois quatros, e assim por diante. Eu não sabia na época, mas o que eu estava fazendo era um &lt;a href="http://en.wikipedia.org/wiki/Forward_chaining"&gt;forward chaining&lt;/a&gt; manual. Mesmo assim, eu só consegui fazer os números pares até 100, minha solução tinha um monte de buracos nos ímpares.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/image-for-isaacs-top-10-marvel-fantastic-776273.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/image-for-isaacs-top-10-marvel-fantastic-776265.jpg" alt="" border="0" /&gt;&lt;/a&gt;Quando eu estava na faculdade, com os skillz mais afiados, eu larguei mão de fazer manualmente e escrevi um script pra fazer o serviço automaticamente. Eu coloquei no script não só as quatro operações básicas, mas também todas as outras que estão no Concrete Mathematics: raiz quadrada, função piso e função teto, binomiais, potências, fatorial, &lt;a href="http://en.wikipedia.org/wiki/Pochhammer_symbol"&gt;fatorial crescente e decrescente&lt;/a&gt;. A única regra é não usar nenhuma notação que envolva letras (como sin, cos e log; se você permitir log, o problema perde a graça).&lt;br /&gt;&lt;br /&gt;Meu script conseguiu finalmente resolver todos os números até 100, e até encontrou múltiplas soluções pra eles! Atribuindo um peso a cada operação, eu mandei ele imprimir somente a soluçao mais simples (por exemplo, adição tem peso baixo, piso e teto tem peso alto). A tabela com as respostas está abaixo, junto com o programa que escrevi na época:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/44.txt"&gt;Solução gerada pelo script&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/solve.c"&gt;Script original, escrito em C&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;O script pode resolver também os 5 cincos, os 6 seis, e qualquer outra combinação, desde que você esteja disposto a esperar o suficiente. O código original é bem ruinzinho, mas na verdade eu me orgulho de achar que meu código escrito há dez anos é ruim, significa que eu aprendi alguma coisa desde então :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-7770571111477333421?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/07/eu-podia-estar-roubando.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-2158992859861495050</guid><pubDate>Tue, 24 Jun 2008 02:37:00 +0000</pubDate><atom:updated>2008-06-24T09:25:52.092-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>cpp</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>livros</category><category domain='http://www.blogger.com/atom/ns#'>complexidade</category><title>Como aprender computação</title><description>Dia desses o &lt;a href="http://lameiro.wordpress.com/"&gt;Lameiro&lt;/a&gt; me passou uma &lt;a href="http://blog.fragmental.com.br/2008/05/20/trilha-de-livros-desenvolvedor/"&gt;lista de livros para desenvolvedores&lt;/a&gt;, e eu achei a lista bastante curiosa. Se eu fosse criar uma similar, eu não colocaria nenhum dos livros citados naquela lista! Ao invés disso, a minha lista com os top 10 livros de computação seria a abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/livros-716370.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/livros-716366.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;1 - &lt;a href="http://books.google.com/books?id=aFcsnUEewLkC&amp;amp;dq=godel+escher+bach&amp;amp;ei=6m1gSMGPIYHAigHU0fmXDA"&gt;Gödel, Escher, Bach&lt;/a&gt; (Hofstadter): Eu começaria com o GEB, por dois motivos. O primeiro é que ele é um ótimo reality check: se você não gostar do GEB, então mude de área, porque computação não é a sua praia :) O segundo motivo é que esse livro tem uma excelente introdução à lógica (&lt;a href="http://en.wikipedia.org/wiki/Propositional_logic"&gt;proposicional&lt;/a&gt; e &lt;a href="http://en.wikipedia.org/wiki/First-order_logic"&gt;de predicados&lt;/a&gt;), que é a ferramenta básica onde você constrói a ciência da computação.&lt;br /&gt;&lt;br /&gt;2 - &lt;a href="http://books.google.com/books?id=pntQAAAAMAAJ&amp;amp;q=concrete+mathematics&amp;amp;dq=concrete+mathematics&amp;amp;source=gbs_book_other_versions_r&amp;amp;cad=2_0&amp;amp;pgis=1"&gt;Concrete Mathematics&lt;/a&gt; (Knuth): Você não precisa saber matemática para programar, mas se você quiser ser um &lt;span style="font-style: italic;"&gt;bom&lt;/span&gt; programador, então matemática é essencial. O Concrete tem todo o básico que você precisa pra fazer análises de complexidade computacional, e tudo escrito de maneira extremamente bem-humorada.&lt;br /&gt;&lt;br /&gt;3 - &lt;a href="http://books.google.com/books?id=zMEBAAAACAAJ&amp;amp;dq=algorithms+in+c%2B%2B&amp;amp;ei=xXNgSLn4Aoa4jgG-lLGJDA"&gt;Algorithms in C++&lt;/a&gt; (Sedgewick): Se você já sabe lógica e matemática, então agora pode partir pro estudo de algoritmos. O Sedgewick tem todos os algoritmos básicos, e é uma leitura bem leve: se você está começando com algoritmos agora, esse precisa ser o seu primeiro livro. Ele não vai muito fundo em nenhum tópico, mas isso é compensado pela extrema didática nos tópicos. O livro ainda tem código exemplo pra todos os algoritmos, e várias edições, uma pra cada linguagem (eu sei que tem, pelo menos, C, C++, Java e Pascal).&lt;br /&gt;&lt;br /&gt;4 - &lt;a href="http://books.google.com/books?id=NLngYyWFl_YC&amp;amp;dq=introduction+to+algorithms&amp;amp;source=gbs_summary_s&amp;amp;cad=0"&gt;Introduction to Algorithms&lt;/a&gt; (Cormen): Os algoritmos que você aprendeu no Sedgewick, você vai estudar em detalhes no Cormen. Esse livro é extremamente formal, e talvez por isso é o livro-texto usado nos cursos de computaçao do &lt;a href="http://web.mit.edu/"&gt;MIT&lt;/a&gt;. Ele também cobre algoritmos mais avançados, que o Sedgewick apenas cita (por exemplo, &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_heap"&gt;Fibonacci Heap&lt;/a&gt;)&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;5 - &lt;a href="http://books.google.com/books?id=QDh9AAAACAAJ&amp;amp;dq=art+of+computer+programming&amp;amp;source=gbs_book_other_versions_r&amp;amp;cad=0_2"&gt;The &lt;/a&gt;&lt;a href="http://books.google.com/books?id=QDh9AAAACAAJ&amp;amp;dq=art+of+computer+programming&amp;amp;source=gbs_book_other_versions_r&amp;amp;cad=0_2"&gt;Art&lt;/a&gt;&lt;a href="http://books.google.com/books?id=QDh9AAAACAAJ&amp;amp;dq=art+of+computer+programming&amp;amp;source=gbs_book_other_versions_r&amp;amp;cad=0_2"&gt; of Computer Programming&lt;/a&gt; (Knuth): O tAoCP está para o Cormen assim como o Cormen está pro Segdewick, aqui você vai dissecar os algoritmos até o último bit deles. Além de ser uma coleção excelente, a encadernação é muito bonita (mas não se engane, ele fica ótimo na prateleira, mas melhor ainda na sua cabeça).&lt;br /&gt;&lt;br /&gt;6 - &lt;a href="http://books.google.com/books?id=QLsqAAAACAAJ&amp;amp;dq=effective+C%2B%2B&amp;amp;ei=VnZgSPjDNabQigG90fSLDA"&gt;Effective C++&lt;/a&gt; (Meyers): Agora que você sabe os algoritmos, precisa de uma linguagem para programá-los. Pra falar a verdade, a escolha de linguagem nem importa tanto assim, mas se você escolher uma, aprenda-a tão bem quanto possível. Eu escolhi C++, e esse livro do Meyers é o que diferencia as crianças dos adultos (especialmente para aquelas horas quando você cria uma classe sem destrutor virtual e não sabe por que a memória está vazando).&lt;br /&gt;&lt;br /&gt;7 - &lt;a href="http://books.google.com/books?id=h2vbDpVhTCAC&amp;amp;q=effective+stl&amp;amp;dq=effective+stl&amp;amp;ei=ZXdgSOvCBI2ujAHwl_ioBA&amp;amp;pgis=1"&gt;Effective STL&lt;/a&gt; (Meyers): Já teve uma época em que eu não gostava de C++, mas isso é porque eu sou velho o suficiente pra ter mexido em C++ antes que os compiladores tivessem templates. Com templates a linguagem fica muito mais atraente, e esse é o livro que vai te ensinar a dominar a &lt;a href="http://www.sgi.com/tech/stl/stl_introduction.html"&gt;STL&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;8 - &lt;a href="http://books.google.com/books?id=to6M9_dbjosC&amp;amp;dq=practice+of+programming&amp;amp;source=gbs_summary_s&amp;amp;cad=0"&gt;The Practice of Programming&lt;/a&gt; (Kernighan, Pike): Se você leu tudo até agora, então você já é um programador muito bom na teoria. Na prática, entretanto, tem um monte de skills que ainda faltam. Nesse livro você aprende sobre as coisas que usualmente não se aprende na escola: debugging, otimização, unit testing, documentação.&lt;br /&gt;&lt;br /&gt;9 - &lt;a href="http://books.google.com/books?id=kse_7qbWbjsC&amp;amp;dq=programming+pearls&amp;amp;source=gbs_summary_s&amp;amp;cad=0"&gt;Programming Pearls&lt;/a&gt; (Bentley): Com os livros lidos até agora, você já deve ser um excelente programador. O passo final é passar de programador para um true hacker, e esse é um passo que não requer só conhecimento, você também precisa de manha, criatividade e insight. Eu não sei se dá pra ensinar essas coisas, mas esse livro certamente é o que chega mais próximo disso.&lt;br /&gt;&lt;br /&gt;10 - &lt;a href="http://books.google.com/books?id=K47ZAAAACAAJ&amp;amp;dq=mythical+man-month&amp;amp;ei=YH9gSNr_BZiijgGHrYCODA"&gt;The Mythical Man-Month&lt;/a&gt; (Brooks): Depois de ler todos os livros acima você estará próximo do nirvana, mas pra atingir o zen da programação de verdade, é preciso lembrar que projetos não precisam só de computadores, precisam de pessoas também. O Mythical Man-Month é um livro de gerência de projetos de software escrito em 1975, mas é surpreendente como ele continua atual. A tecnologia avança, mas as pessoas continuam as mesmas :)&lt;br /&gt;&lt;br /&gt;É claro que pra manter uma lista com só dez itens, muita coisa boa fica de fora. Mas a lista acima tem um mérito: foi com esses livros que eu aprendi computação de verdade (vale lembrar que eu sou autodidata, minha graduação foi em engenharia elétrica, e eu quase não tive computação em aulas). Se funcionou pra mim, pode ser que funcione pra você também :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-2158992859861495050?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/06/como-aprender-computao.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>16</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-2094645274186264547</guid><pubDate>Wed, 18 Jun 2008 03:02:00 +0000</pubDate><atom:updated>2008-06-18T03:24:08.867-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>retro</category><category domain='http://www.blogger.com/atom/ns#'>puzzle</category><category domain='http://www.blogger.com/atom/ns#'>monte carlo</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>complexidade</category><title>Um cientista em minha vida</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/cientvida-733243.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/cientvida-733241.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Eu li lá no &lt;a href="http://100nexos.com/arquivo/608"&gt;blog do Kentaro&lt;/a&gt; que o meme da semana era "Um Cientista em minha vida", onde deveríamos falar sobre algum cientista que fez a diferença pra você. Como eu adoro &lt;a href="http://en.wikipedia.org/wiki/Constrained_writing"&gt;constrained writing&lt;/a&gt;, resolvi participar (na verdade, eu adoro constrained anything, por isso que vivo criando programas em uma linha, programas que rodam em computadores de 8 bits, e assim por diante).&lt;br /&gt;&lt;br /&gt;Eu já falo de cientistas aqui todo o tempo. Olhando no histórico, eu já falei do &lt;a href="http://www.ricbit.com/2008/04/domino-dancing.html"&gt;Knuth&lt;/a&gt;, do &lt;a href="http://www.ricbit.com/2008/04/erds-e-os-logaritmos.html"&gt;Erdös&lt;/a&gt;, do &lt;a href="http://www.ricbit.com/2008/04/meta-assinatura.html"&gt;prof. Routo&lt;/a&gt;, do &lt;a href="http://www.ricbit.com/2008/05/ao-infinito-e-alm.html"&gt;prof. Henrique&lt;/a&gt;, e de vários outros. Em comum, todos eles foram cientistas que eu conheci depois de adulto. Achei apropriado então que eu falasse de um cientista que fez a diferença quando eu era criança, e pra isso vamos ter que rebobinar até a década de 80.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/microhobby-723153.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/microhobby-723151.gif" alt="" border="0" /&gt;&lt;/a&gt;Se você perguntar pra alguém sobre revistas de computador na década de 80, invariavelmente irá ouvir sobre a &lt;a href="http://www.tilt.net/wiki/index.php/Micro_Sistemas"&gt;Micro Sistemas&lt;/a&gt; ("a primeira revista brasileira sobre microcomputadores"). A Micro Sistemas era muito legal, mas o que eu gostava mesmo era de outra revista, menos conhecida, chamada Microhobby.&lt;br /&gt;&lt;br /&gt;A diferença da Micro Sistemas pra Microhobby era mais ou menos a diferença de Informática pra Computação. Na primeira, nós ficávamos encantados com as notícias da maravilhosa terra além da &lt;a href="http://pt.wikipedia.org/wiki/Pol%C3%ADtica_Nacional_de_Inform%C3%A1tica"&gt;reserva de mercado&lt;/a&gt; (onde aprendíamos que a Apple planejava lançar um novo computador chamado &lt;a href="http://en.wikipedia.org/wiki/McIntosh"&gt;McIntosh&lt;/a&gt;, que vinha com um periférico estranho e esquisito chamado &lt;a href="http://en.wikipedia.org/wiki/Computer_mouse"&gt;mouse&lt;/a&gt;), enquanto que na segunda aprendíamos a calcular &lt;a href="http://en.wikipedia.org/wiki/Geodesic"&gt;geodésicas&lt;/a&gt; e a usar o &lt;a href="http://en.wikipedia.org/wiki/Bisection_method"&gt;método de Bolzano&lt;/a&gt; para achar raízes de uma equação.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/RenatodaSilvaOliveira2-792075.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/RenatodaSilvaOliveira2-792072.JPG" alt="" border="0" /&gt;&lt;/a&gt;Mas o diferencial mesmo da Microhobby eram as colunas escritas pelo Renato da Silva Oliveira. Uma googlada rápida revela que o Renato é formado em Física, trabalhou nos planetários de São Paulo, Campinas, Vitória e Tatuí, e atualmente trabalha em uma empresa que vende &lt;a href="http://www.asterdomus.com.br/AsterDomus_0.htm"&gt;planetários infláveis&lt;/a&gt; (how cool is that?!). Mas é claro que eu não sabia disso na época, o que eu sabia era que ele contava historinhas!&lt;br /&gt;&lt;br /&gt;Foi lendo as historinhas do Renato que eu descobri que era possível escrever sobre ciência e computação, com clareza e bom humor. Pena que isso ainda não é muito difundido, a julgar pela quantidade de crianças que ainda acham que ciência é uma coisa chata :(&lt;br /&gt;&lt;br /&gt;As historinhas que ele escrevia sempre tinham o mesmo formato: um certo sr. Nabor Rosenthal, em suas viagens pelo mundo, deparava-se com alguma situação que sugeria uma análise matemática (os tópicos eram os mais variados e iam de &lt;a href="http://en.wikipedia.org/wiki/Graph_theory"&gt;teoria dos grafos&lt;/a&gt; até &lt;a href="http://en.wikipedia.org/wiki/Arecibo_Observatory"&gt;contatos com extraterrestres&lt;/a&gt;). Depois de ponderar sobre o problema sem conseguir resolvê-lo, o Nabor tomava uma dose do raro &lt;a href="http://en.wikipedia.org/wiki/Srinivasa_Ramanujan"&gt;Suco de Ramanujan&lt;/a&gt;, que o colocava num transe que ampliava suas capacidades analíticas, e conseguia solucionar o problema.&lt;br /&gt;&lt;br /&gt;Mas a coluna sempre acabava antes que o Nabor mostrasse qual a solução! Ao invés disso, o leitor tinha um mês pra conseguir resolver o problema, e só no mês seguinte a solução era apresentada. Na década de 80 ainda não tinha &lt;a href="http://www.spoj.pl/"&gt;spoj&lt;/a&gt;, então as colunas do Renato eram o que bombava pra quem gostava de puzzles computacionais.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/tk82c_ps_1g-793058.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/tk82c_ps_1g-793050.jpg" alt="" border="0" /&gt;&lt;/a&gt;Um dos puzzles apresentados foi o segundo puzzle mais difícil da minha vida, eu levei mais de dez anos pra conseguir resolver. Em uma das Microhobby, o Nabor entrou em transe após tomar o Suco de Ramanujan, e durante o transe ele sonhou "com um método para calcular o número pi, usando apenas o gerador de números aleatórios de seu micro" (essa era a época onde o micro mais avançado era o &lt;a href="http://pt.wikipedia.org/wiki/TK82C"&gt;TK-82C&lt;/a&gt;, com 2kb de RAM).&lt;br /&gt;&lt;br /&gt;Na época eu pensei muito e não consegui solucionar, achando que ia precisar de alguma matemática que eu ainda não tinha aprendido. Eu nunca consegui achar a revista seguinte com a solução, tive que passar pelo primário, pelo colégio técnico, e só no meio da faculdade é que caiu a ficha (e eu percebi que poderia ter solucionado ainda no primário, se tivesse insistido o suficiente :)&lt;br /&gt;&lt;br /&gt;O truque é o seguinte: você vai fazer N experimentos, cada um consistindo no sorteio de dois números aleatórios escolhidos uniformemente entre 0 e 1. Se soma dos quadrados dos números for menor ou igual a 1, incremente um contador (digamos, M). Ao final dos experimentos, pi=4*M/N. O script abaixo implementa esse algoritmo:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/pi.py"&gt;Script em python para calcular pi usando números aleatórios&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/circle-768800.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/circle-768786.png" alt="" border="0" /&gt;&lt;/a&gt;O funcionamento é bem simples e baseia-se na figura ao lado. Você começa inscrevendo um quarto de círculo num quadrado de lado 1. Os dois números que você sorteia a cada iteração podem ser interpretados como um ponto dentro do quadrado, e o teste feito é equivalente a testar se o ponto está dentro do círculo ou não. Como a distribuição dos pontos é uniforme, espera-se que a razão M/N seja igual à razão entre as áreas da figura. A área do quadrado é 1, a área do círculo é pi*r&lt;sup&gt;2&lt;/sup&gt;. Como o raio é unitário, então a área do quarto de círculo é pi/4. Isolando pi, chega-se em pi=4*M/N, QED.&lt;br /&gt;&lt;br /&gt;A pergunta que deve ser feita ao encontrar qualquer algoritmo novo é: qual é sua complexidade? Infelizmente, esse método aleatório é bem ruim. No fundo, o que estamos fazendo é aproximar pi por uma fração, cujo denominador é N. Então a precisão máxima que podemos obter é 1/N, e se você quer calcular n dígitos de pi, esse método converge, no melhor caso, em O(10&lt;sup&gt;n&lt;/sup&gt;), e na prática em bem menos que isso, porque os seus geradores de números aleatórios não são perfeitamente uniformes.&lt;br /&gt;&lt;br /&gt;Eu nunca soube qual o método que o Nabor usou pra calcular o pi. Como ele tinha o Suco de Ramanujan e eu não, espero que tenha sido um método melhor que o meu :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-2094645274186264547?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/06/um-cientista-em-minha-vida.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>17</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-843067646841264017</guid><pubDate>Wed, 11 Jun 2008 05:16:00 +0000</pubDate><atom:updated>2008-06-14T01:58:49.232-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>fibonacci</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>binário</category><title>Programa de milhagem</title><description>Olhando no &lt;a href="http://www.google.com/analytics/"&gt;Google Analytics&lt;/a&gt;, eu descobri que alguém chegou aqui no blog procurando por "transformar kilometros em arquivo binarios". Se você é essa pessoa, desculpe, mas eu não entendi sua dúvida. Se você não é essa pessoa, puxe uma cadeira pra ver como até uma pergunta sem sentido pode ser desenvolvida num tema interessante :)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/63miles-762587.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/63miles-762582.jpg" alt="" border="0" /&gt;&lt;/a&gt;Uma coisa que me incomoda toda vez que venho pra Califórnia é ter que lidar com milhas e libras. Eu cresci com o sistema métrico: se você me disser que a distância de São Paulo pra Florianópolis é de 700km, eu sei o que isso significa. Agora, se você me disser que a distância de San Francisco pra Mountain View é de 100 milhas, minha intuição falha, e eu vou precisar converter pra km pra poder ter noção da distância.&lt;br /&gt;&lt;br /&gt;Como esperado, converter mentalmente de milhas pra km é algo que faço todo o tempo por aqui. Existem várias maneiras de converter de cabeça, mas a filosofia Ricbit dita que, de várias maneiras equivalentes, o correto é escolher a mais bizarra! Sendo assim, vou mostrar a conversão utilizando números de Fibonacci.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/rabbit-764600.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/rabbit-764598.jpg" alt="" border="0" /&gt;&lt;/a&gt;Todo mundo conhece os números de Fibonacci, eles estão em todo lugar. Em minha época de estudante, uma das minhas diversões secretas era entrar escondido no andar superior da biblioteca do &lt;a href="http://www.ime.usp.br/"&gt;IME&lt;/a&gt; só pra ler a &lt;a href="http://www.engineering.sdstate.edu/%7Efib/"&gt;Fibonacci Quartely&lt;/a&gt;. Os leitores assíduos da revista conhecem um monte de fatos curiosos sobre os Fibonacci, e eu vou usar dois deles aqui.&lt;br /&gt;&lt;br /&gt;O primeiro é que os números da seqüência de Fibonacci podem ser calculados diretamente, sem precisar fazer toda a recursão F(n+2)=F(n+1)+F(n). Pra isso, basta calcular qual o inteiro mais próximo da expressão abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/formula_fn-736484.png"&gt;&lt;img style="border:0; margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/formula_fn-736482.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Na expressão acima, o phi é a conhecida &lt;a href="http://en.wikipedia.org/wiki/Golden_ratio"&gt;razão áurea&lt;/a&gt;. A demostração dessa fórmula é elementar e &lt;a href="http://everything2.com/node/1882510"&gt;fácil de encontrar na web&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;O segundo é que qualquer número pode ser escrito como uma soma de números distintos de Fibonacci. Por exemplo, 100 pode escrito como 89+8+3. Daí, se você enfileirar os números de Fibonacci, e atribuir a cada número 1 se ele é usado na soma, e 0 se não é, você pode atribuir a qualquer inteiro uma string de zeros e uns que funciona como uma espécie de base binária alternativa (o povo chama isso de base de Fibonacci).&lt;br /&gt;&lt;br /&gt;Fazendo o processo com o número 100, chegamos em 10000101000. Essa base tem algumas propriedades curiosas, por exemplo, ela não é bijetora (de fato, você pode escrever 100 de outras maneiras, como 1100101000). Uma base numérica que tem representação múltipla tem utilidades bastante curiosas em design de circuitos elétricos (mas isso é uma história pra outro dia :).&lt;br /&gt;&lt;br /&gt;Além disso, cada número possui pelo menos uma representação onde não há nenhuma seqüência com dois uns consecutivos (pela própria definição de Fibonacci, se houver dois uns em algum ponto, você pode apagá-los e trocar por um único 1 na posição seguinte). Esse fato é explorado em alguns tipos de &lt;a href="http://en.wikipedia.org/wiki/Signalling_%28telecommunications%29"&gt;sinalização&lt;/a&gt;, para fazer detecção de erro: se você receber dois uns seguidos, certamente recebeu um erro.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/shifted_20031219-799054.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/shifted_20031219-799030.jpg" alt="" border="0" /&gt;&lt;/a&gt;Mas qual a relação disso com milhas e quilômetros? É simples, para converter de milhas para km, basta fazer um shift de Fibonacci!&lt;br /&gt;&lt;br /&gt;Uma milha equivale a 1.609344 km. A razão áurea é 1.61803399. Os dois números, apesar de não serem relacionados, são muito parecidos, e esse é o truque que vamos usar pra converter. Na base binária tradicional, um shift para a esquerda é equivalente a multiplicar por dois; na base de Fibonacci, um shift para a esquerda equivale a multiplicar pela razão áurea. Então, se você tiver um valor em milhas na base de Fibonacci, um shift irá transformar o valor para o equivalente em quilômetros.&lt;br /&gt;&lt;br /&gt;Vamos conferir: 100 é 10000101000. Com um zero extra no final, fica 100001010000, que é 144+13+5=162. Se, ao invés disso, você converter diretamente, teria 160.9km, ou seja, o método realmente aproxima muito bem a conversão! O gráfico abaixo mostra a porcentagem do erro do método em relação ao ideal, e mais abaixo está o programa que converte a milhagem para quilometragem e gera o gráfico:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/miles_error-777211.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/miles_error-777209.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.ricbit.com/code/miles.py"&gt;Script que plota o gráfico acima, em python&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Como pode ser visto, o método esquenta bem rápido, pra distâncias superiores a 10 milhas o erro é inferior a 5%, e acima disso praticamente desaparece. Em comparação, o método naive de aproximar por 1.5 (multiplicar de cabeça por 3 e dividir por 2), tem um erro constante de mais ou menos 8%.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-843067646841264017?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/06/programa-de-milhagem.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>13</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-7742008920512121026</guid><pubDate>Sat, 07 Jun 2008 18:01:00 +0000</pubDate><atom:updated>2008-06-16T20:44:06.632-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>monte carlo</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>cpp</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>complexidade</category><category domain='http://www.blogger.com/atom/ns#'>criptologia</category><title>Primos aleatórios</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/4470_primocruzado-724523.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/4470_primocruzado-724521.jpg" alt="" border="0" /&gt;&lt;/a&gt;Dia desses a &lt;a href="http://www1.folha.uol.com.br/folha/galeria/album/p_20070726-bichos06.shtml"&gt;Alice&lt;/a&gt; me perguntou se era possível criar um gerador de números aleatórios que só retornasse números primos. Eu respondi que sim, mas que provavelmente ela não iria gostar da resposta:&lt;br /&gt;&lt;pre&gt;int&amp;nbsp;random_prime(int&amp;nbsp;n)&amp;nbsp;{&lt;br&gt;&amp;nbsp;int&amp;nbsp;x;&lt;br&gt;&amp;nbsp;do&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;x&amp;nbsp;=&amp;nbsp;random(n);&lt;br&gt;&amp;nbsp;}&amp;nbsp;while&amp;nbsp;(!is_prime(x));&lt;br&gt;&amp;nbsp;return&amp;nbsp;x;&lt;br&gt;}&lt;/pre&gt;&lt;br /&gt;Eu sabia que o que ela queria na verdade era uma fórmula bonitinha; então, como esperado, ela não gostou :) Mas a verdade é que esse algoritmo é bem melhor que as alternativas!&lt;br /&gt;&lt;br /&gt;Antes de mostrar porque isso é verdade, precisamos formalizar um pouco o problema. É claro que não existem algoritmos que geram números aleatórios: se você quiser aleatoriedade real, precisa pegar alguma fonte física, como o &lt;a href="http://en.wikipedia.org/wiki/Radioactivity"&gt;decaimento radiativo&lt;/a&gt;. Assumindo então que existe uma fonte física que gera uma &lt;a href="http://en.wikipedia.org/wiki/Uniform_distribution_%28discrete%29"&gt;distribuiçao uniforme&lt;/a&gt; sobre algum intervalo, para criar o algoritmo que retorna números primos aleatórios, basta criar uma&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Injective_function"&gt;&lt;/a&gt; função bijetora que leve naturais para primos. Ou seja, uma função que, para um dado um número n, retorne o n-ésimo primo.&lt;br /&gt;&lt;br /&gt;O problema é que não existe nenhuma &lt;a href="http://en.wikipedia.org/wiki/Closed-form_expression"&gt;fórmula fechada&lt;/a&gt; que calcule isso de maneira eficiente. Você pode calcular alguma constante irracional que resolva o problema, no estilo da &lt;a href="http://mathworld.wolfram.com/MillsTheorem.html"&gt;constante de Mills&lt;/a&gt;, só que mais cedo ou mais tarde a precisão vai te limitar. Você pode calcular o n-ésimo primo com base em alguma outra distribuição, como a &lt;a href="http://en.wikipedia.org/wiki/M%C3%B6bius_function"&gt;função de Möbius&lt;/a&gt;, mas aí você só está empurrando o problema com a barriga, porque a outra função é tão difícil de calcular quanto a original.&lt;br /&gt;&lt;br /&gt;Uma maneira sem as desvantagens acima é usar o &lt;a href="http://mathworld.wolfram.com/WilsonsTheorem.html"&gt;teorema de Wilson&lt;/a&gt; pra chegar na seguinte fórmula:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/mathtran-765097.png"&gt;&lt;br /&gt;&lt;img style="display:block; border:0; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.ricbit.com/uploaded_images/mathtran-765088.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/dukenukem-706042.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/dukenukem-706029.jpg" alt="" border="0" /&gt;&lt;/a&gt;Mas mesmo essa fórmula ainda está longe do ideal, primeiro porque você vai ter que lidar com números enormes nela (pra n=10 os valores intermediários ficam tão grandes que estouram o limite do que cabe num float), segundo porque, mesmo que você use uma lib para long floats, a complexidade é O(2&lt;sup&gt;n&lt;/sup&gt;), ou seja, mais lento que os programadores do Duke Nukem Forever. Se ainda assim você quiser testar, minha implementação em python é a abaixo:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/nth_prime.py"&gt;Implementação em python da fórmula acima&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sendo assim, quão melhor era a implementação original por tentativa e erro? Pra avaliar isso, precisamos calcular a complexidade daquele algoritmo. Não é difícil ver que a complexidade do algoritmo como um todo é a complexidade do is_prime() multiplicado pelo &lt;a href="http://mathworld.wolfram.com/ExpectationValue.html"&gt;valor esperado&lt;/a&gt; do número de iterações do loop.&lt;br /&gt;&lt;br /&gt;Se você estiver trabalhando numa faixa pequena de primos, pode tabelar todos os primos no intervalo e fazer um is_prime() que seja O(1), mas aí também não tem necessidade da tentativa e erro, você pode indexar seu número aleatório direto na tabela. O caso legal é quando você não pode tabelar, nesse caso você pode implementar o is_prime() usando, por exemplo, o &lt;a href="http://en.wikipedia.org/wiki/AKS_primality_test"&gt;algoritmo AKS&lt;/a&gt;, cuja complexidade é O((log n)&lt;sup&gt;10.5&lt;/sup&gt;).&lt;br /&gt;&lt;br /&gt;O que resta então é calcular o valor esperado do loop. Lembrando que E[x]=sum(x*p(x)), o que precisamos é calcular qual é a probabilidade de ter uma iteração, duas iterações, e assim por diante. Ora, o &lt;a href="http://en.wikipedia.org/wiki/Prime_number_theorem"&gt;teorema dos números primos&lt;/a&gt; nos garante que a quantidade de números primos menores que n é assintoticamente igual a n/log(n), então a chance de um número ser primo, num conjunto com n elementos, é 1/log(n). Vamos chamar isso de "p" só pra ficar mais fácil, e o complemento disso é q=1-p, ou seja, a chance de um número não ser primo.&lt;br /&gt;&lt;br /&gt;Vejamos então: pra você acertar o primo de primeira, a chance é p. Se você acertar o primo na segunda, a chance é pq. Na terceira, é pq&lt;sup&gt;2&lt;/sup&gt;, na quarta pq&lt;sup&gt;3&lt;/sup&gt; e assim por diante. Então o valor esperado é:&lt;br /&gt;&lt;br /&gt;X = 1p + 2pq + 3pq&lt;sup&gt;2&lt;/sup&gt; + 4pq&lt;sup&gt;3&lt;/sup&gt; + ...&lt;br /&gt;X = p (1 + 2q + 3q&lt;sup&gt;2&lt;/sup&gt; + 4q&lt;sup&gt;3&lt;/sup&gt; + ....)&lt;br /&gt;&lt;br /&gt;Quem tem prática com a &lt;a href="http://en.wikipedia.org/wiki/Z_transform"&gt;transformada z&lt;/a&gt; sabe calcular isso de cabeça, mas dá pra calcular também só com matemática elementar. Se você isolar q na soma, fica com:&lt;br /&gt;&lt;br /&gt;X = p (1 + q(2 + 3q + 4q&lt;sup&gt;2&lt;/sup&gt; + ....))&lt;br /&gt;&lt;br /&gt;Agora você tira da cartola y=1+q+q&lt;sup&gt;2&lt;/sup&gt;+q&lt;sup&gt;3&lt;/sup&gt;+... e substitui:&lt;br /&gt;&lt;br /&gt;X = p (1 + q(2 + 3q + 4q&lt;sup&gt;2&lt;/sup&gt; + ....))&lt;br /&gt;X = p (1 + q(y + 1 + 2q + 3q&lt;sup&gt;2&lt;/sup&gt; + ....))&lt;br /&gt;X = p (1 + q(y + X/p)) = p + pqy + pXq/p = p(1+qy) + Xq&lt;br /&gt;X - Xq = p (1 + qy)&lt;br /&gt;X (1-q) = Xp = p (1 + qy)&lt;br /&gt;X = 1 + qy&lt;br /&gt;&lt;br /&gt;Mas y é só a soma de uma PG, e isso nós sabemos que vale y=1/(1-q)=1/p. Então:&lt;br /&gt;&lt;br /&gt;X = 1 + q/p = (p+q)/p = 1/p&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/ipod-729482.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/ipod-729480.jpg" alt="" border="0" /&gt;&lt;/a&gt;Como p=1/log(n), então o valor esperado que nós queríamos é tão somente X=log n (vocês também não se impressionam quando tudo simplifica no final?)&lt;br /&gt;&lt;br /&gt;É claro que eu não iria resistir à tentação de implementar uma simulação pra ver se o valor bate mesmo. A nossa fórmula diz que, para a faixa de 10 milhões de números, o valor esperado tem que ser da ordem de log(10&lt;sup&gt;7&lt;/sup&gt;)=16.1. A simulação abaixo retorna 15.2, bem próximo do valor que foi predito.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/random_prime.cc"&gt;Simulação monte carlo do valor esperado, em C++&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;No fim das contas, a complexidade do algoritmo com tentativa e erro é apenas O(log n), se você tiver um tabelão de primos. Na prática, esse é o método usado por todos que precisam de primos aleatórios: a libgcrypt usada no &lt;a href="http://www.gnupg.org/"&gt;gpg&lt;/a&gt;, por exemplo, utiliza esse método na função &lt;a href="http://www.google.com/codesearch?hl=en&amp;amp;q=libgcrypt+primegen.c+gen_prime+show:MdtcelzX8ZM:j1akSRNJFcg:nQDKjtoXTC4&amp;amp;sa=N&amp;amp;cd=1&amp;amp;ct=rc&amp;amp;cs_p=ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/libgcrypt-1.1.44.tar.gz&amp;amp;cs_f=libgcrypt-1.1.44/cipher/primegen.c"&gt;gen_prime()&lt;/a&gt;, com vários truques pra tornar o teste de primalidade bem rápido.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-7742008920512121026?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/06/primos-aleatrios.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-4746562879956897494</guid><pubDate>Thu, 05 Jun 2008 09:40:00 +0000</pubDate><atom:updated>2008-06-13T21:47:20.655-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>infinito</category><category domain='http://www.blogger.com/atom/ns#'>math</category><category domain='http://www.blogger.com/atom/ns#'>binário</category><title>Aproximações</title><description>Ao longo da vida, encontramos aproximações a todo momento. Na escola, a gravidade é aproximadamente 10 m/s&lt;sup&gt;2&lt;/sup&gt;, e a velocidade da luz é aproximadamente 3x10&lt;sup&gt;8&lt;/sup&gt; m/s. Segundo a Bíblia, pi é aproximadamente três (&lt;a href="http://www.bibliaonline.net/bol/?acao=por_verso&amp;amp;livro=11&amp;amp;capitulo=7-7&amp;amp;versiculo=&amp;amp;versao=1&amp;amp;grupos=&amp;amp;agrupar=&amp;amp;link=bol&amp;amp;cab=1&amp;amp;pag_ini=20&amp;amp;lang=BR"&gt;1 Reis 7:23&lt;/a&gt;). Mas a minha aproximação predileta é uma que os computeiros usam a todo momento: infinito é aproximadamente oito!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/inf8-754160.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/inf8-754158.png" alt="" border="0" /&gt;&lt;/a&gt;De fato, essa aproximação é o que permite aos computadores trabalhar com números negativos, através do &lt;a href="http://en.wikipedia.org/wiki/Two%27s_complement"&gt;complemento de dois&lt;/a&gt;. Lembrando a regra, para calcular o oposto de um número qualquer, basta inverter os bits e somar um. Vamos ver na prática como isso funciona, calculando o oposto de 5.&lt;br /&gt;&lt;br /&gt;Cinco em binário é 101b, e pode ser escrito também como uma soma de potências de dois: 1+4. Para inverter os bits de 5, precisamos lembrar que há infinitos zeros na frente do 101b, então o inverso vai ter infinitas potências de dois:&lt;br /&gt;&lt;pre&gt; x   = 1     + 4&lt;br /&gt;~x   =     2     + 8 + 16 + 32 + ...&lt;br /&gt;~x+1 = 1 + 2     + 8 + 16 + 32 + ...&lt;/pre&gt;&lt;br /&gt;Esse valor, y=~x+1, não se parece com -5. Mas as coisas ficam mais claras se você multiplicar y por dois, parcela a parcela, ...&lt;br /&gt;&lt;pre&gt; y   = 1 + 2     + 8 + 16 + 32 + ...&lt;br /&gt;2y   =     2 + 4     + 16 + 32 + ...&lt;/pre&gt;&lt;br /&gt;... e depois subtrair esse valor do original:&lt;br /&gt;&lt;pre&gt;2y   =      2 + 4     + 16 + 32 + ...&lt;br /&gt; y   =  1 + 2     + 8 + 16 + 32 + ...&lt;br /&gt;2y-y = -1     + 4 - 8&lt;br /&gt; y   = -5&lt;/pre&gt;&lt;br /&gt;Todos as parcelas maiores que 16 cancelam, e do lado de cá, 2y menos y é o próprio y. Então y=-5, QED. Quando calculamos complementos de dois no computador, usualmente fazemos as contas apenas em um byte, mas, no fundo, é a mesma coisa: ao invés de fazer a conta com infinitas parcelas, você aproxima o valor por apenas 8 parcelas.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/escher-lego-744162.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/escher-lego-744117.jpg" alt="" border="0" /&gt;&lt;/a&gt;Seu professor de Cálculo 4 certamente deve ter te avisado dos horrores de manipular &lt;a href="http://en.wikipedia.org/wiki/Divergent_series"&gt;seqüências divergentes&lt;/a&gt;, que invariavelmente levam a paradoxos (como somar apenas parcelas positivas e obter um resultado negativo). No entanto, às vezes até os paradoxos têm utilidades práticas :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-4746562879956897494?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/06/aproximaes.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6306509703738480474.post-8407015952004932743</guid><pubDate>Fri, 30 May 2008 02:42:00 +0000</pubDate><atom:updated>2008-05-30T11:53:52.713-03:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>programação funcional</category><category domain='http://www.blogger.com/atom/ns#'>infinito</category><category domain='http://www.blogger.com/atom/ns#'>python</category><category domain='http://www.blogger.com/atom/ns#'>code</category><category domain='http://www.blogger.com/atom/ns#'>linguagens bizarras</category><title>Python one-liners são Turing-complete</title><description>Quem programa em C há décadas normalmente não se dá conta de quão ilegíveis são as expressões mais comuns da linguagem. Quando eu era um garoto recém-saído do BASIC, eu lembro de ter me assustado com coisas básicas como for(i=0; i&amp;lt;10; i++). Mas isso é idiossincrasia do C, outras linguagens não sofrem disso, como o Python.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/jeff_goldblum-791685.jpg" alt="" border="0" /&gt;Python foi planejada para ser legível. Os programadores mais experientes citam o &lt;a href="http://www.python.org/dev/peps/pep-0020/"&gt;Zen of Python&lt;/a&gt;, que dita que "belo é melhor que feio", e "legibilidade conta". De fato, é até difícil escrever código ilegível em Python. Mas é claro que difícil não é impossível, e se o dr. Ian Malcolm fosse um programador, ele certamente diria que "&lt;span style="font-style: italic;"&gt;obfuscation finds a way&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;Aconteceu comigo semana passada: eu olhava alguns &lt;a href="http://www.pythonbrasil.com.br/moin.cgi/Exerc%C3%ADciosComListas"&gt;exercícios sobre listas&lt;/a&gt; para iniciantes, e notei que, embora eles fossem de fato muito simples, ficariam bem mais divertidos se eu tentasse resolvê-los usando apenas uma linha em cada. Abusando de &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;programação funcional&lt;/a&gt;, eu consegui fazer os dez primeiros assim:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/oneliners.py"&gt;Soluções dos exercícios em uma linha de Python cada.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Depois de brincar algum tempo com one-liners, a pergunta que naturalmente se apresenta é: será que é possível fazer &lt;span style="font-style: italic;"&gt;qualquer&lt;/span&gt; programa em uma linha de Python? A dificuldade vem do fato de que o Python diferencia &lt;a href="http://infohost.nmt.edu/tcc/help/pubs/python22/statements.html"&gt;statements&lt;/a&gt; de expressions, e você só pode ter um statement por linha. Em Python, statements incluem print, if, while, for e atribuições, ou seja, um one-liner só pode usar um único desses.&lt;br /&gt;&lt;br /&gt;Então, colocando a pergunta de outra maneira: é possível demonstrar que um programa em Python com um único statement é &lt;a href="http://en.wikipedia.org/wiki/Turing_completeness"&gt;Turing-complete&lt;/a&gt;? Existem dois caminhos pra demonstrar isso, o primeiro é construir um emulador para uma &lt;a href="http://en.wikipedia.org/wiki/Universal_Turing_machine"&gt;máquina de Turing universal&lt;/a&gt; em uma linha, o segundo é mostrar que é possível converter para uma linha de Python todos os programas possíveis de um sistema que seja Turing-complete, como o &lt;a href="http://en.wikipedia.org/wiki/Lambda_calculus"&gt;cálculo lambda&lt;/a&gt;, ou os &lt;a href="http://en.wikipedia.org/wiki/Tag_system"&gt;tag-systems&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Eu resolvi abordar o problema com a filosofia Ricbit: se existem várias maneiras equivalentes de fazer alguma coisa, escolha a mais bizarra! Assim sendo, vou demonstrar que Python one-liners são Turing-complete através de redução ao &lt;a href="http://en.wikipedia.org/wiki/Brainfuck"&gt;Brainfuck&lt;/a&gt; (cuja universalidade já foi demonstrada &lt;a href="http://www.iwriteiam.nl/Ha_bf_Turing.html"&gt;várias vezes&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Vamos lá então: o estado de um programa em Brainfuck pode descrito em qualquer momento por uma quádrupla (mem, p, stdin, stdout), que são respectivamente a memória, o ponteiro, a entrada e saída. Vou implementar cada operação do Brainfuck como funções que recebem quádruplas e retornam quádruplas, descrevendo assim a transição de estado.&lt;br /&gt;&lt;br /&gt;A operação mais simples é o ponto, que só adiciona o elemento apontado na saída:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/lambda-787583.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 159px; height: 135px;" src="http://www.ricbit.com/uploaded_images/lambda-787577.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;dot = lambda mem, p, stdin, stdout: (mem, p, stdin, stdout+[mem[p]])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para implementar a vírgula, eu preciso primeiro de alguma maneira de modificar um único elemento de uma lista. Se eu pudesse usar atribuições, bastaria algo do tipo mem[p]=value, mas como atribuições em Python são statements, preciso de uma função auxiliar. Além disso, eu preciso fazer o pop() do valor frontal da lista que guarda o stdin, o que me leva à outra auxiliar:&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;change = lambda mem, pos, value: [value if i==pos else a for i, a in enumerate(mem)]&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;&lt;br /&gt;get = lambda s: (s[0], s[1:]) if len(s) else (0,[])&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;comma = lambda mem, p, stdin, stdout: (lambda now, next: (change(mem, p, now), p, next, stdout))(*get(stdin))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Tendo a função change em mãos, fazer os comandos de mais e menos é simples:&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;plus = lambda mem, p, stdin, stdout: (change(mem, p, mem[p]+1), p, stdin, stdout)&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;&lt;br /&gt;minus = lambda mem, p, stdin, stdout: (change(mem, p, mem[p]-1), p, stdin, stdout)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Os comandos de esquerda e direita precisam tomar o cuidado de aumentar os limites da memória se necessário, a universalidade do Brainfuck requer uma fita infinita para os dois lados:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;left = lambda mem, p, stdin, stdout: ([0]+mem if not p else mem, 0 if not p else p-1, stdin, stdout)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;right = lambda mem, p, stdin, stdout: (mem+[0] if p==len(mem)-1 else mem, p+1, stdin, stdout)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/sloth2-792947.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/sloth2-792944.jpg" alt="" border="0" /&gt;&lt;/a&gt;Agora chegamos na parte complicada, que é o operador de loop. Como for e while são statements, e lambdas recursivos precisam de uma atribuição (fat = lambda x: 1 if x&lt;=1 else x*fat(x-1)), então a única saída é apelar pra &lt;a href="http://en.wikipedia.org/wiki/Lazy_evaluation"&gt;lazy evaluation&lt;/a&gt;, que no Python é implementada no módulo &lt;a href="http://docs.python.org/lib/module-itertools.html"&gt;itertools&lt;/a&gt;. (Incluir o módulo itertools poderia tornar o programa um two-liner, mas felizmente é possível importar um módulo usando uma expression ao invés de um statement: a função &lt;a href="http://www.diveintopython.org/functional_programming/dynamic_import.html"&gt;__import__&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;A solução para o operador de loop é criar uma lista infinita contendo [x, f(x), f(f(x)), f(f(f(x))), ...], onde cada f é uma aplicação do conteúdo do loop. Depois, para executar o loop, basta iterar nesta lista infinita, procurando o primeiro elemento onde o elemento apontado pelo ponteiro seja nulo. Precisamos então de uma função que calcule f^n e uma que gere a lista infinita:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;composite = lambda f, n: lambda x: reduce(lambda a, b: b(*a), [f]*n, x)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;infinite = lambda f, x: itertools.imap(lambda n: composite(f, n)(x), itertools.count(0))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Depois, basta criar um &lt;a href="http://en.wikipedia.org/wiki/Predicate_%28mathematics%29"&gt;predicado&lt;/a&gt; que avalie quando o loop deve parar, e pegar o primeiro elemento da lista onde o predicado é verdadeiro:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;predicate = lambda mem, p, stdin, stdout: mem[p] != 0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;getfirst = lambda it: [i for i in itertools.islice(it, 1)][0]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;loop = lambda f: lambda *x: getfirst(itertools.dropwhile(lambda x: predicate(*x), infinite(f,x)))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Tendo todos os comandos, só precisamos de uma função extra para encadeá-los, e depois, só para o programa não ficar grande demais, um shortcut que executa strings diretamente em Brainfuck:&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;br /&gt;chain = lambda f: lambda *x: reduce(lambda y, g: g(*y), f, x)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;bf = {'+':plus, '-':minus, '.':dot, ',':comma, '&amp;lt;':left, '&amp;gt;':right}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;run = lambda f: chain([bf[i] for i in f])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Feito! Agora é só fazer um script para parsear o Brainfuck original e gerar o one-liner. A título de ilustração, esse é o Hello World gerado pelo script:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ricbit.com/uploaded_images/IN495-munch-BST--Scream-1893-742594.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.ricbit.com/uploaded_images/IN495-munch-BST--Scream-1893-742583.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="color: rgb(255, 0, 0);font-size:78%;" &gt;print ''.join(chr(i) for i in ( (lambda itertools: (lambda change, get, chain, composite: (lambda comma, dot, plus, minus, left, right, infinite, predicate, getfirst: (lambda bf, loop: (lambda run: (chain ([run ("++++++++++"), loop (run ("&amp;lt;+++++++&amp;lt;" "++++++++++&amp;lt;" "+++&amp;lt;+&amp;gt;&amp;gt;&amp;gt;&amp;gt;-")), run ("&amp;lt;++.&amp;lt;" "+.+++++++..+++." "&amp;lt;++.&amp;gt;&amp;gt;" "+++++++++++++++" ".&amp;lt;.+++." "------.--------" ".&amp;lt;+.&amp;lt;.")])) ([0],0,[],[]) )( (lambda f: chain([bf[i] for i in f])) ) )( ({'+':plus, '-':minus, '.':dot, ',':comma, '&amp;lt;':left, '&amp;gt;':right}), (lambda f: lambda *x: getfirst(itertools.dropwhile(lambda x: predicate(*x), infinite(f,x)))) ) )( (lambda mem,p,stdin,stdout: (lambda now,next: (change(mem,p,now),p,next,stdout))(*get(stdin))), (lambda mem,p,stdin,stdout: (mem,p,stdin,stdout+[mem[p]])), (lambda mem,p,stdin,stdout: (change(mem,p,mem[p]+1),p,stdin,stdout)), (lambda mem,p,stdin,stdout: (change(mem,p,mem[p]-1),p,stdin,stdout)), (lambda mem,p,stdin,stdout: ([0]+mem if not p else mem, 0 if not p else p-1, stdin, stdout)), (lambda mem,p,stdin,stdout: (mem+[0] if p==len(mem)-1 else mem, p+1, stdin, stdout)), (lambda f,x: itertools.imap(lambda n: composite(f,n)(x), itertools.count(0))), (lambda mem,p,stdin,stdout: mem[p] != 0), (lambda it: [i for i in itertools.islice(it, 1)][0]) ) )( (lambda mem,pos,value: [value if i==pos else a for i,a in enumerate(mem)]), (lambda s: (s[0],s[1:]) if len(s) else (0,[])), (lambda f: lambda *x: reduce(lambda y,g: g(*y), f, x)), (lambda f,n: lambda x: reduce(lambda a,b:b(*a),[f]*n,x)) ) )(__import__("itertools")) )[3])&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;QED, em uma única linha, como prometido! (Eu não prometi que seria uma linha pequena :)&lt;br /&gt;&lt;br /&gt;O script que converte de Brainfuck para Python one-liner está abaixo, para quem quiser brincar:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ricbit.com/code/turing.py"&gt;Conversor para Python one-liner.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Como nota final, vale lembrar que só porque você &lt;span style="font-style: italic;"&gt;pode&lt;/span&gt; escrever qualquer coisa em uma linha, não significa que você &lt;span style="font-style: italic;"&gt;deve&lt;/span&gt; fazer isso. Legibilidade conta :)&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-4036480-1");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6306509703738480474-8407015952004932743?l=www.ricbit.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.ricbit.com/2008/05/python-one-liners-so-turing-complete.html</link><author>noreply@blogger.com (Ricardo Bittencourt)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></item></channel></rss>