function dobro(x)
return x * 2
enddobro (generic function with 1 method)
O objetivo deste capítulo é compreender o conceito de funções em programação e como elas são implementadas em Julia. Vamos explorar como criar nossas próprias funções, como elas podem receber parâmetros e retornar valores, além de introduzir o conceito de recursão.
Na aula anterior, já utilizamos algumas funções predefinidas em Julia. Funções são blocos de código que realizam tarefas específicas e podem ser reutilizados sempre que necessário. Elas nos permitem abstrair operações complexas em comandos simples, tornando o código mais legível e modular.
Vamos relembrar algumas das funções que já utilizamos:
typeof() - Recebe um valor como parâmetro e retorna o seu tipo.div() - Recebe dois números e retorna a divisão inteira do primeiro pelo segundo.print() e println() - Imprimem valores no console, sendo que o segundo adiciona uma quebra de linha após a impressão.Até agora, vimos exemplos de chamadas de funções como sin(0.5) ou sqrt(4). Quando escrevemos o nome da função seguido de parênteses contendo argumentos, estamos “chamando” ou “invocando” essa função.
Mas como essas funções são criadas? Em Julia, podemos declarar nossas próprias funções usando a palavra-chave function:
function dobro(x)
return x * 2
enddobro (generic function with 1 method)
Aqui, dobro é o nome da função, x é um parâmetro (um valor que a função recebe), e return x * 2 especifica o que a função deve calcular e retornar quando chamada. Fornecer parâmetros a uma função é opcional.
Após declarar a função, podemos chamá-la várias vezes com diferentes argumentos:
resultado1 = dobro(5) # Chama a função com o argumento 5
println(resultado1) # Imprime 10
resultado2 = dobro(3.5) # Chama a função com o argumento 3.5
println(resultado2) # Imprime 7.010
7.0
É importante entender a diferença entre declaração e chamada de funções:
Funções como sin(), sqrt() e big() já vêm declaradas em Julia, por isso podemos utilizá-las diretamente.
Uma função pode chamar outra função, permitindo a composição de operações mais complexas:
function imprime(a)
println("Vou imprimir ", a)
end
function imprimeduasvezes(a)
imprime(a)
imprime(a)
endimprimeduasvezes (generic function with 1 method)
Testando nossa nova função:
imprimeduasvezes(13)Vou imprimir 13
Vou imprimir 13
Podemos pedir ajuda ao interpretador para entender melhor como essas funções funcionam. Para isso, usamos o ponto de interrogação ? ou o macro @doc antes do nome da função:
# Exemplos de como acessar a documentação
@doc typeof@doc div@doc printlnAo consultar a documentação, descobrimos que algumas funções como div() podem ser utilizadas com uma sintaxe alternativa, como por exemplo \div. Esse tipo de notação é particularmente útil para operações matemáticas.
Uma categoria importante de funções em Julia são as funções de conversão, que transformam valores de um tipo em outro. Vejamos alguns exemplos:
# Converte uma string para um número em ponto flutuante
parse(Float64, "32")32.0
# Converte um número em ponto flutuante para um inteiro (removendo a parte decimal)
trunc(Int64, 2.25)2
# Converte um inteiro para um número em ponto flutuante
float(2)2.0
# Converte um número para uma string
string(3)"3"
# Converte um número em ponto flutuante para uma string
string(3.57)"3.57"
Julia possui uma grande biblioteca de funções matemáticas prontas para uso. Aqui estão algumas das mais comuns:
| Função | Descrição |
|---|---|
sin(x) |
Calcula o seno de ( x ) em radianos |
cos(x) |
Calcula o cosseno de ( x ) em radianos |
tan(x) |
Calcula a tangente de ( x ) em radianos |
deg2rad(x) |
Converte ( x ) de graus em radianos |
rad2deg(x) |
Converte ( x ) de radianos em graus |
log(x) |
Calcula o logaritmo natural de ( x ) |
log(b, x) |
Calcula o logaritmo de ( x ) na base ( b ) |
log2(x) |
Calcula o logaritmo de ( x ) na base 2 |
log10(x) |
Calcula o logaritmo de ( x ) na base 10 |
exp(x) |
Calcula o expoente da base natural de ( x ) |
abs(x) |
Calcula o valor absoluto de ( x ) |
sqrt(x) |
Calcula a raiz quadrada de ( x ) |
cbrt(x) |
Calcula a raiz cúbica de ( x ) |
factorial(x) |
Calcula o fatorial de ( x ) |
Uma boa prática para se familiarizar com essas funções é experimentá-las com diferentes valores e verificar os resultados. Para funções mais complexas, é possível que já existam implementações prontas em Julia. Uma dica útil é pesquisar na internet usando palavras-chave como “julia lang hiperbolic sin” para encontrar a função desejada. Em geral, pesquisar em inglês tende a produzir melhores resultados.
Em Julia, podemos ter funções com o mesmo nome, mas com diferentes números ou tipos de parâmetros. Isso é chamado de “sobrecarga de funções”:
function recebe(a)
println("Recebi um parâmetro: ", a)
end
function recebe(a, b)
println("Recebi dois parâmetros: ", a, " e ", b)
endrecebe (generic function with 2 methods)
O interpretador decide qual versão da função chamar com base nos argumentos fornecidos:
recebe(1)Recebi um parâmetro: 1
recebe(1, 2)Recebi dois parâmetros: 1 e 2
Também podemos chamar funções usando variáveis e expressões como argumentos:
a = 10
recebe(a)
recebe(a, a + 1)Recebi um parâmetro: 10
Recebi dois parâmetros: 10 e 11
Até agora, vimos funções que apenas imprimem mensagens, mas não devolvem nenhum valor. O tipo de retorno dessas funções é Nothing, indicando que elas não produzem um valor que possa ser atribuído a uma variável.
No entanto, frequentemente queremos que nossas funções calculem e retornem valores. Para isso, usamos a palavra-chave return:
function soma1(a)
return a + 1
endsoma1 (generic function with 1 method)
Agora podemos usar essa função em expressões e atribuições:
resultado = soma1(5)
println("O resultado é: ", resultado)O resultado é: 6
# Também podemos usar o resultado em outras expressões
println("Resultado multiplicado por 2: ", soma1(5) * 2)Resultado multiplicado por 2: 12
Podemos criar funções para cálculos mais complexos:
function hipotenusa(a, b)
hip = sqrt(a^2 + b^2)
return hip
endhipotenusa (generic function with 1 method)
Testando nossa função:
# Calculando a hipotenusa de um triângulo 3-4-5
hipotenusa(3, 4)5.0
Agora vamos explorar um conceito fundamental em programação: a recursão. Uma função recursiva é aquela que chama a si mesma como parte de sua execução. Isso pode parecer estranho à primeira vista, mas é uma técnica poderosa para resolver certos tipos de problemas.
Vamos começar com um exemplo simples: calcular o fatorial de um número. O fatorial de \(n\) (representado por \(n!\)) é o produto de todos os inteiros positivos menores ou iguais a \(n\). Por exemplo, \(5! = 5 \times 4 \times 3 \times 2 \times 1 = 120\).
O fatorial pode ser definido recursivamente como:
Vamos implementar isso em Julia:
function fatorial(n)
if n == 0
return 1 # Caso base
else
return n * fatorial(n - 1) # Chamada recursiva
end
endfatorial (generic function with 1 method)
Testando nossa função:
fatorial(5)120
Para entender como a recursão funciona, vamos acompanhar passo a passo o cálculo de fatorial(3):
fatorial(3)
return 3 * fatorial(2)fatorial(2)
return 2 * fatorial(1)fatorial(1)
return 1 * fatorial(0)fatorial(0)
fatorial(1) = \(1 \times 1 = 1\)fatorial(2) = \(2 \times 1 = 2\)fatorial(3) = \(3 \times 2 = 6\)A recursão tem duas partes fundamentais:
É necessário que a recursão sempre alcance o caso base, caso contrário, a função continuará chamando a si mesma indefinidamente, causando um erro de estouro de pilha (stack overflow).
Vamos implementar uma função recursiva para contagem regressiva:
function contagem(n)
if n < 0
println("Fim!")
else
print(n, " ")
contagem(n - 1)
end
endcontagem (generic function with 1 method)
Testando nossa função:
contagem(5)5 4 3 2 1 0 Fim!
Podemos também usar recursão para calcular a soma dos primeiros \(n\) números inteiros:
function soma(n)
if n == 0
return 0 # Caso base
else
return n + soma(n - 1) # Caso recursivo
end
endsoma (generic function with 1 method)
Testando nossa função:
soma(10)55
Outro exemplo interessante é o cálculo da soma dos termos da série harmônica:
function somaharmonica(atual, n)
# Caso base: quando chegamos ao último termo
if atual > n
return 0.0
else
# Caso recursivo: somamos o termo atual e chamamos a função para o próximo termo
return 1.0 / atual + somaharmonica(atual + 1, n)
end
endsomaharmonica (generic function with 1 method)
Vamos calcular a soma dos 10 primeiros termos da série harmônica:
somaharmonica(1, 10)2.9289682539682538
...).