Você está na página 1de 4

MAC2166 – Turma 04 (semana de 23 a 27 de março de 2020)

Professor: Flávio Soares Corrêa da Silva (fcs@ime.usp.br)

Resolveremos um exercício de duas maneiras diferentes. O objetivo será apresentar o conceito


de funções auxiliares construídas pelo próprio programador e, na segunda maneira de resolver
o exercício, incluir em nossa galeria de conceitos a eficiência computacional de programas.
Este conceito será tratado, mesmo que de forma introdutória, de maneira mais completa ao
longo do semestre.

O exercício que resolveremos será o seguinte: dados dois números naturais 𝑁𝑁 e 𝑀𝑀, 𝑁𝑁 ≥ 𝑀𝑀,
𝑁𝑁 𝑁𝑁!
calcular a combinação simples � � = 𝑀𝑀!(𝑁𝑁−𝑀𝑀)!
𝑀𝑀
Esta fórmula da combinação simples contém diversas repetições da função fatorial. Se
tivéssemos, em Python, um operador pronto para o fatorial, o programa ficaria muito simples
de construir:
def main():
N = int(input(“N: “))
M = int(input(“M: “))
C = fatorial(N)//(fatorial(M)*fatorial(N-M))
print(C)
Na verdade, conforme veremos posteriormente, existe um pacote em Python com funções
matemáticas diversas, inclusive fatorial, que poderia ser utilizado aqui. Bastaria “importar”
este pacote e utilizar o nome e parâmetros apropriados para construir um programa como o
indicado acima.

Entretanto, “faremos de conta” que esta função e este pacote não existem. Em vez disso,
construiremos uma função auxiliar dentro do próprio programa, e a utilizaremos em seguida.

Nosso problema, portanto, passou a ser a construção da função fatorial. Para isso, utilizaremos
a definição de fatorial de números naturais:

• 0! = 1
• 𝑁𝑁! = 𝑁𝑁 ∗ (𝑁𝑁 − 1)!
Este programa poderia ser assim:
def main():
N = int(input(“N: “))
F = 1
Mult = N
while Mult > 0:
F = F * Mult
Mult = Mult - 1
print(F)
O mesmo programa pode ser reescrito, agora, para usar uma função auxiliar com um
parâmetro de entrada e uma resposta escalar como saída:
def main():
N = int(input(“N: “))
F = fatorial(N)
print(F)
Para que o programa funcione, entretanto, ele precisa ser complementado pela função auxiliar
propriamente dita:
def fatorial(valor):
fat = 1
m = valor
while m > 0:
fat = fat * m
m = m – 1
return fat
Ou seja, nosso arquivo agora contém duas funções: uma que se chama main, não aceita
parâmetros externos nem devolve uma resposta, e uma segunda função que se chama fatorial,
a qual recebe um parâmetro (que assume-se que seja um número natural) e devolve, como
resposta, um valor (que também será um número natural).

Funções em Python são, portanto, “mini programas” que podem receber um ou mais
parâmetros e devolver, como resposta, um valor ou uma lista de valores. Listas de valores
como resposta serão detalhadas posteriormente, quando soubermos lidar com valores
compostos em nossos programas e em nossa linguagem Python. Por enquanto, restringiremos
nossos exemplos e exercícios para que as funções devolvam nenhum ou no máximo um valor
como resposta.

Sabendo construir a função fatorial conforme visto acima, podemos combinar esta função com
o programa inicial visto nesta aula e produzir um programa para calcular combinações:
def main():
N = int(input(“N: “))
M = int(input(“M: “))
C = fatorial(N)//(fatorial(M)*fatorial(N-M))
print(C)
def fatorial(valor):
fat = 1
m = valor
while m > 0:
fat = fat * m
m = m – 1
return fat
Este programa está correto, ou seja, sempre que ele receber como dados de entrada valores
que obedeçam às restrições consideradas, ele produzirá a resposta correta esperada.
Entretanto, ele é ineficiente, pois efetua operações desnecessárias que podem levar ao
consumo exagerado de recursos computacionais. Para verificar o motivo da ineficiência,
podemos “simular manualmente” a execução do programa e pensar como faríamos “à mão”
as contas se N = 1000 e M = 999.

Como poderíamos melhorar este programa de forma que ele continuasse correto, mas se
tornasse mais eficiente?

Uma possibilidade é obrigar o programa a efetuar contas como efetuamos “à mão”. Para isso,
podemos criar uma versão ligeiramente generalizada da função fatorial:
def fatorial_gen(valor_de, valor_ate):
fat_gen = 1
m = valor_de
while m > valor_ate:
fat_gen = fat_gen * m
m = m – 1
return fat_gen
Esta função calcula um “fatorial parcial”, do valor inicial valor_de até o valor final valor_ate,
supondo que estes dois valores sejam números naturais e que valor_de ≥ valor_ate. Observe
que, se valor_ate == 0, esta função ficará similar à função fatorial original. Portanto, esta
função é uma generalização da função original, pois a função original é um caso particular
dela.

Para completar, podemos criar duas funções que recebam como parâmetros dois números e
devolvam, respectivamente, o máximo e o mínimo entre estes dois valores:
def maximo(v1, v2):
if v1 >= v2:
resp = v1
else:
resp = v2
return resp
def minimo(v1, v2):
if v1 <= v2:
resp = v1
else:
resp = v2
return resp
Com estas funções à nossa disposição, podemos construir a última versão de hoje para o
programa que calcula combinações:
def main():
N = int(input(“N: “))
M = int(input(“M: “))
C = combinacao(N, M)
print(C)
def combinacao(a, b):
C = fatorial_gen(a, maximo(b, a-b))//fatorial_gen(minimo(b, a-b), 0)
return C
def fatorial_gen(valor_de, valor_ate):
fat_gen = 1
m = valor_de
while m > valor_ate:
fat_gen = fat_gen * m
m = m – 1
return fat_gen
def maximo(v1, v2):
if v1 >= v2:
resp = v1
else:
resp = v2
return resp
def minimo(v1, v2):
if v1 <= v2:
resp = v1
else:
resp = v2
return resp
Analise este programa cuidadosamente, “simule manualmente” todos os estados
intermediários das variáveis do programa, compare com a simulação do programa anterior e
verifique se, de fato, o programa elimina operações desnecessárias efetuadas pela versão
anterior. Considere, por outro lado, a complexidade adicional que foi necessária para obter
este comportamento do programa.

Existe um ponto de equilíbrio entre a eficiência e a legibilidade de um programa. Este ponto de


equilíbrio varia caso a caso, dependendo do uso previsto para o programa, dos computadores
disponíveis, da quantidade de recursos computacionais necessária para resolver um problema
e da frequência de atualizações requeridas para o programa. À medida que avançarmos na
disciplina, voltaremos a tratar destas questões.

Você também pode gostar