Até agora, vimos que o computador é muito bom para fazer cálculos e repetições. Fizemos essas repetições com funções recursivas, que chamam a si mesmas para resolver problemas menores. Agora vamos ver uma forma alternativa de repetir: a abordagem iterativa.
Introdução ao while¶
A estrutura while é uma das formas mais básicas de criar laços (em inglês, loops) em programação. Ela permite repetir um bloco de código enquanto uma condição for verdadeira. A sintaxe básica do while em Julia é:
while condição
# Bloco de código a ser repetido
endO funcionamento do while segue estes passos:
A condição é avaliada
Se a condição for verdadeira, o bloco de código é executado
Após a execução do bloco, a condição é avaliada novamente
Este ciclo continua até que a condição se torne falsa
É importante lembrar que, para evitar um loop infinito (um laço que nunca termina), algo relacionado à condição precisa mudar dentro do bloco de código.
Vamos começar com um exemplo simples: contagem regressiva.
function contagem_regressiva(n)
while n > 0
println(n)
n = n - 1 # Esta linha é essencial para evitar um loop infinito
end
println("Fim!")
end
contagem_regressiva(5)5
4
3
2
1
Fim!
Neste exemplo, a condição n > 0 é inicialmente verdadeira (assumindo que n começa com um valor positivo). O bloco de código imprime o valor atual de n e, em seguida, decrementa n em 1. Eventualmente, n chegará a zero, tornando a condição falsa e encerrando o loop.
Comparando Recursão e Iteração¶
Para entender melhor a diferença entre recursão e iteração, vamos reescrever algumas funções que implementamos anteriormente usando recursão.
Contagem Regressiva¶
Primeiro, vamos relembrar a versão recursiva da contagem regressiva:
function contagem_recursiva(n)
if n <= 0
println("Fim!")
else
println(n)
contagem_recursiva(n - 1)
end
end
contagem_recursiva(5)5
4
3
2
1
Fim!
Comparando as duas implementações, podemos observar que:
Na versão recursiva, o caso base (
n <= 0) corresponde à condição de parada dowhileA chamada recursiva com
n - 1corresponde à atualização dennowhile
Ambas as versões produzem o mesmo resultado, mas com abordagens diferentes.
Soma dos Primeiros N Números¶
Vamos implementar uma função que calcula a soma dos primeiros n números inteiros positivos (1 + 2 + ... + n), usando tanto recursão quanto while.
Versão recursiva:
function soma_recursiva(n)
if n <= 0
return 0
else
return n + soma_recursiva(n - 1)
end
end
println("Soma dos primeiros 5 números (recursiva): ", soma_recursiva(5))Soma dos primeiros 5 números (recursiva): 15
Versão com while:
function soma_while(n)
soma = 0
i = 1
while i <= n
soma = soma + i
i = i + 1
end
return soma
end
println("Soma dos primeiros 5 números (while): ", soma_while(5))Soma dos primeiros 5 números (while): 15
Na versão recursiva, temos um caso base explícito (n <= 0) e uma chamada recursiva que reduz o problema. Na versão com while, utilizamos uma variável de controle i que é incrementada a cada iteração, e uma variável acumuladora soma que armazena o resultado parcial.
Calculando Séries Matemáticas¶
As estruturas de repetição são especialmente úteis para calcular somas de séries matemáticas. Vamos implementar uma função para calcular a aproximação do seno usando a série de Taylor:
Esta série pode ser representada como:
Implementação usando while:
function sin_taylor(x, termos = 10)
resultado = 0.0
termo = x
i = 0
while i < termos
# Adicionamos o termo atual à soma
resultado = resultado + termo
# Calculamos o próximo termo
i = i + 1
termo = -termo * x * x / ((2 * i) * (2 * i + 1))
end
return resultado
end
# Teste com π/6 (30 graus), cujo seno é 0.5
println("sin(π/6) ≈ ", sin_taylor(π/6))
println("sin(π/6) exato: ", sin(π/6))sin(π/6) ≈ 0.49999999999999994
sin(π/6) exato: 0.49999999999999994
Note que o while permite controlar com precisão o número de termos da série que queremos calcular.
Vamos comparar com uma implementação recursiva:
function sin_taylor_recursivo(x, i = 0, termos = 10, termo = x, resultado = 0.0)
if i >= termos
return resultado
else
# Adicionamos o termo atual à soma
novo_resultado = resultado + termo
# Calculamos o próximo termo
novo_i = i + 1
novo_termo = -termo * x * x / ((2 * novo_i) * (2 * novo_i + 1))
return sin_taylor_recursivo(x, novo_i, termos, novo_termo, novo_resultado)
end
end
println("sin(π/6) recursivo ≈ ", sin_taylor_recursivo(π/6))sin(π/6) recursivo ≈ 0.49999999999999994
A versão recursiva é mais complexa, pois precisamos passar vários parâmetros extras para manter o estado entre as chamadas. A versão com while é mais clara e direta neste caso.
Quando Usar Recursão e Iteração?¶
Tanto a recursão quanto a iteração podem ser usadas para resolver problemas de repetição, cada uma com seus pontos fortes:
Vantagens da iteração
Geralmente mais eficiente em termos de memória
Evita o risco de estouro de pilha para entradas grandes
Pode ser mais intuitivo para operações de repetição simples
Permite um controle mais detalhado sobre o processo de iteração
Vantagens da recursão
Frequentemente mais elegante para problemas que se decompõem naturalmente
Pode tornar o código mais conciso e legível para certos algoritmos
Reflete diretamente definições matemáticas recursivas
Particularmente útil para estruturas de dados hierárquicas
Uma regra prática é:
Use iteração quando precisar repetir uma operação um número fixo ou indeterminado de vezes
Use recursão quando o problema puder ser naturalmente dividido em subproblemas menores do mesmo tipo
Verifique seu Aprendizado¶
Qual é a diferença entre usar recursão e iteração para repetições?
Implemente uma função que conte o número de dígitos em um número inteiro usando a estrutura
while.Dado um número inteiro, escreva uma função que inverta seus dígitos (por exemplo, 123 se tornaria 321).
Explore por Conta Própria¶
Pesquise sobre otimização de laços (loop unrolling) e tente aplicar esse conceito em uma função com
while.