Skip to content


Analisando Número de Fibonacci e Recursividade

O número de Fibonacci é bem conhecido no mundo da computação. Ele é representado por uma função recursiva:
Fibonacci e Proporção áurea

Calculando

Tendo isso em mente é bem fácil criar um algoritmo que calcule o número de Fibonacci, certo?
Na internet normalmente encontramos um algoritmo usando um método de recursão simples. Algo parecido com:

Felipe: Esse artigo usa apenas exemplos em C++

fibo1.cpp

#include <iostream>
#include <cstdlib>
 
int F(int n)
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    return F(n - 1) + F(n - 2);
}
 
int main(int argc, char *argv[])
{
    int n = atoi(argv[1]);
    std::cout << F(n) << std::endl;
    return 0;
}

código no pastebin

Compilando:

g++ -o fibo1 fibo1.cpp

Rodando:

./fibo1 8

Deu 21, certo? Isso mesmo.

Analisando a Função

Mas digo para você: Não use esse programa! É totalmente ineficiente. O número de chamadas para calcular F_{N} é exatamente F_{N+1}. A função calcula recursivamente o mesmo número quantas vezes a chamar. Como podemos ver, a taxa de crescimento do número de Fibonacci tende a Proporção áurea:
Fibonacci e Proporção áurea

Lembrando que a razão áurea é definida por:
Razão áurea

Sim, fibo1.cpp é uma função exponencial com Big Theta Notation, em função do tempo, de:
Big Theta Notation 1

O tempo de execução para computar F_{N+1} é \phi \approx 1,6 vezes mais demorado que para calcular F_{N}. Por exemplo, já que \phi^{9} > 60 e percebemos que nosso computador leva um segundo para calcular F_{N}, então levará mais de um minuto para calcular F_{N+9} e mais de uma hora para calcular F_{N+18}.

Podemos verificar isso calculando F_{36} e F_{45}

pet@felipe-opensuse:~/Projetos/C++/algoritmos> time ./fibo1 36
14930352

real 0m1.077s
user 0m1.040s
sys 0m0.008s
pet@felipe-opensuse:~/Projetos/C++/algoritmos> time ./fibo1 45
1134903170

real 0m54.927s
user 0m54.547s
sys 0m0.092s

Em contraste, usando o método de programação dinâmica temos um tempo proporcional a N.

Programação dinâmica

Esse método consiste em guardar os valores dos números já calculados em um array. Fazendo isso, apenas checamos se o array já foi memorizado, e então retornamos o número, caso contrário calculamos recursivamente e assim por diante.
Lembrando que para um int de 32 bits, F_{46} = 1836311903 será o maior numero a ser calculado.

fibo2.cpp

#include <iostream>
#include <cstdlib>
 
namespace Fibonacci {
    int *memory;
    int F(int n)
    {
        // int inicializa como 0
        if (memory[n] != 0) return memory[n];
        int aux = n;
        if (n < 0) return 0;
        if (n > 1) aux = F(n-1) + F(n-2);
        return memory[n] = aux;
    }
}
 
int main(int argc, char *argv[])
{
    int n = atoi(argv[1]);
    Fibonacci::memory = new int[n+1];
    std::cout << Fibonacci::F(n) << std::endl;
    delete [] Fibonacci::memory;
    return 0;
}

código no pastebin

Compilando:

g++ -o fibo2 fibo2.cpp

Rodando:

./fibo2 8

Deu 21, de novo? =)

Aplicamos aqui uma técnica chamada bottom-up dynamic programming. Se aplica em uma função recursiva que podemos salvar tempo por armazenar valores anteriores que serão usados depois. Essa técnica tem sido usada para uma gama grande de algoritmos e aplicações. E essa simples mudança fez com que nosso algoritmo passasse de exponencial para linear.

Agora temos uma função, em relação ao tempo, proporcional ao N.
Big Theta Notation 2

Comparando

Fazendo vários testes, podemos chegar em uma tabela de resultados, em função do tempo:

arquivo F_{8} F_{36} F_{45} F_{46}
fibo1.cpp 0m0.009s 0m1.156s 0m54.927s 1m29.403s
fibo2.cpp 0m0.007s 0m0.007s 0m0.006s 0m0.007s

fibo2.cpp é constante? Sim! Para N relativamente pequeno fibo2.cpp calcula em tempo constante.

Será interessante ver até quanto esse algoritmo agüenta(ta errado né? hehe ¬¬) fazer em tempo constante. Alguém se habilita?

Posted in Algoritmos, Artigos, C++, Matemática. Tagged with , , .

ack, um grep melhorado

Se você é fan do grep(especialmente com o -drecurse), mas sempre vendo o .svn ou outro diretório irritante, você precisa do ack.

Descobri esse programinha num blog do KDE e gostei muito!

Algumas coisas legais:

  • output bonitinho(colorido)
  • highlight
  • boa organização
  • fácil configuração
  • e até mesmo documentação

Digitar menos, o que você quer mais?

Exemplo:

ack in action

Posted in Linux, Software.

Josephus Problem, resolvendo-o de maneira simples

Josephus Problem é um problema bem legal que estudei no livro Concrete Mathematics.

Josephus foi um historiador judeu do primeiro século. A lenda conta que ele e 40 de seus homens estavam presos em uma caverna pelos Romanos. Eles decidiram suicidar-se à ser capturados. Formaram um circulo e começaram a se matar, da 3ª à 3ªa pessoa em ordem da fila. Como Josephus não queria morrer, ele foi capaz de escolher o melhor lugar, afim de sobreviver, e juntar-se os Romanos que o capturaram.

O Problema

Na prática o problema teria N pessoas em um círculo, iria ser percorrido M - 1 pessoas e o M iria ser morto, assim por diante, até sobrar uma única pessoa.

A Solução

Podemos representar a solução por uma função recursiva, para N par e M = 2:

e para N ímpar e M = 2, temos:

Não vou postar a solução genérica aqui pois exige uma grande explicação e esse não é o objetivo do post. Você pode ver na wikipedia ou então comprar o livro, caso queria saber mais.

O interessante é que o algoritmo para solução genérica é bem simples em C++. Usando listas ligadas(linked lists) é simples, fácil de entender e super rápido a execução do programa.

Josephus.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <cstdlib>
 
struct Pessoa {
	int num;
	Pessoa *prox;
	Pessoa(int x, Pessoa *p) {
		num = x;
		prox = p;
	}
};
 
int main(int argc, char *argv[]) {
	//'a' recebe primeira pessoa criada
	//e 'a' é linkado para si mesmo
	//depois 'b' é criado apontado para 'a'
	int N = atoi(argv[1]), M = atoi(argv[2]);
	Pessoa *a = new Pessoa(1, 0);
	a->prox = a;
	Pessoa *b = a;
 
	// Aloca na memória todas as pessoas
	// e 'b' recebe a última(enésima pessoa)
	// pois a contagem começa pela primeira('a')
	for (int i = 2; i <= N; ++i)
		b = (b->prox = new Pessoa(i, a));
 
	// Loop enquanto 'b' não estiver apontado
	// o próximo para ele mesmo
	while (b != b->prox) {
		// 'b' recebe a emésima pessoa
		for (int i = 1; i < M; ++i)
			b = b->prox;
		a = b->prox;
		b->prox = a->prox;
		delete a; // 'a' é morto =/
	}
 
	// O sobrevivente _o/
	std::cout << b->num << std::endl;
}

Ou então se preferir um link para o pastebin.

Analisando o Resultado

após compilar

g++ -o Josephus Josephus.cpp

rode o programa com N = 10 e M = 2

./Josephus 10 2

O valor deu 5? Verifique com a função. Bateu os valores?
Agora vá testando para 1 <= N <= 16 e M = 2.

for n in `seq 16`; do echo -n “$n: “; ./Josephus $n 2; done

Saída do loop:

1: 1
2: 1
3: 3
4: 1
5: 3
6: 5
7: 7
8: 1
9: 3
10: 5
11: 7
12: 9
13: 11
14: 13
15: 15
16: 1

Perceberam um certo padrão entre as respostas? A função genérica usa justamente esse padrão binário para solução.

Ultimamente eu estou mais dedicado ao estudo de algoritmos, C++, C e Python(é claro). Depois pretendo postar uma analise desse algoritmo passo a passo.

Posted in Algoritmos, Artigos, C++, Eventos, Matemática. Tagged with , , .

Voltando com TUDO!

Eu fiquei um bom tempo sem postar nada aqui, sem escrever nenhum tutorial ou artigo. Não posso mentir e dizer que estava ocupado, mas realmente fiquei com um poco de preguiça. Agora nas férias o projeto RobotQt voltará com tudo! Até criei uma página no Ohloh para o projeto para quem quiser acompanhar mais de perto o projeto. Também organizei todas minhas to-do’s list. Como:

  • Atualizar plugin wp-catshow
  • Criar plugin wp-fileupload(novidade :) )
  • Atualizar mais o blog com artigos e tutoriais hehe
  • Contribuir para o KDE4
  • Continuar ferozmente meus estudos de algoritmos

Agora bola pra frente e vamos lá!

Posted in Diversos.

PyConBrasil 2008 lá vou eu!

Galera, é com muita alegria que estou postando novamente aqui.

Primeiramente gostaria de dizer que mudei de trabalho. Estou trabalhando remotamente, em casa, para uma empresa canadense de Open Source e Linux chamada Savoir-faire Linux! Uma maravilha hehehehe

Segundo, é que voltei a trabalhar com coisas que gosto, como Python, C++ e KDE4.

Portanto estarei indo para a PyConBrasil 2008, que vai ser no Rio de Janeiro.

Nós da GruPy-SP estamos tentando fazer algum arranjo para ir de onibus fretado e ficar num hotel por lá, vai ser super legal!

E você, vai?

Posted in Eventos, Python. Tagged with , .

Ajude a sustentar a Wikipédia e outros projetos, sem colocar a mão no bolso, e concorra a um Eee PC!

Ajude a sustentar a Wikipédia e outros projetos, sem colocar a mão no bolso, e concorra a um Eee PC!
…e também a pen drives, card drives, camisetas geeks, livros e mais! O BR-Linux e o Efetividade lançaram uma campanha para ajudar a Wikimedia Foundation e outros mantenedores de projetos que usamos no dia-a-dia on-line. Se você puder doar diretamente, ou contribuir de outra forma, são sempre melhores opções. Mas se não puder, veja as regras da promoção e participe - quanto mais divulgação, maior será a doação do BR-Linux e do Efetividade, e você ainda concorre a diversos brindes!

Brinder Br-Linux e Efetividade.net

Brinder Br-Linux e Efetividade.net

Posted in Diversos, Linux.

Nóis é muito burro!

Esse é meio que um desabafo e engraçado ao mesmo tempo ;)

A história começa quando vim para o Canadá para trabalhar com Java e no fim das contas comecei a trabalhar com ASP.NET. Eu não tenho nada contra ASP.NET, pelo contrário, é uma ótima tecnologia.
Mas o problema é que aqui na empresa onde trabalho, eles não utilizam meu potencial(não que eu tenha muito). Aqui eu fico arrumando layout e controller ASP.NET, tabulando, fazendo relatórios e assim por diante. PELO AMOR NÉ?
E eu percebi que estava enferrujando em programação, prática e inclusive meu conhecimento.

Mas tudo bem. 5 Meses passaram…

Quando eu e o Luiz Vitor estavamos resolvendo o exercício do Alien Numbers (Google Code Jam 2007). E depois de 5 horas conseguimos hehe aquela alegria!!!

from __future__ import alien_number

Aí começamos a fazer do Maze(Labirinto). Tentamos, tentamos, tentamos e aí não deu mais tempo porque comecou o Google Code Jam 2008.

Os 2 primeiros exercícios da primeira fase eram fáceis. Um era sobre serach engine e outro era de esquema de trens. Não era necessários algoritmos complexos para resolver, apenas lógica.
Aí tudo bem, comecei a fazer o primeiro. Depois de uns 15 minutos entendi o que era para fazer e fui jantar. Jantando fui pensando o que iria fazer para resolver o problema. E tinha chegado numa conclusão simples.
Cheguei no meu computador e fui começar meu código. Em 30 min +- mandei minha versão e bééééééé: ERRADO. Aí fui repensar e vi o que estava errado e mandei de novo: bééééééé.
Aí comecei a ficar encucado. E em quanto isso o Bruno Gola e Lameiro já tinham resolvido. E eu e o Luiz nos elogiando: “Cara, nós somos muito burros!!!! hahahah” “Eu sou uma porta, pelo amor!!!”

Hoje comecei o exercício dos treins. Mais fácil do que o primeiro. Entendi a lógica, comecei a codar. E NADA hehehe Fiz um monte de coisa, vários davam certo mas uns davam errado e percebi de novo que era erro de código. Aí agora desisti já, nóis é muito burro e ano que vêm estamos aí. Só agora vou estudar muito! Comprei uns livros feras d+ de algoritmos, que por sinal recomendo a todos que querem ser bons programadores!

Mas falando a verdade, o Bruno Gola e o Lameiro e inclusive o Luiz são muito bons, muito melhor que eu. Mas eu fiquei injuriado pelo fato de eu não ter conseguido CODAR esses problemas, que estavam resolvidos na minha cabeça.

E agora a moral da história, voltando ao começo do post.

Nunca, mas NUNCA, vá trabalhar em um lugar(ou o que seja) onde não te estimulem e exija seu potencial! NUNCA

Poison

Sinceramente, se eu não tivesse para mudar de empresa agora no final do mês, eu largava tudo aqui, tudo mesmo. E voltava para o Brasil.
Prefiro ser pobre, morar num lugar onde a política é sinônimo de palhaçada, ao que desaprender tudo e ser um inútil.

Posted in Artigos.